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