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

1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2
3#[derive(Debug, Clone)]
4pub struct DelayProcessor {
5    time_ms: f32,
6    feedback: f32,
7    mix: f32,
8    delay_buffer_l: Vec<f32>,
9    delay_buffer_r: Vec<f32>,
10    buffer_pos: usize,
11}
12
13impl DelayProcessor {
14    pub fn new(time_ms: f32, feedback: f32, mix: f32) -> Self {
15        // Allocate buffer for up to 2 seconds of delay
16        let max_samples = 88200; // 2 seconds at 44.1kHz
17        Self {
18            time_ms: time_ms.clamp(1.0, 2000.0),
19            feedback: feedback.clamp(0.0, 0.95),
20            mix: mix.clamp(0.0, 1.0),
21            delay_buffer_l: vec![0.0; max_samples],
22            delay_buffer_r: vec![0.0; max_samples],
23            buffer_pos: 0,
24        }
25    }
26}
27
28impl Default for DelayProcessor {
29    fn default() -> Self {
30        Self::new(250.0, 0.4, 0.3)
31    }
32}
33
34impl EffectProcessor for DelayProcessor {
35    fn process(&mut self, samples: &mut [f32], sample_rate: u32) {
36        let delay_samples = ((self.time_ms / 1000.0) * sample_rate as f32) as usize;
37        let delay_samples = delay_samples.min(self.delay_buffer_l.len() - 1);
38
39        for i in (0..samples.len()).step_by(2) {
40            let input_l = samples[i];
41            let input_r = if i + 1 < samples.len() {
42                samples[i + 1]
43            } else {
44                input_l
45            };
46
47            // Read from delayed position
48            let read_pos = (self.buffer_pos + self.delay_buffer_l.len() - delay_samples)
49                % self.delay_buffer_l.len();
50            let delayed_l = self.delay_buffer_l[read_pos];
51            let delayed_r = self.delay_buffer_r[read_pos];
52
53            // Write to delay buffer with feedback
54            self.delay_buffer_l[self.buffer_pos] = input_l + delayed_l * self.feedback;
55            self.delay_buffer_r[self.buffer_pos] = input_r + delayed_r * self.feedback;
56
57            // Mix wet and dry
58            samples[i] = input_l * (1.0 - self.mix) + delayed_l * self.mix;
59            if i + 1 < samples.len() {
60                samples[i + 1] = input_r * (1.0 - self.mix) + delayed_r * self.mix;
61            }
62
63            self.buffer_pos = (self.buffer_pos + 1) % self.delay_buffer_l.len();
64        }
65    }
66
67    fn reset(&mut self) {
68        self.delay_buffer_l.fill(0.0);
69        self.delay_buffer_r.fill(0.0);
70        self.buffer_pos = 0;
71    }
72
73    fn name(&self) -> &str {
74        "Delay"
75    }
76}