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.
 
 

124 lines
3.2 KiB

#ifndef __SVF_H__
#define __SVF_H__
/* CEM3320/Oberheim/Phrophet-style filter as described here: https://arxiv.org/pdf/2111.05592.pdf */
#include <cmath>
#include <cfloat>
#include <iostream>
#include <algorithm>
#include <functional>
#include "../globals.h"
#include "../util.h"
#include "../luts.h"
#define FILTER_K_SCALE (2 * CV_FREQ_MIN / SAMPLE_RATE)
inline float cvToK(float cv) {
return tanf((float) M_PI_2 * std::min(0.5f, (float) FILTER_K_SCALE * exp2f(cv)));
}
class SVF12 {
protected:
float hp, bp, lp;
float as1, as2;
public:
SVF12() : hp(0), bp(0), lp(0), as1(0), as2(0) {}
inline void tick(float *in, float *hpo, float *bpo, float *lpo, size_t bufferSize, float *kK, float *kQ) {
float kQ_1[bufferSize];
for(size_t i = 0; i < bufferSize; ++i) {
kQ_1[i] = 1.f / kQ[i];
}
float kMul[bufferSize];
for(size_t i = 0; i < bufferSize; ++i) {
kMul[i] = 1.f / (1.f + kK[i]*kQ_1[i] + kK[i]*kK[i]);
}
for(size_t i = 0; i < bufferSize; ++i) {
hp = (in[i] - (kQ_1[i] + kK[i]) * as1 - as2) * kMul[i];
float au = hp * kK[i];
bp = au + as1;
as1 = au + bp;
au = bp * kK[i];
lp = au + as2;
as2 = au + lp;
hpo && (hpo[i] = hp);
bpo && (bpo[i] = bp);
lpo && (lpo[i] = lp);
}
}
};
// 12 and 24 dB/oct
class Filter {
public:
enum Type {
TYPE_LP = 0,
TYPE_BP,
TYPE_HP
};
enum Slope {
SLOPE_12 = 0,
SLOPE_24,
};
typedef struct {
float freq;
float res;
Type type;
Slope slope;
} Settings;
private:
Settings const * settings;
SVF12 fltA, fltB;
float freq, res;
public:
void assign(Settings const * settings);
inline void tick(float *in, float *out, size_t bufferSize, float *freqMod) {
float dt = 1.f / (float) bufferSize;
float kK[bufferSize];
float dFreq = dt * (settings->freq - freq);
for(size_t i = 0; i < bufferSize; i++) {
kK[i] = fastCVtoK(freq + freqMod[i]);
freq += dFreq;
}
float kQ[bufferSize];
float dRes = dt * (settings->res - res);
for(size_t i = 0; i < bufferSize; i++) {
kQ[i] = (float) M_SQRT1_2 + res;
res += dRes;
}
switch(settings->type) {
case TYPE_LP:
fltA.tick(in, NULL, NULL, out, bufferSize, kK, kQ);
if(settings->slope == SLOPE_24) {
fltB.tick(out, NULL, NULL, out, bufferSize, kK, kQ);
}
break;
case TYPE_BP:
fltA.tick(in, NULL, out, NULL, bufferSize, kK, kQ);
if(settings->slope == SLOPE_24) {
fltB.tick(out, NULL, out, NULL, bufferSize, kK, kQ);
}
break;
case TYPE_HP:
fltA.tick(in, out, NULL, NULL, bufferSize, kK, kQ);
if(settings->slope == SLOPE_24) {
fltB.tick(out, out, NULL, NULL, bufferSize, kK, kQ);
}
break;
}
}
};
#endif