diff --git a/core/Filter.cpp b/core/Filter.cpp index e4f5551..86efe2d 100644 --- a/core/Filter.cpp +++ b/core/Filter.cpp @@ -1,49 +1,90 @@ #include "Filter.hpp" #include -Filter::Filter(float initCutOff, float initSampleRate) - : cutOff_(initCutOff), feedback_(0.0f), alpha_(0.0f), - sampleRate_(initSampleRate), zL_(0.0f), zR_(0.0f) { - recompute(); -}; +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif -void Filter::process(const float *in, float *out, uint32_t frames) { - filter(in, out, frames, &zL_); -}; -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_); -}; +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(); +} -void Filter::filter(const float *in, float *out, uint32_t frames, float *z) { - for (uint32_t i = 0; i < frames; ++i) { - float feedbackInput = in[i] + (feedback_ * (*z)); - *z = *z + alpha_ * (feedbackInput - *z); - out[i] = *z; +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::recompute() { - float fc = std::fmax(cutOff_, 1.0f); - 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::process(const float *in, float *out, uint32_t frames) { + float lp = lpL_; + float bp = bpL_; -void Filter::setCutOff(float newCutOff) { - cutOff_ = newCutOff; - recompute(); + for (uint32_t i = 0; i < frames; ++i) { + out[i] = processFrame(in[i], lp, bp); + } + + lpL_ = lp; + bpL_ = bp; } + +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_; } - -void Filter::setFeedback(float newFeedback) { - feedback_ = std::fmin(std::fmax(newFeedback, 0.0f), 0.99f); +void Filter::setCutOff(float freq) { + cutOff_ = std::fmax(freq, 1.0f); + updateCoeffs(); } -float Filter::getFeedback() const { return feedback_; } -void Filter::setSampleRate(float newSampleRate) { - sampleRate_ = newSampleRate; - recompute(); +float Filter::getQ() const { return q_; } +void Filter::setQ(float q) { + q_ = std::fmax(q, 0.1f); + updateCoeffs(); +} + +void Filter::setType(FilterType type) { type_ = type; } + +float Filter::getSampleRate() const { return sampleRate_; } +void Filter::setSampleRate(float sr) { + sampleRate_ = sr; + updateCoeffs(); } -float Filter::getSampleRate() const { return sampleRate_; } \ No newline at end of file diff --git a/core/Filter.hpp b/core/Filter.hpp index 4b71f9c..63420e0 100644 --- a/core/Filter.hpp +++ b/core/Filter.hpp @@ -1,33 +1,45 @@ #ifndef FILTER_HPP_INCLUDED #define FILTER_HPP_INCLUDED -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif + #include +constexpr float kMaxNormalizedFrequency = 0.16667f; + class Filter { public: - Filter(float initCutOff = 1.0f, float initSampleRate = 48000.0f); - void process(const float *in, float *out, uint32_t frames); - void processStereo(const float *inLeft, const float *inRight, float *outLeft, - float *outRight, uint32_t frames); + Filter(float initCutOff = 1000.0f, float initQ = 0.707f, + float initSampleRate = 48000.0f); + + 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; - void setFeedback(float newFeedback); - float getFeedback() const; - void setSampleRate(float newSampleRate); + float getQ() 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: - 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 feedback_; - float alpha_; + float q_; float sampleRate_; - float zL_; - float zR_; + FilterType type_; + + float g_; + + float lpL_, bpL_; + float lpR_, bpR_; }; -#endif // FILTER_HPP_INCLUDED \ No newline at end of file +#endif \ No newline at end of file