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

1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2use std::f32::consts::PI;
3
4#[derive(Debug, Clone)]
5pub struct FlangerProcessor {
6    depth: f32,
7    rate: f32,
8    feedback: f32,
9    mix: f32,
10    phase: f32,
11    delay_buffer: Vec<f32>,
12    buffer_pos: usize,
13}
14
15impl FlangerProcessor {
16    pub fn new(depth: f32, rate: f32, feedback: f32, mix: f32) -> Self {
17        Self {
18            depth: depth.clamp(0.0, 1.0),
19            rate: rate.clamp(0.1, 10.0),
20            feedback: feedback.clamp(0.0, 0.95),
21            mix: mix.clamp(0.0, 1.0),
22            phase: 0.0,
23            delay_buffer: vec![0.0; 882], // ~20ms at 44.1kHz
24            buffer_pos: 0,
25        }
26    }
27}
28
29impl Default for FlangerProcessor {
30    fn default() -> Self {
31        Self::new(0.7, 0.5, 0.5, 0.5)
32    }
33}
34
35impl EffectProcessor for FlangerProcessor {
36    fn process(&mut self, samples: &mut [f32], sample_rate: u32) {
37        let max_delay_samples = (0.010 * sample_rate as f32) as usize; // 10ms max delay
38
39        for i in (0..samples.len()).step_by(2) {
40            // Update LFO phase
41            self.phase += self.rate / sample_rate as f32;
42            if self.phase >= 1.0 {
43                self.phase -= 1.0;
44            }
45
46            // Calculate delay offset using sine LFO
47            let lfo = (2.0 * PI * self.phase).sin();
48            let delay_samples =
49                (self.depth * max_delay_samples as f32 * (lfo + 1.0) / 2.0) as usize;
50            let delay_samples = delay_samples.min(self.delay_buffer.len() - 1);
51
52            // Process left and right channels
53            for ch in 0..2 {
54                if i + ch < samples.len() {
55                    let input = samples[i + ch];
56
57                    // Read from delayed position
58                    let read_pos = (self.buffer_pos + self.delay_buffer.len() - delay_samples)
59                        % self.delay_buffer.len();
60                    let delayed = self.delay_buffer[read_pos];
61
62                    // Apply feedback
63                    let output = input + delayed * self.feedback;
64
65                    // Write to delay buffer
66                    self.delay_buffer[self.buffer_pos] = output;
67
68                    // Mix wet and dry
69                    samples[i + ch] = input * (1.0 - self.mix) + delayed * self.mix;
70                }
71            }
72
73            self.buffer_pos = (self.buffer_pos + 1) % self.delay_buffer.len();
74        }
75    }
76
77    fn reset(&mut self) {
78        self.phase = 0.0;
79        self.delay_buffer.fill(0.0);
80        self.buffer_pos = 0;
81    }
82
83    fn name(&self) -> &str {
84        "Flanger"
85    }
86}