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