Skip to main content

vector_calls/
resample.rs

1//! A streaming linear resampler: carries its phase and last sample across blocks
2//! so a live stream has no seam where one block ends and the next begins.
3
4pub struct Resampler {
5    /// Input samples per output sample.
6    step: f64,
7    /// Read position in the virtual input `[prev] ++ block`, in input samples.
8    pos: f64,
9    prev: f32,
10}
11
12impl Resampler {
13    pub fn new(from_rate: u32, to_rate: u32) -> Self {
14        Self { step: from_rate as f64 / to_rate as f64, pos: 0.0, prev: 0.0 }
15    }
16
17    /// Appends the resampled block to `out`.
18    pub fn process(&mut self, input: &[f32], out: &mut Vec<f32>) {
19        if input.is_empty() {
20            return;
21        }
22        let prev = self.prev;
23        let at = |i: usize| if i == 0 { prev } else { input[i - 1] };
24        // Position p reads virtual samples floor(p) and floor(p)+1; the last
25        // readable pair is (len-1, len).
26        while self.pos < input.len() as f64 {
27            let i = self.pos as usize;
28            let frac = (self.pos - i as f64) as f32;
29            let a = at(i);
30            let b = at(i + 1);
31            out.push(a + (b - a) * frac);
32            self.pos += self.step;
33        }
34        self.prev = input[input.len() - 1];
35        self.pos -= input.len() as f64;
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn a_ramp_stays_a_ramp_across_block_boundaries() {
45        let mut rs = Resampler::new(48_000, 16_000);
46        let ramp: Vec<f32> = (0..96).map(|i| i as f32).collect();
47        let mut out = Vec::new();
48        for block in ramp.chunks(7) {
49            rs.process(block, &mut out);
50        }
51        assert!(out.len() >= 31 && out.len() <= 32, "{}", out.len());
52        for pair in out.windows(2).skip(1) {
53            assert!((pair[1] - pair[0] - 3.0).abs() < 1e-3, "{:?}", pair);
54        }
55    }
56
57    #[test]
58    fn upsampling_produces_the_expected_count() {
59        let mut rs = Resampler::new(16_000, 48_000);
60        let mut out = Vec::new();
61        rs.process(&vec![0.5; 160], &mut out);
62        rs.process(&vec![0.5; 160], &mut out);
63        assert!((out.len() as i64 - 960).abs() <= 3, "{}", out.len());
64        assert!(out.iter().skip(3).all(|s| (s - 0.5).abs() < 1e-6));
65    }
66}