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

1use crate::engine::audio::effects::processors::super_trait::EffectProcessor;
2use std::fmt::Debug;
3
4#[derive(Debug, Clone)]
5pub struct ReverbProcessor {
6    room_size: f32,
7    damping: f32,
8    mix: f32,
9    decay: f32,
10    // Comb filters (parallel)
11    comb_buffers: Vec<Vec<f32>>,
12    comb_positions: Vec<usize>,
13    comb_feedback: Vec<f32>,
14    // Allpass filters (series)
15    allpass_buffers: Vec<Vec<f32>>,
16    allpass_positions: Vec<usize>,
17}
18
19impl ReverbProcessor {
20    pub fn new(room_size: f32, damping: f32, decay: f32, mix: f32) -> Self {
21        let room_size = room_size.clamp(0.0, 1.0);
22        let damping = damping.clamp(0.0, 1.0);
23        let decay = decay.clamp(0.0, 2.0);
24
25        // Comb filter delays (in samples at 44.1kHz)
26        let comb_delays = [1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617];
27        let mut comb_buffers = Vec::new();
28        let mut comb_feedback = Vec::new();
29
30        for &delay in &comb_delays {
31            comb_buffers.push(vec![0.0; delay]);
32            // decay controls how long the reverb tails are. Compute a stable feedback < 1.0
33            let base = 0.78 + room_size * 0.14; // base feedback per room size
34            let mult = 0.6 + decay * 0.2; // decay scales length but keep <~1.0
35            let mut fb = base * mult;
36            if fb >= 0.995 {
37                fb = 0.995;
38            }
39            comb_feedback.push(fb);
40        }
41
42        // Allpass filter delays
43        let allpass_delays = [556, 441, 341, 225];
44        let mut allpass_buffers = Vec::new();
45
46        for &delay in &allpass_delays {
47            allpass_buffers.push(vec![0.0; delay]);
48        }
49
50        Self {
51            room_size,
52            damping,
53            mix: mix.clamp(0.0, 1.0),
54            decay,
55            comb_buffers,
56            comb_positions: vec![0; 8],
57            comb_feedback,
58            allpass_buffers,
59            allpass_positions: vec![0; 4],
60        }
61    }
62}
63
64impl Default for ReverbProcessor {
65    fn default() -> Self {
66        Self::new(0.5, 0.5, 0.5, 0.3)
67    }
68}
69
70impl EffectProcessor for ReverbProcessor {
71    fn process(&mut self, samples: &mut [f32], _sample_rate: u32) {
72        for i in 0..samples.len() {
73            let input = samples[i];
74            let mut output = 0.0;
75
76            // Process through parallel comb filters
77            for (j, buffer) in self.comb_buffers.iter_mut().enumerate() {
78                let pos = self.comb_positions[j];
79                let delayed = buffer[pos];
80
81                // Apply damping as a simple attenuation of the delayed sample
82                let filtered = delayed * (1.0 - self.damping);
83                buffer[pos] = input + filtered * self.comb_feedback[j];
84
85                // accumulate delayed signal for wet output
86                output += delayed;
87
88                self.comb_positions[j] = (pos + 1) % buffer.len();
89            }
90
91            output /= self.comb_buffers.len() as f32;
92
93            // Process through series allpass filters
94            for (j, buffer) in self.allpass_buffers.iter_mut().enumerate() {
95                let pos = self.allpass_positions[j];
96                let delayed = buffer[pos];
97
98                buffer[pos] = output + delayed * 0.5;
99                output = delayed - output * 0.5;
100
101                self.allpass_positions[j] = (pos + 1) % buffer.len();
102            }
103
104            // Mix wet and dry
105            samples[i] = input * (1.0 - self.mix) + output * self.mix;
106        }
107    }
108
109    fn reset(&mut self) {
110        for buffer in &mut self.comb_buffers {
111            buffer.fill(0.0);
112        }
113        for buffer in &mut self.allpass_buffers {
114            buffer.fill(0.0);
115        }
116        self.comb_positions.fill(0);
117        self.allpass_positions.fill(0);
118    }
119
120    fn name(&self) -> &str {
121        "Reverb"
122    }
123}