1 /*
2   ZynAddSubFX - a software synthesizer
3 
4   Reverb.cpp - Reverberation effect
5   Copyright (C) 2002-2005 Nasca Octavian Paul
6   Author: Nasca Octavian Paul
7 
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2 of the License, or
11   (at your option) any later version.
12 
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License (version 2 or later) for more details.
17 
18   You should have received a copy of the GNU General Public License (version 2)
19   along with this program; if not, write to the Free Software Foundation,
20   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
21 
22 */
23 
24 #include "Reverb.h"
25 #include "../Misc/Util.h"
26 #include "../DSP/AnalogFilter.h"
27 #include "../DSP/Unison.h"
28 #include <cmath>
29 
Reverb(bool insertion_,float * efxoutl_,float * efxoutr_,unsigned int srate,int bufsize)30 Reverb::Reverb(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize)
31     :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize),
32       // defaults
33       Pvolume(48),
34       Ptime(64),
35       Pidelay(40),
36       Pidelayfb(0),
37       Plpf(127),
38       Phpf(0),
39       Plohidamp(80),
40       Ptype(1),
41       Proomsize(64),
42       Pbandwidth(30),
43       roomsize(1.0f),
44       rs(1.0f),
45       bandwidth(NULL),
46       idelay(NULL),
47       lpf(NULL),
48       hpf(NULL) // no filter
49 {
50     for(int i = 0; i < REV_COMBS * 2; ++i) {
51         comblen[i] = 800 + (int)(RND * 1400.0f);
52         combk[i]   = 0;
53         lpcomb[i]  = 0;
54         combfb[i]  = -0.97f;
55         comb[i]    = NULL;
56     }
57 
58     for(int i = 0; i < REV_APS * 2; ++i) {
59         aplen[i] = 500 + (int)(RND * 500.0f);
60         apk[i]   = 0;
61         ap[i]    = NULL;
62     }
63     setpreset(Ppreset);
64     cleanup(); //do not call this before the comb initialisation
65 }
66 
67 
~Reverb()68 Reverb::~Reverb()
69 {
70     delete [] idelay;
71     delete hpf;
72     delete lpf;
73 
74     for(int i = 0; i < REV_APS * 2; ++i)
75         delete [] ap[i];
76     for(int i = 0; i < REV_COMBS * 2; ++i)
77         delete [] comb[i];
78 
79     if(bandwidth)
80         delete bandwidth;
81 }
82 
83 //Cleanup the effect
cleanup(void)84 void Reverb::cleanup(void)
85 {
86     int i, j;
87     for(i = 0; i < REV_COMBS * 2; ++i) {
88         lpcomb[i] = 0.0f;
89         for(j = 0; j < comblen[i]; ++j)
90             comb[i][j] = 0.0f;
91     }
92 
93     for(i = 0; i < REV_APS * 2; ++i)
94         for(j = 0; j < aplen[i]; ++j)
95             ap[i][j] = 0.0f;
96 
97     if(idelay)
98         for(i = 0; i < idelaylen; ++i)
99             idelay[i] = 0.0f;
100     if(hpf)
101         hpf->cleanup();
102     if(lpf)
103         lpf->cleanup();
104 }
105 
106 //Process one channel; 0=left, 1=right
processmono(int ch,float * output,float * inputbuf)107 void Reverb::processmono(int ch, float *output, float *inputbuf)
108 {
109     //todo: implement the high part from lohidamp
110 
111     for(int j = REV_COMBS * ch; j < REV_COMBS * (ch + 1); ++j) {
112         int &ck = combk[j];
113         const int comblength = comblen[j];
114         float    &lpcombj    = lpcomb[j];
115 
116         for(int i = 0; i < buffersize; ++i) {
117             float fbout = comb[j][ck] * combfb[j];
118             fbout   = fbout * (1.0f - lohifb) + lpcombj * lohifb;
119             lpcombj = fbout;
120 
121             comb[j][ck] = inputbuf[i] + fbout;
122             output[i]  += fbout;
123 
124             if((++ck) >= comblength)
125                 ck = 0;
126         }
127     }
128 
129     for(int j = REV_APS * ch; j < REV_APS * (1 + ch); ++j) {
130         int &ak = apk[j];
131         const int aplength = aplen[j];
132         for(int i = 0; i < buffersize; ++i) {
133             float tmp = ap[j][ak];
134             ap[j][ak] = 0.7f * tmp + output[i];
135             output[i] = tmp - 0.7f * ap[j][ak];
136             if((++ak) >= aplength)
137                 ak = 0;
138         }
139     }
140 }
141 
142 //Effect output
out(const Stereo<float * > & smp)143 void Reverb::out(const Stereo<float *> &smp)
144 {
145     if(!Pvolume && insertion)
146         return;
147 
148     float inputbuf[buffersize];
149     for(int i = 0; i < buffersize; ++i)
150         inputbuf[i] = (smp.l[i] + smp.r[i]) / 2.0f;
151 
152     if(idelay)
153         for(int i = 0; i < buffersize; ++i) {
154             //Initial delay r
155             float tmp = inputbuf[i] + idelay[idelayk] * idelayfb;
156             inputbuf[i]     = idelay[idelayk];
157             idelay[idelayk] = tmp;
158             idelayk++;
159             if(idelayk >= idelaylen)
160                 idelayk = 0;
161         }
162 
163     if(bandwidth)
164         bandwidth->process(buffersize, inputbuf);
165 
166     if(lpf)
167         lpf->filterout(inputbuf);
168     if(hpf)
169         hpf->filterout(inputbuf);
170 
171     processmono(0, efxoutl, inputbuf); //left
172     processmono(1, efxoutr, inputbuf); //right
173 
174     float lvol = rs / REV_COMBS * pangainL;
175     float rvol = rs / REV_COMBS * pangainR;
176     if(insertion != 0) {
177         lvol *= 2.0f;
178         rvol *= 2.0f;
179     }
180     for(int i = 0; i < buffersize; ++i) {
181         efxoutl[i] *= lvol;
182         efxoutr[i] *= rvol;
183     }
184 }
185 
186 
187 //Parameter control
setvolume(unsigned char _Pvolume)188 void Reverb::setvolume(unsigned char _Pvolume)
189 {
190     Pvolume = _Pvolume;
191     if(!insertion) {
192         outvolume = powf(0.01f, (1.0f - Pvolume / 127.0f)) * 4.0f;
193         volume    = 1.0f;
194     }
195     else {
196         volume = outvolume = Pvolume / 127.0f;
197         if(Pvolume == 0)
198             cleanup();
199     }
200 }
201 
settime(unsigned char _Ptime)202 void Reverb::settime(unsigned char _Ptime)
203 {
204     Ptime = _Ptime;
205     float t = powf(60.0f, Ptime / 127.0f) - 0.97f;
206 
207     for(int i = 0; i < REV_COMBS * 2; ++i)
208         combfb[i] =
209             -expf((float)comblen[i] / samplerate_f * logf(0.001f) / t);
210     //the feedback is negative because it removes the DC
211 }
212 
setlohidamp(unsigned char _Plohidamp)213 void Reverb::setlohidamp(unsigned char _Plohidamp)
214 {
215     Plohidamp = (_Plohidamp < 64) ? 64 : _Plohidamp;
216     //remove this when the high part from lohidamp is added
217     if(Plohidamp == 64) {
218         lohidamptype = 0;
219         lohifb = 0.0f;
220     }
221     else {
222         if(Plohidamp < 64)
223             lohidamptype = 1;
224         if(Plohidamp > 64)
225             lohidamptype = 2;
226         float x = fabsf((float)(Plohidamp - 64) / 64.1f);
227         lohifb = x * x;
228     }
229 }
230 
setidelay(unsigned char _Pidelay)231 void Reverb::setidelay(unsigned char _Pidelay)
232 {
233     Pidelay = _Pidelay;
234     float delay = powf(50.0f * Pidelay / 127.0f, 2.0f) - 1.0f;
235 
236     if(idelay)
237         delete [] idelay;
238     idelay = NULL;
239 
240     idelaylen = (int) (samplerate_f * delay / 1000);
241     if(idelaylen > 1) {
242         idelayk = 0;
243         idelay  = new float[idelaylen];
244         memset(idelay, 0, idelaylen * sizeof(float));
245     }
246 }
247 
setidelayfb(unsigned char _Pidelayfb)248 void Reverb::setidelayfb(unsigned char _Pidelayfb)
249 {
250     Pidelayfb = _Pidelayfb;
251     idelayfb  = Pidelayfb / 128.0f;
252 }
253 
sethpf(unsigned char _Phpf)254 void Reverb::sethpf(unsigned char _Phpf)
255 {
256     Phpf = _Phpf;
257     if(Phpf == 0) { //No HighPass
258         if(hpf)
259             delete hpf;
260         hpf = NULL;
261     }
262     else {
263         float fr = expf(powf(Phpf / 127.0f, 0.5f) * logf(10000.0f)) + 20.0f;
264         if(hpf == NULL)
265             hpf = new AnalogFilter(3, fr, 1, 0, samplerate, buffersize);
266         else
267             hpf->setfreq(fr);
268     }
269 }
270 
setlpf(unsigned char _Plpf)271 void Reverb::setlpf(unsigned char _Plpf)
272 {
273     Plpf = _Plpf;
274     if(Plpf == 127) { //No LowPass
275         if(lpf)
276             delete lpf;
277         lpf = NULL;
278     }
279     else {
280         float fr = expf(powf(Plpf / 127.0f, 0.5f) * logf(25000.0f)) + 40.0f;
281         if(!lpf)
282             lpf = new AnalogFilter(2, fr, 1, 0, samplerate, buffersize);
283         else
284             lpf->setfreq(fr);
285     }
286 }
287 
settype(unsigned char _Ptype)288 void Reverb::settype(unsigned char _Ptype)
289 {
290     Ptype = _Ptype;
291     const int NUM_TYPES = 3;
292     const int combtunings[NUM_TYPES][REV_COMBS] = {
293         //this is unused (for random)
294         {0,    0,    0,    0,    0,    0,    0,    0      },
295         //Freeverb by Jezar at Dreampoint
296         {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617   },
297         //duplicate of Freeverb by Jezar at Dreampoint
298         {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617   }
299     };
300 
301     const int aptunings[NUM_TYPES][REV_APS] = {
302         //this is unused (for random)
303         {0,   0,   0,   0    },
304         //Freeverb by Jezar at Dreampoint
305         {225, 341, 441, 556  },
306         //duplicate of Freeverb by Jezar at Dreampoint
307         {225, 341, 441, 556  }
308     };
309 
310     if(Ptype >= NUM_TYPES)
311         Ptype = NUM_TYPES - 1;
312 
313     // adjust the combs according to the samplerate
314     float samplerate_adjust = samplerate_f / 44100.0f;
315     float tmp;
316     for(int i = 0; i < REV_COMBS * 2; ++i) {
317         if(Ptype == 0)
318             tmp = 800.0f + (int)(RND * 1400.0f);
319         else
320             tmp = combtunings[Ptype][i % REV_COMBS];
321         tmp *= roomsize;
322         if(i > REV_COMBS)
323             tmp += 23.0f;
324         tmp *= samplerate_adjust; //adjust the combs according to the samplerate
325         if(tmp < 10.0f)
326             tmp = 10.0f;
327         comblen[i] = (int) tmp;
328         combk[i]   = 0;
329         lpcomb[i]  = 0;
330         if(comb[i])
331             delete [] comb[i];
332         comb[i] = new float[comblen[i]];
333     }
334 
335     for(int i = 0; i < REV_APS * 2; ++i) {
336         if(Ptype == 0)
337             tmp = 500 + (int)(RND * 500.0f);
338         else
339             tmp = aptunings[Ptype][i % REV_APS];
340         tmp *= roomsize;
341         if(i > REV_APS)
342             tmp += 23.0f;
343         tmp *= samplerate_adjust; //adjust the combs according to the samplerate
344         if(tmp < 10)
345             tmp = 10;
346         aplen[i] = (int) tmp;
347         apk[i]   = 0;
348         if(ap[i])
349             delete [] ap[i];
350         ap[i] = new float[aplen[i]];
351     }
352     delete bandwidth;
353     bandwidth = NULL;
354     if(Ptype == 2) { //bandwidth
355         //TODO the size of the unison buffer may be too small, though this has
356         //not been verified yet.
357         //As this cannot be resized in a RT context, a good upper bound should
358         //be found
359         bandwidth = new Unison(buffersize / 4 + 1, 2.0f, samplerate_f);
360         bandwidth->setSize(50);
361         bandwidth->setBaseFrequency(1.0f);
362     }
363     settime(Ptime);
364     cleanup();
365 }
366 
setroomsize(unsigned char _Proomsize)367 void Reverb::setroomsize(unsigned char _Proomsize)
368 {
369     Proomsize = _Proomsize;
370     if(!Proomsize)
371         this->Proomsize = 64;  //this is because the older versions consider roomsize=0
372     roomsize = (this->Proomsize - 64.0f) / 64.0f;
373     if(roomsize > 0.0f)
374         roomsize *= 2.0f;
375     roomsize = powf(10.0f, roomsize);
376     rs = sqrtf(roomsize);
377     settype(Ptype);
378 }
379 
setbandwidth(unsigned char _Pbandwidth)380 void Reverb::setbandwidth(unsigned char _Pbandwidth)
381 {
382     Pbandwidth = _Pbandwidth;
383     float v = Pbandwidth / 127.0f;
384     if(bandwidth)
385         bandwidth->setBandwidth(powf(v, 2.0f) * 200.0f);
386 }
387 
setpreset(unsigned char npreset)388 void Reverb::setpreset(unsigned char npreset)
389 {
390     const int     PRESET_SIZE = 13;
391     const int     NUM_PRESETS = 13;
392     unsigned char presets[NUM_PRESETS][PRESET_SIZE] = {
393         //Cathedral1
394         {80,  64, 63,  24, 0,  0, 0, 85,  5,  83,  1, 64,  20},
395         //Cathedral2
396         {80,  64, 69,  35, 0,  0, 0, 127, 0,  71,  0, 64,  20},
397         //Cathedral3
398         {80,  64, 69,  24, 0,  0, 0, 127, 75, 78,  1, 85,  20},
399         //Hall1
400         {90,  64, 51,  10, 0,  0, 0, 127, 21, 78,  1, 64,  20},
401         //Hall2
402         {90,  64, 53,  20, 0,  0, 0, 127, 75, 71,  1, 64,  20},
403         //Room1
404         {100, 64, 33,  0,  0,  0, 0, 127, 0,  106, 0, 30,  20},
405         //Room2
406         {100, 64, 21,  26, 0,  0, 0, 62,  0,  77,  1, 45,  20},
407         //Basement
408         {110, 64, 14,  0,  0,  0, 0, 127, 5,  71,  0, 25,  20},
409         //Tunnel
410         {85,  80, 84,  20, 42, 0, 0, 51,  0,  78,  1, 105, 20},
411         //Echoed1
412         {95,  64, 26,  60, 71, 0, 0, 114, 0,  64,  1, 64,  20},
413         //Echoed2
414         {90,  64, 40,  88, 71, 0, 0, 114, 0,  88,  1, 64,  20},
415         //VeryLong1
416         {90,  64, 93,  15, 0,  0, 0, 114, 0,  77,  0, 95,  20},
417         //VeryLong2
418         {90,  64, 111, 30, 0,  0, 0, 114, 90, 74,  1, 80,  20}
419     };
420 
421     if(npreset >= NUM_PRESETS)
422         npreset = NUM_PRESETS - 1;
423     for(int n = 0; n < PRESET_SIZE; ++n)
424         changepar(n, presets[npreset][n]);
425     if(insertion)
426         changepar(0, presets[npreset][0] / 2);  //lower the volume if reverb is insertion effect
427     Ppreset = npreset;
428 }
429 
430 
changepar(int npar,unsigned char value)431 void Reverb::changepar(int npar, unsigned char value)
432 {
433     switch(npar) {
434         case 0:
435             setvolume(value);
436             break;
437         case 1:
438             setpanning(value);
439             break;
440         case 2:
441             settime(value);
442             break;
443         case 3:
444             setidelay(value);
445             break;
446         case 4:
447             setidelayfb(value);
448             break;
449 //      case 5:
450 //          setrdelay(value);
451 //          break;
452 //      case 6:
453 //          seterbalance(value);
454 //          break;
455         case 7:
456             setlpf(value);
457             break;
458         case 8:
459             sethpf(value);
460             break;
461         case 9:
462             setlohidamp(value);
463             break;
464         case 10:
465             settype(value);
466             break;
467         case 11:
468             setroomsize(value);
469             break;
470         case 12:
471             setbandwidth(value);
472             break;
473     }
474 }
475 
getpar(int npar) const476 unsigned char Reverb::getpar(int npar) const
477 {
478     switch(npar) {
479         case 0:  return Pvolume;
480         case 1:  return Ppanning;
481         case 2:  return Ptime;
482         case 3:  return Pidelay;
483         case 4:  return Pidelayfb;
484         case 7:  return Plpf;
485         case 8:  return Phpf;
486         case 9:  return Plohidamp;
487         case 10: return Ptype;
488         case 11: return Proomsize;
489         case 12: return Pbandwidth;
490         default: return 0;
491     }
492 }
493