// from https://www.musicdsp.org/en/latest/Analysis/97-envelope-detector.html // with some modifications pub struct EnvelopeFollower { x1: f32, x2: f32, ga: f32, gr: f32, } impl EnvelopeFollower { pub fn new() -> Self { Self { x1: 0.0, x2: 0.0, ga: 0.0, gr: 0.0, } } /// attack and release are in seconds pub fn set_attack_release(&mut self, sample_rate: f32, attack: f32, release: f32) { self.ga = (-1.0 / (sample_rate * attack)).exp(); self.gr = (-1.0 / (sample_rate * release)).exp(); } pub fn process(&mut self, input: f32) -> f32 { let in_abs = input.abs(); // 2nd order lowpass if self.x1 < in_abs { self.x1 = in_abs + self.ga * (self.x1 - in_abs); self.x2 = self.x1 + self.ga * (self.x2 - self.x1); } else { self.x1 = in_abs + self.gr * (self.x1 - in_abs); self.x2 = self.x1 + self.gr * (self.x2 - self.x1); } self.x2 } }