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