1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//! An audio buffer `AudioBuffer<T>` with a format, sample rates, numbers of channels and a buffer.
//! It can be convert into another format and mix by the specified volume.

use std::{mem::MaybeUninit, os::raw::c_int};

use super::format::AudioFormat;
use crate::{
    bind::{self, SDL_MixAudioFormat},
    Result, Sdl, SdlError,
};

/// An audio buffer with a format, sample rates, numbers of channels and a buffer.
#[derive(Debug, Clone)]
pub struct AudioBuffer<T> {
    format: AudioFormat,
    samples: u32,
    channels: u8,
    buffer: Vec<T>,
}

impl<T> AudioBuffer<T> {
    /// Constructs an audio buffer from arguments.
    /// The size of type which stored by buffer must equal to the format bit size.
    ///
    /// # Panics
    ///
    /// Panics if the size of type `T` does not equal to the format bit size.
    #[must_use]
    pub fn new(format: AudioFormat, samples: u32, channels: u8, buffer: Vec<T>) -> Self {
        assert_eq!(format.bit_size as usize, std::mem::size_of::<T>() * 8);
        Self {
            format,
            samples,
            channels,
            buffer,
        }
    }

    /// Returns the format of the audio buffer.
    pub fn format(&self) -> &AudioFormat {
        &self.format
    }

    /// Returns the sample rates of the audio buffer.
    #[must_use]
    pub fn samples(&self) -> u32 {
        self.samples
    }

    /// Returns the numbers of channels of the audio buffer.
    #[must_use]
    pub fn channels(&self) -> u8 {
        self.channels
    }

    /// Convert into another `AudioBuffer` with different format, sample rate or channels.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to convert into a specific format.
    pub fn convert<U: Default + Clone>(
        self,
        format: AudioFormat,
        samples: u32,
        channels: u8,
    ) -> Result<AudioBuffer<U>> {
        let mut dst = AudioBuffer::<U> {
            format,
            samples,
            channels,
            buffer: vec![],
        };
        self.convert_in(&mut dst)?;
        Ok(dst)
    }

    /// Convert and write into another existing `AudioBuffer`.
    ///
    /// # Errors
    ///
    /// Returns `Err` if failed to convert between `self` and `other`.
    pub fn convert_in<U: Default + Clone>(self, other: &mut AudioBuffer<U>) -> Result<()> {
        let mut cvt = MaybeUninit::uninit();
        let ret = unsafe {
            bind::SDL_BuildAudioCVT(
                cvt.as_mut_ptr(),
                self.format.as_raw(),
                self.channels,
                self.samples as c_int,
                other.format.as_raw(),
                other.channels,
                other.samples as c_int,
            )
        };
        if ret == 0 {
            return Err(SdlError::UnsupportedFeature);
        }
        if ret < 0 {
            return Err(SdlError::Others { msg: Sdl::error() });
        }
        let mut cvt = unsafe { cvt.assume_init() };
        if cvt.needed == 0 {
            return Err(SdlError::UnsupportedFeature);
        }
        let len = self.samples as usize * self.channels as usize * std::mem::size_of::<T>();
        cvt.len = len as c_int;
        other.buffer.clear();
        other
            .buffer
            .resize(len * cvt.len_mult as usize, U::default());
        cvt.buf = as_u8_slice_mut(&mut other.buffer).as_mut_ptr();
        let ret = unsafe { bind::SDL_ConvertAudio(&mut cvt) };
        if ret < 0 {
            Err(SdlError::Others { msg: Sdl::error() })
        } else {
            Ok(())
        }
    }
}

impl<T: Default + Clone> AudioBuffer<T> {
    /// Mix into another `AudioBuffer` with the specified `volume`.
    ///
    /// The max value of `volume` is `128`, saturating if it is over the max.
    #[must_use]
    pub fn mix(&self, volume: u8) -> Self {
        let mut dst = self.clone();
        self.mix_in(&mut dst, volume).unwrap();
        dst
    }

    /// Mix into another existing `AudioBuffer` with the specified `volume`.
    ///
    /// The max value of `volume` is `128`, saturating if it is over the max.
    ///
    /// # Errors
    ///
    /// Return `Err` if the formats of `self` and `dst` are different.
    pub fn mix_in(&self, dst: &mut Self, volume: u8) -> Result<()> {
        if self.format.as_raw() != dst.format.as_raw() {
            return Err(SdlError::Others {
                msg: "Cannot mix in buffers which have different format".into(),
            });
        }
        dst.buffer.clear();
        dst.buffer.resize(self.buffer.len(), T::default());
        let len = self.buffer.len() * std::mem::size_of::<T>();
        unsafe {
            bind::SDL_MixAudioFormat(
                as_u8_slice_mut(&mut dst.buffer).as_mut_ptr().cast(),
                as_u8_slice(&self.buffer).as_ptr().cast(),
                self.format.as_raw(),
                len as u32,
                volume.min(bind::SDL_MIX_MAXVOLUME as u8) as c_int,
            );
        }
        Ok(())
    }
}

fn as_u8_slice<T>(slice: &[T]) -> &[u8] {
    let size = std::mem::size_of::<T>();
    unsafe { std::slice::from_raw_parts(slice.as_ptr().cast(), std::mem::size_of_val(slice)) }
}

fn as_u8_slice_mut<T>(slice: &mut [T]) -> &mut [u8] {
    let size = std::mem::size_of::<T>();
    unsafe {
        std::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), std::mem::size_of_val(slice))
    }
}