1 /*
2 Reverb.cc
3
4 Copyright 2002-16 Tim Goetze <tim@quitte.de>
5
6 http://quitte.de/dsp/
7
8 Three reverb units: JVRev, Plate and PlateX2.
9
10 The former is a rewrite of STK's JVRev, a traditional design.
11
12 Original comment:
13
14 This is based on some of the famous
15 Stanford CCRMA reverbs (NRev, KipRev)
16 all based on the Chowning/Moorer/
17 Schroeder reverberators, which use
18 networks of simple allpass and comb
19 delay filters.
20
21 The algorithm is mostly unchanged in this implementation; the delay
22 line lengths have been fiddled with to make the stereo field more
23 evenly weighted, denormal protection and a bandwidth control have been
24 added as well.
25
26 The latter two are based on the circuit discussed in Jon Dattorro's
27 September 1997 JAES paper on effect design (part 1: reverb & filters).
28 */
29 /*
30 This program is free software; you can redistribute it and/or
31 modify it under the terms of the GNU General Public License
32 as published by the Free Software Foundation; either version 3
33 of the License, or (at your option) any later version.
34
35 This program is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
43 02111-1307, USA or point your web browser to http://www.gnu.org.
44 */
45
46 #include "basics.h"
47
48 #include "Reverb.h"
49 #include "Descriptor.h"
50
51 int JVRev_length[9] = { 4199, 4999, 5399, 5801, 1051, 337, 113, 573, 487 };
52
53 void
init()54 JVRev::init()
55 {
56 double s = fs/44100.;
57
58 for(int i = 0; i < 9; ++i)
59 {
60 int v = (int) (s * JVRev_length[i]);
61 v |= 1;
62 while(!DSP::isprime(v))
63 v += 2;
64 length[i] = v;
65 }
66
67 for(int i = 0; i < 4; ++i)
68 comb[i].init(length[i]);
69
70 for(int i = 0; i < 3; ++i)
71 allpass[i].init(length[i+4]);
72
73 left.init(length[7]);
74 right.init(length[8]);
75
76 /* such a simple number, yet I couldn't find a better one. */
77 apc = .7;
78 }
79
80 void
set_t60(sample_t t)81 JVRev::set_t60 (sample_t t)
82 {
83 t60 = t;
84
85 t = max(.00001, t);
86 t = -3/(t*fs);
87
88 for(int i=0; i<4; ++i)
89 comb[i].c = pow(10, t*length[i]);
90 }
91
92 void
activate()93 JVRev::activate()
94 {
95 bandwidth.reset();
96 tone.reset();
97
98 for(int i=0; i<3; ++i)
99 allpass[i].reset();
100
101 for(int i=0; i<4; ++i)
102 comb[i].reset();
103
104 left.reset();
105 right.reset();
106
107 set_t60(getport(1));
108 tone.set_f(1800*over_fs);
109 }
110
111 void
cycle(uint frames)112 JVRev::cycle(uint frames)
113 {
114 sample_t bw = .005 + .994*getport(0);
115 bandwidth.set(exp(-M_PI*(1. - bw)));
116
117 if(t60 != *ports[1])
118 set_t60(getport(1));
119
120 double wet = getport(2);
121 wet = .38*wet*wet;
122 double dry = 1 - wet;
123
124 sample_t * s = ports[3];
125
126 sample_t * dl = ports[4];
127 sample_t * dr = ports[5];
128
129 for(uint i = 0; i < frames; ++i)
130 {
131 sample_t x = s[i], a = x + normal;
132
133 a = bandwidth.process(a);
134 x *= dry;
135
136 /* diffusors */
137 a = allpass[0].process(a,-apc);
138 a = allpass[1].process(a,-apc);
139 a = allpass[2].process(a,-apc);
140
141 /* tank */
142 sample_t t = 0;
143 a -= normal;
144
145 for(int j=0; j<4; ++j)
146 t += comb[j].process(a);
147
148 t = tone.process(t);
149
150 dl[i] = x + wet*left.putget(t);
151 dr[i] = x + wet*right.putget(t);
152 }
153 }
154
155 /* //////////////////////////////////////////////////////////////////////// */
156
157 PortInfo
158 JVRev::port_info [] =
159 {
160 { "bandwidth", INPUT | CONTROL, {DEFAULT_MID, 0, 1} },
161 { "t60 (s)", INPUT | CONTROL | GROUP, {DEFAULT_MID, 0, 5.6} },
162 { "blend", INPUT | CONTROL, {DEFAULT_LOW, 0, 1} },
163
164 { "in", INPUT | AUDIO },
165 { "out.l", OUTPUT | AUDIO },
166 { "out.r", OUTPUT | AUDIO }
167 };
168
169 template <> void
setup()170 Descriptor<JVRev>::setup()
171 {
172 Label = "JVRev";
173 Name = CAPS "JVRev - Stanford-style reverb from STK";
174 autogen();
175 }
176
177 /* //////////////////////////////////////////////////////////////////////// */
178
179 void
init()180 PlateStub::init()
181 {
182 f_lfo = -1;
183
184 # define L(i) ((int) (l[i] * fs))
185 static float l[] = {
186 0.004771345048889486, 0.0035953092974026408,
187 0.01273478713752898, 0.0093074829474816042,
188 0.022579886428547427, 0.030509727495715868,
189 0.14962534861059779, 0.060481838647894894, 0.12499579987231611,
190 0.14169550754342933, 0.089244313027116023, 0.10628003091293972
191 };
192
193 /* lh */
194 input.lattice[0].init(L(0));
195 input.lattice[1].init(L(1));
196
197 /* rh */
198 input.lattice[2].init(L(2));
199 input.lattice[3].init(L(3));
200
201 /* modulated, width about 12 samples @ 44.1 */
202 tank.mlattice[0].init(L(4), (int) (0.000403221 * fs));
203 tank.mlattice[1].init(L(5), (int) (0.000403221 * fs));
204
205 /* lh */
206 tank.delay[0].init(L(6));
207 tank.lattice[0].init(L(7));
208 tank.delay[1].init(L(8));
209
210 /* rh */
211 tank.delay[2].init(L(9));
212 tank.lattice[1].init(L(10));
213 tank.delay[3].init(L(11));
214 # undef L
215
216 # define T(i) ((int) (t[i] * fs))
217 static float t[] = {
218 0.0089378717113000241, 0.099929437854910791, 0.064278754074123853,
219 0.067067638856221232, 0.066866032727394914, 0.006283391015086859,
220 0.01186116057928161, 0.12187090487550822, 0.041262054366452743,
221 0.089815530392123921, 0.070931756325392295, 0.011256342192802662
222 };
223
224 for(int i = 0; i < 12; ++i)
225 tank.taps[i] = T(i);
226 # undef T
227
228 /* tuned for soft attack, ambience */
229 indiff1 = .742;
230 indiff2 = .712;
231
232 dediff1 = .723;
233 dediff2 = .729;
234 }
235
236 inline void
process(sample_t x,sample_t decay,sample_t * _xl,sample_t * _xr)237 PlateStub::process(sample_t x, sample_t decay, sample_t * _xl, sample_t * _xr)
238 {
239 x = input.bandwidth.process(x);
240
241 /* lh */
242 x = input.lattice[0].process(x, indiff1);
243 x = input.lattice[1].process(x, indiff1);
244
245 /* rh */
246 x = input.lattice[2].process(x, indiff2);
247 x = input.lattice[3].process(x, indiff2);
248
249 /* summation point */
250 register double xl = x + decay*tank.delay[3].get();
251 register double xr = x + decay*tank.delay[1].get();
252
253 /* lh */
254 xl = tank.mlattice[0].process(xl, dediff1);
255 xl = tank.delay[0].putget(xl);
256 xl = tank.damping[0].process(xl);
257 xl *= decay;
258 xl = tank.lattice[0].process(xl, dediff2);
259 tank.delay[1].put(xl);
260
261 /* rh */
262 xr = tank.mlattice[1].process(xr, dediff1);
263 xr = tank.delay[2].putget(xr);
264 xr = tank.damping[1].process(xr);
265 xr *= decay;
266 xr = tank.lattice[1].process(xr, dediff2);
267 tank.delay[3].put(xr);
268
269 /* gather output */
270 xl = .6 * tank.delay[2] [tank.taps[0]];
271 xl += .6 * tank.delay[2] [tank.taps[1]];
272 xl -= .6 * tank.lattice[1] [tank.taps[2]];
273 xl += .6 * tank.delay[3] [tank.taps[3]];
274 xl -= .6 * tank.delay[0] [tank.taps[4]];
275 xl += .6 * tank.lattice[0] [tank.taps[5]];
276
277 xr = .6 * tank.delay[0] [tank.taps[6]];
278 xr += .6 * tank.delay[0] [tank.taps[7]];
279 xr -= .6 * tank.lattice[0] [tank.taps[8]];
280 xr += .6 * tank.delay[1] [tank.taps[9]];
281 xr -= .6 * tank.delay[2] [tank.taps[10]];
282 xr += .6 * tank.lattice[1] [tank.taps[11]];
283
284 *_xl = xl;
285 *_xr = xr;
286 }
287
288 /* //////////////////////////////////////////////////////////////////////// */
289
290 void
cycle(uint frames)291 Plate::cycle(uint frames)
292 {
293 sample_t bw = .005 + .994*getport(0);
294 input.bandwidth.set(exp (-M_PI * (1. - bw)));
295
296 sample_t decay = .749*getport(1);
297
298 double damp = exp(-M_PI * (.0005+.9995*getport(2)));
299 tank.damping[0].set(damp);
300 tank.damping[1].set(damp);
301
302 sample_t blend = getport(3);
303 blend = pow(blend, 1.6); /* linear is not a good choice for this pot */
304 sample_t dry = 1 - blend;
305
306 sample_t * s = ports[4];
307
308 sample_t * dl = ports[5];
309 sample_t * dr = ports[6];
310
311 /* modulated lattice interpolation needs float truncation */
312 DSP::FPTruncateMode _truncate;
313
314 for(uint i = 0; i < frames; ++i)
315 {
316 normal = -normal;
317 sample_t x = s[i] + normal;
318
319 sample_t xl, xr;
320
321 PlateStub::process(x, decay, &xl, &xr);
322
323 x = dry * s[i];
324
325 dl[i] = x + blend*xl;
326 dr[i] = x + blend*xr;
327 }
328 }
329
330 /* //////////////////////////////////////////////////////////////////////// */
331
332 PortInfo
333 Plate::port_info [] =
334 {
335 {"bandwidth", INPUT | CONTROL, {DEFAULT_MID, 0, 1} },
336 {"tail", INPUT | CONTROL | GROUP, {DEFAULT_HIGH, 0, 1} },
337 {"damping", INPUT | CONTROL, {DEFAULT_MID, 0, 1} },
338 {"blend", INPUT | CONTROL | GROUP, {DEFAULT_LOW, 0, 1} },
339
340 {"in", INPUT | AUDIO},
341 {"out.l", OUTPUT | AUDIO},
342 {"out.r", OUTPUT | AUDIO}
343 };
344
345 template <> void
setup()346 Descriptor<Plate>::setup()
347 {
348 Label = "Plate";
349 Name = CAPS "Plate - Versatile plate reverb";
350 autogen();
351 }
352
353 /* //////////////////////////////////////////////////////////////////////// */
354
355 void
cycle(uint frames)356 PlateX2::cycle(uint frames)
357 {
358 sample_t bw = .005 + .994*getport(0);
359 input.bandwidth.set(exp (-M_PI * (1. - bw)));
360
361 sample_t decay = .749*getport(1);
362
363 double damp = exp(-M_PI * (.0005+.9995*getport(2)));
364 tank.damping[0].set(damp);
365 tank.damping[1].set(damp);
366
367 sample_t blend = getport(3);
368 blend = pow(blend, 1.53);
369 sample_t dry = 1 - blend;
370
371 sample_t * sl = ports[4];
372 sample_t * sr = ports[5];
373 sample_t * dl = ports[6];
374 sample_t * dr = ports[7];
375
376 /* the modulated lattices interpolate, which needs truncated float */
377 DSP::FPTruncateMode _truncate;
378
379 for(uint i = 0; i < frames; ++i)
380 {
381 normal = -normal;
382 sample_t x = (sl[i] + sr[i] + normal) * .5;
383
384 sample_t xl, xr;
385 PlateStub::process(x, decay, &xl, &xr);
386
387 dl[i] = blend*xl + dry*sl[i];
388 dr[i] = blend*xr + dry*sr[i];
389 }
390 }
391
392 /* //////////////////////////////////////////////////////////////////////// */
393
394 PortInfo
395 PlateX2::port_info [] =
396 {
397 {"bandwidth", INPUT | CONTROL, {DEFAULT_MID, 0, 1} /* .9995 */ },
398 {"tail", INPUT | CONTROL | GROUP, {DEFAULT_MID, 0, 1} /* .5 */ },
399 {"damping", INPUT | CONTROL, {DEFAULT_HIGH, 0, 1} /* .0005 */ },
400 {"blend", INPUT | CONTROL | GROUP, {DEFAULT_LOW, 0, 1} },
401
402 {"in.l", INPUT | AUDIO},
403 {"in.r", INPUT | AUDIO},
404 {"out.l", OUTPUT | AUDIO},
405 {"out.r", OUTPUT | AUDIO}
406 };
407
408 template <> void
setup()409 Descriptor<PlateX2>::setup()
410 {
411 Label = "PlateX2";
412 Name = CAPS "PlateX2 - Versatile plate reverb, stereo inputs";
413 autogen();
414 }
415
416
417