feat: change to an SVF filter design
This commit is contained in:
parent
821f3d7d65
commit
a80c6276a8
2 changed files with 106 additions and 53 deletions
109
core/Filter.cpp
109
core/Filter.cpp
|
|
@ -1,49 +1,90 @@
|
||||||
#include "Filter.hpp"
|
#include "Filter.hpp"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
Filter::Filter(float initCutOff, float initSampleRate)
|
#ifndef M_PI
|
||||||
: cutOff_(initCutOff), feedback_(0.0f), alpha_(0.0f),
|
#define M_PI 3.14159265358979323846
|
||||||
sampleRate_(initSampleRate), zL_(0.0f), zR_(0.0f) {
|
#endif
|
||||||
recompute();
|
|
||||||
};
|
Filter::Filter(float initCutOff, float initQ, float initSampleRate)
|
||||||
|
: cutOff_(initCutOff), q_(initQ), sampleRate_(initSampleRate),
|
||||||
|
type_(kLowPass), g_(0.0f), lpL_(0.0f), bpL_(0.0f), lpR_(0.0f),
|
||||||
|
bpR_(0.0f) {
|
||||||
|
updateCoeffs();
|
||||||
|
}
|
||||||
|
|
||||||
|
Filter::FilterType Filter::getType() const { return type_; }
|
||||||
|
|
||||||
|
void Filter::updateCoeffs() {
|
||||||
|
float f = cutOff_ / std::fmax(sampleRate_, 1.0f);
|
||||||
|
if (f > kMaxNormalizedFrequency)
|
||||||
|
f = kMaxNormalizedFrequency;
|
||||||
|
g_ = 2.0f * std::sin(M_PI * f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Filter::processFrame(float input, float &lp, float &bp) const {
|
||||||
|
|
||||||
|
float hp = input - (bp / q_) - lp;
|
||||||
|
|
||||||
|
bp = bp + g_ * hp;
|
||||||
|
lp = lp + g_ * bp;
|
||||||
|
|
||||||
|
switch (type_) {
|
||||||
|
case kHighPass:
|
||||||
|
return hp;
|
||||||
|
case kBandPass:
|
||||||
|
return bp;
|
||||||
|
case kNotch:
|
||||||
|
return input - lp;
|
||||||
|
case kLowPass:
|
||||||
|
default:
|
||||||
|
return lp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Filter::process(const float *in, float *out, uint32_t frames) {
|
void Filter::process(const float *in, float *out, uint32_t frames) {
|
||||||
filter(in, out, frames, &zL_);
|
float lp = lpL_;
|
||||||
};
|
float bp = bpL_;
|
||||||
void Filter::processStereo(const float *inLeft, const float *inRight,
|
|
||||||
float *outLeft, float *outRight, uint32_t frames) {
|
|
||||||
filter(inLeft, outLeft, frames, &zL_);
|
|
||||||
filter(inRight, outRight, frames, &zR_);
|
|
||||||
};
|
|
||||||
|
|
||||||
void Filter::filter(const float *in, float *out, uint32_t frames, float *z) {
|
|
||||||
for (uint32_t i = 0; i < frames; ++i) {
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
float feedbackInput = in[i] + (feedback_ * (*z));
|
out[i] = processFrame(in[i], lp, bp);
|
||||||
*z = *z + alpha_ * (feedbackInput - *z);
|
|
||||||
out[i] = *z;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Filter::recompute() {
|
lpL_ = lp;
|
||||||
float fc = std::fmax(cutOff_, 1.0f);
|
bpL_ = bp;
|
||||||
float rc = 1.0f / (2.0f * M_PI * fc);
|
|
||||||
float val = 1.0f - std::exp(-1.0f / (rc * sampleRate_));
|
|
||||||
alpha_ = std::fmin(val, 0.999f);
|
|
||||||
};
|
|
||||||
|
|
||||||
void Filter::setCutOff(float newCutOff) {
|
|
||||||
cutOff_ = newCutOff;
|
|
||||||
recompute();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Filter::processStereo(const float *inL, const float *inR, float *outL,
|
||||||
|
float *outR, uint32_t frames) {
|
||||||
|
float lpL = lpL_, bpL = bpL_;
|
||||||
|
float lpR = lpR_, bpR = bpR_;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < frames; ++i) {
|
||||||
|
outL[i] = processFrame(inL[i], lpL, bpL);
|
||||||
|
outR[i] = processFrame(inR[i], lpR, bpR);
|
||||||
|
}
|
||||||
|
|
||||||
|
lpL_ = lpL;
|
||||||
|
bpL_ = bpL;
|
||||||
|
lpR_ = lpR;
|
||||||
|
bpR_ = bpR;
|
||||||
|
}
|
||||||
|
|
||||||
float Filter::getCutOff() const { return cutOff_; }
|
float Filter::getCutOff() const { return cutOff_; }
|
||||||
|
void Filter::setCutOff(float freq) {
|
||||||
void Filter::setFeedback(float newFeedback) {
|
cutOff_ = std::fmax(freq, 1.0f);
|
||||||
feedback_ = std::fmin(std::fmax(newFeedback, 0.0f), 0.99f);
|
updateCoeffs();
|
||||||
}
|
}
|
||||||
float Filter::getFeedback() const { return feedback_; }
|
|
||||||
|
|
||||||
void Filter::setSampleRate(float newSampleRate) {
|
float Filter::getQ() const { return q_; }
|
||||||
sampleRate_ = newSampleRate;
|
void Filter::setQ(float q) {
|
||||||
recompute();
|
q_ = std::fmax(q, 0.1f);
|
||||||
|
updateCoeffs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Filter::setType(FilterType type) { type_ = type; }
|
||||||
|
|
||||||
float Filter::getSampleRate() const { return sampleRate_; }
|
float Filter::getSampleRate() const { return sampleRate_; }
|
||||||
|
void Filter::setSampleRate(float sr) {
|
||||||
|
sampleRate_ = sr;
|
||||||
|
updateCoeffs();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,45 @@
|
||||||
#ifndef FILTER_HPP_INCLUDED
|
#ifndef FILTER_HPP_INCLUDED
|
||||||
#define FILTER_HPP_INCLUDED
|
#define FILTER_HPP_INCLUDED
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI 3.14159265358979323846
|
|
||||||
#endif
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
constexpr float kMaxNormalizedFrequency = 0.16667f;
|
||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
Filter(float initCutOff = 1.0f, float initSampleRate = 48000.0f);
|
Filter(float initCutOff = 1000.0f, float initQ = 0.707f,
|
||||||
void process(const float *in, float *out, uint32_t frames);
|
float initSampleRate = 48000.0f);
|
||||||
void processStereo(const float *inLeft, const float *inRight, float *outLeft,
|
|
||||||
float *outRight, uint32_t frames);
|
enum FilterType { kLowPass, kHighPass, kBandPass, kNotch, kFilterTypeCount };
|
||||||
|
|
||||||
|
void setCutOff(float freq);
|
||||||
|
void setQ(float q);
|
||||||
|
void setSampleRate(float sr);
|
||||||
|
void setType(FilterType type);
|
||||||
|
|
||||||
void recompute();
|
|
||||||
void setCutOff(float newCutOff);
|
|
||||||
float getCutOff() const;
|
float getCutOff() const;
|
||||||
void setFeedback(float newFeedback);
|
float getQ() const;
|
||||||
float getFeedback() const;
|
|
||||||
void setSampleRate(float newSampleRate);
|
|
||||||
float getSampleRate() const;
|
float getSampleRate() const;
|
||||||
|
FilterType getType() const;
|
||||||
|
|
||||||
|
void process(const float *in, float *out, uint32_t frames);
|
||||||
|
void processStereo(const float *inL, const float *inR, float *outL,
|
||||||
|
float *outR, uint32_t frames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void filter(const float *in, float *out, uint32_t frames, float *z);
|
void updateCoeffs();
|
||||||
|
|
||||||
|
float processFrame(float input, float &lp, float &bp) const;
|
||||||
|
|
||||||
float cutOff_;
|
float cutOff_;
|
||||||
float feedback_;
|
float q_;
|
||||||
float alpha_;
|
|
||||||
float sampleRate_;
|
float sampleRate_;
|
||||||
float zL_;
|
FilterType type_;
|
||||||
float zR_;
|
|
||||||
|
float g_;
|
||||||
|
|
||||||
|
float lpL_, bpL_;
|
||||||
|
float lpR_, bpR_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // FILTER_HPP_INCLUDED
|
#endif
|
||||||
Loading…
Add table
Add a link
Reference in a new issue