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., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 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
47 // filter coefficients
48 double a0
, a1
, a2
, b1
, b2
;
49 typedef std::complex<double> cfloat
;
56 inline void set_null()
59 b1
= b2
= a1
= a2
= 0.f
;
62 /** Lowpass filter based on Robert Bristow-Johnson's equations
63 * Perhaps every synth code that doesn't use SVF uses these
65 * @param fc resonant frequency
66 * @param q resonance (gain at fc)
67 * @param sr sample rate
68 * @param gain amplification (gain at 0Hz)
70 inline void set_lp_rbj(float fc
, float q
, float sr
, float gain
= 1.0)
72 double omega
=(2.0*M_PI
*fc
/sr
);
75 double alpha
=(sn
/(2*q
));
76 double inv
=(1.0/(1.0+alpha
));
78 a2
= a0
= (gain
*inv
*(1.0 - cs
)*0.5);
81 b2
= ((1.0 - alpha
)*inv
);
84 // different lowpass filter, based on Zoelzer's equations, modified by
85 // me (kfoltman) to use polynomials to approximate tangent function
86 // not very accurate, but perhaps good enough for synth work :)
87 // odsr is "one divided by samplerate"
88 // from how it looks, it perhaps uses bilinear transform - but who knows :)
89 inline void set_lp_zoelzer(float fc
, float q
, float odsr
, float gain
=1.0)
91 double omega
=(M_PI
*fc
*odsr
);
92 double omega2
=omega
*omega
;
93 double K
=omega
*(1+omega2
*omega2
*(1.0/1.45));
96 double iQK
=1.0f
/(QK
+K
);
99 b1
= (2.*(KK
-1.f
)*inv
);
100 a2
= a0
= (inv
*gain
*KK
);
104 /** Highpass filter based on Robert Bristow-Johnson's equations
105 * @param fc resonant frequency
106 * @param q resonance (gain at fc)
107 * @param sr sample rate
108 * @param gain amplification (gain at sr/2)
110 inline void set_hp_rbj(float fc
, float q
, float esr
, float gain
=1.0)
112 double omega
=(double)(2*M_PI
*fc
/esr
);
113 double sn
=sin(omega
);
114 double cs
=cos(omega
);
115 double alpha
=(double)(sn
/(2*q
));
117 double inv
=(double)(1.0/(1.0+alpha
));
119 a0
= (gain
*inv
*(1 + cs
)/2);
123 b2
= ((1 - alpha
)*inv
);
126 // this replaces sin/cos with polynomial approximation
127 inline void set_hp_rbj_optimized(float fc
, float q
, float esr
, float gain
=1.0)
129 double omega
=(double)(2*M_PI
*fc
/esr
);
130 double sn
=omega
+omega
*omega
*omega
*(1.0/6.0)+omega
*omega
*omega
*omega
*omega
*(1.0/120);
131 double cs
=1-omega
*omega
*(1.0/2.0)+omega
*omega
*omega
*omega
*(1.0/24);
132 double alpha
=(double)(sn
/(2*q
));
134 double inv
=(double)(1.0/(1.0+alpha
));
136 a0
= (gain
*inv
*(1 + cs
)*(1.0/2.0));
140 b2
= ((1. - alpha
)*inv
);
143 /** Bandpass filter based on Robert Bristow-Johnson's equations (normalized to 1.0 at center frequency)
144 * @param fc center frequency (gain at fc = 1.0)
145 * @param q =~ fc/bandwidth (not quite, but close) - 1/Q = 2*sinh(ln(2)/2*BW*w0/sin(w0))
146 * @param sr sample rate
147 * @param gain amplification (gain at sr/2)
149 inline void set_bp_rbj(double fc
, double q
, double esr
, double gain
=1.0)
151 double omega
=(double)(2*M_PI
*fc
/esr
);
152 double sn
=sin(omega
);
153 double cs
=cos(omega
);
154 double alpha
=(double)(sn
/(2*q
));
156 double inv
=(double)(1.0/(1.0+alpha
));
158 a0
= (double)(gain
*inv
*alpha
);
160 a2
= (double)(-gain
*inv
*alpha
);
161 b1
= (double)(-2*cs
*inv
);
162 b2
= (double)((1 - alpha
)*inv
);
166 inline void set_br_rbj(double fc
, double q
, double esr
, double gain
=1.0)
168 double omega
=(double)(2*M_PI
*fc
/esr
);
169 double sn
=sin(omega
);
170 double cs
=cos(omega
);
171 double alpha
=(double)(sn
/(2*q
));
173 double inv
=(double)(1.0/(1.0+alpha
));
176 a1
= (-gain
*inv
*2.*cs
);
179 b2
= ((1. - alpha
)*inv
);
181 // this is mine (and, I guess, it sucks/doesn't work)
182 void set_allpass(float freq
, float pole_r
, float sr
)
184 double a
=prewarp(freq
, sr
);
186 set_bilinear(a
*a
+q
*q
, -2.0f
*a
, 1, a
*a
+q
*q
, 2.0f
*a
, 1);
188 /// prewarping for bilinear transform, maps given digital frequency to analog counterpart for analog filter design
189 static inline double prewarp(float freq
, float sr
)
191 if (freq
>sr
*0.49) freq
=(float)(sr
*0.49);
192 return (double)(tan(M_PI
*freq
/sr
));
194 /// convert analog angular frequency value to digital
195 static inline double unwarp(float omega
, float sr
)
198 return (2 / T
) * atan(omega
* T
/ 2);
200 /// convert analog filter time constant to digital counterpart
201 static inline double unwarpf(float t
, float sr
)
203 // this is most likely broken and works by pure accident!
204 double omega
= 1.0 / t
;
205 omega
= unwarp(omega
, sr
);
206 // I really don't know why does it have to be M_PI and not 2 * M_PI!
207 double f
= M_PI
/ omega
;
210 /// set digital filter parameters based on given analog filter parameters
211 void set_bilinear(double aa0
, double aa1
, double aa2
, double ab0
, double ab1
, double ab2
)
213 double q
=(double)(1.0/(ab0
+ab1
+ab2
));
214 a0
= (aa0
+aa1
+aa2
)*q
;
216 a2
= (aa0
-aa1
+aa2
)*q
;
218 b2
= (ab0
-ab1
+ab2
)*q
;
221 /// set digital filter parameters directly
222 void set_bilinear_direct(double aa0
, double aa1
, double aa2
, double ab1
, double ab2
)
233 /// @param freq peak frequency
234 /// @param q q (correlated to freq/bandwidth, @see set_bp_rbj)
235 /// @param peak peak gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
236 inline void set_peakeq_rbj(double freq
, double q
, double peak
, double sr
)
238 double A
= sqrt(peak
);
239 double w0
= freq
* 2 * M_PI
* (1.0 / sr
);
240 double alpha
= sin(w0
) / (2 * q
);
241 double ib0
= 1.0 / (1 + alpha
/A
);
242 a1
= b1
= -2*cos(w0
) * ib0
;
243 a0
= ib0
* (1 + alpha
*A
);
244 a2
= ib0
* (1 - alpha
*A
);
245 b2
= ib0
* (1 - alpha
/A
);
248 /// RBJ low shelf EQ - amplitication of 'peak' at 0 Hz and of 1.0 (0dB) at sr/2 Hz
249 /// @param freq corner frequency (gain at freq is sqrt(peak))
250 /// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated below fc) is
251 /// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
252 inline void set_lowshelf_rbj(float freq
, float q
, float peak
, float sr
)
254 double A
= sqrt(peak
);
255 double w0
= freq
* 2 * M_PI
* (1.0 / sr
);
256 double alpha
= sin(w0
) / (2 * q
);
257 double cw0
= cos(w0
);
258 double tmp
= 2 * sqrt(A
) * alpha
;
259 double b0
= 0.f
, ib0
= 0.f
;
261 a0
= A
*( (A
+1) - (A
-1)*cw0
+ tmp
);
262 a1
= 2*A
*( (A
-1) - (A
+1)*cw0
);
263 a2
= A
*( (A
+1) - (A
-1)*cw0
- tmp
);
264 b0
= (A
+1) + (A
-1)*cw0
+ tmp
;
265 b1
= -2*( (A
-1) + (A
+1)*cw0
);
266 b2
= (A
+1) + (A
-1)*cw0
- tmp
;
276 /// RBJ high shelf EQ - amplitication of 0dB at 0 Hz and of peak at sr/2 Hz
277 /// @param freq corner frequency (gain at freq is sqrt(peak))
278 /// @param q q (relates bandwidth and peak frequency), the higher q, the louder the resonant peak (situated above fc) is
279 /// @param peak shelf gain (1.0 means no peak, >1.0 means a peak, less than 1.0 is a dip)
280 inline void set_highshelf_rbj(float freq
, float q
, float peak
, float sr
)
282 double A
= sqrt(peak
);
283 double w0
= freq
* 2 * M_PI
* (1.0 / sr
);
284 double alpha
= sin(w0
) / (2 * q
);
285 double cw0
= cos(w0
);
286 double tmp
= 2 * sqrt(A
) * alpha
;
287 double b0
= 0.f
, ib0
= 0.f
;
289 a0
= A
*( (A
+1) + (A
-1)*cw0
+ tmp
);
290 a1
= -2*A
*( (A
-1) + (A
+1)*cw0
);
291 a2
= A
*( (A
+1) + (A
-1)*cw0
- tmp
);
292 b0
= (A
+1) - (A
-1)*cw0
+ tmp
;
293 b1
= 2*( (A
-1) - (A
+1)*cw0
);
294 b2
= (A
+1) - (A
-1)*cw0
- tmp
;
304 /// copy coefficients from another biquad
305 inline void copy_coeffs(const biquad_coeffs
&src
)
314 /// Return the filter's gain at frequency freq
315 /// @param freq Frequency to look up
316 /// @param sr Filter sample rate (used to convert frequency to angular frequency)
317 float freq_gain(float freq
, float sr
) const
319 typedef std::complex<double> cfloat
;
320 freq
*= 2.0 * M_PI
/ sr
;
321 cfloat z
= 1.0 / exp(cfloat(0.0, freq
));
323 return std::abs(h_z(z
));
326 /// Return H(z) the filter's gain at frequency freq
327 /// @param z Z variable (e^jw)
328 cfloat
h_z(const cfloat
&z
) const
331 return (cfloat(a0
) + double(a1
) * z
+ double(a2
) * z
*z
) / (cfloat(1.0) + double(b1
) * z
+ double(b2
) * z
*z
);
337 * Two-pole two-zero filter, for floating point values.
338 * Uses "traditional" Direct I form (separate FIR and IIR halves).
339 * don't use this for integers because it won't work
341 struct biquad_d1
: public biquad_coeffs
351 /// Constructor (initializes state to all zeros)
356 /// direct I form with four state variables
357 inline double process(double in
)
359 double out
= in
* a0
+ x1
* a1
+ x2
* a2
- y1
* b1
- y2
* b2
;
367 /// direct I form with zero input
368 inline double process_zeroin()
370 double out
= - y1
* b1
- y2
* b2
;
376 /// simplified version for lowpass case with two zeros at -1
377 inline double process_lp(double in
)
379 double out
= a0
*(in
+ x1
+ x1
+ x2
) - y1
* b1
- y2
* b2
;
386 /// simplified version for highpass case with two zeros at 1
387 inline double process_hp(double in
)
389 double out
= a0
*(in
- x1
- x1
+ x2
) - y1
* b1
- y2
* b2
;
396 /// Sanitize (set to 0 if potentially denormal) filter state
397 inline void sanitize()
404 /// Reset state variables
412 inline bool empty() const {
413 return (y1
== 0. && y2
== 0.);
419 * Two-pole two-zero filter, for floating point values.
420 * Uses slightly faster Direct II form (combined FIR and IIR halves).
421 * However, when used with wildly varying coefficients, it may
422 * make more zipper noise than Direct I form, so it's better to
423 * use it when filter coefficients are not changed mid-stream.
425 struct biquad_d2
: public biquad_coeffs
431 /// Constructor (initializes state to all zeros)
436 /// direct II form with two state variables
437 inline double process(double in
)
440 dsp::sanitize_denormal(n
);
445 double tmp
= n
- w1
* b1
- w2
* b2
;
446 double out
= tmp
* a0
+ w1
* a1
+ w2
* a2
;
452 // direct II form with two state variables, lowpass version
453 // interesting fact: this is actually slower than the general version!
454 inline double process_lp(double in
)
456 double tmp
= in
- w1
* b1
- w2
* b2
;
457 double out
= (tmp
+ w2
+ w1
* 2) * a0
;
463 /// Is the filter state completely silent? (i.e. set to 0 by sanitize function)
464 inline bool empty() const {
465 return (w1
== 0.f
&& w2
== 0.f
);
469 /// Sanitize (set to 0 if potentially denormal) filter state
470 inline void sanitize()
476 /// Reset state variables
485 * Two-pole two-zero filter, for floating point values.
486 * Uses "traditional" Direct I form (separate FIR and IIR halves).
487 * don't use this for integers because it won't work
489 struct biquad_d1_lerp
: public biquad_coeffs
491 double a0cur
, a1cur
, a2cur
, b1cur
, b2cur
;
492 double a0delta
, a1delta
, a2delta
, b1delta
, b2delta
;
501 /// Constructor (initializes state to all zeros)
506 #define _DO_COEFF(coeff) coeff##delta = (coeff - coeff##cur) * (frac)
507 void big_step(double frac
)
516 /// direct I form with four state variables
517 inline double process(double in
)
519 double out
= in
* a0cur
+ x1
* a1cur
+ x2
* a2cur
- y1
* b1cur
- y2
* b2cur
;
532 /// direct I form with zero input
533 inline double process_zeroin()
535 double out
= - y1
* b1
- y2
* b2
;
543 /// simplified version for lowpass case with two zeros at -1
544 inline double process_lp(double in
)
546 double out
= a0
*(in
+ x1
+ x1
+ x2
) - y1
* b1
- y2
* b2
;
553 /// Sanitize (set to 0 if potentially denormal) filter state
554 inline void sanitize()
560 dsp::sanitize(a0cur
);
561 dsp::sanitize(a1cur
);
562 dsp::sanitize(a2cur
);
563 dsp::sanitize(b1cur
);
564 dsp::sanitize(b2cur
);
566 /// Reset state variables
579 inline bool empty() {
580 return (y1
== 0. && y2
== 0.);
585 /// Compose two filters in series
586 template<class F1
, class F2
>
587 class filter_compose
{
589 typedef std::complex<float> cfloat
;
593 float process(float value
) {
594 return f2
.process(f1
.process(value
));
597 inline cfloat
h_z(const cfloat
&z
) const {
598 return f1
.h_z(z
) * f2
.h_z(z
);
601 /// Return the filter's gain at frequency freq
602 /// @param freq Frequency to look up
603 /// @param sr Filter sample rate (used to convert frequency to angular frequency)
604 float freq_gain(float freq
, float sr
) const
606 typedef std::complex<double> cfloat
;
607 freq
*= 2.0 * M_PI
/ sr
;
608 cfloat z
= 1.0 / exp(cfloat(0.0, freq
));
610 return std::abs(h_z(z
));
619 /// Compose two filters in parallel
620 template<class F1
, class F2
>
623 typedef std::complex<double> cfloat
;
627 double process(double value
) {
628 return f2
.process(value
) + f1
.process(value
);
631 inline cfloat
h_z(const cfloat
&z
) const {
632 return f1
.h_z(z
) + f2
.h_z(z
);
635 /// Return the filter's gain at frequency freq
636 /// @param freq Frequency to look up
637 /// @param sr Filter sample rate (used to convert frequency to angular frequency)
638 float freq_gain(float freq
, float sr
) const
640 typedef std::complex<double> cfloat
;
641 freq
*= 2.0 * M_PI
/ sr
;
642 cfloat z
= 1.0 / exp(cfloat(0.0, freq
));
644 return std::abs(h_z(z
));