zynaddsubfx

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

SVFilter.cpp (5515B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   SVFilter.cpp - Several state-variable filters
      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 <cstdio>
     16 #include <cstring>
     17 #include <cassert>
     18 #include "../Misc/Util.h"
     19 #include "SVFilter.h"
     20 
     21 #define errx(...) {}
     22 #define warnx(...) {}
     23 #ifndef errx
     24 #include <err.h>
     25 #endif
     26 
     27 namespace zyn {
     28 
     29 SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq,
     30                    unsigned char Fstages, unsigned int srate, int bufsize)
     31     :Filter(srate, bufsize),
     32       type(Ftype),
     33       stages(Fstages),
     34       freq(Ffreq),
     35       q(Fq),
     36       gain(1.0f)
     37 {
     38     if(stages >= MAX_FILTER_STAGES)
     39         stages = MAX_FILTER_STAGES;
     40     outgain = 1.0f;
     41     cleanup();
     42     setfreq_and_q(Ffreq, Fq);
     43     freq_smoothing.reset(Ffreq);
     44     freq_smoothing.sample_rate(srate);
     45 }
     46 
     47 SVFilter::~SVFilter()
     48 {}
     49 
     50 void SVFilter::cleanup()
     51 {
     52     for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i)
     53         st[i].low = st[i].high = st[i].band = st[i].notch = 0.0f;
     54 }
     55 
     56 SVFilter::response::response(float b0, float b1, float b2,
     57                              float a0, float a1 ,float a2)
     58 {
     59     a[0] = a0;
     60     a[1] = a1;
     61     a[2] = a2;
     62     b[0] = b0;
     63     b[1] = b1;
     64     b[2] = b2;
     65 }
     66 
     67 SVFilter::response SVFilter::computeResponse(int type,
     68         float freq, float pq, int stages, float gain, float fs)
     69 {
     70     typedef SVFilter::response res;
     71     float f = freq / fs * 4.0;
     72     if(f > 0.99999f)
     73        f = 0.99999f;
     74     float q   = 1.0f - atanf(sqrtf(pq)) * 2.0f / PI;
     75     q         =  powf(q, 1.0f / (stages + 1));
     76     float qrt = sqrtf(q);
     77     float g   = powf(gain, 1.0 / (stages + 1));
     78     if(type == 0) { //Low
     79         return res{0, g*f*f*qrt, 0,
     80                    1,   (q*f+f*f-2),    (1-q*f)};
     81     }
     82     if(type == 1) {//High
     83         //g *= qrt/(1+f*q);
     84         g *= qrt;
     85         return res{g,    -2*g,    g,
     86                    //1,   (f*f-2*f*q-2)/(1+f*q),    1};
     87                    1,   (q*f+f*f-2),    (1-q*f)};
     88     }
     89     if(type == 2) {//Band
     90         g *= f*qrt;
     91         return res{g,   -g, 0,
     92                    1,   (q*f+f*f-2),    (1-q*f)};
     93     }
     94     if(type == 3 || true) {//Notch
     95         g *= qrt;
     96         return res{g, -2*g+g*f*f, g,
     97                    1,   (q*f+f*f-2),    (1-q*f)};
     98     }
     99 }
    100 
    101 
    102 
    103 void SVFilter::computefiltercoefs(void)
    104 {
    105     par.f = freq / samplerate_f * 4.0f;
    106     if(par.f > 0.99999f)
    107         par.f = 0.99999f;
    108     par.q      = 1.0f - atanf(sqrtf(q)) * 2.0f / PI;
    109     par.q      = powf(par.q, 1.0f / (stages + 1));
    110     par.q_sqrt = sqrtf(par.q);
    111 }
    112 
    113 
    114 void SVFilter::setfreq(float frequency)
    115 {
    116     if(frequency < 0.1f)
    117         frequency = 0.1f;
    118     float rap = freq / frequency;
    119     if(rap < 1.0f)
    120         rap = 1.0f / rap;
    121 
    122     freq = frequency;
    123     computefiltercoefs();
    124 }
    125 
    126 void SVFilter::setfreq_and_q(float frequency, float q_)
    127 {
    128     q = q_;
    129     setfreq(frequency);
    130 }
    131 
    132 void SVFilter::setq(float q_)
    133 {
    134     q = q_;
    135     computefiltercoefs();
    136 }
    137 
    138 void SVFilter::settype(int type_)
    139 {
    140     type = type_;
    141     computefiltercoefs();
    142 }
    143 
    144 void SVFilter::setgain(float dBgain)
    145 {
    146     gain = dB2rap(dBgain);
    147     computefiltercoefs();
    148 }
    149 
    150 void SVFilter::setstages(int stages_)
    151 {
    152     if(stages_ >= MAX_FILTER_STAGES)
    153         stages_ = MAX_FILTER_STAGES - 1;
    154     if (stages != stages_) {
    155         stages = stages_;
    156         cleanup();
    157         computefiltercoefs();
    158     }
    159 }
    160 
    161 float *SVFilter::getfilteroutfortype(SVFilter::fstage &x) {
    162     float *out = NULL;
    163     switch(type) {
    164         case 0:
    165             out = &x.low;
    166             break;
    167         case 1:
    168             out = &x.high;
    169             break;
    170         case 2:
    171             out = &x.band;
    172             break;
    173         case 3:
    174             out = &x.notch;
    175             break;
    176         default:
    177             out = &x.low;
    178             warnx("Impossible SVFilter type encountered [%d]", type);
    179     }
    180     return out;
    181 }
    182 
    183 
    184 // simplifying the responses
    185 // xl = xl*z(-1) +      pf*xb*z(-1)
    186 // xh = pq1*x    - xl - pq*xb*z(-1)
    187 // xb = pf*xh    +         xb*z(-1)
    188 // xn = xh       + xl
    189 //
    190 // xl = pf*xb*z(-1)/(1-z(-1))
    191 // xb = pf*xh/(1-z(-1))
    192 // xl = pf*pfxh*z(-1)/(1-z(-1))^2
    193 
    194 
    195 
    196 void SVFilter::singlefilterout(float *smp, SVFilter::fstage &x, SVFilter::parameters &par, int buffersize )
    197 {
    198     float *out = getfilteroutfortype(x);
    199     for(int i = 0; i < buffersize; ++i) {
    200         x.low   = x.low + par.f * x.band;
    201         x.high  = par.q_sqrt * smp[i] - x.low - par.q * x.band;
    202         x.band  = par.f * x.high + x.band;
    203         x.notch = x.high + x.low;
    204         smp[i]  = *out;
    205     }
    206 }
    207 
    208 void SVFilter::filterout(float *smp)
    209 {
    210     assert((buffersize % 8) == 0);
    211 
    212     float freqbuf[buffersize];
    213 
    214     if ( freq_smoothing.apply( freqbuf, buffersize, freq ) )
    215     {
    216         /* 8 sample chunks seems to work OK for AnalogFilter, so do that here too. */
    217         for ( int i = 0; i < buffersize; i += 8 )
    218         {
    219             freq = freqbuf[i];
    220             computefiltercoefs();
    221 
    222             for(int j = 0; j < stages + 1; ++j)
    223                 singlefilterout(smp + i, st[j], par, 8 );
    224         }
    225 
    226         freq = freqbuf[buffersize - 1];
    227         computefiltercoefs();
    228     }
    229     else
    230         for(int i = 0; i < stages + 1; ++i)
    231             singlefilterout(smp, st[i], par, buffersize );
    232 
    233     for(int i = 0; i < buffersize; ++i)
    234         smp[i] *= outgain;
    235 }
    236 
    237 }