#pragma once #include namespace serum { // =========================================================================== // Small RBJ-cookbook biquad (direct form 1) used by EQ and the Hyper crossover. // =========================================================================== class Biquad { public: void setSampleRate (double sr) noexcept { sampleRate = sr; } void clear() noexcept { x1 = x2 = y1 = y2 = 0.0; } float process (float in) noexcept { const double out = b0 * in + b1 * x1 + b2 * x2 - a1 * y1 - a2 * y2; x2 = x1; x1 = in; y2 = y1; y1 = out; return (float) out; } void setLowpass (double freq, double q) { const double w0 = 2.0 * juce::MathConstants::pi * freq / sampleRate; const double cw = std::cos (w0); const double sw = std::sin (w0); const double alpha = sw / (2.0 * q); const double a0 = 1.0 + alpha; b0 = ((1.0 - cw) / 2.0) / a0; b1 = (1.0 - cw) / a0; b2 = b0; a1 = (-2.0 * cw) / a0; a2 = (1.0 - alpha) / a0; } void setHighpass (double freq, double q) { const double w0 = 2.0 * juce::MathConstants::pi * freq / sampleRate; const double cw = std::cos (w0); const double sw = std::sin (w0); const double alpha = sw / (2.0 * q); const double a0 = 1.0 + alpha; b0 = ((1.0 + cw) / 2.0) / a0; b1 = -(1.0 + cw) / a0; b2 = b0; a1 = (-2.0 * cw) / a0; a2 = (1.0 - alpha) / a0; } void setLowShelf (double freq, double gainDb) { const double a = std::pow (10.0, gainDb / 40.0); const double w0 = 2.0 * juce::MathConstants::pi * freq / sampleRate; const double cw = std::cos (w0); const double sw = std::sin (w0); const double alpha = sw / 2.0 * std::sqrt (2.0); const double a0 = (a + 1.0) + (a - 1.0) * cw + 2.0 * std::sqrt (a) * alpha; b0 = (a * ((a + 1.0) - (a - 1.0) * cw + 2.0 * std::sqrt (a) * alpha)) / a0; b1 = (2.0 * a * ((a - 1.0) - (a + 1.0) * cw)) / a0; b2 = (a * ((a + 1.0) - (a - 1.0) * cw - 2.0 * std::sqrt (a) * alpha)) / a0; a1 = (-2.0 * ((a - 1.0) + (a + 1.0) * cw)) / a0; a2 = ((a + 1.0) + (a - 1.0) * cw - 2.0 * std::sqrt (a) * alpha) / a0; } void setHighShelf (double freq, double gainDb) { const double a = std::pow (10.0, gainDb / 40.0); const double w0 = 2.0 * juce::MathConstants::pi * freq / sampleRate; const double cw = std::cos (w0); const double sw = std::sin (w0); const double alpha = sw / 2.0 * std::sqrt (2.0); const double a0 = (a + 1.0) - (a - 1.0) * cw + 2.0 * std::sqrt (a) * alpha; b0 = (a * ((a + 1.0) + (a - 1.0) * cw + 2.0 * std::sqrt (a) * alpha)) / a0; b1 = (-2.0 * a * ((a - 1.0) + (a + 1.0) * cw)) / a0; b2 = (a * ((a + 1.0) + (a - 1.0) * cw - 2.0 * std::sqrt (a) * alpha)) / a0; a1 = (2.0 * ((a - 1.0) - (a + 1.0) * cw)) / a0; a2 = ((a + 1.0) - (a - 1.0) * cw - 2.0 * std::sqrt (a) * alpha) / a0; } void setPeak (double freq, double gainDb, double q) { const double a = std::pow (10.0, gainDb / 40.0); const double w0 = 2.0 * juce::MathConstants::pi * freq / sampleRate; const double cw = std::cos (w0); const double sw = std::sin (w0); const double alpha = sw / (2.0 * q); const double a0 = 1.0 + alpha / a; b0 = (1.0 + alpha * a) / a0; b1 = (-2.0 * cw) / a0; b2 = (1.0 - alpha * a) / a0; a1 = (-2.0 * cw) / a0; a2 = (1.0 - alpha / a) / a0; } double sampleRate = 44100.0; double b0 = 1.0, b1 = 0.0, b2 = 0.0, a1 = 0.0, a2 = 0.0; double x1 = 0.0, x2 = 0.0, y1 = 0.0, y2 = 0.0; }; } // namespace serum