/* ZynAddSubFX - a software synthesizer Alienwah.C - "AlienWah" effect 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 <math.h> #include "Alienwah.h" #include <stdio.h> Alienwah::Alienwah(int insertion_,REALTYPE *efxoutl_,REALTYPE *efxoutr_){ efxoutl=efxoutl_; efxoutr=efxoutr_; oldl=NULL; oldr=NULL; filterpars=NULL; insertion=insertion_; Ppreset=0; setpreset(Ppreset); cleanup(); oldclfol.a=fb;oldclfol.b=0.0; oldclfor.a=fb;oldclfor.b=0.0; }; Alienwah::~Alienwah(){ if (oldl!=NULL) delete [] oldl; if (oldr!=NULL) delete [] oldr ; }; /* * Apply the effect */ void Alienwah::out(REALTYPE *smpsl,REALTYPE *smpsr){ int i; REALTYPE lfol,lfor; COMPLEXTYPE clfol,clfor,out,tmp; lfo.effectlfoout(&lfol,&lfor); lfol*=depth*PI*2.0;lfor*=depth*PI*2.0; clfol.a=cos(lfol+phase)*fb;clfol.b=sin(lfol+phase)*fb; clfor.a=cos(lfor+phase)*fb;clfor.b=sin(lfor+phase)*fb; for (i=0;i<SOUND_BUFFER_SIZE;i++){ REALTYPE x=((REALTYPE) i)/SOUND_BUFFER_SIZE; REALTYPE x1=1.0-x; //left tmp.a=clfol.a*x+oldclfol.a*x1; tmp.b=clfol.b*x+oldclfol.b*x1; out.a=tmp.a*oldl[oldk].a-tmp.b*oldl[oldk].b +(1-fabs(fb))*smpsl[i]*panning; out.b=tmp.a*oldl[oldk].b+tmp.b*oldl[oldk].a; oldl[oldk].a=out.a; oldl[oldk].b=out.b; REALTYPE l=out.a*10.0*(fb+0.1); //right tmp.a=clfor.a*x+oldclfor.a*x1; tmp.b=clfor.b*x+oldclfor.b*x1; out.a=tmp.a*oldr[oldk].a-tmp.b*oldr[oldk].b +(1-fabs(fb))*smpsr[i]*(1.0-panning); out.b=tmp.a*oldr[oldk].b+tmp.b*oldr[oldk].a; oldr[oldk].a=out.a; oldr[oldk].b=out.b; REALTYPE r=out.a*10.0*(fb+0.1); if (++oldk>=Pdelay) oldk=0; //LRcross efxoutl[i]=l*(1.0-lrcross)+r*lrcross; efxoutr[i]=r*(1.0-lrcross)+l*lrcross; }; oldclfol.a=clfol.a;oldclfol.b=clfol.b; oldclfor.a=clfor.a;oldclfor.b=clfor.b; }; /* * Cleanup the effect */ void Alienwah::cleanup(){ for (int i=0;i<Pdelay;i++) { oldl[i].a=0.0; oldl[i].b=0.0; oldr[i].a=0.0; oldr[i].b=0.0; }; oldk=0; }; /* * Parameter control */ void Alienwah::setdepth(unsigned char Pdepth){ this->Pdepth=Pdepth; depth=(Pdepth/127.0); }; void Alienwah::setfb(unsigned char Pfb){ this->Pfb=Pfb; fb=fabs((Pfb-64.0)/64.1); fb=sqrt(fb); if (fb<0.4) fb=0.4; if (Pfb<64) fb=-fb; }; void Alienwah::setvolume(unsigned char Pvolume){ this->Pvolume=Pvolume; outvolume=Pvolume/127.0; if (insertion==0) volume=1.0; else volume=outvolume; }; void Alienwah::setpanning(unsigned char Ppanning){ this->Ppanning=Ppanning; panning=Ppanning/127.0; }; void Alienwah::setlrcross(unsigned char Plrcross){ this->Plrcross=Plrcross; lrcross=Plrcross/127.0; }; void Alienwah::setphase(unsigned char Pphase){ this->Pphase=Pphase; phase=(Pphase-64.0)/64.0*PI; }; void Alienwah::setdelay(unsigned char Pdelay){ if (oldl!=NULL) delete [] oldl; if (oldr!=NULL) delete [] oldr; if (Pdelay>=MAX_ALIENWAH_DELAY) Pdelay=MAX_ALIENWAH_DELAY; this->Pdelay=Pdelay; oldl=new COMPLEXTYPE[Pdelay]; oldr=new COMPLEXTYPE[Pdelay]; cleanup(); }; void Alienwah::setpreset(unsigned char npreset){ const int PRESET_SIZE=11; const int NUM_PRESETS=4; unsigned char presets[NUM_PRESETS][PRESET_SIZE]={ //AlienWah1 {127,64,70,0,0,62,60,105,25,0,64}, //AlienWah2 {127,64,73,106,0,101,60,105,17,0,64}, //AlienWah3 {127,64,63,0,1,100,112,105,31,0,42}, //AlienWah4 {93,64,25,0,1,66,101,11,47,0,86}}; if (npreset>=NUM_PRESETS) npreset=NUM_PRESETS-1; for (int n=0;n<PRESET_SIZE;n++) changepar(n,presets[npreset][n]); if (insertion==0) changepar(0,presets[npreset][0]/2);//lower the volume if this is system effect Ppreset=npreset; }; void Alienwah::changepar(int npar,unsigned char value){ switch(npar){ case 0: setvolume(value); break; case 1: setpanning(value); break; case 2: lfo.Pfreq=value; lfo.updateparams(); break; case 3: lfo.Prandomness=value; lfo.updateparams(); break; case 4: lfo.PLFOtype=value; lfo.updateparams(); break; case 5: lfo.Pstereo=value; lfo.updateparams(); break; case 6: setdepth(value); break; case 7: setfb(value); break; case 8: setdelay(value); break; case 9: setlrcross(value); break; case 10:setphase(value); break; }; }; unsigned char Alienwah::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(Pfb); break; case 8: return(Pdelay); break; case 9: return(Plrcross); break; case 10:return(Pphase); break; default:return (0); }; };