/* ZynAddSubFX - a software synthesizer Distorsion.cpp - Distorsion 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 "Distorsion.h" /* * Waveshape (this is called by OscilGen::waveshape and Distorsion::process) */ void waveshapesmps(int n, REALTYPE *smps, unsigned char type, unsigned char drive) { int i; REALTYPE ws = drive / 127.0; REALTYPE tmpv; switch(type) { case 1: ws = pow(10, ws * ws * 3.0) - 1.0 + 0.001; //Arctangent for(i = 0; i < n; i++) smps[i] = atan(smps[i] * ws) / atan(ws); break; case 2: ws = ws * ws * 32.0 + 0.0001; //Asymmetric if(ws < 1.0) tmpv = sin(ws) + 0.1; else tmpv = 1.1; for(i = 0; i < n; i++) smps[i] = sin(smps[i] * (0.1 + ws - ws * smps[i])) / tmpv; ; break; case 3: ws = ws * ws * ws * 20.0 + 0.0001; //Pow for(i = 0; i < n; i++) { smps[i] *= ws; if(fabs(smps[i]) < 1.0) { smps[i] = (smps[i] - pow(smps[i], 3.0)) * 3.0; if(ws < 1.0) smps[i] /= ws; } else smps[i] = 0.0; } break; case 4: ws = ws * ws * ws * 32.0 + 0.0001; //Sine if(ws < 1.57) tmpv = sin(ws); else tmpv = 1.0; for(i = 0; i < n; i++) smps[i] = sin(smps[i] * ws) / tmpv; break; case 5: ws = ws * ws + 0.000001; //Quantisize for(i = 0; i < n; i++) smps[i] = floor(smps[i] / ws + 0.5) * ws; break; case 6: ws = ws * ws * ws * 32 + 0.0001; //Zigzag if(ws < 1.0) tmpv = sin(ws); else tmpv = 1.0; for(i = 0; i < n; i++) smps[i] = asin(sin(smps[i] * ws)) / tmpv; break; case 7: ws = pow(2.0, -ws * ws * 8.0); //Limiter for(i = 0; i < n; i++) { REALTYPE tmp = smps[i]; if(fabs(tmp) > ws) { if(tmp >= 0.0) smps[i] = 1.0; else smps[i] = -1.0; } else smps[i] /= ws; } break; case 8: ws = pow(2.0, -ws * ws * 8.0); //Upper Limiter for(i = 0; i < n; i++) { REALTYPE tmp = smps[i]; if(tmp > ws) smps[i] = ws; smps[i] *= 2.0; } break; case 9: ws = pow(2.0, -ws * ws * 8.0); //Lower Limiter for(i = 0; i < n; i++) { REALTYPE tmp = smps[i]; if(tmp < -ws) smps[i] = -ws; smps[i] *= 2.0; } break; case 10: ws = (pow(2.0, ws * 6.0) - 1.0) / pow(2.0, 6.0); //Inverse Limiter for(i = 0; i < n; i++) { REALTYPE tmp = smps[i]; if(fabs(tmp) > ws) { if(tmp >= 0.0) smps[i] = tmp - ws; else smps[i] = tmp + ws; } else smps[i] = 0; } break; case 11: ws = pow(5, ws * ws * 1.0) - 1.0; //Clip for(i = 0; i < n; i++) smps[i] = smps[i] * (ws + 0.5) * 0.9999 - floor( 0.5 + smps[i] * (ws + 0.5) * 0.9999); break; case 12: ws = ws * ws * ws * 30 + 0.001; //Asym2 if(ws < 0.3) tmpv = ws; else tmpv = 1.0; for(i = 0; i < n; i++) { REALTYPE tmp = smps[i] * ws; if((tmp > -2.0) && (tmp < 1.0)) smps[i] = tmp * (1.0 - tmp) * (tmp + 2.0) / tmpv; else smps[i] = 0.0; } break; case 13: ws = ws * ws * ws * 32.0 + 0.0001; //Pow2 if(ws < 1.0) tmpv = ws * (1 + ws) / 2.0; else tmpv = 1.0; for(i = 0; i < n; i++) { REALTYPE tmp = smps[i] * ws; if((tmp > -1.0) && (tmp < 1.618034)) smps[i] = tmp * (1.0 - tmp) / tmpv; else if(tmp > 0.0) smps[i] = -1.0; else smps[i] = -2.0; } break; case 14: ws = pow(ws, 5.0) * 80.0 + 0.0001; //sigmoid if(ws > 10.0) tmpv = 0.5; else tmpv = 0.5 - 1.0 / (exp(ws) + 1.0); for(i = 0; i < n; i++) { REALTYPE tmp = smps[i] * ws; if(tmp < -10.0) tmp = -10.0; else if(tmp > 10.0) tmp = 10.0; tmp = 0.5 - 1.0 / (exp(tmp) + 1.0); smps[i] = tmp / tmpv; } break; /**\todo update to Distorsion::changepar (Ptype max) if there is added more waveshapings functions*/ } } Distorsion::Distorsion(const int &insertion_, REALTYPE *efxoutl_, REALTYPE *efxoutr_) :Effect(insertion_, efxoutl_, efxoutr_, NULL, 0) { lpfl = new AnalogFilter(2, 22000, 1, 0); lpfr = new AnalogFilter(2, 22000, 1, 0); hpfl = new AnalogFilter(3, 20, 1, 0); hpfr = new AnalogFilter(3, 20, 1, 0); //default values Pvolume = 50; Plrcross = 40; Pdrive = 90; Plevel = 64; Ptype = 0; Pnegate = 0; Plpf = 127; Phpf = 0; Pstereo = 0; Pprefiltering = 0; setpreset(Ppreset); cleanup(); } Distorsion::~Distorsion() { delete lpfl; delete lpfr; delete hpfl; delete hpfr; } /* * Cleanup the effect */ void Distorsion::cleanup() { lpfl->cleanup(); hpfl->cleanup(); lpfr->cleanup(); hpfr->cleanup(); } /* * Apply the filters */ void Distorsion::applyfilters(REALTYPE *efxoutl, REALTYPE *efxoutr) { lpfl->filterout(efxoutl); hpfl->filterout(efxoutl); if(Pstereo != 0) { //stereo lpfr->filterout(efxoutr); hpfr->filterout(efxoutr); } } /* * Effect output */ void Distorsion::out(const Stereo &smp) { int i; REALTYPE l, r, lout, rout; REALTYPE inputvol = pow(5.0, (Pdrive - 32.0) / 127.0); if(Pnegate != 0) inputvol *= -1.0; if(Pstereo != 0) { //Stereo for(i = 0; i < SOUND_BUFFER_SIZE; i++) { efxoutl[i] = smp.l[i] * inputvol * panning; efxoutr[i] = smp.r[i] * inputvol * (1.0 - panning); } } else { for(i = 0; i < SOUND_BUFFER_SIZE; i++) efxoutl[i] = (smp.l[i] * panning + smp.r[i] * (1.0 - panning)) * inputvol; ; } if(Pprefiltering != 0) applyfilters(efxoutl, efxoutr); //no optimised, yet (no look table) waveshapesmps(SOUND_BUFFER_SIZE, efxoutl, Ptype + 1, Pdrive); if(Pstereo != 0) waveshapesmps(SOUND_BUFFER_SIZE, efxoutr, Ptype + 1, Pdrive); if(Pprefiltering == 0) applyfilters(efxoutl, efxoutr); if(Pstereo == 0) for(i = 0; i < SOUND_BUFFER_SIZE; i++) efxoutr[i] = efxoutl[i]; REALTYPE level = dB2rap(60.0 * Plevel / 127.0 - 40.0); for(i = 0; i < SOUND_BUFFER_SIZE; i++) { lout = efxoutl[i]; rout = efxoutr[i]; l = lout * (1.0 - lrcross) + rout * lrcross; r = rout * (1.0 - lrcross) + lout * lrcross; lout = l; rout = r; efxoutl[i] = lout * 2.0 * level; efxoutr[i] = rout * 2.0 * level; } } /* * Parameter control */ void Distorsion::setvolume(unsigned char Pvolume) { this->Pvolume = Pvolume; if(insertion == 0) { outvolume = pow(0.01, (1.0 - Pvolume / 127.0)) * 4.0; volume = 1.0; } else volume = outvolume = Pvolume / 127.0; ; if(Pvolume == 0) cleanup(); } void Distorsion::setpanning(unsigned char Ppanning) { this->Ppanning = Ppanning; panning = (Ppanning + 0.5) / 127.0; } void Distorsion::setlrcross(unsigned char Plrcross) { this->Plrcross = Plrcross; lrcross = Plrcross / 127.0 * 1.0; } void Distorsion::setlpf(unsigned char Plpf) { this->Plpf = Plpf; REALTYPE fr = exp(pow(Plpf / 127.0, 0.5) * log(25000.0)) + 40; lpfl->setfreq(fr); lpfr->setfreq(fr); } void Distorsion::sethpf(unsigned char Phpf) { this->Phpf = Phpf; REALTYPE fr = exp(pow(Phpf / 127.0, 0.5) * log(25000.0)) + 20.0; hpfl->setfreq(fr); hpfr->setfreq(fr); } void Distorsion::setpreset(unsigned char npreset) { const int PRESET_SIZE = 11; const int NUM_PRESETS = 6; unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { //Overdrive 1 {127, 64, 35, 56, 70, 0, 0, 96, 0, 0, 0 }, //Overdrive 2 {127, 64, 35, 29, 75, 1, 0, 127, 0, 0, 0 }, //A. Exciter 1 {64, 64, 35, 75, 80, 5, 0, 127, 105, 1, 0 }, //A. Exciter 2 {64, 64, 35, 85, 62, 1, 0, 127, 118, 1, 0 }, //Guitar Amp {127, 64, 35, 63, 75, 2, 0, 55, 0, 0, 0 }, //Quantisize {127, 64, 35, 88, 75, 4, 0, 127, 0, 1, 0 } }; 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, (int) (presets[npreset][0] / 1.5)); //lower the volume if this is system effect Ppreset = npreset; cleanup(); } void Distorsion::changepar(int npar, unsigned char value) { switch(npar) { case 0: setvolume(value); break; case 1: setpanning(value); break; case 2: setlrcross(value); break; case 3: Pdrive = value; break; case 4: Plevel = value; break; case 5: if(value > 13) Ptype = 13; //this must be increased if more distorsion types are added else Ptype = value; break; case 6: if(value > 1) Pnegate = 1; else Pnegate = value; break; case 7: setlpf(value); break; case 8: sethpf(value); break; case 9: if(value > 1) Pstereo = 1; else Pstereo = value; break; case 10: Pprefiltering = value; break; } } unsigned char Distorsion::getpar(int npar) const { switch(npar) { case 0: return Pvolume; break; case 1: return Ppanning; break; case 2: return Plrcross; break; case 3: return Pdrive; break; case 4: return Plevel; break; case 5: return Ptype; break; case 6: return Pnegate; break; case 7: return Plpf; break; case 8: return Phpf; break; case 9: return Pstereo; break; case 10: return Pprefiltering; break; } return 0; //in case of bogus parameter number }