rg3d_sound/decoder/
wav.rs

1use crate::{buffer::DataSource, error::SoundError};
2use hound::WavReader;
3use std::{
4    fmt::{Debug, Formatter},
5    io::{Read, Seek, SeekFrom},
6    sync::{Arc, Mutex},
7    time::Duration,
8};
9
10/// Wav decoder
11pub(in crate) struct WavDecoder {
12    reader: WavReader<DataSource>,
13}
14
15impl Debug for WavDecoder {
16    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
17        write!(f, "WavDecoder")
18    }
19}
20
21#[derive(Clone)]
22struct WrappedDataSource {
23    data_source: Arc<Mutex<DataSource>>,
24}
25
26impl WrappedDataSource {
27    fn into_inner(self) -> DataSource {
28        Arc::try_unwrap(self.data_source)
29            .unwrap()
30            .into_inner()
31            .unwrap()
32    }
33}
34
35impl Read for WrappedDataSource {
36    fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
37        self.data_source.lock().unwrap().read(buf)
38    }
39}
40
41impl Seek for WrappedDataSource {
42    fn seek(&mut self, pos: SeekFrom) -> Result<u64, std::io::Error> {
43        self.data_source.lock().unwrap().seek(pos)
44    }
45}
46
47impl WavDecoder {
48    pub fn new(mut source: DataSource) -> Result<Self, DataSource> {
49        let pos = source.seek(SeekFrom::Current(0)).unwrap();
50        let mut wrapped_source = WrappedDataSource {
51            data_source: Arc::new(Mutex::new(source)),
52        };
53
54        let reader = match WavReader::new(wrapped_source.clone()) {
55            Ok(old_reader) => {
56                drop(old_reader);
57                // Once we ensure that this is correct WAV source we need to re-create reader
58                // with inner value of WrappedDataSource to eliminate mutex locking overhead.
59                // This is some sort of a hack to bypass design flaws of the `hound` crate.
60                wrapped_source.seek(SeekFrom::Start(pos)).unwrap();
61                WavReader::new(wrapped_source.into_inner()).unwrap()
62            }
63            Err(_) => {
64                wrapped_source.seek(SeekFrom::Start(pos)).unwrap();
65                return Err(wrapped_source.into_inner());
66            }
67        };
68
69        Ok(Self { reader })
70    }
71
72    pub fn rewind(&mut self) -> Result<(), SoundError> {
73        self.reader.seek(0)?;
74        Ok(())
75    }
76
77    pub fn time_seek(&mut self, location: Duration) {
78        let _ = self
79            .reader
80            .seek((location.as_secs_f64() * self.reader.spec().sample_rate as f64) as u32);
81    }
82
83    pub fn duration(&self) -> Option<Duration> {
84        Some(Duration::from_secs_f32(
85            self.reader.duration() as f32 / self.reader.spec().sample_rate as f32,
86        ))
87    }
88
89    pub fn channel_count(&self) -> usize {
90        self.reader.spec().channels as usize
91    }
92
93    pub fn sample_rate(&self) -> usize {
94        self.reader.spec().sample_rate as usize
95    }
96}
97
98impl Iterator for WavDecoder {
99    type Item = f32;
100
101    #[inline]
102    fn next(&mut self) -> Option<Self::Item> {
103        let spec = self.reader.spec();
104        match (spec.bits_per_sample, spec.sample_format) {
105            (8, hound::SampleFormat::Int) => self
106                .reader
107                .samples::<i8>()
108                .next()
109                .and_then(|s| s.ok().map(|s| s as f32 / i8::MAX as f32)),
110            (16, hound::SampleFormat::Int) => self
111                .reader
112                .samples::<i16>()
113                .next()
114                .and_then(|s| s.ok().map(|s| s as f32 / i16::MAX as f32)),
115            (24, hound::SampleFormat::Int) => self
116                .reader
117                .samples::<i32>()
118                .next()
119                .and_then(|s| s.ok().map(|s| s as f32 / 0x7fffff as f32)),
120            (32, hound::SampleFormat::Int) => self
121                .reader
122                .samples::<i32>()
123                .next()
124                .and_then(|s| s.ok().map(|s| s as f32 / i32::MAX as f32)),
125            (32, hound::SampleFormat::Float) => {
126                self.reader.samples::<f32>().next().and_then(|s| s.ok())
127            }
128            _ => None,
129        }
130    }
131}