EQ.cpp (8315B)
1 /* 2 ZynAddSubFX - a software synthesizer 3 4 EQ.cpp - EQ effect 5 Copyright (C) 2002-2005 Nasca Octavian Paul 6 Author: Nasca Octavian Paul 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License 10 as published by the Free Software Foundation; either version 2 11 of the License, or (at your option) any later version. 12 */ 13 14 #include <cmath> 15 #include <rtosc/ports.h> 16 #include <rtosc/port-sugar.h> 17 #include "EQ.h" 18 #include "../DSP/AnalogFilter.h" 19 #include "../Misc/Allocator.h" 20 21 namespace zyn { 22 23 using rtosc::RtData; 24 #define rObject EQ 25 #define rBegin [](const char *msg, RtData &d) {\ 26 rObject *obj = (rObject*)d.obj; 27 #define rEQ(offset) \ 28 int nfilt = atoi(msg-2); \ 29 int id = 10+nfilt*5+offset; \ 30 if(rtosc_narguments(msg)) \ 31 { \ 32 obj->changepar(id, enum_key_from_msg(d.port->meta(), msg)); \ 33 } else { \ 34 d.reply(d.loc, "i", obj->getpar(id)); } 35 36 #define rEnd } 37 38 static rtosc::Ports filterports { 39 {"Ptype::i:S", rProp(parameter) rProp(enumerated) rOptions(Off, LP1, HP1, LP2, 40 HP2, BP, notch, peak, l.shelf, h.shelf) rDefault(0) 41 rShort("type") rDoc("Filter Type"), 0, 42 rBegin; 43 rEQ(0); 44 rEnd}, 45 {"Pfreq::i", rProp(parameter) rMap(min, 0) rMap(max, 127) 46 rDefault(64) 47 rShort("freq"), 0, 48 rBegin; 49 rEQ(1); 50 rEnd}, 51 {"Pgain::i", rProp(parameter) rMap(min, 0) rMap(max, 127) 52 rDefault(64) 53 rShort("gain"), 0, 54 rBegin; 55 rEQ(2); 56 rEnd}, 57 {"Pq::i", rProp(parameter) rMap(min, 0) rMap(max, 127) 58 rDefault(64) 59 rShort("q") rDoc("Resonance/Bandwidth"), 0, 60 rBegin; 61 rEQ(3); 62 rEnd}, 63 {"Pstages::i", rProp(parameter) rMap(min, 0) rMap(max, 4) 64 rDefault(0) 65 rShort("stages") rDoc("Additional filter stages"), 0, 66 rBegin; 67 rEQ(4); 68 rEnd}, 69 }; 70 71 rtosc::Ports EQ::ports = { 72 rEffParVol(rDefault(67)), 73 {"filter#8/", 0, &filterports, 74 rBegin; 75 (void)obj; 76 SNIP; 77 filterports.dispatch(msg, d); 78 rEnd}, 79 {"coeff:", rProp(internal) rDoc("Get equalizer Coefficients"), NULL, 80 [](const char *, rtosc::RtData &d) 81 { 82 EQ *eq = (EQ*)d.obj; 83 float a[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; 84 float b[MAX_EQ_BANDS*MAX_FILTER_STAGES*3]; 85 memset(a, 0, sizeof(a)); 86 memset(b, 0, sizeof(b)); 87 eq->getFilter(a,b); 88 89 char type[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2+1] = {}; 90 rtosc_arg_t val[MAX_EQ_BANDS*MAX_FILTER_STAGES*3*2] = {}; 91 for(int i=0; i<MAX_EQ_BANDS*MAX_FILTER_STAGES*3; ++i) { 92 int stride = MAX_EQ_BANDS*MAX_FILTER_STAGES*3; 93 type[i] = type[i+stride] = 'f'; 94 val[i].f = b[i]; 95 val[i+stride].f = a[i]; 96 } 97 d.replyArray(d.loc, type, val); 98 }}, 99 }; 100 101 #undef rObject 102 #undef rBegin 103 #undef rEnd 104 105 EQ::EQ(EffectParams pars) 106 :Effect(pars) 107 { 108 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 109 filter[i].l = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); 110 filter[i].r = memory.alloc<AnalogFilter>(6, 1000.0f, 1.0f, 0, pars.srate, pars.bufsize); 111 } 112 //default values 113 Pvolume = 50; 114 115 setpreset(Ppreset); 116 cleanup(); 117 } 118 119 EQ::~EQ() 120 { 121 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 122 memory.dealloc(filter[i].l); 123 memory.dealloc(filter[i].r); 124 } 125 } 126 127 // Cleanup the effect 128 void EQ::cleanup(void) 129 { 130 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 131 filter[i].l->cleanup(); 132 filter[i].r->cleanup(); 133 } 134 } 135 136 //Effect output 137 void EQ::out(const Stereo<float *> &smp) 138 { 139 for(int i = 0; i < buffersize; ++i) { 140 efxoutl[i] = smp.l[i] * volume; 141 efxoutr[i] = smp.r[i] * volume; 142 } 143 144 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 145 if(filter[i].Ptype == 0) 146 continue; 147 filter[i].l->filterout(efxoutl); 148 filter[i].r->filterout(efxoutr); 149 } 150 } 151 152 153 //Parameter control 154 void EQ::setvolume(unsigned char _Pvolume) 155 { 156 Pvolume = _Pvolume; 157 outvolume = powf(0.005f, (1.0f - Pvolume / 127.0f)) * 10.0f; 158 volume = (!insertion) ? 1.0f : outvolume; 159 } 160 161 unsigned char EQ::getpresetpar(unsigned char npreset, unsigned int npar) 162 { 163 #define PRESET_SIZE 1 164 #define NUM_PRESETS 2 165 static const unsigned char presets[NUM_PRESETS][PRESET_SIZE] = { 166 {67}, //EQ 1 167 {67} //EQ 2 168 }; 169 if(npreset < NUM_PRESETS && npar < PRESET_SIZE) { 170 return presets[npreset][npar]; 171 } else if (npar >= 10 && npar < (10 + MAX_EQ_BANDS * 5)) { 172 static const unsigned char bp_preset[5] = { 0, 64, 64, 64, 0 }; 173 return bp_preset[npar % 5]; 174 } 175 return 0; 176 } 177 178 void EQ::setpreset(unsigned char npreset) 179 { 180 181 if(npreset >= NUM_PRESETS) 182 npreset = NUM_PRESETS - 1; 183 for(int n = 0; n != 128; n++) 184 changepar(n, getpresetpar(npreset, n)); 185 Ppreset = npreset; 186 } 187 188 189 void EQ::changepar(int npar, unsigned char value) 190 { 191 switch(npar) { 192 case 0: 193 setvolume(value); 194 break; 195 } 196 if(npar < 10) 197 return; 198 199 int nb = (npar - 10) / 5; //number of the band (filter) 200 if(nb >= MAX_EQ_BANDS) 201 return; 202 int bp = npar % 5; //band paramenter 203 204 float tmp; 205 switch(bp) { 206 case 0: 207 filter[nb].Ptype = value; 208 if(value > 9) 209 filter[nb].Ptype = 0; //has to be changed if more filters will be added 210 if(filter[nb].Ptype != 0) { 211 filter[nb].l->settype(value - 1); 212 filter[nb].r->settype(value - 1); 213 } 214 break; 215 case 1: 216 filter[nb].Pfreq = value; 217 tmp = 600.0f * powf(30.0f, (value - 64.0f) / 64.0f); 218 filter[nb].l->setfreq(tmp); 219 filter[nb].r->setfreq(tmp); 220 break; 221 case 2: 222 filter[nb].Pgain = value; 223 tmp = 30.0f * (value - 64.0f) / 64.0f; 224 filter[nb].l->setgain(tmp); 225 filter[nb].r->setgain(tmp); 226 break; 227 case 3: 228 filter[nb].Pq = value; 229 tmp = powf(30.0f, (value - 64.0f) / 64.0f); 230 filter[nb].l->setq(tmp); 231 filter[nb].r->setq(tmp); 232 break; 233 case 4: 234 filter[nb].Pstages = value; 235 if(value >= MAX_FILTER_STAGES) 236 filter[nb].Pstages = MAX_FILTER_STAGES - 1; 237 filter[nb].l->setstages(value); 238 filter[nb].r->setstages(value); 239 break; 240 } 241 } 242 243 unsigned char EQ::getpar(int npar) const 244 { 245 switch(npar) { 246 case 0: 247 return Pvolume; 248 break; 249 } 250 251 if(npar < 10) 252 return 0; 253 254 int nb = (npar - 10) / 5; //number of the band (filter) 255 if(nb >= MAX_EQ_BANDS) 256 return 0; 257 int bp = npar % 5; //band paramenter 258 switch(bp) { 259 case 0: 260 return filter[nb].Ptype; 261 break; 262 case 1: 263 return filter[nb].Pfreq; 264 break; 265 case 2: 266 return filter[nb].Pgain; 267 break; 268 case 3: 269 return filter[nb].Pq; 270 break; 271 case 4: 272 return filter[nb].Pstages; 273 break; 274 default: return 0; //in case of bogus parameter number 275 } 276 } 277 278 279 float EQ::getfreqresponse(float freq) 280 { 281 float resp = 1.0f; 282 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 283 if(filter[i].Ptype == 0) 284 continue; 285 resp *= filter[i].l->H(freq); 286 } 287 return rap2dB(resp * outvolume); 288 } 289 290 //Not exactly the most efficient manner to derive the total taps, but it should 291 //be fast enough in practice 292 void EQ::getFilter(float *a, float *b) const 293 { 294 a[0] = 1; 295 b[0] = 1; 296 off_t off=0; 297 for(int i = 0; i < MAX_EQ_BANDS; ++i) { 298 auto &F = filter[i]; 299 if(F.Ptype == 0) 300 continue; 301 const float Fb[3] = {F.l->coeff.c[0], F.l->coeff.c[1], F.l->coeff.c[2]}; 302 const float Fa[3] = {1.0f, -F.l->coeff.d[1], -F.l->coeff.d[2]}; 303 304 for(int j=0; j<F.Pstages+1; ++j) { 305 for(int k=0; k<3; ++k) { 306 a[off] = Fa[k]; 307 b[off] = Fb[k]; 308 off++; 309 } 310 } 311 } 312 } 313 314 }