+ Monosynth: use interpolated biquad to reduce filter zipper noise (part 2)
[calf.git] / src / calf / biquad.h
bloba0a4b8a3128a5a45f2d5ea776d650e43c2174a3f
1 /* Calf DSP Library
2 * Biquad filters
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
26 #include <complex>
27 #include "primitives.h"
29 namespace dsp {
31 /**
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>
45 class biquad_coeffs
47 public:
48 // filter coefficients
49 Coeff a0, a1, a2, b1, b2;
50 typedef std::complex<double> cfloat;
52 biquad_coeffs()
54 set_null();
57 inline void set_null()
59 a0 = 1.0;
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
65 * equations :)
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);
74 float sn=sin(omega);
75 float cs=cos(omega);
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);
80 a1 = a0 + a0;
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));
95 Coeff KK=K*K;
96 Coeff QK=q*(KK+1.f);
97 Coeff iQK=1.0f/(QK+K);
98 Coeff inv=q*iQK;
99 b2 = (Coeff)(iQK*(QK-K));
100 b1 = (Coeff)(2.f*(KK-1.f)*inv);
101 a2 = a0 = (Coeff)(inv*gain*KK);
102 a1 = a0 + a0;
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);
114 Coeff sn=sin(omega);
115 Coeff cs=cos(omega);
116 Coeff alpha=(float)(sn/(2*q));
118 float inv=(float)(1.0/(1.0+alpha));
120 a0 = (Coeff)(gain*inv*(1 + cs)/2);
121 a1 = -2.f * a0;
122 a2 = a0;
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));
138 a1 = -2.f * a0;
139 a2 = a0;
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);
153 float sn=sin(omega);
154 float cs=cos(omega);
155 float alpha=(float)(sn/(2*q));
157 float inv=(float)(1.0/(1.0+alpha));
159 a0 = (float)(gain*inv*alpha);
160 a1 = 0.f;
161 a2 = (float)(-gain*inv*alpha);
162 b1 = (float)(-2*cs*inv);
163 b2 = (float)((1 - alpha)*inv);
166 // rbj's bandreject
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);
170 float sn=sin(omega);
171 float cs=cos(omega);
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);
186 float q=pole_r;
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)
198 float T = 1.0 / 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;
209 return f / sr;
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;
216 a1 = 2*(aa0-aa2)*q;
217 a2 = (aa0-aa1+aa2)*q;
218 b1 = 2*(ab0-ab2)*q;
219 b2 = (ab0-ab1+ab2)*q;
222 /// RBJ peaking EQ
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);
247 float cw0 = cos(w0);
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;
258 ib0 = 1.0 / b0;
259 b1 *= ib0;
260 b2 *= ib0;
261 a0 *= ib0;
262 a1 *= ib0;
263 a2 *= ib0;
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);
275 float cw0 = cos(w0);
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;
286 ib0 = 1.0 / b0;
287 b1 *= ib0;
288 b2 *= ib0;
289 a0 *= ib0;
290 a1 *= ib0;
291 a2 *= ib0;
294 /// copy coefficients from another biquad
295 template<class U>
296 inline void copy_coeffs(const biquad_coeffs<U> &src)
298 a0 = src.a0;
299 a1 = src.a1;
300 a2 = src.a2;
301 b1 = src.b1;
302 b2 = src.b2;
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;
340 /// input[n-1]
341 T x1;
342 /// input[n-2]
343 T x2;
344 /// output[n-1]
345 T y1;
346 /// output[n-2]
347 T y2;
348 /// Constructor (initializes state to all zeros)
349 biquad_d1()
351 reset();
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;
357 x2 = x1;
358 y2 = y1;
359 x1 = in;
360 y1 = out;
361 return out;
364 /// direct I form with zero input
365 inline T process_zeroin()
367 T out = - y1 * b1 - y2 * b2;
368 y2 = y1;
369 y1 = out;
370 return out;
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;
377 x2 = x1;
378 y2 = y1;
379 x1 = in;
380 y1 = out;
381 return out;
383 /// Sanitize (set to 0 if potentially denormal) filter state
384 inline void sanitize()
386 dsp::sanitize(x1);
387 dsp::sanitize(y1);
388 dsp::sanitize(x2);
389 dsp::sanitize(y2);
391 /// Reset state variables
392 inline void reset()
394 dsp::zero(x1);
395 dsp::zero(y1);
396 dsp::zero(x2);
397 dsp::zero(y2);
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;
420 /// state[n-1]
421 float w1;
422 /// state[n-2]
423 float w2;
424 /// Constructor (initializes state to all zeros)
425 biquad_d2()
427 reset();
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;
434 w2 = w1;
435 w1 = tmp;
436 return out;
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;
445 w2 = w1;
446 w1 = tmp;
447 return out;
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()
459 dsp::sanitize(w1);
460 dsp::sanitize(w2);
463 /// Reset state variables
464 inline void reset()
466 dsp::zero(w1);
467 dsp::zero(w2);
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;
486 /// input[n-1]
487 T x1;
488 /// input[n-2]
489 T x2;
490 /// output[n-1]
491 T y1;
492 /// output[n-2]
493 T y2;
494 /// Constructor (initializes state to all zeros)
495 biquad_d1_lerp()
497 reset();
499 #define _DO_COEFF(coeff) coeff##delta = (coeff - coeff##cur) * (frac)
500 void big_step(Coeff frac)
502 _DO_COEFF(a0);
503 _DO_COEFF(a1);
504 _DO_COEFF(a2);
505 _DO_COEFF(b1);
506 _DO_COEFF(b2);
508 #undef _DO_COEFF
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;
513 x2 = x1;
514 y2 = y1;
515 x1 = in;
516 y1 = out;
517 a0cur += a0delta;
518 a1cur += a1delta;
519 a2cur += a2delta;
520 b1cur += b1delta;
521 b2cur += b2delta;
522 return out;
525 /// direct I form with zero input
526 inline T process_zeroin()
528 T out = - y1 * b1 - y2 * b2;
529 y2 = y1;
530 y1 = out;
531 b1cur += b1delta;
532 b2cur += b2delta;
533 return out;
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;
540 x2 = x1;
541 y2 = y1;
542 x1 = in;
543 y1 = out;
544 return out;
546 /// Sanitize (set to 0 if potentially denormal) filter state
547 inline void sanitize()
549 dsp::sanitize(x1);
550 dsp::sanitize(y1);
551 dsp::sanitize(x2);
552 dsp::sanitize(y2);
553 dsp::sanitize(a0cur);
554 dsp::sanitize(a1cur);
555 dsp::sanitize(a2cur);
556 dsp::sanitize(b1cur);
557 dsp::sanitize(b2cur);
559 /// Reset state variables
560 inline void reset()
562 dsp::zero(x1);
563 dsp::zero(y1);
564 dsp::zero(x2);
565 dsp::zero(y2);
566 dsp::zero(a0cur);
567 dsp::zero(a1cur);
568 dsp::zero(a2cur);
569 dsp::zero(b1cur);
570 dsp::zero(b2cur);
572 inline bool empty() {
573 return (y1 == 0.f && y2 == 0.f);
580 #endif