audio_engine/
wav.rs

1use hound::WavReader;
2use std::io::{Read, Seek};
3
4use crate::SoundSource;
5
6/// A SourceSource, from wav encoded sound data.
7pub struct WavDecoder<T: Seek + Read + Send + 'static> {
8    reader: WavReader<T>,
9    channels: u16,
10    sample_rate: u32,
11}
12impl<T: Seek + Read + Send + 'static> WavDecoder<T> {
13    /// Create a new WavDecoder from the given .wav data.
14    pub fn new(data: T) -> Result<Self, hound::Error> {
15        let reader = WavReader::new(data)?;
16        Ok(Self {
17            channels: reader.spec().channels,
18            sample_rate: reader.spec().sample_rate,
19            reader,
20        })
21    }
22
23    #[allow(clippy::needless_range_loop)]
24    fn inner_write_sample<S: hound::Sample>(
25        &mut self,
26        buffer: &mut [i16],
27        to_i16: impl Fn(S) -> i16,
28    ) -> usize {
29        let mut samples = self.reader.samples::<S>();
30        for i in 0..buffer.len() {
31            if let Some(sample) = samples.next() {
32                buffer[i] = match sample {
33                    Ok(x) => to_i16(x),
34                    Err(err) => {
35                        log::error!("error while decoding wav: {}", err);
36                        // Returning the current number of decoded samples before the error,
37                        // indicating that the SoundSource finished.
38                        // FIXME: If this SoundSource was marked to loop, then this Error will
39                        // repeat indefinitely. Maybe there should be a mechanism to report errors
40                        // from a SoundSource.
41                        return i;
42                    }
43                }
44            } else {
45                return i;
46            }
47        }
48        buffer.len()
49    }
50}
51impl<T: Seek + Read + Send + 'static> SoundSource for WavDecoder<T> {
52    fn reset(&mut self) {
53        self.reader.seek(0).unwrap();
54    }
55
56    fn channels(&self) -> u16 {
57        self.channels
58    }
59
60    fn sample_rate(&self) -> u32 {
61        self.sample_rate
62    }
63
64    fn write_samples(&mut self, buffer: &mut [i16]) -> usize {
65        let sample_format = self.reader.spec().sample_format;
66        let bits_per_sample = self.reader.spec().bits_per_sample;
67        match (sample_format, bits_per_sample) {
68            // Float (always 32 bit, unclear if WAV supports floats with different bit-depth, but hound does not)
69            (hound::SampleFormat::Float, _) => self.inner_write_sample(buffer, f32_to_i16),
70            // 24bit or 32bit
71            (hound::SampleFormat::Int, x) if x > 16 => {
72                self.inner_write_sample(buffer, |x: i32| (x >> (bits_per_sample - 16)) as i16)
73            }
74            // 16bit
75            (hound::SampleFormat::Int, x) if x == 16 => self.inner_write_sample(buffer, |x: i16| x),
76            // 8bit
77            (hound::SampleFormat::Int, _) => {
78                self.inner_write_sample(buffer, |x: i8| (x as i16) << 8)
79            }
80        }
81    }
82}
83
84fn f32_to_i16(mut x: f32) -> i16 {
85    if x > 1.0 {
86        x = 1.0
87    }
88    if x < -1.0 {
89        x = -1.0
90    }
91    if x >= 0.0 {
92        (x * i16::MAX as f32) as i16
93    } else {
94        (-x * i16::MIN as f32) as i16
95    }
96}