/* ZynAddSubFX - a software synthesizer EQ.cpp - EQ 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 "EQ.h" #include "../DSP/AnalogFilter.h" #include "../Misc/Allocator.h" EQ::EQ(EffectParams pars) :Effect(pars) { for(int i = 0; i < MAX_EQ_BANDS; ++i) { filter[i].Ptype = 0; filter[i].Pfreq = 64; filter[i].Pgain = 64; filter[i].Pq = 64; filter[i].Pstages = 0; filter[i].l = memory.alloc(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); filter[i].r = memory.alloc(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); } //default values Pvolume = 50; setpreset(Ppreset); cleanup(); } EQ::~EQ() { for(int i = 0; i < MAX_EQ_BANDS; ++i) { memory.dealloc(filter[i].l); memory.dealloc(filter[i].r); } } // Cleanup the effect void EQ::cleanup(void) { for(int i = 0; i < MAX_EQ_BANDS; ++i) { filter[i].l->cleanup(); filter[i].r->cleanup(); } } //Effect output void EQ::out(const Stereo &smp) { for(int i = 0; i < buffersize; ++i) { efxoutl[i] = smp.l[i] * volume; efxoutr[i] = smp.r[i] * volume; } for(int i = 0; i < MAX_EQ_BANDS; ++i) { if(filter[i].Ptype == 0) continue; filter[i].l->filterout(efxoutl); filter[i].r->filterout(efxoutr); } } //Parameter control void EQ::setvolume(unsigned char _Pvolume) { Pvolume = _Pvolume; outvolume = powf(0.005f, (1.0f - Pvolume / 127.0f)) * 10.0f; volume = (!insertion) ? 1.0f : outvolume; } void EQ::setpreset(unsigned char npreset) { const int PRESET_SIZE = 1; const int NUM_PRESETS = 2; unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { {67}, //EQ 1 {67} //EQ 2 }; if(npreset >= NUM_PRESETS) npreset = NUM_PRESETS - 1; for(int n = 0; n < PRESET_SIZE; ++n) changepar(n, presets[npreset][n]); Ppreset = npreset; } void EQ::changepar(int npar, unsigned char value) { switch(npar) { case 0: setvolume(value); break; } if(npar < 10) return; int nb = (npar - 10) / 5; //number of the band (filter) if(nb >= MAX_EQ_BANDS) return; int bp = npar % 5; //band paramenter float tmp; switch(bp) { case 0: filter[nb].Ptype = value; if(value > 9) filter[nb].Ptype = 0; //has to be changed if more filters will be added if(filter[nb].Ptype != 0) { filter[nb].l->settype(value - 1); filter[nb].r->settype(value - 1); } break; case 1: filter[nb].Pfreq = value; tmp = 600.0f * powf(30.0f, (value - 64.0f) / 64.0f); filter[nb].l->setfreq(tmp); filter[nb].r->setfreq(tmp); break; case 2: filter[nb].Pgain = value; tmp = 30.0f * (value - 64.0f) / 64.0f; filter[nb].l->setgain(tmp); filter[nb].r->setgain(tmp); break; case 3: filter[nb].Pq = value; tmp = powf(30.0f, (value - 64.0f) / 64.0f); filter[nb].l->setq(tmp); filter[nb].r->setq(tmp); break; case 4: filter[nb].Pstages = value; if(value >= MAX_FILTER_STAGES) filter[nb].Pstages = MAX_FILTER_STAGES - 1; filter[nb].l->setstages(value); filter[nb].r->setstages(value); break; } } unsigned char EQ::getpar(int npar) const { switch(npar) { case 0: return Pvolume; break; } if(npar < 10) return 0; int nb = (npar - 10) / 5; //number of the band (filter) if(nb >= MAX_EQ_BANDS) return 0; int bp = npar % 5; //band paramenter switch(bp) { case 0: return filter[nb].Ptype; break; case 1: return filter[nb].Pfreq; break; case 2: return filter[nb].Pgain; break; case 3: return filter[nb].Pq; break; case 4: return filter[nb].Pstages; break; default: return 0; //in case of bogus parameter number } } float EQ::getfreqresponse(float freq) { float resp = 1.0f; for(int i = 0; i < MAX_EQ_BANDS; ++i) { if(filter[i].Ptype == 0) continue; resp *= filter[i].l->H(freq); } return rap2dB(resp * outvolume); } //Not exactly the most efficient manner to derive the total taps, but it should //be fast enough in practice void EQ::getFilter(float *a, float *b) const { a[0] = 1; b[0] = 1; off_t off=0; for(int i = 0; i < MAX_EQ_BANDS; ++i) { auto &F = filter[i]; if(F.Ptype == 0) continue; const double Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; const double Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; for(int j=0; j