|
|
|
@ -52,6 +52,46 @@ public: |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class SVF12Stereo { |
|
|
|
|
protected: |
|
|
|
|
float hp[2], bp[2], lp[2]; |
|
|
|
|
float as1[2], as2[2]; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
SVF12Stereo() : hp{0, 0}, bp{0, 0}, lp{0, 0}, as1{0, 0}, as2{0, 0} {} |
|
|
|
|
|
|
|
|
|
inline void tick(float *in, float *hpo, float *bpo, float *lpo, size_t bufferSize, float *kK, float *kQ) { |
|
|
|
|
size_t frameCount = bufferSize / 2; |
|
|
|
|
|
|
|
|
|
float kQ_1[frameCount]; |
|
|
|
|
for(size_t i = 0; i < frameCount; ++i) { |
|
|
|
|
kQ_1[i] = 1.f / kQ[i]; |
|
|
|
|
} |
|
|
|
|
float kMul[frameCount]; |
|
|
|
|
for(size_t i = 0; i < frameCount; ++i) { |
|
|
|
|
kMul[i] = 1.f / (1.f + kK[i]*kQ_1[i] + kK[i]*kK[i]); |
|
|
|
|
} |
|
|
|
|
for(size_t i = 0, j = 0; i < bufferSize; ++i) { |
|
|
|
|
size_t ch = i & 1; |
|
|
|
|
|
|
|
|
|
hp[ch] = (in[i] - (kQ_1[j] + kK[j]) * as1[ch] - as2[ch]) * kMul[j]; |
|
|
|
|
float au = hp[ch] * kK[j]; |
|
|
|
|
bp[ch] = au + as1[ch]; |
|
|
|
|
as1[ch] = au + bp[ch]; |
|
|
|
|
au = bp[ch] * kK[j]; |
|
|
|
|
lp[ch] = au + as2[ch]; |
|
|
|
|
as2[ch] = au + lp[ch]; |
|
|
|
|
|
|
|
|
|
hpo && (hpo[i] = hp[ch]); |
|
|
|
|
bpo && (bpo[i] = bp[ch]); |
|
|
|
|
lpo && (lpo[i] = lp[ch]); |
|
|
|
|
|
|
|
|
|
j += ch; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 12 and 24 dB/oct
|
|
|
|
|
class Filter { |
|
|
|
|
public: |
|
|
|
@ -120,5 +160,74 @@ public: |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// 12 and 24 dB/oct
|
|
|
|
|
class FilterStereo { |
|
|
|
|
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; |
|
|
|
|
SVF12Stereo fltA, fltB; |
|
|
|
|
float freq, res; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
void assign(Settings const * settings); |
|
|
|
|
|
|
|
|
|
inline void tick(float *in, float *out, size_t bufferSize, float *freqMod) { |
|
|
|
|
size_t frameCount = bufferSize / 2; |
|
|
|
|
|
|
|
|
|
float dt = 1.f / (float) frameCount; |
|
|
|
|
|
|
|
|
|
float kK[frameCount]; |
|
|
|
|
float dFreq = dt * (settings->freq - freq); |
|
|
|
|
for(size_t i = 0; i < frameCount; i++) { |
|
|
|
|
kK[i] = fastCVtoK(freq + freqMod[i]); |
|
|
|
|
freq += dFreq; |
|
|
|
|
} |
|
|
|
|
float kQ[frameCount]; |
|
|
|
|
float dRes = dt * (settings->res - res); |
|
|
|
|
for(size_t i = 0; i < frameCount; 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 |