devalang_wasm/engine/audio/effects/processors/
lowpass.rs

1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct LowpassProcessor {
5    pub cutoff: f32,
6    pub resonance: f32,
7    prev_l: f32,
8    prev_r: f32,
9}
10
11impl LowpassProcessor {
12    pub fn new(cutoff: f32, resonance: f32) -> Self {
13        Self {
14            cutoff: cutoff.clamp(20.0, 20000.0),
15            resonance: resonance.clamp(0.0, 1.0),
16            prev_l: 0.0,
17            prev_r: 0.0,
18        }
19    }
20}
21
22impl Default for LowpassProcessor {
23    fn default() -> Self {
24        Self::new(5000.0, 0.1)
25    }
26}
27
28impl EffectProcessor for LowpassProcessor {
29    fn process(&mut self, samples: &mut [f32], sr: u32) {
30        let fs = sr as f32;
31        let fc = self.cutoff.max(20.0).min(fs * 0.49);
32        let omega = 2.0 * std::f32::consts::PI * fc / fs;
33        let alpha = omega / (omega + 1.0);
34
35        for i in (0..samples.len()).step_by(2) {
36            let x_l = samples[i];
37            self.prev_l = self.prev_l + alpha * (x_l - self.prev_l);
38            samples[i] = self.prev_l;
39            if i + 1 < samples.len() {
40                let x_r = samples[i + 1];
41                self.prev_r = self.prev_r + alpha * (x_r - self.prev_r);
42                samples[i + 1] = self.prev_r;
43            }
44        }
45    }
46
47    fn reset(&mut self) {
48        self.prev_l = 0.0;
49        self.prev_r = 0.0;
50    }
51
52    fn name(&self) -> &str {
53        "Lowpass"
54    }
55}