1 #ifndef FILTERS_BIQUAD_H
2 #define FILTERS_BIQUAD_H
10 #include "math_defs.h"
13 /* Filters implementation is based on the "Cookbook formulae for audio
14 * EQ biquad filter coefficients" by Robert Bristow-Johnson
15 * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
17 /* Implementation note: For the shelf and peaking filters, the specified gain
18 * is for the centerpoint of the transition band. This better fits EFX filter
19 * behavior, which expects the shelf's reference frequency to reach the given
20 * gain. To set the gain for the shelf or peak itself, use the square root of
21 * the desired linear gain (or halve the dB gain).
24 enum class BiquadType
{
25 /** EFX-style low-pass filter, specifying a gain and reference frequency. */
27 /** EFX-style high-pass filter, specifying a gain and reference frequency. */
29 /** Peaking filter, specifying a gain and reference frequency. */
32 /** Low-pass cut-off filter, specifying a cut-off frequency. */
34 /** High-pass cut-off filter, specifying a cut-off frequency. */
36 /** Band-pass filter, specifying a center frequency. */
40 template<typename Real
>
42 /* Last two delayed components for direct form II. */
43 Real mZ1
{0.0f
}, mZ2
{0.0f
};
44 /* Transfer function coefficients "b" (numerator) */
45 Real mB0
{1.0f
}, mB1
{0.0f
}, mB2
{0.0f
};
46 /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */
47 Real mA1
{0.0f
}, mA2
{0.0f
};
49 void setParams(BiquadType type
, Real f0norm
, Real gain
, Real rcpQ
);
52 * Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using
53 * the reference gain and shelf slope parameter.
54 * \param gain 0 < gain
55 * \param slope 0 < slope <= 1
57 static Real
rcpQFromSlope(Real gain
, Real slope
)
58 { return std::sqrt((gain
+ 1.0f
/gain
)*(1.0f
/slope
- 1.0f
) + 2.0f
); }
61 * Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the
62 * normalized reference frequency and bandwidth.
63 * \param f0norm 0 < f0norm < 0.5.
64 * \param bandwidth 0 < bandwidth
66 static Real
rcpQFromBandwidth(Real f0norm
, Real bandwidth
)
68 const Real w0
{al::MathDefs
<Real
>::Tau() * f0norm
};
69 return 2.0f
*std::sinh(std::log(Real
{2.0f
})/2.0f
*bandwidth
*w0
/std::sin(w0
));
73 void clear() noexcept
{ mZ1
= mZ2
= 0.0f
; }
76 * Sets the filter state for the specified filter type and its parameters.
78 * \param type The type of filter to apply.
79 * \param f0norm The normalized reference frequency (ref / sample_rate).
80 * This is the center point for the Shelf, Peaking, and BandPass filter
81 * types, or the cutoff frequency for the LowPass and HighPass filter
83 * \param gain The gain for the reference frequency response. Only used by
84 * the Shelf and Peaking filter types.
85 * \param slope Slope steepness of the transition band.
87 void setParamsFromSlope(BiquadType type
, Real f0norm
, Real gain
, Real slope
)
89 gain
= std::max
<Real
>(gain
, 0.001f
); /* Limit -60dB */
90 setParams(type
, f0norm
, gain
, rcpQFromSlope(gain
, slope
));
94 * Sets the filter state for the specified filter type and its parameters.
96 * \param type The type of filter to apply.
97 * \param f0norm The normalized reference frequency (ref / sample_rate).
98 * This is the center point for the Shelf, Peaking, and BandPass filter
99 * types, or the cutoff frequency for the LowPass and HighPass filter
101 * \param gain The gain for the reference frequency response. Only used by
102 * the Shelf and Peaking filter types.
103 * \param bandwidth Normalized bandwidth of the transition band.
105 void setParamsFromBandwidth(BiquadType type
, Real f0norm
, Real gain
, Real bandwidth
)
106 { setParams(type
, f0norm
, gain
, rcpQFromBandwidth(f0norm
, bandwidth
)); }
108 void copyParamsFrom(const BiquadFilterR
&other
)
117 void process(const al::span
<const Real
> src
, Real
*dst
);
118 /** Processes this filter and the other at the same time. */
119 void dualProcess(BiquadFilterR
&other
, const al::span
<const Real
> src
, Real
*dst
);
121 /* Rather hacky. It's just here to support "manual" processing. */
122 std::pair
<Real
,Real
> getComponents() const noexcept
{ return {mZ1
, mZ2
}; }
123 void setComponents(Real z1
, Real z2
) noexcept
{ mZ1
= z1
; mZ2
= z2
; }
124 Real
processOne(const Real in
, Real
&z1
, Real
&z2
) const noexcept
126 const Real out
{in
*mB0
+ z1
};
127 z1
= in
*mB1
- out
*mA1
+ z2
;
128 z2
= in
*mB2
- out
*mA2
;
133 template<typename Real
>
135 BiquadFilterR
<Real
> &f0
, &f1
;
137 void process(const al::span
<const Real
> src
, Real
*dst
)
138 { f0
.dualProcess(f1
, src
, dst
); }
141 using BiquadFilter
= BiquadFilterR
<float>;
142 using DualBiquad
= DualBiquadR
<float>;
144 #endif /* FILTERS_BIQUAD_H */