zynaddsubfx

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

commit 58dc57da72fed304127ce3ccb5997bc0c632d8aa
parent 33645ee3cae670493d0d75ef6abef62953ba2fb1
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Sun, 17 Jul 2016 13:26:20 -0400

Convert State Variable Filter To Biquad For UI Vis

Diffstat:
Msrc/DSP/SVFilter.cpp | 59++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/DSP/SVFilter.h | 9+++++++++
Msrc/Params/FilterParams.cpp | 49+++++++++++++++++++++++++++++++++----------------
3 files changed, 100 insertions(+), 17 deletions(-)

diff --git a/src/DSP/SVFilter.cpp b/src/DSP/SVFilter.cpp @@ -51,6 +51,51 @@ void SVFilter::cleanup() abovenq = false; } +SVFilter::response::response(float b0, float b1, float b2, + float a0, float a1 ,float a2) +{ + a[0] = a0; + a[1] = a1; + a[2] = a2; + b[0] = b0; + b[1] = b1; + b[2] = b2; +} + +SVFilter::response SVFilter::computeResponse(int type, + float freq, float pq, int stages, float gain, float fs) +{ + typedef SVFilter::response res; + float f = freq / fs * 4.0; + if(f > 0.99999f) + f = 0.99999f; + float q = 1.0f - atanf(sqrtf(pq)) * 2.0f / PI; + q = powf(q, 1.0f / (stages + 1)); + float qrt = sqrtf(q); + float g = powf(gain, 1.0 / (stages + 1)); + if(type == 0) { //Low + return res{0, g*f*f*qrt, 0, + 1, (q*f+f*f-2), (1-q*f)}; + } + if(type == 1) {//High + //g *= qrt/(1+f*q); + g *= qrt; + return res{g, -2*g, g, + //1, (f*f-2*f*q-2)/(1+f*q), 1}; + 1, (q*f+f*f-2), (1-q*f)}; + } + if(type == 2) {//Band + g *= f*qrt; + return res{g, -g, 0, + 1, (q*f+f*f-2), (1-q*f)}; + } + if(type == 3 || true) {//Notch + g *= qrt; + return res{g, -2*g+g*f*f, g, + 1, (q*f+f*f-2), (1-q*f)}; + } +} + void SVFilter::computefiltercoefs(void) { par.f = freq / samplerate_f * 4.0f; @@ -136,7 +181,8 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) out = &x.notch; break; default: - errx(1, "Impossible SVFilter type encountered [%d]", type); + out = &x.low; + warnx("Impossible SVFilter type encountered [%d]", type); } for(int i = 0; i < buffersize; ++i) { @@ -148,6 +194,17 @@ void SVFilter::singlefilterout(float *smp, fstage &x, parameters &par) } } +// simplifying the responses +// xl = xl*z(-1) + pf*xb*z(-1) +// xh = pq1*x - xl - pq*xb*z(-1) +// xb = pf*xh + xb*z(-1) +// xn = xh + xl +// +// xl = pf*xb*z(-1)/(1-z(-1)) +// xb = pf*xh/(1-z(-1)) +// xl = pf*pfxh*z(-1)/(1-z(-1))^2 + + void SVFilter::filterout(float *smp) { for(int i = 0; i < stages + 1; ++i) diff --git a/src/DSP/SVFilter.h b/src/DSP/SVFilter.h @@ -36,6 +36,15 @@ class SVFilter:public Filter void setstages(int stages_); void cleanup(); + struct response { + response(float b0, float b1, float b2, + float a0, float a1 ,float a2); + float a[3]; + float b[3]; + }; + static response computeResponse(int type, + float freq, float pq, int stages, float g, float fs); + private: struct fstage { float low, high, band, notch; diff --git a/src/Params/FilterParams.cpp b/src/Params/FilterParams.cpp @@ -15,6 +15,7 @@ #include "../Misc/Util.h" #include "../Misc/Time.h" #include "../DSP/AnalogFilter.h" +#include "../DSP/SVFilter.h" #include <cmath> #include <cstdio> #include <cstdlib> @@ -89,6 +90,9 @@ const rtosc::Ports FilterParams::ports = { rToggle(Psequencereversed, "If the modulator input is inverted"), //{"Psequence#" FF_MAX_SEQUENCE "/nvowel", "", NULL, [](){}}, + {"type-svf::i", rProp(parameter) rShort("type") + rOptions(low, high, band, notch) + rDoc("Filter Type"), 0, rOptionCb(Ptype)}, //UI reader {"Pvowels:", rDoc("Get Formant Vowels"), NULL, @@ -132,24 +136,37 @@ const rtosc::Ports FilterParams::ports = { rDoc("Get a frequency response"), NULL, [](const char *, RtData &d) { FilterParams *obj = (FilterParams *) d.obj; - int order = 0; - float gain = dB2rap(obj->getgain()); - if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) - gain = 1.0; - auto cf = AnalogFilter::computeCoeff(obj->Ptype, - Filter::getrealfreq(obj->getfreq()), - obj->getq(), obj->Pstages, - gain, 48000, order); - if(order == 2) { + if(obj->Pcategory == 0) { + int order = 0; + float gain = dB2rap(obj->getgain()); + if(obj->Ptype != 6 && obj->Ptype != 7 && obj->Ptype != 8) + gain = 1.0; + auto cf = AnalogFilter::computeCoeff(obj->Ptype, + Filter::getrealfreq(obj->getfreq()), + obj->getq(), obj->Pstages, + gain, 48000, order); + if(order == 2) { + d.reply(d.loc, "fffffff", + (float)obj->Pstages, + cf.c[0], cf.c[1], cf.c[2], + 0.0, cf.d[1], cf.d[2]); + } else if(order == 1) { + d.reply(d.loc, "fffff", + (float)obj->Pstages, + cf.c[0], cf.c[1], + 0.0, cf.d[1]); + } + } else if(obj->Pcategory == 2) { + int order = 0; + float gain = dB2rap(obj->getgain()); + auto cf = SVFilter::computeResponse(obj->Ptype, + Filter::getrealfreq(obj->getfreq()), + obj->getq(), obj->Pstages, + gain, 48000); d.reply(d.loc, "fffffff", (float)obj->Pstages, - cf.c[0], cf.c[1], cf.c[2], - 0.0, cf.d[1], cf.d[2]); - } else if(order == 1) { - d.reply(d.loc, "fffff", - (float)obj->Pstages, - cf.c[0], cf.c[1], - 0.0, cf.d[1]); + cf.b[0], cf.b[1], cf.b[2], + 0.0, -cf.a[1], -cf.a[2]); } }}, // "", NULL, [](){}},"/freq"