irapt/
interpolate.rs

1use alloc::boxed::Box;
2use alloc::collections::VecDeque;
3
4use crate::fir_filter::{hamming, lowpass_fir_filter, scale_lowpass_filter};
5
6use itertools::{zip, Itertools};
7
8pub struct InterpolationFilter {
9    factor: u8,
10    filter: Box<[f64]>,
11    window: VecDeque<f64>,
12}
13
14impl InterpolationFilter {
15    pub fn new(half_window_len: u32, factor: u8) -> Self {
16        let mut filter: Box<[f64]> =
17            lowpass_fir_filter(half_window_len * 2 * u32::from(factor) + 1, 1.0 / f64::from(factor), hamming).collect();
18        scale_lowpass_filter(&mut filter);
19        let window = VecDeque::with_capacity(filter.len());
20        Self { factor, filter, window }
21    }
22
23    pub fn window_len(&self) -> usize {
24        (self.filter.len() - 1) / usize::from(self.factor)
25    }
26
27    pub fn interpolate<'a>(&'a mut self, values: impl IntoIterator<Item = f64> + 'a) -> impl Iterator<Item = f64> + 'a {
28        let factor = self.factor as f64;
29        let scaled = values.into_iter().map(move |value| value * factor);
30        let mut extended = Itertools::intersperse(scaled, 0.0);
31
32        self.window.clear();
33        self.window.extend(extended.by_ref().take(self.filter.len() - 1));
34
35        let interpolated = extended.map(move |value| {
36            if self.window.len() == self.filter.len() {
37                self.window.pop_front();
38            }
39            self.window.push_back(value);
40            zip(self.window.iter().rev(), &*self.filter).map(|(x, y)| x * y).sum()
41        });
42        interpolated
43    }
44}