zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

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 }