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