1 /*
2
3 Echotron.C - Echotron effect
4 Author: Ryan Billing & Josep Andreu
5
6 Adapted effect structure of ZynAddSubFX - a software synthesizer
7 Author: Nasca Octavian Paul
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of version 2 of the GNU General Public License
11 as published by the Free Software Foundation.
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) 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 <stdio.h>
25 #include <stdlib.h>
26 #include <math.h>
27
28 #include "Echotron.h"
29
30 //TODO: make LV2 plugins deal with this correctly
31 #ifndef DATADIR
32 #define DATADIR "/usr/local/share/rakarrack"
33 #endif
34
Echotron(float * efxoutl_,float * efxoutr_,double sample_rate,uint32_t intermediate_bufsize)35 Echotron::Echotron (float * efxoutl_, float * efxoutr_, double sample_rate, uint32_t intermediate_bufsize)
36 {
37 efxoutl = efxoutl_;
38 efxoutr = efxoutr_;
39
40 initparams=0;
41 //default values
42 Ppreset = 0;
43 Pvolume = 50;
44 Ppanning = 64;
45 Plrcross = 100;
46 Phidamp = 60;
47 Filenum = 0;
48 Plength = 10;
49 Puser = 0;
50 fb = 0.0f;
51 lfeedback = 0.0f;
52 rfeedback = 0.0f;
53 File = loaddefault();
54 fPERIOD = 256; //best guess until we know better
55 fSAMPLE_RATE = sample_rate;
56
57 lfo = new EffectLFO(sample_rate);
58 dlfo = new EffectLFO(sample_rate);
59
60
61 maxx_size = (sample_rate * 6); //6 Seconds delay time
62
63 lxn = new delayline(6.0f, ECHOTRON_F_SIZE, sample_rate);
64 rxn = new delayline(6.0f, ECHOTRON_F_SIZE, sample_rate);
65
66 lxn->set_mix(0.0f);
67 rxn->set_mix(0.0f);
68
69 offset = 0;
70
71 interpbuf = new float[intermediate_bufsize];
72 lpfl = new AnalogFilter (0, 800, 1, 0, sample_rate, interpbuf);
73 lpfr = new AnalogFilter (0, 800, 1, 0, sample_rate, interpbuf);
74
75 float center, qq;
76 for (int i = 0; i < ECHOTRON_MAXFILTERS; i++) {
77 center = 500;
78 qq = 1.0f;
79 filterbank[i].sfreq = center;
80 filterbank[i].sq = qq;
81 filterbank[i].sLP = 0.25f;
82 filterbank[i].sBP = -1.0f;
83 filterbank[i].sHP = 0.5f;
84 filterbank[i].sStg = 1.0f;
85 filterbank[i].l = new RBFilter (0, center, qq, 0, sample_rate, interpbuf);
86 filterbank[i].r = new RBFilter (0, center, qq, 0, sample_rate, interpbuf);
87
88 filterbank[i].l->setmix (1,filterbank[i].sLP , filterbank[i].sBP,filterbank[i].sHP);
89 filterbank[i].r->setmix (1,filterbank[i].sLP , filterbank[i].sBP,filterbank[i].sHP);
90 };
91
92 setpreset (Ppreset);
93 cleanup ();
94 };
95
~Echotron()96 Echotron::~Echotron ()
97 {
98 delete lxn;
99 delete rxn;
100 delete lpfl;
101 delete lpfr;
102 for (int i = 0; i < ECHOTRON_MAXFILTERS; i++) {
103 delete filterbank[i].l;
104 delete filterbank[i].r;
105 }
106 delete[] interpbuf;
107 };
108
109 /*
110 * Cleanup the effect
111 */
112 void
cleanup()113 Echotron::cleanup ()
114 {
115
116 lxn->cleanup();
117 rxn->cleanup();
118 lxn->set_averaging(0.05f);
119 rxn->set_averaging(0.05f);
120
121 lpfl->cleanup ();
122 lpfr->cleanup ();
123
124 };
125
126 /*
127 * Effect output
128 */
129 void
out(float * smpsl,float * smpsr,uint32_t period)130 Echotron::out (float * smpsl, float * smpsr, uint32_t period)
131 {
132
133 unsigned int i;
134 int j, k;
135 int length = Plength>File.fLength?File.fLength:Plength;
136 float l,r,lyn, ryn;
137 float rxindex,lxindex;
138
139 fPERIOD = period;
140
141 if((Pmoddly)||(Pmodfilts)) modulate_delay();
142 else interpl = interpr = 0;
143
144 float tmpmodl = oldldmod;
145 float tmpmodr = oldrdmod;
146
147 for (i = 0; i < period; i++) {
148 tmpmodl+=interpl;
149 tmpmodr+=interpr;
150
151 l = lxn->delay( (lpfl->filterout_s(smpsl[i] + lfeedback) ), 0.0f, 0, 1, 0); //High Freq damping
152 r = rxn->delay( (lpfr->filterout_s(smpsr[i] + rfeedback) ), 0.0f, 0, 1, 0);
153
154 //Convolve
155 lyn = 0.0f;
156 ryn = 0.0f;
157
158 if(Pfilters) {
159
160 j=0;
161 for (k=0; k<length; k++) {
162 lxindex = File.ltime[k] + tmpmodl;
163 rxindex = File.rtime[k] + tmpmodr;
164
165 if((File.iStages[k]>=0)&&(j<ECHOTRON_MAXFILTERS)) {
166 lyn += filterbank[j].l->filterout_s(lxn->delay(l, lxindex, k, 0, 0)) * File.ldata[k]; //filter each tap specified
167 ryn += filterbank[j].r->filterout_s(rxn->delay(r, lxindex, k, 0, 0)) * File.rdata[k];
168 j++;
169 } else {
170 lyn += lxn->delay(l, lxindex, k, 0, 0) * File.ldata[k];
171 ryn += rxn->delay(r, rxindex, k, 0, 0) * File.rdata[k];
172 }
173
174 }
175
176 } else {
177 for (k=0; k<length; k++) {
178 lxindex = File.ltime[k] + tmpmodl;
179 rxindex = File.rtime[k] + tmpmodr;
180
181 lyn += lxn->delay(l, lxindex, k, 0, 0) * File.ldata[k];
182 ryn += rxn->delay(r, rxindex, k, 0, 0) * File.rdata[k];
183 }
184
185 }
186
187 lfeedback = (lrcross*ryn + ilrcross*lyn) * lpanning;
188 rfeedback = (lrcross*lyn + ilrcross*ryn) * rpanning;
189 efxoutl[i] = lfeedback;
190 efxoutr[i] = rfeedback;
191 lfeedback *= fb;
192 rfeedback *= fb;
193
194 };
195
196 if(initparams) init_params();
197
198 };
199
200
201 /*
202 * Parameter control
203 */
204 void
setvolume(int Pvolume)205 Echotron::setvolume (int Pvolume)
206 {
207 this->Pvolume = Pvolume;
208 outvolume = (float)Pvolume / 127.0f;
209 if (Pvolume == 0)
210 cleanup ();
211
212 };
213
214 void
setpanning(int value)215 Echotron::setpanning (int value)
216 {
217 Ppanning = value;
218 rpanning = ((float)Ppanning) / 64.0f;
219 lpanning = 2.0f - rpanning;
220 lpanning = 10.0f * powf(lpanning, 4);
221 rpanning = 10.0f * powf(rpanning, 4);
222 lpanning = 1.0f - 1.0f/(lpanning + 1.0f);
223 rpanning = 1.0f - 1.0f/(rpanning + 1.0f);
224 lpanning *= 1.1f;
225 rpanning *= 1.1f;
226 if(lpanning>1.0f) lpanning = 1.0f;
227 if(rpanning>1.0f) rpanning = 1.0f;
228 };
229
230 int
setfile(int value)231 Echotron::setfile(int value)
232 {
233
234 DlyFile filedata;
235
236 if(!Puser) {
237 Filenum = value;
238 memset(Filename,0,sizeof(Filename));
239 sprintf(Filename, "%s/%d.dly",DATADIR,Filenum+1);
240 }
241
242 filedata = loadfile(Filename);
243 applyfile(filedata);
244 if(error)
245 return 0;
246 return 1;
247 /*
248
249 if ((fs = fopen (Filename, "r")) == NULL) {
250 loaddefault();
251 return(0);
252 }
253
254 while (fgets(wbuf,sizeof wbuf,fs) != NULL) {
255 //fgets(wbuf,sizeof wbuf,fs);
256 if(wbuf[0]!='#') break;
257 memset(wbuf,0,sizeof(wbuf));
258 }
259
260 sscanf(wbuf,"%f\t%f\t%d",&subdiv_fmod,&subdiv_dmod,&f_qmode); //Second line has tempo subdivision
261 //printf("subdivs:\t%f\t%f\n",subdiv_fmod,subdiv_dmod);
262
263 int count = 0;
264 memset(iStages,0,sizeof(iStages));
265
266
267
268 while ((fgets(wbuf,sizeof wbuf,fs) != NULL) && (count<ECHOTRON_F_SIZE)) {
269 if(wbuf[0]==10) break; // Check Carriage Return
270 if(wbuf[0]=='#') continue;
271 sscanf(wbuf,"%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%d",&tPan, &tTime, &tLevel,
272 &tLP, &tBP, &tHP, &tFreq, &tQ, &tiStages);
273 //printf("params:\n%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%d\n",tPan, tTime, tLevel,
274 //tLP, tBP, tHP, tFreq, tQ, tiStages);
275 if((tPan<-1.0f) || (tPan>1.0f)) {
276 error_num=5;
277 break;
278 } else fPan[count]=tPan;
279
280 if((tTime <-6.0) || (tTime>6.0f)) {
281 error_num=6;
282 break;
283 } else fTime[count]=fabs(tTime);
284
285 if((tLevel <-10.0f) || (tLevel>10.0f)) {
286 error_num=7;
287 break;
288 } else fLevel[count]=tLevel;
289
290 if((tLP <-2.0f) || (tLP>2.0f)) {
291 error_num=8;
292 break;
293 } else fLP[count]=tLP;
294
295 if((tBP<-2.0f) || (tBP>2.0f)) {
296 error_num=9;
297 break;
298 } else fBP[count]=tBP;
299
300 if((tHP<-2.0f) || (tHP>2.0f)) {
301 error_num=10;
302 break;
303 } else fHP[count]=tHP;
304
305 if((tFreq <20.0f) || (tFreq>26000.0f)) {
306 error_num=11;
307 break;
308 } else fFreq[count]=tFreq;
309
310 if((tQ <0.0) || (tQ>300.0f)) {
311 error_num=12;
312 break;
313 } else fQ[count]=tQ;
314
315 if((tiStages<0) || (tiStages>MAX_FILTER_STAGES)) {
316 error_num=13;
317 break;
318 } else iStages[count]=tiStages-1; //check in main loop if <0, then skip filter
319
320
321 memset(wbuf,0,sizeof(wbuf));
322 count++;
323 }
324 fclose(fs);
325
326 if(!Pchange) Plength=count;
327 cleanup();
328 init_params();
329 return(1);
330 */
331 };
332
333 DlyFile
loadfile(char * Filename)334 Echotron::loadfile(char* Filename)
335 {
336 float tPan=0.0f;
337 float tTime=0.0f;
338 float tLevel=0.0f;
339 float tLP=0.0f;
340 float tBP=0.0f;
341 float tHP=0.0f;
342 float tFreq=20.0f;
343 float tQ=1.0f;
344 int tiStages = 0;
345
346 FILE *fs;
347 DlyFile f;
348
349 char wbuf[128];
350
351 error = 0;
352
353 if ((fs = fopen (Filename, "r")) == NULL) {
354 error = 1;
355 return loaddefault();
356 }
357
358 while (fgets(wbuf,sizeof wbuf,fs) != NULL) {
359 //fgets(wbuf,sizeof wbuf,fs);
360 if(wbuf[0]!='#') break;
361 memset(wbuf,0,sizeof(wbuf));
362 }
363
364 sscanf(wbuf,"%f\t%f\t%d",&f.subdiv_fmod,&f.subdiv_dmod,&f.f_qmode); //Second line has tempo subdivision
365 //printf("subdivs:\t%f\t%f\n",subdiv_fmod,subdiv_dmod);
366
367 int count = 0;
368 memset(f.iStages,0,sizeof(f.iStages));
369
370
371
372 while ((fgets(wbuf,sizeof wbuf,fs) != NULL) && (count<ECHOTRON_F_SIZE)) {
373 if(wbuf[0]==10) break; // Check Carriage Return
374 if(wbuf[0]=='#') continue;
375 sscanf(wbuf,"%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%d",&tPan, &tTime, &tLevel,
376 &tLP, &tBP, &tHP, &tFreq, &tQ, &tiStages);
377 //printf("params:\n%f\t%f\t%f\t%f\t%f\t%f\t%f\t%f\t%d\n",tPan, tTime, tLevel,
378 //tLP, tBP, tHP, tFreq, tQ, tiStages);
379 if((tPan<-1.0f) || (tPan>1.0f)) {
380 error=5;
381 break;
382 } else f.fPan[count]=tPan;
383
384 if((tTime <-6.0) || (tTime>6.0f)) {
385 error=6;
386 break;
387 } else f.fTime[count]=fabs(tTime);
388
389 if((tLevel <-10.0f) || (tLevel>10.0f)) {
390 error=7;
391 break;
392 } else f.fLevel[count]=tLevel;
393
394 if((tLP <-2.0f) || (tLP>2.0f)) {
395 error=8;
396 break;
397 } else f.fLP[count]=tLP;
398
399 if((tBP<-2.0f) || (tBP>2.0f)) {
400 error=9;
401 break;
402 } else f.fBP[count]=tBP;
403
404 if((tHP<-2.0f) || (tHP>2.0f)) {
405 error=10;
406 break;
407 } else f.fHP[count]=tHP;
408
409 if((tFreq <20.0f) || (tFreq>26000.0f)) {
410 error=11;
411 break;
412 } else f.fFreq[count]=tFreq;
413
414 if((tQ <0.0) || (tQ>300.0f)) {
415 error=12;
416 break;
417 } else f.fQ[count]=tQ;
418
419 if((tiStages<0) || (tiStages>MAX_FILTER_STAGES)) {
420 error=13;
421 break;
422 } else f.iStages[count]=tiStages-1; //check in main loop if <0, then skip filter
423
424
425 memset(wbuf,0,sizeof(wbuf));
426 count++;
427 }
428 fclose(fs);
429
430 f.fLength = count;
431 return f;
432 };
433
434 void
applyfile(DlyFile f)435 Echotron::applyfile(DlyFile f)
436 {
437 //if(!Pchange) Llength=f.fLength;//ssj this doesn't do anything does it?
438 cleanup();
439 File = f;
440 init_params();
441 }
442
443 DlyFile
loaddefault()444 Echotron::loaddefault()
445 {
446 DlyFile f;
447 strcpy(f.Filename,"default");
448 f.fLength = 1;
449 f.fPan[0] = 0.0f; //
450 f.fTime[0] = 1.0f; //default 1 measure delay
451 f.fLevel[0] = 0.7f;
452 f.fLP[0] = 1.0f;
453 f.fBP[0] = -1.0f;
454 f.fHP[0] = 1.0f;
455 f.fFreq[0]=800.0f;;
456 f.fQ[0]=2.0f;
457 f.iStages[0]=1;
458 f.subdiv_dmod = 1.0f;
459 f.subdiv_fmod = 1.0f;
460 f.f_qmode = 0;
461 return f;
462 }
463
init_params()464 void Echotron::init_params()
465 {
466
467 float hSR = fSAMPLE_RATE*0.5f;
468 float tpanl, tpanr;
469 float tmptempo;
470 int tfcnt = 0;
471
472 initparams=0;
473 depth = ((float) (Pdepth - 64))/64.0f;
474 dlyrange = 0.008*f_pow2(4.5f*depth);
475 width = ((float) Pwidth)/127.0f;
476
477 tmptempo = (float) Ptempo;
478 lfo->Pfreq = lrintf(File.subdiv_fmod*tmptempo);
479 dlfo->Pfreq = lrintf(File.subdiv_dmod*tmptempo);
480
481 for(int i=0; i<File.fLength; i++) {
482 // tmp_time=lrintf(fTime[i]*tempo_coeff*fSAMPLE_RATE);
483 // if(tmp_time<maxx_size) rtime[i]=tmp_time; else rtime[i]=maxx_size;
484
485 File.ltime[i] = File.rtime[i] = File.fTime[i]*tempo_coeff;
486
487
488 if(File.fPan[i]>=0.0f) {
489 tpanr = 1.0;
490 tpanl = 1.0f - File.fPan[i];
491 } else {
492 tpanl = 1.0;
493 tpanr = 1.0f + File.fPan[i];
494 }
495
496 File.ldata[i]=File.fLevel[i]*tpanl;
497 File.rdata[i]=File.fLevel[i]*tpanr;
498
499 if((tfcnt<ECHOTRON_MAXFILTERS)&&(File.iStages[i]>=0)) {
500 int Freq=File.fFreq[i]*f_pow2(depth*4.5f);
501 if (Freq<20.0) Freq=20.0f;
502 if (Freq>hSR) Freq=hSR;
503 filterbank[tfcnt].l->setfreq_and_q(Freq,File.fQ[i]);
504 filterbank[tfcnt].r->setfreq_and_q(Freq,File.fQ[i]);
505 filterbank[tfcnt].l->setstages(File.iStages[i]);
506 filterbank[tfcnt].r->setstages(File.iStages[i]);
507 filterbank[tfcnt].l->setmix (1, File.fLP[i] , File.fBP[i], File.fHP[i]);
508 filterbank[tfcnt].r->setmix (1, File.fLP[i] , File.fBP[i], File.fHP[i]);
509 filterbank[tfcnt].l->setmode(File.f_qmode);
510 filterbank[tfcnt].r->setmode(File.f_qmode);
511 tfcnt++;
512 }
513 }
514
515 };
516
modulate_delay()517 void Echotron::modulate_delay()
518 {
519
520 float lfmod, rfmod, lfol, lfor, dlfol, dlfor;
521 float fperiod = 1.0f/fPERIOD;
522
523 lfo->effectlfoout (&lfol, &lfor);
524 dlfo->effectlfoout (&dlfol, &dlfor);
525 if(Pmodfilts) {
526 lfmod = f_pow2((lfol*width + 0.25f + depth)*4.5f);
527 rfmod = f_pow2((lfor*width + 0.25f + depth)*4.5f);
528 for(int i=0; i<ECHOTRON_MAXFILTERS; i++) {
529
530 filterbank[i].l->setfreq(lfmod*File.fFreq[i]);
531 filterbank[i].r->setfreq(rfmod*File.fFreq[i]);
532
533 }
534
535 }
536
537 if(Pmoddly) {
538 oldldmod = ldmod;
539 oldrdmod = rdmod;
540 ldmod = width*dlfol;
541 rdmod = width*dlfor;
542
543 // ldmod=lrintf(dlyrange*tempo_coeff*fSAMPLE_RATE*ldmod);
544 // rdmod=lrintf(dlyrange*tempo_coeff*fSAMPLE_RATE*rdmod);
545 ldmod=dlyrange*tempo_coeff*ldmod;
546 rdmod=dlyrange*tempo_coeff*rdmod;
547 interpl = (ldmod - oldldmod)*fperiod;
548 interpr = (rdmod - oldrdmod)*fperiod;
549 } else {
550 oldldmod = 0.0f;
551 oldrdmod = 0.0f;
552 ldmod = 0.0f;
553 rdmod = 0.0f;
554 interpl = 0.0f;
555 interpr = 0.0f;
556 }
557
558 };
559
560
561 void
sethidamp(int Phidamp)562 Echotron::sethidamp (int Phidamp)
563 {
564 this->Phidamp = Phidamp;
565 hidamp = 1.0f - (float)Phidamp / 127.1f;
566 float fr = 20.0f*f_pow2(hidamp*10.0f);
567 lpfl->setfreq (fr);
568 lpfr->setfreq (fr);
569 };
570
571 void
setfb(int value)572 Echotron::setfb(int value)
573 {
574
575 fb = (float)value/64.0f;
576 }
577
578
579 void
setpreset(int npreset)580 Echotron::setpreset (int npreset)
581 {
582 const int PRESET_SIZE = 16;
583 const int NUM_PRESETS = 5;
584 int pdata[PRESET_SIZE];
585 int presets[NUM_PRESETS][PRESET_SIZE] = {
586 //Summer
587 {64, 45, 34, 4, 0, 76, 3, 41, 0, 96, -13, 64, 1, 1, 1, 1},
588 //Ambience
589 {96, 64, 16, 4, 0, 180, 50, 64, 1, 96, -4, 64, 1, 0, 0, 0},
590 //Arranjer
591 {64, 64, 10, 4, 0, 400, 32, 64, 1, 96, -8, 64, 1, 0, 0, 0},
592 //Suction
593 {0, 47, 28, 8, 0, 92, 0, 64, 3, 32, 0, 64, 1, 1, 1, 1},
594 //SucFlange
595 {64, 36, 93, 8, 0, 81, 0, 64, 3, 32, 0, 64, 1, 0, 1, 1}
596
597 };
598
599 if(npreset>NUM_PRESETS-1) {
600 Fpre->ReadPreset(41,npreset-NUM_PRESETS+1,pdata);
601 for (int n = 0; n < PRESET_SIZE; n++)
602 changepar (n, pdata[n]);
603 } else {
604 for (int n = 0; n < PRESET_SIZE; n++)
605 changepar (n, presets[npreset][n]);
606 }
607 Ppreset = npreset;
608 };
609
610
611 void
changepar(int npar,int value)612 Echotron::changepar (int npar, int value)
613 {
614 float tmptempo;
615 switch (npar) {
616 case 0:
617 setvolume (value);
618 break;
619 case 1:
620 Pdepth=value;
621 initparams=1;
622 break;
623 case 2:
624 Pwidth=value;
625 initparams=1;
626 break;
627 case 3:
628 Plength = value;
629 if(Plength>127) Plength = 127;
630 //initparams=1;//no longer re-init, just don't process extra length
631 break;
632 case 4:
633 Puser = value;
634 break;
635 case 5:
636 Ptempo = value;
637
638 tmptempo = (float) Ptempo;
639 tempo_coeff = 60.0f / tmptempo;
640 lfo->Pfreq = lrintf(File.subdiv_fmod*tmptempo);
641 dlfo->Pfreq = lrintf(File.subdiv_dmod*tmptempo);
642 lfo->updateparams (fPERIOD);
643 initparams=1;
644 break;
645 case 6:
646 sethidamp (value);
647 break;
648 case 7:
649 Plrcross = value;
650 lrcross = ((float)(Plrcross)-64)/64.0;
651 ilrcross = 1.0f - abs(lrcross);
652 break;
653 case 8:
654 if(!setfile(value)) error=4;
655 break;
656 case 9:
657 lfo->Pstereo = value;
658 dlfo->Pstereo = value;
659 lfo->updateparams (fPERIOD);
660 dlfo->updateparams (fPERIOD);
661 break;
662 case 10:
663 Pfb = value;
664 setfb(value);
665 break;
666 case 11:
667 setpanning (value);
668 break;
669 case 12:
670 Pmoddly = value;//delay modulation on/off
671 break;
672 case 13:
673 Pmodfilts = value;//filter modulation on/off
674 if(!Pmodfilts) initparams=1;
675 break;
676 case 14:
677 //LFO Type
678 lfo->PLFOtype = value;
679 lfo->updateparams (fPERIOD);
680 dlfo->PLFOtype = value;
681 dlfo->updateparams (fPERIOD);
682 break;
683 case 15:
684 Pfilters = value;//Pfilters
685 break;
686 };
687 };
688
689 int
getpar(int npar)690 Echotron::getpar (int npar)
691 {
692 switch (npar) {
693 case 0:
694 return (Pvolume);
695 break;
696 case 1:
697 return (Pdepth);
698 break;
699 case 2:
700 return(Pwidth);
701 break;
702 case 3:
703 return(Plength);
704 break;
705 case 8:
706 return (Filenum);
707 break;
708 case 5:
709 return (Ptempo);
710 break;
711 case 6:
712 return (Phidamp);
713 break;
714 case 7:
715 return(Plrcross);
716 break;
717 case 4:
718 return(Puser);
719 break;
720 case 9:
721 return(lfo->Pstereo);
722 break;
723 case 10:
724 return(Pfb);
725 break;
726 case 11:
727 return(Ppanning);
728 break;
729 case 12:
730 return(Pmoddly); //modulate delays
731 break;
732 case 13:
733 return(Pmodfilts); //modulate filters
734 break;
735 case 14:
736 return(lfo->PLFOtype);
737 break;
738 case 15:
739 return(Pfilters); //Filter delay line on/off
740 break;
741
742
743 };
744 return (0); //in case of bogus parameter number
745 };
746