/* ZynAddSubFX - a software synthesizer EffectMgr.cpp - Effect manager, an interface betwen the program and 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 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 "EffectMgr.h" #include "Effect.h" #include "Reverb.h" #include "Echo.h" #include "Chorus.h" #include "Distorsion.h" #include "EQ.h" #include "DynamicFilter.h" #include "../Misc/XMLwrapper.h" #include "../Params/FilterParams.h" #include using namespace std; EffectMgr::EffectMgr(const bool insertion_, pthread_mutex_t *mutex_) :insertion(insertion_), efxoutl(new float[synth->buffersize]), efxoutr(new float[synth->buffersize]), filterpars(NULL), nefx(0), efx(NULL), mutex(mutex_), dryonly(false) { setpresettype("Peffect"); memset(efxoutl, 0, synth->bufferbytes); memset(efxoutr, 0, synth->bufferbytes); defaults(); } EffectMgr::~EffectMgr() { delete efx; delete [] efxoutl; delete [] efxoutr; } void EffectMgr::defaults(void) { changeeffect(0); setdryonly(false); } //Change the effect void EffectMgr::changeeffect(int _nefx) { cleanup(); if(nefx == _nefx) return; nefx = _nefx; memset(efxoutl, 0, synth->bufferbytes); memset(efxoutr, 0, synth->bufferbytes); delete efx; switch(nefx) { case 1: efx = new Reverb(insertion, efxoutl, efxoutr); break; case 2: efx = new Echo(insertion, efxoutl, efxoutr); break; case 3: efx = new Chorus(insertion, efxoutl, efxoutr); break; case 4: efx = new Phaser(insertion, efxoutl, efxoutr); break; case 5: efx = new Alienwah(insertion, efxoutl, efxoutr); break; case 6: efx = new Distorsion(insertion, efxoutl, efxoutr); break; case 7: efx = new EQ(insertion, efxoutl, efxoutr); break; case 8: efx = new DynamicFilter(insertion, efxoutl, efxoutr); break; //put more effect here default: efx = NULL; break; //no effect (thru) } if(efx) filterpars = efx->filterpars; } //Obtain the effect number int EffectMgr::geteffect(void) { return nefx; } // Cleanup the current effect void EffectMgr::cleanup(void) { if(efx) efx->cleanup(); } // Get the preset of the current effect unsigned char EffectMgr::getpreset(void) { if(efx) return efx->Ppreset; else return 0; } // Change the preset of the current effect void EffectMgr::changepreset_nolock(unsigned char npreset) { if(efx) efx->setpreset(npreset); } //Change the preset of the current effect(with thread locking) void EffectMgr::changepreset(unsigned char npreset) { pthread_mutex_lock(mutex); changepreset_nolock(npreset); pthread_mutex_unlock(mutex); } //Change a parameter of the current effect void EffectMgr::seteffectpar_nolock(int npar, unsigned char value) { if(!efx) return; efx->changepar(npar, value); } // Change a parameter of the current effect (with thread locking) void EffectMgr::seteffectpar(int npar, unsigned char value) { pthread_mutex_lock(mutex); seteffectpar_nolock(npar, value); pthread_mutex_unlock(mutex); } //Get a parameter of the current effect unsigned char EffectMgr::geteffectpar(int npar) { if(!efx) return 0; return efx->getpar(npar); } // Apply the effect void EffectMgr::out(float *smpsl, float *smpsr) { if(!efx) { if(!insertion) for(int i = 0; i < synth->buffersize; ++i) { smpsl[i] = 0.0f; smpsr[i] = 0.0f; efxoutl[i] = 0.0f; efxoutr[i] = 0.0f; } return; } for(int i = 0; i < synth->buffersize; ++i) { smpsl[i] += denormalkillbuf[i]; smpsr[i] += denormalkillbuf[i]; efxoutl[i] = 0.0f; efxoutr[i] = 0.0f; } efx->out(smpsl, smpsr); float volume = efx->volume; if(nefx == 7) { //this is need only for the EQ effect memcpy(smpsl, efxoutl, synth->bufferbytes); memcpy(smpsr, efxoutr, synth->bufferbytes); return; } //Insertion effect if(insertion != 0) { float v1, v2; if(volume < 0.5f) { v1 = 1.0f; v2 = volume * 2.0f; } else { v1 = (1.0f - volume) * 2.0f; v2 = 1.0f; } if((nefx == 1) || (nefx == 2)) v2 *= v2; //for Reverb and Echo, the wet function is not liniar if(dryonly) //this is used for instrument effect only for(int i = 0; i < synth->buffersize; ++i) { smpsl[i] *= v1; smpsr[i] *= v1; efxoutl[i] *= v2; efxoutr[i] *= v2; } else // normal instrument/insertion effect for(int i = 0; i < synth->buffersize; ++i) { smpsl[i] = smpsl[i] * v1 + efxoutl[i] * v2; smpsr[i] = smpsr[i] * v1 + efxoutr[i] * v2; } } else // System effect for(int i = 0; i < synth->buffersize; ++i) { efxoutl[i] *= 2.0f * volume; efxoutr[i] *= 2.0f * volume; smpsl[i] = efxoutl[i]; smpsr[i] = efxoutr[i]; } } // Get the effect volume for the system effect float EffectMgr::sysefxgetvolume(void) { return (!efx) ? 1.0f : efx->outvolume; } // Get the EQ response float EffectMgr::getEQfreqresponse(float freq) { return (nefx == 7) ? efx->getfreqresponse(freq) : 0.0f; } void EffectMgr::setdryonly(bool value) { dryonly = value; } void EffectMgr::add2XML(XMLwrapper *xml) { xml->addpar("type", geteffect()); if(!efx || !geteffect()) return; xml->addpar("preset", efx->Ppreset); xml->beginbranch("EFFECT_PARAMETERS"); for(int n = 0; n < 128; ++n) { int par = geteffectpar(n); if(par == 0) continue; xml->beginbranch("par_no", n); xml->addpar("par", par); xml->endbranch(); } if(filterpars) { xml->beginbranch("FILTER"); filterpars->add2XML(xml); xml->endbranch(); } xml->endbranch(); } void EffectMgr::getfromXML(XMLwrapper *xml) { changeeffect(xml->getpar127("type", geteffect())); if(!efx || !geteffect()) return; efx->Ppreset = xml->getpar127("preset", efx->Ppreset); if(xml->enterbranch("EFFECT_PARAMETERS")) { for(int n = 0; n < 128; ++n) { seteffectpar_nolock(n, 0); //erase effect parameter if(xml->enterbranch("par_no", n) == 0) continue; int par = geteffectpar(n); seteffectpar_nolock(n, xml->getpar127("par", par)); xml->exitbranch(); } if(filterpars) if(xml->enterbranch("FILTER")) { filterpars->getfromXML(xml); xml->exitbranch(); } xml->exitbranch(); } cleanup(); }