proteus_lib/dsp/effects/basic_reverb/
mod.rs1use log::info;
4use serde::{Deserialize, Serialize};
5
6use super::EffectContext;
7
8const DEFAULT_DURATION_MS: u64 = 100;
9const MAX_AMPLITUDE: f32 = 0.8;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12#[serde(default)]
13pub struct BasicReverbSettings {
14 pub duration_ms: u64,
15 pub amplitude: f32,
16}
17
18impl BasicReverbSettings {
19 pub fn new(duration_ms: u64, amplitude: f32) -> Self {
20 Self {
21 duration_ms: duration_ms.clamp(0, u64::MAX),
22 amplitude: amplitude.clamp(0.0, MAX_AMPLITUDE),
23 }
24 }
25
26 fn amplitude(&self) -> f32 {
27 self.amplitude.clamp(0.0, MAX_AMPLITUDE)
28 }
29}
30
31impl Default for BasicReverbSettings {
32 fn default() -> Self {
33 Self {
34 duration_ms: DEFAULT_DURATION_MS,
35 amplitude: 0.7,
36 }
37 }
38}
39
40#[derive(Clone, Serialize, Deserialize)]
42#[serde(default)]
43pub struct BasicReverbEffect {
44 pub enabled: bool,
45 #[serde(alias = "dry_wet", alias = "wet_dry")]
46 pub mix: f32,
47 #[serde(flatten)]
48 pub settings: BasicReverbSettings,
49 #[serde(skip)]
50 state: Option<BasicReverbState>,
51}
52
53impl Default for BasicReverbEffect {
54 fn default() -> Self {
55 Self {
56 enabled: true,
57 mix: 0.0,
58 settings: BasicReverbSettings::default(),
59 state: None,
60 }
61 }
62}
63
64impl std::fmt::Debug for BasicReverbEffect {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("BasicReverbEffect")
67 .field("enabled", &self.enabled)
68 .field("mix", &self.mix)
69 .field("settings", &self.settings)
70 .finish()
71 }
72}
73
74impl BasicReverbEffect {
75 pub fn new(mix: f32) -> Self {
77 Self {
78 mix: mix.clamp(0.0, 1.0),
79 ..Default::default()
80 }
81 }
82
83 pub fn process(&mut self, samples: &[f32], context: &EffectContext, _drain: bool) -> Vec<f32> {
85 self.ensure_state(context);
86 if !self.enabled || self.mix <= 0.0 {
87 return samples.to_vec();
88 }
89
90 if context.impulse_response_spec.is_some() {
92 return samples.to_vec();
93 }
94
95 let Some(state) = self.state.as_mut() else {
96 return samples.to_vec();
97 };
98
99 let amplitude = if self.mix > 0.0 {
100 self.mix.clamp(0.0, MAX_AMPLITUDE)
101 } else {
102 self.settings.amplitude()
103 };
104
105 if samples.is_empty() {
106 if _drain {
107 return state.drain_tail(amplitude);
108 }
109 return Vec::new();
110 }
111
112 let mut output = Vec::with_capacity(samples.len());
113 state.process_samples(samples, amplitude, &mut output);
114 output
115 }
116
117 pub fn reset_state(&mut self) {
119 if let Some(state) = self.state.as_mut() {
120 state.reset();
121 }
122 self.state = None;
123 }
124
125 pub fn settings_mut(&mut self) -> &mut BasicReverbSettings {
127 &mut self.settings
128 }
129
130 fn ensure_state(&mut self, context: &EffectContext) {
131 let delay_samples = delay_samples(
132 context.sample_rate,
133 context.channels,
134 self.settings.duration_ms,
135 );
136 let needs_reset = self
137 .state
138 .as_ref()
139 .map(|state| state.delay_samples != delay_samples)
140 .unwrap_or(true);
141 if needs_reset {
142 self.state = Some(BasicReverbState::new(delay_samples));
143 }
144 }
145}
146
147#[derive(Clone)]
148struct BasicReverbState {
149 delay_samples: usize,
150 delay_line: Vec<f32>,
151 write_pos: usize,
152}
153
154impl BasicReverbState {
155 fn new(delay_samples: usize) -> Self {
156 info!("Using Basic Reverb!");
157 Self {
158 delay_samples,
159 delay_line: vec![0.0; delay_samples.max(1)],
160 write_pos: 0,
161 }
162 }
163
164 fn reset(&mut self) {
165 self.delay_line.fill(0.0);
166 self.write_pos = 0;
167 }
168
169 fn process_samples(&mut self, samples: &[f32], amplitude: f32, out: &mut Vec<f32>) {
170 if self.delay_samples == 0 {
171 out.extend_from_slice(samples);
172 return;
173 }
174
175 let delay_len = self.delay_line.len();
176 for &sample in samples {
177 let delayed = self.delay_line[self.write_pos];
178 let output = sample + (delayed * amplitude);
179 out.push(output);
180
181 self.delay_line[self.write_pos] = sample + (delayed * amplitude);
183 self.write_pos += 1;
184 if self.write_pos >= delay_len {
185 self.write_pos = 0;
186 }
187 }
188 }
189
190 fn drain_tail(&mut self, amplitude: f32) -> Vec<f32> {
191 if self.delay_samples == 0 {
192 return Vec::new();
193 }
194
195 let delay_len = self.delay_line.len();
196 let mut out = Vec::with_capacity(delay_len);
197 for _ in 0..delay_len {
198 let delayed = self.delay_line[self.write_pos];
199 let output = delayed * amplitude;
200 out.push(output);
201
202 self.delay_line[self.write_pos] = delayed * amplitude;
204 self.write_pos += 1;
205 if self.write_pos >= delay_len {
206 self.write_pos = 0;
207 }
208 }
209
210 out
211 }
212}
213
214fn delay_samples(sample_rate: u32, channels: usize, duration_ms: u64) -> usize {
215 if duration_ms == 0 {
216 return 0;
217 }
218 let ns = duration_ms.saturating_mul(1_000_000);
219 let samples = ns.saturating_mul(sample_rate as u64) / 1_000_000_000 * channels as u64;
220 samples as usize
221}