Avoid static constexpr for arrays iterated over at run-time
[openal-soft.git] / alc / filters / biquad.h
blob9af954aea57aa4729fc0a22b9114dd98275dcf91
1 #ifndef FILTERS_BIQUAD_H
2 #define FILTERS_BIQUAD_H
4 #include <cmath>
5 #include <cstddef>
6 #include <utility>
8 #include "math_defs.h"
11 /* Filters implementation is based on the "Cookbook formulae for audio
12 * EQ biquad filter coefficients" by Robert Bristow-Johnson
13 * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
15 /* Implementation note: For the shelf and peaking filters, the specified gain
16 * is for the centerpoint of the transition band. This better fits EFX filter
17 * behavior, which expects the shelf's reference frequency to reach the given
18 * gain. To set the gain for the shelf or peak itself, use the square root of
19 * the desired linear gain (or halve the dB gain).
22 enum class BiquadType {
23 /** EFX-style low-pass filter, specifying a gain and reference frequency. */
24 HighShelf,
25 /** EFX-style high-pass filter, specifying a gain and reference frequency. */
26 LowShelf,
27 /** Peaking filter, specifying a gain and reference frequency. */
28 Peaking,
30 /** Low-pass cut-off filter, specifying a cut-off frequency. */
31 LowPass,
32 /** High-pass cut-off filter, specifying a cut-off frequency. */
33 HighPass,
34 /** Band-pass filter, specifying a center frequency. */
35 BandPass,
38 template<typename Real>
39 class BiquadFilterR {
40 /* Last two delayed components for direct form II. */
41 Real mZ1{0.0f}, mZ2{0.0f};
42 /* Transfer function coefficients "b" (numerator) */
43 Real mB0{1.0f}, mB1{0.0f}, mB2{0.0f};
44 /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */
45 Real mA1{0.0f}, mA2{0.0f};
47 public:
48 void clear() noexcept { mZ1 = mZ2 = 0.0f; }
50 /**
51 * Sets the filter state for the specified filter type and its parameters.
53 * \param type The type of filter to apply.
54 * \param gain The gain for the reference frequency response. Only used by
55 * the Shelf and Peaking filter types.
56 * \param f0norm The reference frequency normal (ref_freq / sample_rate).
57 * This is the center point for the Shelf, Peaking, and
58 * BandPass filter types, or the cutoff frequency for the
59 * LowPass and HighPass filter types.
60 * \param rcpQ The reciprocal of the Q coefficient for the filter's
61 * transition band. Can be generated from rcpQFromSlope or
62 * rcpQFromBandwidth as needed.
64 void setParams(BiquadType type, Real gain, Real f0norm, Real rcpQ);
66 void copyParamsFrom(const BiquadFilterR &other)
68 mB0 = other.mB0;
69 mB1 = other.mB1;
70 mB2 = other.mB2;
71 mA1 = other.mA1;
72 mA2 = other.mA2;
76 void process(Real *dst, const Real *src, const size_t numsamples);
78 /* Rather hacky. It's just here to support "manual" processing. */
79 std::pair<Real,Real> getComponents() const noexcept { return {mZ1, mZ2}; }
80 void setComponents(Real z1, Real z2) noexcept { mZ1 = z1; mZ2 = z2; }
81 Real processOne(const Real in, Real &z1, Real &z2) const noexcept
83 Real out{in*mB0 + z1};
84 z1 = in*mB1 - out*mA1 + z2;
85 z2 = in*mB2 - out*mA2;
86 return out;
89 /**
90 * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using
91 * the reference gain and shelf slope parameter.
92 * \param gain 0 < gain
93 * \param slope 0 < slope <= 1
95 static Real rcpQFromSlope(Real gain, Real slope)
96 { return std::sqrt((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); }
98 /**
99 * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the
100 * normalized reference frequency and bandwidth.
101 * \param f0norm 0 < f0norm < 0.5.
102 * \param bandwidth 0 < bandwidth
104 static Real rcpQFromBandwidth(Real f0norm, Real bandwidth)
106 const Real w0{al::MathDefs<Real>::Tau() * f0norm};
107 return 2.0f*std::sinh(std::log(Real{2.0f})/2.0f*bandwidth*w0/std::sin(w0));
111 using BiquadFilter = BiquadFilterR<float>;
113 #endif /* FILTERS_BIQUAD_H */