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:
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"