3 * Copyright (C) 2001-2007 Krzysztof Foltman
5 * Most of code in this file is based on freely
6 * available other work of other people (filter equations).
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General
19 * Public License along with this program; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21 * Boston, MA 02111-1307, USA.
23 #ifndef __CALF_BIQUAD_H
24 #define __CALF_BIQUAD_H
27 #include "primitives.h"
32 * Coefficients for two-pole two-zero filter, for floating point values,
33 * plus a bunch of functions to set them to typical values.
35 * Coefficient calculation is based on famous Robert Bristow-Johnson's equations,
36 * except where it's not.
37 * The coefficient calculation is NOT mine, the only exception is the lossy
38 * optimization in Zoelzer and rbj HP filter code.
40 * See http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt for reference.
42 * don't use this for integers because it won't work
44 template<class Coeff
= float>
48 // filter coefficients
49 Coeff a0
, a1
, a2
, b1
, b2
;
50 typedef std::complex<double> cfloat
;
57 inline void set_null()
60 b1
= b2
= a1
= a2
= 0.f
;
63 /** Lowpass filter based on Robert Bristow-Johnson's equations
64 * Perhaps every synth code that doesn't use SVF uses these
66 * @param fc resonant frequency
67 * @param q resonance (gain at fc)
68 * @param sr sample rate
69 * @param gain amplification (gain at 0Hz)
71 inline void set_lp_rbj(float fc
, float q
, float sr
, float gain
= 1.0)
73 float omega
=(float)(2*M_PI
*fc
/sr
);
76 float alpha
=(float)(sn
/(2*q
));
77 float inv
=(float)(1.0/(1.0+alpha
));
79 a2
= a0
= (float)(gain
*inv
*(1 - cs
)*0.5f
);
81 b1
= (float)(-2*cs
*inv
);
82 b2
= (float)((1 - alpha
)*inv
);
85 // different lowpass filter, based on Zoelzer's equations, modified by
86 // me (kfoltman) to use polynomials to approximate tangent function
87 // not very accurate, but perhaps good enough for synth work :)
88 // odsr is "one divided by samplerate"
89 // from how it looks, it perhaps uses bilinear transform - but who knows :)
90 inline void set_lp_zoelzer(float fc
, float q
, float odsr
, float gain
=1.0)
92 Coeff omega
=(Coeff
)(M_PI
*fc
*odsr
);
93 Coeff omega2
=omega
*omega
;
94 Coeff K
=omega
*(1+omega2
*omega2
*Coeff(1.0/1.45));
97 Coeff iQK
=1.0f
/(QK
+K
);
99 b2
= (Coeff
)(iQK
*(QK
-K
));
100 b1
= (Coeff
)(2.f
*(KK
-1.f
)*inv
);
101 a2
= a0
= (Coeff
)(inv
*gain
*KK
);
105 /** Highpass filter based on Robert Bristow-Johnson's equations
106 * @param fc resonant frequency
107 * @param q resonance (gain at fc)
108 * @param sr sample rate
109 * @param gain amplification (gain at sr/2)
111 inline void set_hp_rbj(float fc
, float q
, float esr
, float gain
=1.0)
113 Coeff omega
=(float)(2*M_PI
*fc
/esr
);
116 Coeff alpha
=(float)(sn
/(2*q
));
118 float inv
=(float)(1.0/(1.0+alpha
));
120 a0
= (Coeff
)(gain
*inv
*(1 + cs
)/2);
123 b1
= (Coeff
)(-2*cs
*inv
);
124 b2
= (Coeff
)((1 - alpha
)*inv
);
127 // this replaces sin/cos with polynomial approximation
128 inline void set_hp_rbj_optimized(float fc
, float q
, float esr
, float gain
=1.0)
130 Coeff omega
=(float)(2*M_PI
*fc
/esr
);
131 Coeff sn
=omega
+omega
*omega
*omega
*(1.0/6.0)+omega
*omega
*omega
*omega
*omega
*(1.0/120);
132 Coeff cs
=1-omega
*omega
*(1.0/2.0)+omega
*omega
*omega
*omega
*(1.0/24);
133 Coeff alpha
=(float)(sn
/(2*q
));
135 float inv
=(float)(1.0/(1.0+alpha
));
137 a0
= (Coeff
)(gain
*inv
*(1 + cs
)*(1.0/2.0));
140 b1
= (Coeff
)(-2*cs
*inv
);
141 b2
= (Coeff
)((1 - alpha
)*inv
);
144 /** Bandpass filter based on Robert Bristow-Johnson's equations (normalized to 1.0 at center frequency)
145 * @param fc center frequency (gain at fc = 1.0)
146 * @param q =~ fc/bandwidth (not quite, but close) - 1/Q = 2*sinh(ln(2)/2*BW*w0/sin(w0))
147 * @param sr sample rate
148 * @param gain amplification (gain at sr/2)
150 inline void set_bp_rbj(double fc
, double q
, double esr
, double gain
=1.0)
152 float omega
=(float)(2*M_PI
*fc
/esr
);
155 float alpha
=(float)(sn
/(2*q
));
157 float inv
=(float)(1.0/(1.0+alpha
));
159 a0
= (float)(gain
*inv
*alpha
);
161 a2
= (float)(-gain
*inv
*alpha
);
162 b1
= (float)(-2*cs
*inv
);
163 b2
= (float)((1 - alpha
)*inv
);
167 inline void set_br_rbj(double fc
, double q
, double esr
, double gain
=1.0)
169 float omega
=(float)(2*M_PI
*fc
/esr
);
172 float alpha
=(float)(sn
/(2*q
));
174 float inv
=(float)(1.0/(1.0+alpha
));
176 a0
= (Coeff
)(gain
*inv
);
177 a1
= (Coeff
)(-gain
*inv
*2*cs
);
178 a2
= (Coeff
)(gain
*inv
);
179 b1
= (Coeff
)(-2*cs
*inv
);
180 b2
= (Coeff
)((1 - alpha
)*inv
);
182 // this is mine (and, I guess, it sucks/doesn't work)
183 void set_allpass(float freq
, float pole_r
, float sr
)
185 float a
=prewarp(freq
, sr
);
187 set_bilinear(a
*a
+q
*q
, -2.0f
*a
, 1, a
*a
+q
*q
, 2.0f
*a
, 1);
189 /// prewarping for bilinear transform, maps given digital frequency to analog counterpart for analog filter design
190 static inline float prewarp(float freq
, float sr
)
192 if (freq
>sr
*0.49) freq
=(float)(sr
*0.49);
193 return (float)(tan(M_PI
*freq
/sr
));
195 /// convert analog angular frequency value to digital
196 static inline float unwarp(float omega
, float sr
)
199 return (2 / T
) * atan(omega
* T
/ 2);
201 /// convert analog filter time constant to digital counterpart
202 static inline float unwarpf(float t
, float sr
)
204 // this is most likely broken and works by pure accident!
205 float omega
= 1.0 / t
;
206 omega
= unwarp(omega
, sr
);
207 // I really don't know why does it have to be M_PI and not 2 * M_PI!
208 float f
= M_PI
/ omega
;
211 /// set digital filter parameters based on given analog filter parameters
212 void set_bilinear(float aa0
, float aa1
, float aa2
, float ab0
, float ab1
, float ab2
)
214 float q
=(float)(1.0/(ab0
+ab1
+ab2
));
215 a0
= (aa0
+aa1
+aa2
)*q
;
217 a2
= (aa0
-aa1
+aa2
)*q
;
219 b2
= (ab0
-ab1
+ab2
)*q
;
223 /// @param freq peak frequency
224 /// @param q q (correlated to freq/bandwidth, @see set_bp_rbj)
225 /// @param peak peak gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
226 inline void set_peakeq_rbj(float freq
, float q
, float peak
, float sr
)
228 float A
= sqrt(peak
);
229 float w0
= freq
* 2 * M_PI
* (1.0 / sr
);
230 float alpha
= sin(w0
) / (2 * q
);
231 float ib0
= 1.0 / (1 + alpha
/A
);
232 a1
= b1
= -2*cos(w0
) * ib0
;
233 a0
= ib0
* (1 + alpha
*A
);
234 a2
= ib0
* (1 - alpha
*A
);
235 b2
= ib0
* (1 - alpha
/A
);
238 /// RBJ low shelf EQ - amplitication of 'peak' at 0 Hz and of 1.0 (0dB) at sr/2 Hz
239 /// @param freq corner frequency (gain at freq is sqrt(peak))
240 /// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated below fc) is
241 /// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
242 inline void set_lowshelf_rbj(float freq
, float q
, float peak
, float sr
)
244 float A
= sqrt(peak
);
245 float w0
= freq
* 2 * M_PI
* (1.0 / sr
);
246 float alpha
= sin(w0
) / (2 * q
);
248 float tmp
= 2 * sqrt(A
) * alpha
;
249 float b0
= 0.f
, ib0
= 0.f
;
251 a0
= A
*( (A
+1) - (A
-1)*cw0
+ tmp
);
252 a1
= 2*A
*( (A
-1) - (A
+1)*cw0
);
253 a2
= A
*( (A
+1) - (A
-1)*cw0
- tmp
);
254 b0
= (A
+1) + (A
-1)*cw0
+ tmp
;
255 b1
= -2*( (A
-1) + (A
+1)*cw0
);
256 b2
= (A
+1) + (A
-1)*cw0
- tmp
;
266 /// RBJ high shelf EQ - amplitication of 0dB at 0 Hz and of peak at sr/2 Hz
267 /// @param freq corner frequency (gain at freq is sqrt(peak))
268 /// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated above fc) is
269 /// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
270 inline void set_highshelf_rbj(float freq
, float q
, float peak
, float sr
)
272 float A
= sqrt(peak
);
273 float w0
= freq
* 2 * M_PI
* (1.0 / sr
);
274 float alpha
= sin(w0
) / (2 * q
);
276 float tmp
= 2 * sqrt(A
) * alpha
;
277 float b0
= 0.f
, ib0
= 0.f
;
279 a0
= A
*( (A
+1) + (A
-1)*cw0
+ tmp
);
280 a1
= -2*A
*( (A
-1) + (A
+1)*cw0
);
281 a2
= A
*( (A
+1) + (A
-1)*cw0
- tmp
);
282 b0
= (A
+1) - (A
-1)*cw0
+ tmp
;
283 b1
= 2*( (A
-1) - (A
+1)*cw0
);
284 b2
= (A
+1) - (A
-1)*cw0
- tmp
;
294 /// copy coefficients from another biquad
296 inline void copy_coeffs(const biquad_coeffs
<U
> &src
)
305 /// Return the filter's gain at frequency freq
306 /// @param freq Frequency to look up
307 /// @param sr Filter sample rate (used to convert frequency to angular frequency)
308 float freq_gain(float freq
, float sr
)
310 typedef std::complex<double> cfloat
;
311 freq
*= 2.0 * M_PI
/ sr
;
312 cfloat z
= 1.0 / exp(cfloat(0.0, freq
));
314 return std::abs(h_z(z
));
317 /// Return H(z) the filter's gain at frequency freq
318 /// @param z Z variable (e^jw)
319 cfloat
h_z(const cfloat
&z
)
322 return (cfloat(a0
) + double(a1
) * z
+ double(a2
) * z
*z
) / (cfloat(1.0) + double(b1
) * z
+ double(b2
) * z
*z
);
328 * Two-pole two-zero filter, for floating point values.
329 * Uses "traditional" Direct I form (separate FIR and IIR halves).
330 * don't use this for integers because it won't work
332 template<class Coeff
= float, class T
= float>
333 struct biquad_d1
: public biquad_coeffs
<Coeff
>
335 using biquad_coeffs
<Coeff
>::a0
;
336 using biquad_coeffs
<Coeff
>::a1
;
337 using biquad_coeffs
<Coeff
>::a2
;
338 using biquad_coeffs
<Coeff
>::b1
;
339 using biquad_coeffs
<Coeff
>::b2
;
348 /// Constructor (initializes state to all zeros)
353 /// direct I form with four state variables
354 inline T
process(T in
)
356 T out
= in
* a0
+ x1
* a1
+ x2
* a2
- y1
* b1
- y2
* b2
;
364 /// direct I form with zero input
365 inline T
process_zeroin()
367 T out
= - y1
* b1
- y2
* b2
;
373 /// simplified version for lowpass case with two zeros at -1
374 inline T
process_lp(T in
)
376 T out
= a0
*(in
+ x1
+ x1
+ x2
) - y1
* b1
- y2
* b2
;
383 /// Sanitize (set to 0 if potentially denormal) filter state
384 inline void sanitize()
391 /// Reset state variables
399 inline bool empty() {
400 return (y1
== 0.f
&& y2
== 0.f
);
406 * Two-pole two-zero filter, for floating point values.
407 * Uses slightly faster Direct II form (combined FIR and IIR halves).
408 * However, when used with wildly varying coefficients, it may
409 * make more zipper noise than Direct I form, so it's better to
410 * use it when filter coefficients are not changed mid-stream.
412 template<class Coeff
= float, class T
= float>
413 struct biquad_d2
: public biquad_coeffs
<Coeff
>
415 using biquad_coeffs
<Coeff
>::a0
;
416 using biquad_coeffs
<Coeff
>::a1
;
417 using biquad_coeffs
<Coeff
>::a2
;
418 using biquad_coeffs
<Coeff
>::b1
;
419 using biquad_coeffs
<Coeff
>::b2
;
424 /// Constructor (initializes state to all zeros)
429 /// direct II form with two state variables
430 inline T
process(T in
)
432 T tmp
= in
- w1
* b1
- w2
* b2
;
433 T out
= tmp
* a0
+ w1
* a1
+ w2
* a2
;
439 // direct II form with two state variables, lowpass version
440 // interesting fact: this is actually slower than the general version!
441 inline T
process_lp(T in
)
443 T tmp
= in
- w1
* b1
- w2
* b2
;
444 T out
= (tmp
+ w2
+ w1
* 2) * a0
;
450 /// Is the filter state completely silent? (i.e. set to 0 by sanitize function)
451 inline bool empty() {
452 return (w1
== 0.f
&& w2
== 0.f
);
456 /// Sanitize (set to 0 if potentially denormal) filter state
457 inline void sanitize()
463 /// Reset state variables
472 * Two-pole two-zero filter, for floating point values.
473 * Uses "traditional" Direct I form (separate FIR and IIR halves).
474 * don't use this for integers because it won't work
476 template<class Coeff
= float, class T
= float>
477 struct biquad_d1_lerp
: public biquad_coeffs
<Coeff
>
479 using biquad_coeffs
<Coeff
>::a0
;
480 using biquad_coeffs
<Coeff
>::a1
;
481 using biquad_coeffs
<Coeff
>::a2
;
482 using biquad_coeffs
<Coeff
>::b1
;
483 using biquad_coeffs
<Coeff
>::b2
;
484 Coeff a0cur
, a1cur
, a2cur
, b1cur
, b2cur
;
485 Coeff a0delta
, a1delta
, a2delta
, b1delta
, b2delta
;
494 /// Constructor (initializes state to all zeros)
499 #define _DO_COEFF(coeff) coeff##delta = (coeff - coeff##cur) * (frac)
500 void big_step(Coeff frac
)
509 /// direct I form with four state variables
510 inline T
process(T in
)
512 T out
= in
* a0cur
+ x1
* a1cur
+ x2
* a2cur
- y1
* b1cur
- y2
* b2cur
;
525 /// direct I form with zero input
526 inline T
process_zeroin()
528 T out
= - y1
* b1
- y2
* b2
;
536 /// simplified version for lowpass case with two zeros at -1
537 inline T
process_lp(T in
)
539 T out
= a0
*(in
+ x1
+ x1
+ x2
) - y1
* b1
- y2
* b2
;
546 /// Sanitize (set to 0 if potentially denormal) filter state
547 inline void sanitize()
553 dsp::sanitize(a0cur
);
554 dsp::sanitize(a1cur
);
555 dsp::sanitize(a2cur
);
556 dsp::sanitize(b1cur
);
557 dsp::sanitize(b2cur
);
559 /// Reset state variables
572 inline bool empty() {
573 return (y1
== 0.f
&& y2
== 0.f
);