Skip to main content

lavende_core/audio/
resample.rs

1pub mod sinc {
2    use crate::audio::buffer::PooledBuffer;
3    use std::collections::VecDeque;
4    pub struct SincResampler {
5        ratio: f32,
6        index: f32,
7        channels: usize,
8        taps: usize,
9        table: Vec<f32>,
10        buffer: Vec<VecDeque<f32>>,
11    }
12    impl SincResampler {
13        pub fn new(source_rate: u32, target_rate: u32, channels: usize) -> Self {
14            let taps = 32;
15            let mut table = Vec::with_capacity(taps);
16            let m = taps as f32 - 1.0;
17            let half_taps = (taps / 2) as f32;
18            for i in 0..taps {
19                let offset = i as f32 - half_taps;
20                let a0 = 0.42;
21                let a1 = 0.5;
22                let a2 = 0.08;
23                let pi_n_m = 2.0 * std::f32::consts::PI * i as f32 / m;
24                let window = a0 - a1 * pi_n_m.cos() + a2 * (2.0 * pi_n_m).cos();
25                table.push(Self::sinc(offset) * window);
26            }
27            Self {
28                ratio: source_rate as f32 / target_rate as f32,
29                index: 0.0,
30                channels,
31                taps,
32                table,
33                buffer: vec![VecDeque::from(vec![0.0; taps]); channels],
34            }
35        }
36        fn sinc(x: f32) -> f32 {
37            if x.abs() < 1e-6 {
38                return 1.0;
39            }
40            let pi_x = std::f32::consts::PI * x;
41            pi_x.sin() / pi_x
42        }
43        pub fn process(&mut self, input: &[i16], output: &mut PooledBuffer) {
44            let num_frames = input.len() / self.channels;
45            for frame in 0..num_frames {
46                for ch in 0..self.channels {
47                    self.buffer[ch].pop_front();
48                    self.buffer[ch].push_back(input[frame * self.channels + ch] as f32);
49                }
50                while self.index < 1.0 {
51                    for ch in 0..self.channels {
52                        let mut sum = 0.0;
53                        for i in 0..self.taps {
54                            sum += self.buffer[ch][i] * self.table[i];
55                        }
56                        output.push(sum.clamp(i16::MIN as f32, i16::MAX as f32) as i16);
57                    }
58                    self.index += self.ratio;
59                }
60                self.index -= 1.0;
61            }
62        }
63        pub fn reset(&mut self) {
64            self.index = 0.0;
65            for ch in &mut self.buffer {
66                for x in ch {
67                    *x = 0.0;
68                }
69            }
70        }
71        pub fn is_passthrough(&self) -> bool {
72            (self.ratio - 1.0).abs() < f32::EPSILON
73        }
74    }
75    #[cfg(test)]
76    mod tests {
77        use super::*;
78        #[test]
79        fn test_sinc_function() {
80            assert!((SincResampler::sinc(0.0) - 1.0).abs() < 1e-6);
81            assert!((SincResampler::sinc(1e-7) - 1.0).abs() < 1e-6);
82            let val = SincResampler::sinc(1.0);
83            assert!(val.abs() < 0.01);
84            assert!((SincResampler::sinc(2.0) - SincResampler::sinc(-2.0)).abs() < 1e-6);
85        }
86        #[test]
87        fn test_resampler_new_same_rate() {
88            let resampler = SincResampler::new(48000, 48000, 2);
89            assert!(resampler.is_passthrough());
90            assert_eq!(resampler.channels, 2);
91            assert_eq!(resampler.taps, 32);
92            assert_eq!(resampler.table.len(), 32);
93            assert_eq!(resampler.buffer.len(), 2);
94        }
95        #[test]
96        fn test_resampler_new_downsample() {
97            let resampler = SincResampler::new(48000, 44100, 2);
98            assert!(!resampler.is_passthrough());
99            assert!(resampler.ratio > 1.0);
100            assert_eq!(resampler.channels, 2);
101        }
102        #[test]
103        fn test_resampler_new_upsample() {
104            let resampler = SincResampler::new(44100, 48000, 2);
105            assert!(!resampler.is_passthrough());
106            assert!(resampler.ratio < 1.0);
107        }
108        #[test]
109        fn test_resampler_reset() {
110            let mut resampler = SincResampler::new(48000, 44100, 2);
111            resampler.index = 0.5;
112            for ch in &mut resampler.buffer {
113                for x in ch.iter_mut() {
114                    *x = 100.0;
115                }
116            }
117            resampler.reset();
118            assert_eq!(resampler.index, 0.0);
119            for ch in &resampler.buffer {
120                for &x in ch.iter() {
121                    assert_eq!(x, 0.0);
122                }
123            }
124        }
125        #[test]
126        fn test_resampler_process_empty() {
127            let mut resampler = SincResampler::new(48000, 48000, 2);
128            let input: Vec<i16> = vec![];
129            let mut output = Vec::new();
130            resampler.process(&input, &mut output);
131            assert!(output.is_empty());
132        }
133        #[test]
134        fn test_resampler_process_silence() {
135            let mut resampler = SincResampler::new(48000, 48000, 2);
136            let input = vec![0i16; 20];
137            let mut output = Vec::new();
138            resampler.process(&input, &mut output);
139            assert!(!output.is_empty());
140            for &sample in &output {
141                assert_eq!(sample, 0);
142            }
143        }
144        #[test]
145        fn test_resampler_process_mono() {
146            let mut resampler = SincResampler::new(48000, 48000, 1);
147            let input = vec![1000i16; 10];
148            let mut output = Vec::new();
149            resampler.process(&input, &mut output);
150            assert!(!output.is_empty());
151        }
152        #[test]
153        fn test_resampler_process_clamp() {
154            let mut resampler = SincResampler::new(48000, 48000, 1);
155            let input = vec![i16::MAX; 100];
156            let mut output = Vec::new();
157            resampler.process(&input, &mut output);
158            for &sample in &output {
159                assert!(sample >= i16::MIN && sample <= i16::MAX);
160            }
161        }
162        #[test]
163        fn test_is_passthrough_exact() {
164            let resampler = SincResampler::new(48000, 48000, 2);
165            assert!(resampler.is_passthrough());
166        }
167        #[test]
168        fn test_is_not_passthrough() {
169            let resampler = SincResampler::new(48000, 44100, 2);
170            assert!(!resampler.is_passthrough());
171        }
172        #[test]
173        fn test_resampler_table_generation() {
174            let resampler = SincResampler::new(48000, 44100, 2);
175            assert_eq!(resampler.table.len(), 32);
176            for &val in &resampler.table {
177                assert!(val.is_finite());
178            }
179        }
180        #[test]
181        fn test_resampler_multiple_channels() {
182            for channels in 1..=8 {
183                let resampler = SincResampler::new(48000, 44100, channels);
184                assert_eq!(resampler.buffer.len(), channels);
185                for ch_buffer in &resampler.buffer {
186                    assert_eq!(ch_buffer.len(), 32);
187                }
188            }
189        }
190    }
191}
192pub mod linear {
193    use crate::audio::buffer::PooledBuffer;
194    pub struct LinearResampler {
195        ratio: f32,
196        index: f32,
197        last_samples: Vec<i16>,
198        channels: usize,
199    }
200    impl LinearResampler {
201        pub fn new(source_rate: u32, target_rate: u32, channels: usize) -> Self {
202            Self {
203                ratio: source_rate as f32 / target_rate as f32,
204                index: 0.0,
205                last_samples: vec![0; channels],
206                channels,
207            }
208        }
209        pub fn process(&mut self, input: &[i16], output: &mut PooledBuffer) {
210            let num_frames = input.len() / self.channels;
211            while self.index < num_frames as f32 {
212                let idx = self.index as usize;
213                let fract = self.index.fract();
214                for c in 0..self.channels {
215                    let s1 = if idx == 0 {
216                        self.last_samples[c]
217                    } else {
218                        input[(idx - 1) * self.channels + c]
219                    } as f32;
220                    let s2 = if idx < num_frames {
221                        input[idx * self.channels + c]
222                    } else {
223                        input[(num_frames - 1) * self.channels + c]
224                    } as f32;
225                    output.push((s1 * (1.0 - fract) + s2 * fract) as i16);
226                }
227                self.index += self.ratio;
228            }
229            self.index -= num_frames as f32;
230            if num_frames > 0 {
231                for c in 0..self.channels {
232                    self.last_samples[c] = input[(num_frames - 1) * self.channels + c];
233                }
234            }
235        }
236        pub fn reset(&mut self) {
237            self.index = 0.0;
238            self.last_samples.fill(0);
239        }
240        pub fn is_passthrough(&self) -> bool {
241            (self.ratio - 1.0).abs() < f32::EPSILON
242        }
243    }
244}
245pub mod hermite {
246    use crate::audio::buffer::PooledBuffer;
247    pub struct HermiteResampler {
248        ratio: f32,
249        index: f32,
250        channels: usize,
251        last_samples: Vec<i16>,
252    }
253    impl HermiteResampler {
254        pub fn new(source_rate: u32, target_rate: u32, channels: usize) -> Self {
255            Self {
256                ratio: source_rate as f32 / target_rate as f32,
257                index: 0.0,
258                channels,
259                last_samples: vec![0; channels],
260            }
261        }
262        #[inline]
263        fn hermite(p: [f32; 4], t: f32) -> f32 {
264            let c0 = p[1];
265            let c1 = 0.5 * (p[2] - p[0]);
266            let c2 = p[0] - 2.5 * p[1] + 2.0 * p[2] - 0.5 * p[3];
267            let c3 = 0.5 * (p[3] - p[0]) + 1.5 * (p[1] - p[2]);
268            ((c3 * t + c2) * t + c1) * t + c0
269        }
270        pub fn process(&mut self, input: &[i16], output: &mut PooledBuffer) {
271            let num_frames = input.len() / self.channels;
272            let num_frames_f = num_frames as f32;
273            while self.index < num_frames_f {
274                let idx = self.index as usize;
275                let t = self.index.fract();
276                for ch in 0..self.channels {
277                    let base_idx = idx * self.channels + ch;
278                    let p0 = if idx == 0 {
279                        self.last_samples[ch]
280                    } else {
281                        input[base_idx - self.channels]
282                    } as f32;
283                    let p1 = input[base_idx] as f32;
284                    let p2 = if idx + 1 < num_frames {
285                        input[base_idx + self.channels]
286                    } else {
287                        input[(num_frames - 1) * self.channels + ch]
288                    } as f32;
289                    let p3 = if idx + 2 < num_frames {
290                        input[base_idx + 2 * self.channels]
291                    } else {
292                        input[(num_frames - 1) * self.channels + ch]
293                    } as f32;
294                    let s = Self::hermite([p0, p1, p2, p3], t)
295                        .clamp(i16::MIN as f32, i16::MAX as f32) as i16;
296                    output.push(s);
297                }
298                self.index += self.ratio;
299            }
300            self.index -= num_frames as f32;
301            if num_frames > 0 {
302                for ch in 0..self.channels {
303                    self.last_samples[ch] = input[(num_frames - 1) * self.channels + ch];
304                }
305            }
306        }
307        pub fn reset(&mut self) {
308            self.index = 0.0;
309            self.last_samples.fill(0);
310        }
311        pub fn is_passthrough(&self) -> bool {
312            (self.ratio - 1.0).abs() < f32::EPSILON
313        }
314    }
315}
316use crate::audio::buffer::PooledBuffer;
317pub use hermite::HermiteResampler;
318pub use linear::LinearResampler;
319pub use sinc::SincResampler;
320pub enum Resampler {
321    Linear(LinearResampler),
322    Hermite(HermiteResampler),
323    Sinc(SincResampler),
324}
325impl Resampler {
326    pub fn hermite(source_rate: u32, target_rate: u32, channels: usize) -> Self {
327        Self::Hermite(HermiteResampler::new(source_rate, target_rate, channels))
328    }
329    pub fn linear(source_rate: u32, target_rate: u32, channels: usize) -> Self {
330        Self::Linear(LinearResampler::new(source_rate, target_rate, channels))
331    }
332    pub fn sinc(source_rate: u32, target_rate: u32, channels: usize) -> Self {
333        Self::Sinc(SincResampler::new(source_rate, target_rate, channels))
334    }
335    pub fn is_passthrough(&self) -> bool {
336        match self {
337            Self::Linear(r) => r.is_passthrough(),
338            Self::Hermite(r) => r.is_passthrough(),
339            Self::Sinc(r) => r.is_passthrough(),
340        }
341    }
342    pub fn process(&mut self, input: &[i16], output: &mut PooledBuffer) {
343        match self {
344            Self::Linear(r) => r.process(input, output),
345            Self::Hermite(r) => r.process(input, output),
346            Self::Sinc(r) => r.process(input, output),
347        }
348    }
349    pub fn reset(&mut self) {
350        match self {
351            Self::Linear(r) => r.reset(),
352            Self::Hermite(r) => r.reset(),
353            Self::Sinc(r) => r.reset(),
354        }
355    }
356}