diff --git a/src/yaw-vowel/filter.cpp b/src/yaw-vowel/filter.cpp index ff27cad..32d8a98 100644 --- a/src/yaw-vowel/filter.cpp +++ b/src/yaw-vowel/filter.cpp @@ -2,23 +2,58 @@ void Resonator::clear() { - xp = xpp = yp = ypp = 0; + xp = xpp = yp = ypp = 0; } -void Resonator::process(float* output, const float* const input, uint32_t frames) +inline float Resonator::process(float x) { - for(uint32_t i = 0; i < frames; ++i){ - float x = static_cast(input[i] * scale); - float y = x - xpp - app * ypp + ap * yp; - output[i] = y; - xpp = xp; - xp = x; - ypp = yp; - yp = y; - } + // Apply biquad filter. + float y = scale * x - xpp - app * ypp + ap * yp; + // Update biquad memory. + xpp = xp; + xp = x; + ypp = yp; + yp = y; + return y; } void Resonator::set(double _app, double _ap, double _scale) { - app = _app; ap = _ap; scale = _scale; + app = _app; + ap = _ap; + scale = _scale; +} + +Filter::Filter(){}; + +void Filter::process(float **outputs, const float **inputs, uint32_t frames) +{ + for (uint chn = 0; chn < 2; ++chn) + { + for (auto &r : res[chn]) + { + for (uint32_t j = 0; j < frames; ++j) + { + outputs[chn][j] += r.process(inputs[chn][j]); + } + } + } +} + +// Compute filter coefficients from +// frequency as a proportion of the sample rate +// REMEMBER: THAT'S DOUBLE THE Nyquist RATE, dummy +// and resonance in [0, 1] +void Filter::set(double x, double y, double p) +{ + double r = p * 0.049 + 0.95; // Filter unstable at r = 1. + double app = r * r; + double xap = (1.0 + r * r) * cos(M_PI * x); + double yap = (1.0 + r * r) * cos(M_PI * y); + double scale = sqrt(0.5 - 0.5 * r * r); + for (auto &channelFilter : res) + { + channelFilter[0].set(app, xap, scale); + channelFilter[1].set(app, yap, scale); + } } \ No newline at end of file diff --git a/src/yaw-vowel/filter.h b/src/yaw-vowel/filter.h index a8d8278..23395cb 100644 --- a/src/yaw-vowel/filter.h +++ b/src/yaw-vowel/filter.h @@ -8,7 +8,7 @@ public: Resonator(): xp(0), xpp(0), yp(0), ypp(0), app(0), ap(0), scale(1){}; - void process(float *output, const float *const input, uint32_t frames); + inline float process(float x); void clear(); void set(double _app, double _ap, double _scale); @@ -25,46 +25,10 @@ private: class Filter { public: - Filter(){}; - - void process(float **outputs, const float **inputs, uint32_t frames) - { - for (uint chn = 0; chn < 2; ++chn) - { - for (uint32_t j = 0; j < frames; ++j) - { - outputs[chn][j] = inputs[chn][j]; - } - - for (auto& r : res[chn]) - { - r.process(outputs[chn], outputs[chn], frames); - } - } - - - } - - //Compute filter coefficients from - //frequency as a proportion of the sample rate - //REMEMBER: THAT'S DOUBLE THE Nyquist RATE, dummy - //and resonance in [0, 1] - void set(double x, double y, double p) - { - double r = p * 0.99; - double app = r * r; - double xap = (1.0 + r * r) * cos(M_PI * x); - double yap = (1.0 + r * r) * cos(M_PI * y); - double scale = sqrt(0.5 - 0.5 * r * r); - for (auto& channelFilter : res) - { - channelFilter[0].set(app, xap, scale); - channelFilter[1].set(app, xap, scale); - channelFilter[2].set(app, yap, scale); - channelFilter[3].set(app, yap, scale); - } - } + Filter(); + void process(float **outputs, const float **inputs, uint32_t frames); + void set(double x, double y, double p); private: - std::array, 2> res; + std::array, 2> res; }; \ No newline at end of file