rich_sdl2_rust/audio/
buffer.rs

1//! An audio buffer `AudioBuffer<T>` with a format, sample rates, numbers of channels and a buffer.
2//! It can be convert into another format and mix by the specified volume.
3
4use 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/// An audio buffer with a format, sample rates, numbers of channels and a buffer.
13#[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    /// Constructs an audio buffer from arguments.
23    /// The size of type which stored by buffer must equal to the format bit size.
24    ///
25    /// # Panics
26    ///
27    /// Panics if the size of type `T` does not equal to the format bit size.
28    #[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    /// Returns the format of the audio buffer.
40    pub fn format(&self) -> &AudioFormat {
41        &self.format
42    }
43
44    /// Returns the sample rates of the audio buffer.
45    #[must_use]
46    pub fn samples(&self) -> u32 {
47        self.samples
48    }
49
50    /// Returns the numbers of channels of the audio buffer.
51    #[must_use]
52    pub fn channels(&self) -> u8 {
53        self.channels
54    }
55
56    /// Convert into another `AudioBuffer` with different format, sample rate or channels.
57    ///
58    /// # Errors
59    ///
60    /// Returns `Err` if failed to convert into a specific format.
61    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    /// Convert and write into another existing `AudioBuffer`.
78    ///
79    /// # Errors
80    ///
81    /// Returns `Err` if failed to convert between `self` and `other`.
82    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    /// Mix into another `AudioBuffer` with the specified `volume`.
123    ///
124    /// The max value of `volume` is `128`, saturating if it is over the max.
125    #[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    /// Mix into another existing `AudioBuffer` with the specified `volume`.
133    ///
134    /// The max value of `volume` is `128`, saturating if it is over the max.
135    ///
136    /// # Errors
137    ///
138    /// Return `Err` if the formats of `self` and `dst` are different.
139    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}