forked from klang-modular/synthapp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.1 KiB
117 lines
2.1 KiB
#ifndef __SVF_H__
|
|
#define __SVF_H__
|
|
|
|
/* CEM3320/Oberheim/Phrophet-style filter as described here: https://arxiv.org/pdf/2111.05592.pdf */
|
|
|
|
#include <math.h>
|
|
|
|
#include "util.h"
|
|
|
|
class SVF12 {
|
|
protected:
|
|
float as1, as2;
|
|
float kdiv;
|
|
float kK, kQ;
|
|
|
|
inline void updateCoeffs() {
|
|
kdiv = 1 + kK/kQ + kK*kK;
|
|
}
|
|
|
|
public:
|
|
typedef struct {
|
|
float hp; // high-pass
|
|
float bp; // band-pass
|
|
float lp; // low-pass
|
|
} Output;
|
|
|
|
SVF12() {
|
|
as1 = 0;
|
|
as2 = 0;
|
|
kK = tan(M_PI_4);
|
|
kQ = M_SQRT1_2;
|
|
updateCoeffs();
|
|
}
|
|
|
|
void setFrequency(float f) {
|
|
kK = tan(M_PI_4 * clamp(f, 0, 1));
|
|
updateCoeffs();
|
|
}
|
|
|
|
void setQ(float q) {
|
|
kQ = q;
|
|
updateCoeffs();
|
|
}
|
|
|
|
Output tick(float as) {
|
|
Output out;
|
|
out.hp = (as - (1/kQ + kK) * as1 - as2) / kdiv;
|
|
float au = out.hp * kK;
|
|
out.bp = au + as1;
|
|
as1 = au + out.bp;
|
|
au = out.bp * kK;
|
|
out.lp = au + as2;
|
|
as2 = au + out.lp;
|
|
return out;
|
|
}
|
|
};
|
|
|
|
// 12 and 24 dB/oct
|
|
class SVF {
|
|
public:
|
|
enum Mode {
|
|
MODE_HP_12,
|
|
MODE_HP_24,
|
|
MODE_BP_12,
|
|
MODE_BP_24,
|
|
MODE_LP_12,
|
|
MODE_LP_24,
|
|
};
|
|
|
|
private:
|
|
Mode mode;
|
|
SVF12 first, second;
|
|
|
|
public:
|
|
SVF() {
|
|
this->mode = MODE_LP_24;
|
|
}
|
|
|
|
void setMode(Mode mode) {
|
|
this->mode = mode;
|
|
}
|
|
|
|
void setFrequency(float f) {
|
|
first.setFrequency(f);
|
|
second.setFrequency(f);
|
|
}
|
|
|
|
void setQ(float q) {
|
|
first.setQ(q);
|
|
second.setQ(q);
|
|
}
|
|
|
|
float tick(float as) {
|
|
SVF12::Output in = first.tick(as);
|
|
switch(mode) {
|
|
case MODE_HP_12:
|
|
return in.hp;
|
|
|
|
case MODE_HP_24:
|
|
return second.tick(in.hp).hp;
|
|
|
|
case MODE_BP_12:
|
|
return in.bp;
|
|
|
|
case MODE_BP_24:
|
|
return second.tick(in.bp).bp;
|
|
|
|
case MODE_LP_12:
|
|
return in.lp;
|
|
|
|
case MODE_LP_24:
|
|
return second.tick(in.lp).lp;
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif |