1 /*
2   ZynAddSubFX - a software synthesizer
3 
4   RBEcho.C - Echo effect
5   Copyright (C) 2002-2005 Nasca Octavian Paul
6   Author: Nasca Octavian Paul
7 
8   Modified for rakarrack by Josep Andreu
9   Reverse Echo effect by Transmogrifox
10 
11   This program is free software; you can redistribute it and/or modify
12   it under the terms of version 2 of the GNU General Public License
13   as published by the Free Software Foundation.
14 
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License (version 2) for more details.
19 
20   You should have received a copy of the GNU General Public License (version 2)
21   along with this program; if not, write to the Free Software Foundation,
22   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
23 
24 */
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include "RBEcho.h"
30 
RBEcho(float * efxoutl_,float * efxoutr_,double sample_rate)31 RBEcho::RBEcho (float * efxoutl_, float * efxoutr_, double sample_rate)
32 {
33     efxoutl = efxoutl_;
34     efxoutr = efxoutr_;
35     fSAMPLE_RATE = sample_rate;
36 
37     //default values
38     Ppreset = 0;
39     Pvolume = 50;
40     Ppanning = 64;
41     Pdelay = 60;
42     Plrdelay = 100;
43     Plrcross = 100;
44     Pfb = 40;
45     Phidamp = 60;
46     Psubdiv = 1;
47     subdiv = 1.0f;
48     reverse = ireverse = 0.0f;
49     pingpong = 0.0f;
50     ipingpong = 1.0f;
51 
52     lrdelay = 0;
53     Srate_Attack_Coeff = 1.0f / (sample_rate * ATTACK);
54     maxx_delay = 1 + sample_rate * MAX_DELAY;
55 
56     ldelay = new delayline(2.0f, 3, sample_rate);
57     rdelay = new delayline(2.0f, 3, sample_rate);
58 
59     setpreset (Ppreset);
60     cleanup ();
61 };
62 
~RBEcho()63 RBEcho::~RBEcho ()
64 {
65 	delete ldelay;
66 	delete rdelay;
67 };
68 
69 /*
70  * Cleanup the effect
71  */
72 void
cleanup()73 RBEcho::cleanup ()
74 {
75     ldelay->cleanup();
76     rdelay->cleanup();
77     ldelay->set_averaging(0.25f);
78     rdelay->set_averaging(0.25f);
79     oldl = 0.0;
80     oldr = 0.0;
81 };
82 
83 
84 /*
85  * Initialize the delays
86  */
87 void
initdelays()88 RBEcho::initdelays ()
89 {
90     oldl = 0.0;
91     oldr = 0.0;
92 
93     if(Plrdelay>0) {
94         ltime = delay + lrdelay;
95         rtime = delay - lrdelay;
96     } else {
97         ltime = delay - lrdelay;
98         rtime = delay + lrdelay;
99     }
100 
101     if(ltime > 2.0f) ltime = 2.0f;
102     if(ltime<0.01f) ltime = 0.01f;
103 
104     if(rtime > 2.0f) rtime = 2.0f;
105     if(rtime<0.01f) rtime = 0.01f;
106 
107 
108 };
109 
110 /*
111  * Effect output
112  */
113 void
out(float * smpsl,float * smpsr,uint32_t period)114 RBEcho::out (float * smpsl, float * smpsr, uint32_t period)
115 {
116     unsigned int i;
117     float ldl, rdl;
118     float avg, ldiff, rdiff, tmp;
119 
120 
121     for (i = 0; i < period; i++) {
122 
123         //LowPass Filter
124         ldl = lfeedback * hidamp + oldl * (1.0f - hidamp);
125         rdl = rfeedback * hidamp + oldr * (1.0f - hidamp);
126         oldl = ldl + DENORMAL_GUARD;
127         oldr = rdl + DENORMAL_GUARD;
128 
129         ldl = ldelay->delay_simple((ldl + smpsl[i]), delay, 0, 1, 0);
130         rdl = rdelay->delay_simple((rdl + smpsr[i]), delay, 0, 1, 0);
131 
132 
133         if(Preverse) {
134             rvl = ldelay->delay_simple(oldl, delay, 1, 0, 1)*ldelay->envelope();
135             rvr = rdelay->delay_simple(oldr, delay, 1, 0, 1)*rdelay->envelope();
136             ldl = ireverse*ldl + reverse*rvl;
137             rdl = ireverse*rdl + reverse*rvr;
138 
139         }
140 
141 
142         //lfeedback = lpanning * fb * ldl;
143         //rfeedback = rpanning * fb * rdl;
144         lfeedback = rpanning * fb * ldl;
145         rfeedback = lpanning * fb * rdl;
146 
147         if(Pes) {
148             ldl *= cosf(lrcross);
149             rdl *= sinf(lrcross);
150 
151             avg = (ldl + rdl) * 0.5f;
152             ldiff = ldl - avg;
153             rdiff = rdl - avg;
154 
155             tmp = avg + ldiff * pes;
156             ldl = 0.5 * tmp;
157 
158             tmp = avg + rdiff * pes;
159             rdl = 0.5f * tmp;
160 
161 
162         }
163         //efxoutl[i] = (ipingpong*ldl + pingpong *ldelay->delay_simple(0.0f, ltime, 2, 0, 0)) * lpanning;
164         //efxoutr[i] = (ipingpong*rdl + pingpong *rdelay->delay_simple(0.0f, rtime, 2, 0, 0)) * rpanning;
165         efxoutl[i] = (ipingpong*ldl + pingpong *ldelay->delay_simple(0.0f, ltime, 2, 0, 0)) * rpanning;
166         efxoutr[i] = (ipingpong*rdl + pingpong *rdelay->delay_simple(0.0f, rtime, 2, 0, 0)) * lpanning;
167 
168     };
169 
170 };
171 
172 
173 /*
174  * Parameter control
175  */
176 void
setvolume(int Pvolume)177 RBEcho::setvolume (int Pvolume)
178 {
179     this->Pvolume = Pvolume;
180     outvolume = (float)Pvolume / 127.0f;
181 
182 };
183 
184 void
setpanning(int Ppanning)185 RBEcho::setpanning (int Ppanning)
186 {
187     this->Ppanning = Ppanning;
188     lpanning = ((float)Ppanning) / 64.0f;
189     rpanning = 2.0f - lpanning;
190     lpanning = 10.0f * powf(lpanning, 4);
191     rpanning = 10.0f * powf(rpanning, 4);
192     lpanning = 1.0f - 1.0f/(lpanning + 1.0f);
193     rpanning = 1.0f - 1.0f/(rpanning + 1.0f);
194     lpanning *= 1.1f;
195     rpanning *= 1.1f;
196 };
197 
198 void
setreverse(int Preverse)199 RBEcho::setreverse (int Preverse)
200 {
201     this->Preverse = Preverse;
202     reverse = (float) Preverse / 127.0f;
203     ireverse = 1.0f - reverse;
204 };
205 
206 void
setdelay(int Pdelay)207 RBEcho::setdelay (int Pdelay)
208 {
209     this->Pdelay = Pdelay;
210     fdelay= 60.0f/((float) Pdelay);
211     if (fdelay < 0.01f) fdelay = 0.01f;
212     if (fdelay > (float) MAX_DELAY) fdelay = (float) MAX_DELAY;  //Constrains 10ms ... MAX_DELAY
213     delay = subdiv * fdelay;
214     initdelays ();
215 };
216 
217 void
setlrdelay(int Plrdelay)218 RBEcho::setlrdelay (int Plrdelay)
219 {
220     float tmp;
221     this->Plrdelay = Plrdelay;
222     lrdelay = delay * fabs(((float)Plrdelay - 64.0f) / 65.0f);
223 
224     tmp = fabs( ((float) Plrdelay - 64.0f)/32.0f);
225     pingpong = 1.0f - 1.0f/(5.0f*tmp*tmp + 1.0f);
226     pingpong *= 1.05159f;
227     ipingpong = 1.0f - pingpong;
228     initdelays ();
229 };
230 
231 void
setlrcross(int Plrcross)232 RBEcho::setlrcross (int Plrcross)
233 {
234     this->Plrcross = Plrcross;
235     lrcross = D_PI * (float)Plrcross / 128.0f;
236 
237 };
238 
239 void
setfb(int Pfb)240 RBEcho::setfb (int Pfb)
241 {
242     this->Pfb = Pfb;
243     fb = (float)Pfb / 128.0f;
244 };
245 
246 void
sethidamp(int Phidamp)247 RBEcho::sethidamp (int Phidamp)
248 {
249     this->Phidamp = Phidamp;
250     hidamp = f_exp(-D_PI * 500.0f * ((float) Phidamp)/fSAMPLE_RATE);
251 };
252 
253 void
setpreset(int npreset)254 RBEcho::setpreset (int npreset)
255 {
256     const int PRESET_SIZE = 10;
257     const int NUM_PRESETS = 3;
258     int pdata[PRESET_SIZE];
259     int presets[NUM_PRESETS][PRESET_SIZE] = {
260         //Echo 1
261         {64, 64, 90, 64, 64, 64, 64, 0, 1, 96},
262         //Echo 2
263         {64, 64, 90, 64, 64, 64, 64, 0, 2 ,96},
264         //Echo 3
265         {64, 64, 90, 64, 64, 64, 64, 0, 3 ,96}
266     };
267 
268     if(npreset>NUM_PRESETS-1) {
269         Fpre->ReadPreset(32,npreset-NUM_PRESETS+1,pdata);
270         for (int n = 0; n < PRESET_SIZE; n++)
271             changepar (n, pdata[n]);
272     } else {
273         for (int n = 0; n < PRESET_SIZE; n++)
274             changepar (n, presets[npreset][n]);
275     }
276     Ppreset = npreset;
277 };
278 
279 
280 void
changepar(int npar,int value)281 RBEcho::changepar (int npar, int value)
282 {
283     switch (npar) {
284     case 0:
285         setvolume (value);
286         break;
287     case 1:
288         setpanning (value);
289         break;
290     case 2:
291         setdelay (value);
292         break;
293     case 3:
294         setlrdelay (value);
295         break;
296     case 4:
297         setlrcross (value);
298         break;
299     case 5:
300         setfb (value);
301         break;
302     case 6:
303         sethidamp (value);
304         break;
305     case 7:
306         setreverse (value);
307         break;
308     case 8:
309         Psubdiv = value;
310         subdiv = 1.0f/((float)(value + 1));
311         delay = subdiv * fdelay;
312         initdelays ();
313         break;
314     case 9:
315         Pes = value;
316         pes = 8.0f * (float)Pes / 127.0f;
317         break;
318     };
319 };
320 
321 int
getpar(int npar)322 RBEcho::getpar (int npar)
323 {
324     switch (npar) {
325     case 0:
326         return (Pvolume);
327         break;
328     case 1:
329         return (Ppanning);
330         break;
331     case 2:
332         return (Pdelay);
333         break;
334     case 3:
335         return (Plrdelay);
336         break;
337     case 4:
338         return (Plrcross);
339         break;
340     case 5:
341         return (Pfb);
342         break;
343     case 6:
344         return (Phidamp);
345         break;
346     case 7:
347         return (Preverse);
348         break;
349     case 8:
350         return (Psubdiv);
351         break;
352     case 9:
353         return (Pes);
354         break;
355 
356     };
357     return (0);			//in case of bogus parameter number
358 };
359