Files

108 lines
3.8 KiB
C++

#pragma once
#include <JuceHeader.h>
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<double>::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<double>::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<double>::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<double>::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<double>::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