1const DC_OFFSET: f32 = 1e-8;
2const STEREO_SPREAD: usize = 23;
3
4const COMBTUNING_L1: usize = 1116;
5const COMBTUNING_R1: usize = 1116 + STEREO_SPREAD;
6const COMBTUNING_L2: usize = 1188;
7const COMBTUNING_R2: usize = 1188 + STEREO_SPREAD;
8const COMBTUNING_L3: usize = 1277;
9const COMBTUNING_R3: usize = 1277 + STEREO_SPREAD;
10const COMBTUNING_L4: usize = 1356;
11const COMBTUNING_R4: usize = 1356 + STEREO_SPREAD;
12const COMBTUNING_L5: usize = 1422;
13const COMBTUNING_R5: usize = 1422 + STEREO_SPREAD;
14const COMBTUNING_L6: usize = 1491;
15const COMBTUNING_R6: usize = 1491 + STEREO_SPREAD;
16const COMBTUNING_L7: usize = 1557;
17const COMBTUNING_R7: usize = 1557 + STEREO_SPREAD;
18const COMBTUNING_L8: usize = 1617;
19const COMBTUNING_R8: usize = 1617 + STEREO_SPREAD;
20const ALLPASSTUNING_L1: usize = 556;
21const ALLPASSTUNING_R1: usize = 556 + STEREO_SPREAD;
22const ALLPASSTUNING_L2: usize = 441;
23const ALLPASSTUNING_R2: usize = 441 + STEREO_SPREAD;
24const ALLPASSTUNING_L3: usize = 341;
25const ALLPASSTUNING_R3: usize = 341 + STEREO_SPREAD;
26const ALLPASSTUNING_L4: usize = 225;
27const ALLPASSTUNING_R4: usize = 225 + STEREO_SPREAD;
28
29#[derive(Clone)]
30struct Comb {
31 feedback: f32,
32 filterstore: f32,
33 damp1: f32,
34 damp2: f32,
35 buffer: Vec<f32>,
36 bufidx: usize,
37}
38
39impl Comb {
40 fn new(size: usize) -> Self {
41 Self {
42 feedback: 0f32,
43 filterstore: 0f32,
44 damp1: 0f32,
45 damp2: 0f32,
46 buffer: vec![DC_OFFSET; size],
47 bufidx: 0,
48 }
49 }
50
51 fn set_damp(&mut self, val: f32) {
52 self.damp1 = val;
53 self.damp2 = 1f32 - val;
54 }
55
56 fn set_feedback(&mut self, val: f32) {
57 self.feedback = val;
58 }
59
60 fn process(&mut self, input: f32) -> f32 {
61 let mut _tmp = self.buffer[self.bufidx];
62 self.filterstore = _tmp * self.damp2 + self.filterstore * self.damp1;
63 self.buffer[self.bufidx] = input + self.filterstore * self.feedback;
64 self.bufidx += 1;
65 if self.bufidx >= self.buffer.len() {
66 self.bufidx = 0
67 }
68 _tmp
69 }
70}
71
72#[derive(Clone)]
73struct AllPass {
74 feedback: f32,
75 buffer: Vec<f32>,
76 bufidx: usize,
77}
78
79impl AllPass {
80 fn new(size: usize, feedback: f32) -> Self {
81 Self {
82 feedback,
83 buffer: vec![DC_OFFSET; size],
84 bufidx: 0,
85 }
86 }
87
88 fn process(&mut self, input: f32) -> f32 {
89 let bufout: f32 = self.buffer[self.bufidx];
90 let output: f32 = bufout - input;
91 self.buffer[self.bufidx] = input + bufout * self.feedback;
92 self.bufidx += 1;
93 if self.bufidx >= self.buffer.len() {
94 self.bufidx = 0
95 }
96 output
97 }
98}
99
100#[derive(Clone)]
101struct LRPair<T> {
102 l: T,
103 r: T,
104}
105
106#[derive(Clone)]
107pub struct Reverb {
108 roomsize: f32,
109 damp: f32,
110 wet: f32,
111 wet1: f32,
112 wet2: f32,
113 width: f32,
114 gain: f32,
115 comb: [LRPair<Comb>; 8],
116 allpass: [LRPair<AllPass>; 4],
117}
118
119impl Default for Reverb {
120 fn default() -> Self {
121 Self::new()
122 }
123}
124
125impl Reverb {
126 pub fn new() -> Self {
127 let mut rev = Self {
128 roomsize: 0.5 * 0.28 + 0.7,
129 damp: 0.2 * 1.0,
130 wet: 1.0 * 3.0,
131 wet1: 0.0,
132 wet2: 0.0,
133 width: 1.0,
134 gain: 0.015,
135 comb: [
136 LRPair {
137 l: Comb::new(COMBTUNING_L1),
138 r: Comb::new(COMBTUNING_R1),
139 },
140 LRPair {
141 l: Comb::new(COMBTUNING_L2),
142 r: Comb::new(COMBTUNING_R2),
143 },
144 LRPair {
145 l: Comb::new(COMBTUNING_L3),
146 r: Comb::new(COMBTUNING_R3),
147 },
148 LRPair {
149 l: Comb::new(COMBTUNING_L4),
150 r: Comb::new(COMBTUNING_R4),
151 },
152 LRPair {
153 l: Comb::new(COMBTUNING_L5),
154 r: Comb::new(COMBTUNING_R5),
155 },
156 LRPair {
157 l: Comb::new(COMBTUNING_L6),
158 r: Comb::new(COMBTUNING_R6),
159 },
160 LRPair {
161 l: Comb::new(COMBTUNING_L7),
162 r: Comb::new(COMBTUNING_R7),
163 },
164 LRPair {
165 l: Comb::new(COMBTUNING_L8),
166 r: Comb::new(COMBTUNING_R8),
167 },
168 ],
169 allpass: [
170 LRPair {
171 l: AllPass::new(ALLPASSTUNING_L1, 0.5f32),
172 r: AllPass::new(ALLPASSTUNING_R1, 0.5f32),
173 },
174 LRPair {
175 l: AllPass::new(ALLPASSTUNING_L2, 0.5f32),
176 r: AllPass::new(ALLPASSTUNING_R2, 0.5f32),
177 },
178 LRPair {
179 l: AllPass::new(ALLPASSTUNING_L3, 0.5f32),
180 r: AllPass::new(ALLPASSTUNING_R3, 0.5f32),
181 },
182 LRPair {
183 l: AllPass::new(ALLPASSTUNING_L4, 0.5f32),
184 r: AllPass::new(ALLPASSTUNING_R4, 0.5f32),
185 },
186 ],
187 };
188 rev.set_params(&Default::default());
189 rev
190 }
191
192 pub fn reset(&mut self) {
193 self.comb = [
194 LRPair {
195 l: Comb::new(COMBTUNING_L1),
196 r: Comb::new(COMBTUNING_R1),
197 },
198 LRPair {
199 l: Comb::new(COMBTUNING_L2),
200 r: Comb::new(COMBTUNING_R2),
201 },
202 LRPair {
203 l: Comb::new(COMBTUNING_L3),
204 r: Comb::new(COMBTUNING_R3),
205 },
206 LRPair {
207 l: Comb::new(COMBTUNING_L4),
208 r: Comb::new(COMBTUNING_R4),
209 },
210 LRPair {
211 l: Comb::new(COMBTUNING_L5),
212 r: Comb::new(COMBTUNING_R5),
213 },
214 LRPair {
215 l: Comb::new(COMBTUNING_L6),
216 r: Comb::new(COMBTUNING_R6),
217 },
218 LRPair {
219 l: Comb::new(COMBTUNING_L7),
220 r: Comb::new(COMBTUNING_R7),
221 },
222 LRPair {
223 l: Comb::new(COMBTUNING_L8),
224 r: Comb::new(COMBTUNING_R8),
225 },
226 ];
227 self.allpass = [
228 LRPair {
229 l: AllPass::new(ALLPASSTUNING_L1, 0.5f32),
230 r: AllPass::new(ALLPASSTUNING_R1, 0.5f32),
231 },
232 LRPair {
233 l: AllPass::new(ALLPASSTUNING_L2, 0.5f32),
234 r: AllPass::new(ALLPASSTUNING_R2, 0.5f32),
235 },
236 LRPair {
237 l: AllPass::new(ALLPASSTUNING_L3, 0.5f32),
238 r: AllPass::new(ALLPASSTUNING_R3, 0.5f32),
239 },
240 LRPair {
241 l: AllPass::new(ALLPASSTUNING_L4, 0.5f32),
242 r: AllPass::new(ALLPASSTUNING_R4, 0.5f32),
243 },
244 ];
245 }
246
247 pub fn process_replace(&mut self, left_out: &mut [f32; 64], right_out: &mut [f32; 64]) {
248 for k in 0..64 {
249 let mut out_r = 0f32;
250 let mut out_l = 0f32;
251
252 let input = (2.0 * left_out[k] + DC_OFFSET) * self.gain;
254
255 for comb in self.comb.iter_mut() {
256 out_l += comb.l.process(input);
257 out_r += comb.r.process(input);
258 }
259
260 for allpass in self.allpass.iter_mut() {
261 out_l = allpass.l.process(out_l);
262 out_r = allpass.r.process(out_r);
263 }
264
265 out_l -= DC_OFFSET;
266 out_r -= DC_OFFSET;
267
268 left_out[k] = out_l * self.wet1 + out_r * self.wet2;
269 right_out[k] = out_r * self.wet1 + out_l * self.wet2;
270 }
271 }
272
273 pub fn process_mix(
274 &mut self,
275 in_0: &mut [f32; 64],
276 left_out: &mut [f32; 64],
277 right_out: &mut [f32; 64],
278 ) {
279 for k in 0..64 {
280 let mut out_r = 0f32;
281 let mut out_l = out_r;
282 let input = (2.0 * in_0[k] + DC_OFFSET) * self.gain;
283
284 for comb in self.comb.iter_mut() {
285 out_l += comb.l.process(input);
286 out_r += comb.r.process(input);
287 }
288
289 for allpass in self.allpass.iter_mut() {
290 out_l = allpass.l.process(out_l);
291 out_r = allpass.r.process(out_r);
292 }
293
294 out_l -= DC_OFFSET;
295 out_r -= DC_OFFSET;
296
297 left_out[k] += out_l * self.wet1 + out_r * self.wet2;
298 right_out[k] += out_r * self.wet1 + out_l * self.wet2;
299 }
300 }
301
302 fn update(&mut self) {
303 self.wet1 = self.wet * (self.width / 2f32 + 0.5f32);
304 self.wet2 = self.wet * ((1f32 - self.width) / 2f32);
305 for comb in self.comb.iter_mut() {
306 comb.l.set_feedback(self.roomsize);
307 comb.r.set_feedback(self.roomsize);
308 comb.l.set_damp(self.damp);
309 comb.r.set_damp(self.damp);
310 }
311 }
312}
313
314#[derive(Debug, Clone, Copy, PartialEq)]
315pub struct ReverbParams {
316 pub roomsize: f32,
318 pub damp: f32,
320 pub width: f32,
322 pub level: f32,
324}
325
326impl Default for ReverbParams {
327 fn default() -> Self {
328 Self {
329 roomsize: 0.2,
330 damp: 0.0,
331 width: 0.5,
332 level: 0.9,
333 }
334 }
335}
336
337impl Reverb {
338 fn set_room_size(&mut self, value: f32) {
340 self.roomsize = value * 0.28 + 0.7;
341 }
342
343 fn room_size(&self) -> f32 {
345 (self.roomsize - 0.7) / 0.28
346 }
347
348 fn set_damp(&mut self, value: f32) {
350 self.damp = value * 1.0;
351 }
352
353 fn damp(&self) -> f32 {
355 self.damp / 1.0
356 }
357
358 fn set_level(&mut self, value: f32) {
360 let value = value.clamp(0.0, 1.0);
361 self.wet = value * 3.0;
362 }
363
364 fn level(&self) -> f32 {
366 self.wet / 3.0
367 }
368
369 fn set_width(&mut self, value: f32) {
371 self.width = value;
372 }
373
374 fn width(&self) -> f32 {
376 self.width
377 }
378}
379
380impl Reverb {
381 pub fn set_params(&mut self, params: &ReverbParams) {
383 self.set_room_size(params.roomsize);
384 self.set_damp(params.damp);
385 self.set_width(params.width);
386 self.set_level(params.level);
387 self.update();
388 }
389
390 pub fn params(&self) -> ReverbParams {
392 ReverbParams {
393 roomsize: self.room_size(),
394 damp: self.damp(),
395 level: self.level(),
396 width: self.width(),
397 }
398 }
399}