]> git.tdb.fi Git - ext/openal.git/blob - core/filters/biquad.h
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / filters / biquad.h
1 #ifndef CORE_FILTERS_BIQUAD_H
2 #define CORE_FILTERS_BIQUAD_H
3
4 #include <algorithm>
5 #include <cmath>
6 #include <cstddef>
7 #include <utility>
8
9 #include "alnumbers.h"
10 #include "alspan.h"
11
12
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
16  */
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).
22  */
23
24 enum class BiquadType {
25     /** EFX-style low-pass filter, specifying a gain and reference frequency. */
26     HighShelf,
27     /** EFX-style high-pass filter, specifying a gain and reference frequency. */
28     LowShelf,
29     /** Peaking filter, specifying a gain and reference frequency. */
30     Peaking,
31
32     /** Low-pass cut-off filter, specifying a cut-off frequency. */
33     LowPass,
34     /** High-pass cut-off filter, specifying a cut-off frequency. */
35     HighPass,
36     /** Band-pass filter, specifying a center frequency. */
37     BandPass,
38 };
39
40 template<typename Real>
41 class BiquadFilterR {
42     /* Last two delayed components for direct form II. */
43     Real mZ1{0}, mZ2{0};
44     /* Transfer function coefficients "b" (numerator) */
45     Real mB0{1}, mB1{0}, mB2{0};
46     /* Transfer function coefficients "a" (denominator; a0 is pre-applied). */
47     Real mA1{0}, mA2{0};
48
49     void setParams(BiquadType type, Real f0norm, Real gain, Real rcpQ);
50
51     /**
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
56      */
57     static Real rcpQFromSlope(Real gain, Real slope)
58     { return std::sqrt((gain + Real{1}/gain)*(Real{1}/slope - Real{1}) + Real{2}); }
59
60     /**
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
65      */
66     static Real rcpQFromBandwidth(Real f0norm, Real bandwidth)
67     {
68         const Real w0{al::numbers::pi_v<Real>*Real{2} * f0norm};
69         return 2.0f*std::sinh(std::log(Real{2})/Real{2}*bandwidth*w0/std::sin(w0));
70     }
71
72 public:
73     void clear() noexcept { mZ1 = mZ2 = Real{0}; }
74
75     /**
76      * Sets the filter state for the specified filter type and its parameters.
77      *
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
82      * types.
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.
86      */
87     void setParamsFromSlope(BiquadType type, Real f0norm, Real gain, Real slope)
88     {
89         gain = std::max<Real>(gain, 0.001f); /* Limit -60dB */
90         setParams(type, f0norm, gain, rcpQFromSlope(gain, slope));
91     }
92
93     /**
94      * Sets the filter state for the specified filter type and its parameters.
95      *
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
100      * types.
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.
104      */
105     void setParamsFromBandwidth(BiquadType type, Real f0norm, Real gain, Real bandwidth)
106     { setParams(type, f0norm, gain, rcpQFromBandwidth(f0norm, bandwidth)); }
107
108     void copyParamsFrom(const BiquadFilterR &other)
109     {
110         mB0 = other.mB0;
111         mB1 = other.mB1;
112         mB2 = other.mB2;
113         mA1 = other.mA1;
114         mA2 = other.mA2;
115     }
116
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);
120
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
125     {
126         const Real out{in*mB0 + z1};
127         z1 = in*mB1 - out*mA1 + z2;
128         z2 = in*mB2 - out*mA2;
129         return out;
130     }
131 };
132
133 template<typename Real>
134 struct DualBiquadR {
135     BiquadFilterR<Real> &f0, &f1;
136
137     void process(const al::span<const Real> src, Real *dst)
138     { f0.dualProcess(f1, src, dst); }
139 };
140
141 using BiquadFilter = BiquadFilterR<float>;
142 using DualBiquad = DualBiquadR<float>;
143
144 #endif /* CORE_FILTERS_BIQUAD_H */