/* ZynAddSubFX - a software synthesizer Chorus.C - Chorus and Flange effects Copyright (C) 2002-2005 Nasca Octavian Paul Author: Nasca Octavian Paul This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License (version 2) for more details. You should have received a copy of the GNU General Public License (version 2) along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include "Chorus.h" #include Chorus::Chorus(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ efxoutl=efxoutl_; efxoutr=efxoutr_; dlk=0;drk=0; maxdelay=(int)(MAX_CHORUS_DELAY/1000.0*SAMPLE_RATE); delayl=new REALTYPE[maxdelay]; delayr=new REALTYPE[maxdelay]; insertion=insertion_; filterpars=NULL; Ppreset=0; setpreset(Ppreset); lfo.effectlfoout(&lfol,&lfor); dl2=getdelay(lfol); dr2=getdelay(lfor); cleanup(); }; Chorus::~Chorus(){ delete [] delayl; delete [] delayr; }; /* * get the delay value in samples; xlfo is the current lfo value */ REALTYPE Chorus::getdelay(REALTYPE xlfo){ REALTYPE result; if (Pflangemode==0){ result=(delay+xlfo*depth)*SAMPLE_RATE; } else result=0; //check if it is too big delay(caused bu errornous setdelay() and setdepth() if ((result+0.5)>=maxdelay) { fprintf(stderr,"%s","WARNING: Chorus.C::getdelay(..) too big delay (see setdelay and setdepth funcs.)\n"); result=maxdelay-1.0; }; return(result); }; /* * Apply the effect */ void Chorus::out(REALTYPE *smpsl,REALTYPE *smpsr){ int i; dl1=dl2;dr1=dr2; lfo.effectlfoout(&lfol,&lfor); dl2=getdelay(lfol); dr2=getdelay(lfor); for (i=0;i=maxdelay) dlk=0; REALTYPE tmp=dlk-mdel+maxdelay*2.0;//where should I get the sample from F2I(tmp,dlhi); dlhi%=maxdelay; dlhi2=(dlhi-1+maxdelay)%maxdelay; dllo=1.0-fmod(tmp,1.0); efxoutl[i]=delayl[dlhi2]*dllo+delayl[dlhi]*(1.0-dllo); delayl[dlk]=inl+efxoutl[i]*fb; //Right channel //compute the delay in samples using linear interpolation between the lfo delays mdel=(dr1*(SOUND_BUFFER_SIZE-i)+dr2*i)/SOUND_BUFFER_SIZE; if (++drk>=maxdelay) drk=0; tmp=drk-mdel+maxdelay*2.0;//where should I get the sample from F2I(tmp,dlhi); dlhi%=maxdelay; dlhi2=(dlhi-1+maxdelay)%maxdelay; dllo=1.0-fmod(tmp,1.0); efxoutr[i]=delayr[dlhi2]*dllo+delayr[dlhi]*(1.0-dllo); delayr[dlk]=inr+efxoutr[i]*fb; }; if (Poutsub!=0) for (i=0;iPdepth=Pdepth; depth=(pow(8.0,(Pdepth/127.0)*2.0)-1.0)/1000.0;//seconds }; void Chorus::setdelay(unsigned char Pdelay){ this->Pdelay=Pdelay; delay=(pow(10.0,(Pdelay/127.0)*2.0)-1.0)/1000.0;//seconds }; void Chorus::setfb(unsigned char Pfb){ this->Pfb=Pfb; fb=(Pfb-64.0)/64.1; }; void Chorus::setvolume(unsigned char Pvolume){ this->Pvolume=Pvolume; outvolume=Pvolume/127.0; if (insertion==0) volume=1.0; else volume=outvolume; }; void Chorus::setpanning(unsigned char Ppanning){ this->Ppanning=Ppanning; panning=Ppanning/127.0; }; void Chorus::setlrcross(unsigned char Plrcross){ this->Plrcross=Plrcross; lrcross=Plrcross/127.0; }; void Chorus::setpreset(unsigned char npreset){ const int PRESET_SIZE=12; const int NUM_PRESETS=10; unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ //Chorus1 {64,64,50,0,0,90,40,85,64,119,0,0}, //Chorus2 {64,64,45,0,0,98,56,90,64,19,0,0}, //Chorus3 {64,64,29,0,1,42,97,95,90,127,0,0}, //Celeste1 {64,64,26,0,0,42,115,18,90,127,0,0}, //Celeste2 {64,64,29,117,0,50,115,9,31,127,0,1}, //Flange1 {64,64,57,0,0,60,23,3,62,0,0,0}, //Flange2 {64,64,33,34,1,40,35,3,109,0,0,0}, //Flange3 {64,64,53,34,1,94,35,3,54,0,0,1}, //Flange4 {64,64,40,0,1,62,12,19,97,0,0,0}, //Flange5 {64,64,55,105,0,24,39,19,17,0,0,1}}; if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; for (int n=0;n1) value=1; Pflangemode=value; break; case 11:if (value>1) value=1; Poutsub=value; break; }; }; unsigned char Chorus::getpar(int npar){ switch (npar){ case 0: return(Pvolume); break; case 1: return(Ppanning); break; case 2: return(lfo.Pfreq); break; case 3: return(lfo.Prandomness); break; case 4: return(lfo.PLFOtype); break; case 5: return(lfo.Pstereo); break; case 6: return(Pdepth); break; case 7: return(Pdelay); break; case 8: return(Pfb); break; case 9: return(Plrcross); break; case 10:return(Pflangemode); break; case 11:return(Poutsub); break; default:return (0); }; };