Add missing linear resampler to the option setting list
[openal-soft.git] / alc / filters / biquad.cpp
blobfefdc8e10ee0bb985c87d5138ef7477a5cb618f1
2 #include "config.h"
4 #include "biquad.h"
6 #include <algorithm>
7 #include <cassert>
8 #include <cmath>
10 #include "opthelpers.h"
13 template<typename Real>
14 void BiquadFilterR<Real>::setParams(BiquadType type, Real f0norm, Real gain, Real rcpQ)
16 // Limit gain to -100dB
17 assert(gain > 0.00001f);
19 const Real w0{al::MathDefs<Real>::Tau() * f0norm};
20 const Real sin_w0{std::sin(w0)};
21 const Real cos_w0{std::cos(w0)};
22 const Real alpha{sin_w0/2.0f * rcpQ};
24 Real sqrtgain_alpha_2;
25 Real a[3]{ 1.0f, 0.0f, 0.0f };
26 Real b[3]{ 1.0f, 0.0f, 0.0f };
28 /* Calculate filter coefficients depending on filter type */
29 switch(type)
31 case BiquadType::HighShelf:
32 sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
33 b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
34 b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 );
35 b[2] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
36 a[0] = (gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
37 a[1] = 2.0f* ((gain-1.0f) - (gain+1.0f)*cos_w0 );
38 a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
39 break;
40 case BiquadType::LowShelf:
41 sqrtgain_alpha_2 = 2.0f * std::sqrt(gain) * alpha;
42 b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2);
43 b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 );
44 b[2] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2);
45 a[0] = (gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2;
46 a[1] = -2.0f* ((gain-1.0f) + (gain+1.0f)*cos_w0 );
47 a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2;
48 break;
49 case BiquadType::Peaking:
50 b[0] = 1.0f + alpha * gain;
51 b[1] = -2.0f * cos_w0;
52 b[2] = 1.0f - alpha * gain;
53 a[0] = 1.0f + alpha / gain;
54 a[1] = -2.0f * cos_w0;
55 a[2] = 1.0f - alpha / gain;
56 break;
58 case BiquadType::LowPass:
59 b[0] = (1.0f - cos_w0) / 2.0f;
60 b[1] = 1.0f - cos_w0;
61 b[2] = (1.0f - cos_w0) / 2.0f;
62 a[0] = 1.0f + alpha;
63 a[1] = -2.0f * cos_w0;
64 a[2] = 1.0f - alpha;
65 break;
66 case BiquadType::HighPass:
67 b[0] = (1.0f + cos_w0) / 2.0f;
68 b[1] = -(1.0f + cos_w0);
69 b[2] = (1.0f + cos_w0) / 2.0f;
70 a[0] = 1.0f + alpha;
71 a[1] = -2.0f * cos_w0;
72 a[2] = 1.0f - alpha;
73 break;
74 case BiquadType::BandPass:
75 b[0] = alpha;
76 b[1] = 0.0f;
77 b[2] = -alpha;
78 a[0] = 1.0f + alpha;
79 a[1] = -2.0f * cos_w0;
80 a[2] = 1.0f - alpha;
81 break;
84 mA1 = a[1] / a[0];
85 mA2 = a[2] / a[0];
86 mB0 = b[0] / a[0];
87 mB1 = b[1] / a[0];
88 mB2 = b[2] / a[0];
91 template<typename Real>
92 void BiquadFilterR<Real>::process(const al::span<const Real> src, Real *dst)
94 const Real b0{mB0};
95 const Real b1{mB1};
96 const Real b2{mB2};
97 const Real a1{mA1};
98 const Real a2{mA2};
99 Real z1{mZ1};
100 Real z2{mZ2};
102 /* Processing loop is Transposed Direct Form II. This requires less storage
103 * compared to Direct Form I (only two delay components, instead of a four-
104 * sample history; the last two inputs and outputs), and works better for
105 * floating-point which favors summing similarly-sized values while being
106 * less bothered by overflow.
108 * See: http://www.earlevel.com/main/2003/02/28/biquads/
110 auto proc_sample = [b0,b1,b2,a1,a2,&z1,&z2](Real input) noexcept -> Real
112 const Real output{input*b0 + z1};
113 z1 = input*b1 - output*a1 + z2;
114 z2 = input*b2 - output*a2;
115 return output;
117 std::transform(src.cbegin(), src.cend(), dst, proc_sample);
119 mZ1 = z1;
120 mZ2 = z2;
123 template<typename Real>
124 void BiquadFilterR<Real>::dualProcess(BiquadFilterR &other, const al::span<const Real> src,
125 Real *dst)
127 const Real b00{mB0};
128 const Real b01{mB1};
129 const Real b02{mB2};
130 const Real a01{mA1};
131 const Real a02{mA2};
132 const Real b10{other.mB0};
133 const Real b11{other.mB1};
134 const Real b12{other.mB2};
135 const Real a11{other.mA1};
136 const Real a12{other.mA2};
137 Real z01{mZ1};
138 Real z02{mZ2};
139 Real z11{other.mZ1};
140 Real z12{other.mZ2};
142 auto proc_sample = [b00,b01,b02,a01,a02,b10,b11,b12,a11,a12,&z01,&z02,&z11,&z12](Real input) noexcept -> Real
144 const Real tmpout{input*b00 + z01};
145 z01 = input*b01 - tmpout*a01 + z02;
146 z02 = input*b02 - tmpout*a02;
147 input = tmpout;
149 const Real output{input*b10 + z11};
150 z11 = input*b11 - output*a11 + z12;
151 z12 = input*b12 - output*a12;
152 return output;
154 std::transform(src.cbegin(), src.cend(), dst, proc_sample);
156 mZ1 = z01;
157 mZ2 = z02;
158 other.mZ1 = z11;
159 other.mZ2 = z12;
162 template class BiquadFilterR<float>;
163 template class BiquadFilterR<double>;