yagi 0.1.0

Batteries-included DSP library
Documentation
use core::f32;

pub struct PeakHold {
    hold: usize,
    current: Vec<f32>,
    current_max: f32,
    previous: Vec<f32>,
}

impl PeakHold {
    pub fn new(hold: usize) -> Self {
        Self {
            hold,
            current: vec![],
            current_max: f32::MIN,
            previous: vec![f32::MIN; hold],
        }
    }

    pub fn reset(&mut self) {
        self.current.clear();
        self.current_max = f32::MIN;
        self.previous = vec![f32::MIN; self.hold];
    }

    pub fn execute(&mut self, x: f32) -> f32 {
        self.current.push(x);
        self.current_max = self.current_max.max(x);

        let previous_max = self.previous.pop().unwrap();

        let max = previous_max.max(self.current_max);

        if self.current.len() == self.hold {
            self.swap();
        }

        max
    }

    fn swap(&mut self) {
        debug_assert!(self.previous.is_empty());
        let mut max = f32::MIN;
        for &x in self.current.iter().rev() {
            max = max.max(x);
            self.previous.push(max);
        }
        self.current.clear();
        self.current_max = f32::MIN;
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_simple_peak() {
        let hold = 3;
        let input = [0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];
        let expected = [0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0];

        let mut peak_hold = PeakHold::new(hold);

        for (&x, &exp_y) in input.iter().zip(expected.iter()) {
            assert_eq!(peak_hold.execute(x), exp_y);
        }
    }

    #[test]
    fn test_double_peak() {
        let hold = 3;
        let input = [0.0, 0.0, 1.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0];
        let expected = [0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 0.0];

        let mut peak_hold = PeakHold::new(hold);

        for (&x, &exp_y) in input.iter().zip(expected.iter()) {
            assert_eq!(peak_hold.execute(x), exp_y);
        }
    }

    #[test]
    fn test_long_run() {
        let hold = 3;
        #[rustfmt::skip]
        let input = [
            0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 1.0, 1.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            1.0, 2.0, 3.0, 0.0, 4.0, 0.0, 0.0, 0.0, 0.0, 0.0,
            4.0, 3.0, 2.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
        ];
        #[rustfmt::skip]
        let expected = [
            0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
            0.0, 0.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 0.0, 0.0,
            1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
            1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
            1.0, 2.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 0.0, 0.0,
            4.0, 4.0, 4.0, 4.0, 3.0, 2.0, 1.0, 1.0, 0.0, 0.0,
        ];

        let mut peak_hold = PeakHold::new(hold);

        for (&x, &exp_y) in input.iter().zip(expected.iter()) {
            assert_eq!(peak_hold.execute(x), exp_y);
        }
    }
}