|
- /*
- 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 the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <cmath>
- #include <rtosc/ports.h>
- #include <rtosc/port-sugar.h>
- #include "EQ.h"
- #include "../DSP/AnalogFilter.h"
- #include "../Misc/Allocator.h"
-
- namespace zyncarla {
-
- using rtosc::RtData;
- #define rObject EQ
- #define rBegin [](const char *msg, RtData &d) {\
- rObject *obj = (rObject*)d.obj;
- #define rEQ(offset) \
- int nfilt = atoi(msg-2); \
- int id = 10+nfilt*5+offset; \
- if(rtosc_narguments(msg)) \
- obj->changepar(id, rtosc_argument(msg,0).i);\
- else \
- d.reply(d.loc, "i", obj->getpar(id))
-
- #define rEnd }
-
- static rtosc::Ports filterports {
- {"Ptype::i", rProp(parameter) rOptions(Off, LP1, HP1, LP2,
- HP2, BP, notch, peak, l.shelf, h.shelf)
- rShort("type") rDoc("Filter Type"), 0,
- rBegin;
- rEQ(0);
- rEnd},
- {"Pfreq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
- rShort("freq"), 0,
- rBegin;
- rEQ(1);
- rEnd},
- {"Pgain::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
- rShort("gain"), 0,
- rBegin;
- rEQ(2);
- rEnd},
- {"Pq::i", rProp(parameter) rMap(min, 0) rMap(max, 127)
- rShort("q") rDoc("Resonance/Bandwidth"), 0,
- rBegin;
- rEQ(3);
- rEnd},
- {"Pstages::i", rProp(parameter) rMap(min, 0) rMap(max, 4)
- rShort("stages") rDoc("Additional filter stages"), 0,
- rBegin;
- rEQ(4);
- rEnd},
- };
-
- rtosc::Ports EQ::ports = {
- {"filter#8/", 0, &filterports,
- rBegin;
- (void)obj;
- SNIP;
- filterports.dispatch(msg, d);
- rEnd},
- {"coeff:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL,
- [](const char *, rtosc::RtData &d)
- {
- EQ *eq = (EQ*)d.obj;
- float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
- float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3];
- memset(a, 0, sizeof(a));
- memset(b, 0, sizeof(b));
- eq->getFilter(a,b);
-
- char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {};
- rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {};
- for(int i=0; i<MAX_EQ_BANDS*MAX_FILTER_STAGES*3; ++i) {
- int stride = MAX_EQ_BANDS*MAX_FILTER_STAGES*3;
- type[i] = type[i+stride] = 'f';
- val[i].f = b[i];
- val[i+stride].f = a[i];
- }
- d.replyArray(d.loc, type, val);
- }},
- };
-
- #undef rObject
- #undef rBegin
- #undef rEnd
-
- 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<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize);
- filter[i].r = memory.alloc<AnalogFilter>(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<float *> &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<F.Pstages+1; ++j) {
- for(int k=0; k<3; ++k) {
- a[off] = Fa[k];
- b[off] = Fb[k];
- off++;
- }
- }
- }
- }
-
- }
|