/* ZynAddSubFX - a software synthesizer Alienwah.cpp - "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 or later) 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 "Alienwah.h" Alienwah::Alienwah(bool insertion_, float *efxoutl_, float *efxoutr_, unsigned int srate, int bufsize) :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0, srate, bufsize), lfo(srate, bufsize), oldl(NULL), oldr(NULL) { setpreset(Ppreset); cleanup(); oldclfol = complex(fb, 0.0f); oldclfor = complex(fb, 0.0f); } Alienwah::~Alienwah() { if(oldl != NULL) delete [] oldl; if(oldr != NULL) delete [] oldr; } //Apply the effect void Alienwah::out(const Stereo &smp) { float lfol, lfor; //Left/Right LFOs complex clfol, clfor; /**\todo Rework, as optimization can be used when the new complex type is * utilized. * Before all calculations needed to be done with individual float, * but now they can be done together*/ lfo.effectlfoout(&lfol, &lfor); lfol *= depth * PI * 2.0f; lfor *= depth * PI * 2.0f; clfol = complex(cosf(lfol + phase) * fb, sinf(lfol + phase) * fb); //rework clfor = complex(cosf(lfor + phase) * fb, sinf(lfor + phase) * fb); //rework for(int i = 0; i < buffersize; ++i) { float x = ((float) i) / buffersize_f; float x1 = 1.0f - x; //left complex tmp = clfol * x + oldclfol * x1; complex out = tmp * oldl[oldk]; out += (1 - fabs(fb)) * smp.l[i] * pangainL; oldl[oldk] = out; float l = out.real() * 10.0f * (fb + 0.1f); //right tmp = clfor * x + oldclfor * x1; out = tmp * oldr[oldk]; out += (1 - fabs(fb)) * smp.r[i] * pangainR; oldr[oldk] = out; float r = out.real() * 10.0f * (fb + 0.1f); if(++oldk >= Pdelay) oldk = 0; //LRcross efxoutl[i] = l * (1.0f - lrcross) + r * lrcross; efxoutr[i] = r * (1.0f - lrcross) + l * lrcross; } oldclfol = clfol; oldclfor = clfor; } //Cleanup the effect void Alienwah::cleanup(void) { for(int i = 0; i < Pdelay; ++i) { oldl[i] = complex(0.0f, 0.0f); oldr[i] = complex(0.0f, 0.0f); } oldk = 0; } //Parameter control void Alienwah::setdepth(unsigned char _Pdepth) { Pdepth = _Pdepth; depth = Pdepth / 127.0f; } void Alienwah::setfb(unsigned char _Pfb) { Pfb = _Pfb; fb = fabs((Pfb - 64.0f) / 64.1f); fb = sqrtf(fb); if(fb < 0.4f) fb = 0.4f; if(Pfb < 64) fb = -fb; } void Alienwah::setvolume(unsigned char _Pvolume) { Pvolume = _Pvolume; outvolume = Pvolume / 127.0f; if(insertion == 0) volume = 1.0f; else volume = outvolume; } void Alienwah::setphase(unsigned char _Pphase) { Pphase = _Pphase; phase = (Pphase - 64.0f) / 64.0f * PI; } void Alienwah::setdelay(unsigned char _Pdelay) { if(oldl != NULL) delete [] oldl; if(oldr != NULL) delete [] oldr; Pdelay = (_Pdelay >= MAX_ALIENWAH_DELAY) ? MAX_ALIENWAH_DELAY : _Pdelay; oldl = new complex[Pdelay]; oldr = new complex[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) const { switch(npar) { case 0: return Pvolume; case 1: return Ppanning; case 2: return lfo.Pfreq; case 3: return lfo.Prandomness; case 4: return lfo.PLFOtype; case 5: return lfo.Pstereo; case 6: return Pdepth; case 7: return Pfb; case 8: return Pdelay; case 9: return Plrcross; case 10: return Pphase; default: return 0; } }