rich_sdl2_rust/audio/
buffer.rs1use std::{mem::MaybeUninit, os::raw::c_int};
5
6use super::format::AudioFormat;
7use crate::{
8 bind::{self, SDL_MixAudioFormat},
9 Result, Sdl, SdlError,
10};
11
12#[derive(Debug, Clone)]
14pub struct AudioBuffer<T> {
15 format: AudioFormat,
16 samples: u32,
17 channels: u8,
18 buffer: Vec<T>,
19}
20
21impl<T> AudioBuffer<T> {
22 #[must_use]
29 pub fn new(format: AudioFormat, samples: u32, channels: u8, buffer: Vec<T>) -> Self {
30 assert_eq!(format.bit_size as usize, std::mem::size_of::<T>() * 8);
31 Self {
32 format,
33 samples,
34 channels,
35 buffer,
36 }
37 }
38
39 pub fn format(&self) -> &AudioFormat {
41 &self.format
42 }
43
44 #[must_use]
46 pub fn samples(&self) -> u32 {
47 self.samples
48 }
49
50 #[must_use]
52 pub fn channels(&self) -> u8 {
53 self.channels
54 }
55
56 pub fn convert<U: Default + Clone>(
62 self,
63 format: AudioFormat,
64 samples: u32,
65 channels: u8,
66 ) -> Result<AudioBuffer<U>> {
67 let mut dst = AudioBuffer::<U> {
68 format,
69 samples,
70 channels,
71 buffer: vec![],
72 };
73 self.convert_in(&mut dst)?;
74 Ok(dst)
75 }
76
77 pub fn convert_in<U: Default + Clone>(self, other: &mut AudioBuffer<U>) -> Result<()> {
83 let mut cvt = MaybeUninit::uninit();
84 let ret = unsafe {
85 bind::SDL_BuildAudioCVT(
86 cvt.as_mut_ptr(),
87 self.format.as_raw(),
88 self.channels,
89 self.samples as c_int,
90 other.format.as_raw(),
91 other.channels,
92 other.samples as c_int,
93 )
94 };
95 if ret == 0 {
96 return Err(SdlError::UnsupportedFeature);
97 }
98 if ret < 0 {
99 return Err(SdlError::Others { msg: Sdl::error() });
100 }
101 let mut cvt = unsafe { cvt.assume_init() };
102 if cvt.needed == 0 {
103 return Err(SdlError::UnsupportedFeature);
104 }
105 let len = self.samples as usize * self.channels as usize * std::mem::size_of::<T>();
106 cvt.len = len as c_int;
107 other.buffer.clear();
108 other
109 .buffer
110 .resize(len * cvt.len_mult as usize, U::default());
111 cvt.buf = as_u8_slice_mut(&mut other.buffer).as_mut_ptr();
112 let ret = unsafe { bind::SDL_ConvertAudio(&mut cvt) };
113 if ret < 0 {
114 Err(SdlError::Others { msg: Sdl::error() })
115 } else {
116 Ok(())
117 }
118 }
119}
120
121impl<T: Default + Clone> AudioBuffer<T> {
122 #[must_use]
126 pub fn mix(&self, volume: u8) -> Self {
127 let mut dst = self.clone();
128 self.mix_in(&mut dst, volume).unwrap();
129 dst
130 }
131
132 pub fn mix_in(&self, dst: &mut Self, volume: u8) -> Result<()> {
140 if self.format.as_raw() != dst.format.as_raw() {
141 return Err(SdlError::Others {
142 msg: "Cannot mix in buffers which have different format".into(),
143 });
144 }
145 dst.buffer.clear();
146 dst.buffer.resize(self.buffer.len(), T::default());
147 let len = self.buffer.len() * std::mem::size_of::<T>();
148 unsafe {
149 bind::SDL_MixAudioFormat(
150 as_u8_slice_mut(&mut dst.buffer).as_mut_ptr().cast(),
151 as_u8_slice(&self.buffer).as_ptr().cast(),
152 self.format.as_raw(),
153 len as u32,
154 volume.min(bind::SDL_MIX_MAXVOLUME as u8) as c_int,
155 );
156 }
157 Ok(())
158 }
159}
160
161fn as_u8_slice<T>(slice: &[T]) -> &[u8] {
162 let size = std::mem::size_of::<T>();
163 unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), std::mem::size_of_val(slice)) }
164}
165
166fn as_u8_slice_mut<T>(slice: &mut [T]) -> &mut [u8] {
167 let size = std::mem::size_of::<T>();
168 unsafe {
169 std::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), std::mem::size_of_val(slice))
170 }
171}