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.
 
 

114 lines
2.6 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 "../globals.h"
#include "util.h"
#define FILTER_K_BASE 6.214608098422192
#ifdef USE_LUTS
#define K_LUT_SIZE 64
extern float kLUT[K_LUT_SIZE];
inline float freqToK(float x) {
float intPart, fracPart = modf(x * (K_LUT_SIZE - 1), &intPart);
int index = (int) intPart;
return fracPart < FLT_EPSILON ? kLUT[index] : (1 - fracPart) * kLUT[index] + fracPart * kLUT[index + 1];
}
#else
inline float freqToK(float x) {
return tan(M_PI_4 * 0.002 * exp(x * FILTER_K_BASE));
}
#endif
inline float noteToFltFreq(float note) {
return ((note - 69) / 12.0) / (FILTER_K_BASE * M_LOG2E);
}
class SVF12 {
public:
typedef struct {
float lp; // low-pass
float bp; // band-pass
float hp; // high-pass
} Output;
protected:
float as1, as2;
public:
SVF12() : as1(0), as2(0) {}
inline Output tick(float in, float kK, float kQ) {
Output out;
float kdiv = 1 + kK/kQ + kK*kK;
out.hp = (in - (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 Filter {
public:
enum Type {
TYPE_LP = 0,
TYPE_BP = 42,
TYPE_HP = 84
};
enum Slope {
SLOPE_24 = 0,
SLOPE_12 = 64,
};
typedef struct {
float freq;
float res;
Type type;
Slope slope;
} Settings;
private:
Settings const * settings;
SVF12 fltA, fltB;
public:
void assign(Settings const * settings);
inline float tick(float in, float freqAdd) {
float freq = clamp(settings->freq + freqAdd, 0, 1);
//float kK = tan(M_PI_4 * clamp(0.002 * exp(freq * FILTER_K_BASE), 0, 1));
float kK = freqToK(freq);
float kQ = M_SQRT1_2 + settings->res;
SVF12::Output outA = fltA.tick(in, kK, kQ);
switch(settings->type) {
case TYPE_LP:
return settings->slope == SLOPE_24 ? fltB.tick(outA.lp, kK, kQ).lp : outA.lp;
case TYPE_BP:
return settings->slope == SLOPE_24 ? fltB.tick(outA.bp, kK, kQ).bp : outA.bp;
case TYPE_HP:
return settings->slope == SLOPE_24 ? fltB.tick(outA.hp, kK, kQ).hp : outA.hp;
}
}
};
#endif