1 /*
2 
3   Synthfilter.C  - Approximate digital model of an analog JFET phaser.
4   Analog modeling implemented by Ryan Billing aka Transmogrifox.
5   November, 2009
6 
7   Credit to:
8   ///////////////////
9   ZynAddSubFX - a software synthesizer
10 
11   Phaser.C - Phaser effect
12   Copyright (C) 2002-2005 Nasca Octavian Paul
13   Author: Nasca Octavian Paul
14 
15   Modified for rakarrack by Josep Andreu
16 
17   DSP analog modeling theory & practice largely influenced by various CCRMA publications, particularly works by Julius O. Smith.
18   ////////////////////
19 
20 
21   This program is free software; you can redistribute it and/or modify
22   it under the terms of version 2 of the GNU General Public License
23   as published by the Free Software Foundation.
24 
25   This program is distributed in the hope that it will be useful,
26   but WITHOUT ANY WARRANTY; without even the implied warranty of
27   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28   GNU General Public License (version 2) for more details.
29 
30   You should have received a copy of the GNU General Public License (version 2)
31   along with this program; if not, write to the Free Software Foundation,
32   Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
33 
34 */
35 
36 #include <math.h>
37 #include "Synthfilter.h"
38 #include <stdio.h>
39 
40 #define ONE_  0.99999f        // To prevent LFO ever reaching 1.0 for filter stability purposes
41 #define ZERO_ 0.00001f        // Same idea as above.
42 
Synthfilter(float * efxoutl_,float * efxoutr_,double sample_rate)43 Synthfilter::Synthfilter (float * efxoutl_, float * efxoutr_, double sample_rate)
44 {
45     efxoutl = efxoutl_;
46     efxoutr = efxoutr_;
47 
48     lyn1 = new float[MAX_SFILTER_STAGES];
49     ryn1 = new float[MAX_SFILTER_STAGES];
50     lx1hp = new float[MAX_SFILTER_STAGES];
51     rx1hp = new float[MAX_SFILTER_STAGES];
52     ly1hp = new float[MAX_SFILTER_STAGES];
53     ry1hp = new float[MAX_SFILTER_STAGES];
54 
55     Plpstages = 4;
56     Phpstages = 2;
57 
58     delta = 1.0/sample_rate;
59     Rmin = 185.0f;		// 2N5457 typical on resistance at Vgs = 0
60     Rmax = 22000.0f;		// Resistor
61     C = 0.00000005f;		// 50 nF
62     Chp = 0.00000005f;
63     Clp = 0.00000005f;
64     att = delta * 5.0f;		//200ms
65     rls = delta * 5.0f;		//200ms
66 
67     lfo = new EffectLFO(sample_rate);
68 
69 
70     Ppreset = 0;
71     setpreset (Ppreset);
72     cleanup ();
73 };
74 
~Synthfilter()75 Synthfilter::~Synthfilter ()
76 {
77 	delete[] lyn1;
78 	delete[] ryn1;
79 	delete[] lx1hp;
80 	delete[] rx1hp;
81 	delete[] ly1hp;
82 	delete[] ry1hp;
83 	delete lfo;
84 };
85 
86 
87 /*
88  * Effect output
89  */
90 void
out(float * smpsl,float * smpsr,uint32_t period)91 Synthfilter::out (float * smpsl, float * smpsr, uint32_t period)
92 {
93     unsigned int i;
94 	int j;
95     float lfol, lfor, lgain, rgain,rmod, lmod, d;
96     inv_period = 1.f/(float)period;
97     lgain = 0.0;
98     rgain = 0.0;
99 
100     lfo->effectlfoout (&lfol, &lfor);
101     lmod = lfol*width + depth + env*sns;
102     rmod = lfor*width + depth + env*sns;
103 
104     if (lmod > ONE_)
105         lmod = ONE_;
106     else if (lmod < ZERO_)
107         lmod = ZERO_;
108     if (rmod > ONE_)
109         rmod = ONE_;
110     else if (rmod < ZERO_)
111         rmod = ZERO_;
112 
113     lmod = 1.0f - lmod;
114     rmod = 1.0f - rmod;
115     lmod*=lmod;
116     rmod*=rmod;
117 
118     float xl = (lmod - oldlgain) * inv_period;
119     float xr = (rmod - oldrgain) * inv_period;
120     float gl = oldlgain;	// Linear interpolation between LFO samples
121     float gr = oldrgain;
122 
123     for (i = 0; i < period; i++) {
124 
125         float lxn = bandgain*smpsl[i];
126         float rxn = bandgain*smpsr[i]; //extra gain
127 
128         gl += xl;
129         gr += xr;   //linear interpolation of LFO
130 
131         //Envelope detection
132         envdelta = (fabsf (efxoutl[i]) + fabsf (efxoutr[i])) - env;    //envelope follower from Compressor.C
133         if (delta > 0.0)
134             env += att * envdelta;
135         else
136             env += rls * envdelta;
137 
138         //End envelope power detection
139 
140         if (Plpstages<1) {
141             lxn += fbl;
142             rxn += fbr;
143         }
144 
145 
146         //Left channel Low Pass Filter
147         for (j = 0; j < Plpstages; j++) {
148             d = 1.0f + fabs(lxn)*distortion;  // gain decreases as signal amplitude increases.
149 
150             //low pass filter:  alpha*x[n] + (1-alpha)*y[n-1]
151             // alpha = lgain = dt/(RC + dt)
152             lgain = delta/( (Rmax * gl * d + Rmin) * Clp + delta);
153             lyn1[j] = lgain * lxn + (1.0f - lgain) * lyn1[j];
154             lyn1[j] += DENORMAL_GUARD;
155             lxn = lyn1[j];
156             if (j==0) lxn += fbl;  //Insert feedback after first filter stage
157         };
158 
159 
160         //Left channel High Pass Filter
161         for (j = 0; j < Phpstages; j++) {
162 
163             //high pass filter:  alpha*(y[n-1] + x[n] - x[n-1]) // alpha = lgain = RC/(RC + dt)
164             lgain = (Rmax * gl + Rmin) * Chp/( (Rmax * gl  + Rmin) * Chp + delta);
165             ly1hp[j] = lgain * (lxn + ly1hp[j] - lx1hp[j]);
166 
167             ly1hp[j] += DENORMAL_GUARD;
168             lx1hp[j] = lxn;
169             lxn = ly1hp[j];
170 
171         };
172 
173 
174         //Right channel Low Pass Filter
175         for (j = 0; j < Plpstages; j++) {
176             d = 1.0f + fabs(rxn)*distortion;  //This is symmetrical. FET is not, so this deviates slightly, however sym dist. is better sounding than a real FET.
177 
178             rgain = delta/((Rmax*gr*d + Rmin)*Clp + delta);
179             ryn1[j] = rgain * rxn + (1.0f - rgain) * ryn1[j];
180             ryn1[j] += DENORMAL_GUARD;
181             rxn = ryn1[j];
182             if (j==0) rxn += fbr;  //Insert feedback after first filter stage
183         };
184 
185         //Right channel High Pass Filter
186         for (j = 0; j < Phpstages; j++) {
187             d = 1.0f + fabs(rxn)*distortion;  // gain decreases as signal amplitude increases.
188 
189             //high pass filter:  alpha*(y[n-1] + x[n] - x[n-1]) // alpha = rgain = RC/(RC + dt)
190             rgain = (Rmax * gr  + Rmin) * Chp/( (Rmax * gr + Rmin) * Chp + delta);
191             ry1hp[j] = rgain * (rxn + ry1hp[j] - rx1hp[j]);
192 
193             ry1hp[j] += DENORMAL_GUARD;
194             rx1hp[j] = rxn;
195             rxn = ry1hp[j];
196         };
197 
198         fbl = lxn * fb;
199         fbr = rxn * fb;
200 
201         efxoutl[i] = lxn;
202         efxoutr[i] = rxn;
203 
204     };
205 
206     oldlgain = lmod;
207     oldrgain = rmod;
208 
209     if (Poutsub != 0)
210         for (i = 0; i < period; i++) {
211             efxoutl[i] *= -1.0f;
212             efxoutr[i] *= -1.0f;
213         };
214 
215 };
216 
217 /*
218  * Cleanup the effect
219  */
220 void
cleanup()221 Synthfilter::cleanup ()
222 {
223     fbl = 0.0f;
224     fbr = 0.0f;
225     oldlgain = 0.0f;
226     oldrgain = 0.0f;
227     env = 0.0f;
228     envdelta = 0.0f;
229     for (int i = 0; i <MAX_SFILTER_STAGES; i++) {
230         lyn1[i] = 0.0f;
231         ryn1[i] = 0.0f;
232 
233         ly1hp[i] = 0.0f;
234         lx1hp[i] = 0.0f;
235         ry1hp[i] = 0.0f;
236         rx1hp[i] = 0.0f;
237     };
238 };
239 
240 /*
241  * Parameter control
242  */
243 void
setwidth(int Pwidth)244 Synthfilter::setwidth (int Pwidth)
245 {
246     this->Pwidth = Pwidth;
247     width = ((float)Pwidth / 127.0f);
248 };
249 
250 
251 void
setfb(int Pfb)252 Synthfilter::setfb (int Pfb)
253 {
254     this->Pfb = Pfb;
255     fb = (float) Pfb;
256     if (fb<0.0f) fb /= 18.0f;
257     else if (fb>0.0f) fb/=65.0f;
258     if(Plpstages<=2) fb *= 0.3;  //keep filter stable when phase shift is small
259 
260 };
261 
262 void
setvolume(int Pvolume)263 Synthfilter::setvolume (int Pvolume)
264 {
265     this->Pvolume = Pvolume;
266     // outvolume is needed in calling program
267     outvolume = (float)Pvolume / 127.0f;
268 };
269 
270 void
setdistortion(int Pdistortion)271 Synthfilter::setdistortion (int Pdistortion)
272 {
273     this->Pdistortion = Pdistortion;
274     distortion = (float)Pdistortion / 127.0f;
275 };
276 
277 
278 void
setdepth(int Pdepth)279 Synthfilter::setdepth (int Pdepth)
280 {
281     this->Pdepth = Pdepth;
282     depth = (float)(Pdepth - 32) / 95.0f;  //Pdepth input should be 0-127. .
283 };
284 
285 
286 void
setpreset(int npreset)287 Synthfilter::setpreset (int npreset)
288 {
289     const int PRESET_SIZE = 16;
290     const int NUM_PRESETS = 7;
291     int pdata[PRESET_SIZE];
292     int presets[NUM_PRESETS][PRESET_SIZE] = {
293         //Low Pass
294         {0, 20, 14, 0, 1, 64, 110, -40, 6, 0, 0, 32, -32, 500, 100, 0},
295         //High Pass
296         {0, 20, 14, 0, 1, 64, 110, -40, 0, 6, 0, 32, -32, 500, 100, 0},
297         //Band Pass
298         {0, 20, 14, 0, 1, 64, 110, -40, 4, 4, 0, 32, -32, 500, 100, 0},
299         //Lead Synth
300         {0, 89, 31, 0, 1, 95, 38, -16, 1, 2, 1, 114, -32, 92, 215, 29},
301         //Water
302         {20, 69, 88, 0, 6, 0, 76, -50, 6, 2, 1, 0, 19, 114, 221, 127},
303         //Pan Filter
304         {0, 20, 100, 0, 5, 127, 127, -64, 2, 0, 0, 57, 0, 340, 288, 110},
305         //Multi
306         {64, 45, 88, 0, 1, 127, 81, 0, 4, 2, 0, 67, 0, 394, 252, 61}
307 
308 
309     };
310 
311     if(npreset>NUM_PRESETS-1) {
312         Fpre->ReadPreset(27,npreset-NUM_PRESETS+1,pdata);
313         for (int n = 0; n < PRESET_SIZE; n++)
314             changepar (n, pdata[n]);
315     } else {
316 
317         for (int n = 0; n < PRESET_SIZE; n++)
318             changepar (n, presets[npreset][n]);
319     }
320     Ppreset = npreset;
321 };
322 
323 
324 void
changepar(int npar,int value)325 Synthfilter::changepar (int npar, int value)
326 {
327     switch (npar) {
328     case 0:
329         setvolume (value);
330         break;
331     case 1:
332         setdistortion (value);
333         break;
334     case 2:
335         lfo->Pfreq = value;
336         lfo->updateparams (PERIOD);
337         break;
338     case 3:
339         lfo->Prandomness = value;
340         lfo->updateparams (PERIOD);
341         break;
342     case 4:
343         lfo->PLFOtype = value;
344         lfo->updateparams (PERIOD);
345         break;
346     case 5:
347         lfo->Pstereo = value;
348         lfo->updateparams (PERIOD);
349         break;
350     case 6:
351         setwidth (value);
352         break;
353     case 7:
354         setfb (value);
355         break;
356     case 8:
357         Plpstages = value;
358         if (Plpstages >= MAX_SFILTER_STAGES)
359             Plpstages = MAX_SFILTER_STAGES ;
360         if(Plpstages<=2) fb = (float) Pfb * 0.25/65.0f;  //keep filter stable when phase shift is small
361         cleanup ();
362         break;
363     case 9:
364         Phpstages = value;
365         if (Phpstages >= MAX_SFILTER_STAGES)
366             Phpstages = MAX_SFILTER_STAGES ;
367         cleanup ();
368         break;
369     case 10:
370         if (value > 1)
371             value = 1;
372         Poutsub = value;
373         break;
374     case 11:
375         setdepth (value);
376         break;
377     case 12:
378         Penvelope = value;
379         sns = (float) Penvelope/8.0f;
380         break;
381     case 13:
382         Pattack = value;
383         if(Pattack < 5) Pattack = 5;
384         att = delta * 1000.0f/((float) Pattack);
385         break;
386     case 14:
387         Prelease = value;
388         if(Prelease < 5) Prelease = 5;
389         rls = delta * 1000.0f/((float) Prelease);
390         break;
391     case 15:
392         Pbandwidth = value;
393         Chp = C * (1.0f + ((float) value)/64.0f);  // C*3
394         Clp = C * (1.0f - ((float) value)/190.0f); // C/3
395         break;
396     };
397 
398     if(Phpstages && Plpstages)
399         bandgain = powf(((float)(Phpstages*Plpstages + 3)), (1.0f - (float) Pbandwidth/127.0f));
400     else bandgain = 1.0f;
401 
402 };
403 
404 int
getpar(int npar)405 Synthfilter::getpar (int npar)
406 {
407     switch (npar) {
408     case 0:
409         return (Pvolume);
410         break;
411     case 1:
412         return (Pdistortion);
413         break;
414     case 2:
415         return (lfo->Pfreq);
416         break;
417     case 3:
418         return (lfo->Prandomness);
419         break;
420     case 4:
421         return (lfo->PLFOtype);
422         break;
423     case 5:
424         return (lfo->Pstereo);
425         break;
426     case 6:
427         return (Pwidth);
428         break;
429     case 7:
430         return (Pfb);
431         break;
432     case 8:
433         return (Plpstages);
434         break;
435     case 9:
436         return (Phpstages);
437         break;
438     case 10:
439         return (Poutsub);
440         break;
441     case 11:
442         return (Pdepth);
443         break;
444     case 12:
445         return (Penvelope);
446         break;
447     case 13:
448         return (Pattack);
449         break;
450     case 14:
451         return (Prelease);
452         break;
453     case 15:
454         return (Pbandwidth);
455         break;
456 
457     default:
458         return (0);
459     };
460 
461 };
462