LMMS
Loading...
Searching...
No Matches
biquad.h
Go to the documentation of this file.
1/* Calf DSP Library
2 * Biquad filters
3 * Copyright (C) 2001-2007 Krzysztof Foltman
4 *
5 * Most of code in this file is based on freely
6 * available other work of other people (filter equations).
7 *
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.
12 *
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.
17 *
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
22 */
23#ifndef __CALF_BIQUAD_H
24#define __CALF_BIQUAD_H
25
26#include <complex>
27#include "primitives.h"
28
29#ifndef M_PI
30#define M_PI 3.14159265358979323846264338327
31#endif
32
33namespace dsp {
34
49{
50public:
51 // filter coefficients
52 double a0, a1, a2, b1, b2;
54
56 {
57 set_null();
58 }
59
60 inline void set_null()
61 {
62 a0 = 1.0;
63 b1 = b2 = a1 = a2 = 0.f;
64 }
65
74 inline void set_lp_rbj(float fc, float q, float sr, float gain = 1.0)
75 {
76 double omega=(2.0*M_PI*fc/sr);
77 double sn=sin(omega);
78 double cs=cos(omega);
79 double alpha=(sn/(2*q));
80 double inv=(1.0/(1.0+alpha));
81
82 a2 = a0 = (gain*inv*(1.0 - cs)*0.5);
83 a1 = a0 + a0;
84 b1 = (-2.0*cs*inv);
85 b2 = ((1.0 - alpha)*inv);
86 }
87
88 // different lowpass filter, based on Zoelzer's equations, modified by
89 // me (kfoltman) to use polynomials to approximate tangent function
90 // not very accurate, but perhaps good enough for synth work :)
91 // odsr is "one divided by samplerate"
92 // from how it looks, it perhaps uses bilinear transform - but who knows :)
93 inline void set_lp_zoelzer(float fc, float q, float odsr, float gain=1.0)
94 {
95 double omega=(M_PI*fc*odsr);
96 double omega2=omega*omega;
97 double K=omega*(1+omega2*omega2*(1.0/1.45));
98 double KK=K*K;
99 double QK=q*(KK+1.f);
100 double iQK=1.0f/(QK+K);
101 double inv=q*iQK;
102 b2 = (iQK*(QK-K));
103 b1 = (2.*(KK-1.f)*inv);
104 a2 = a0 = (inv*gain*KK);
105 a1 = a0 + a0;
106 }
107
114 inline void set_hp_rbj(float fc, float q, float esr, float gain=1.0)
115 {
116 double omega=(double)(2*M_PI*fc/esr);
117 double sn=sin(omega);
118 double cs=cos(omega);
119 double alpha=(double)(sn/(2*q));
120
121 double inv=(double)(1.0/(1.0+alpha));
122
123 a0 = (gain*inv*(1 + cs)/2);
124 a1 = -2.f * a0;
125 a2 = a0;
126 b1 = (-2*cs*inv);
127 b2 = ((1 - alpha)*inv);
128 }
129
130 // this replaces sin/cos with polynomial approximation
131 inline void set_hp_rbj_optimized(float fc, float q, float esr, float gain=1.0)
132 {
133 double omega=(double)(2*M_PI*fc/esr);
134 double sn=omega+omega*omega*omega*(1.0/6.0)+omega*omega*omega*omega*omega*(1.0/120);
135 double cs=1-omega*omega*(1.0/2.0)+omega*omega*omega*omega*(1.0/24);
136 double alpha=(double)(sn/(2*q));
137
138 double inv=(double)(1.0/(1.0+alpha));
139
140 a0 = (gain*inv*(1 + cs)*(1.0/2.0));
141 a1 = -2.f * a0;
142 a2 = a0;
143 b1 = (-2.*cs*inv);
144 b2 = ((1. - alpha)*inv);
145 }
146
153 inline void set_bp_rbj(double fc, double q, double esr, double gain=1.0)
154 {
155 double omega=(double)(2*M_PI*fc/esr);
156 double sn=sin(omega);
157 double cs=cos(omega);
158 double alpha=(double)(sn/(2*q));
159
160 double inv=(double)(1.0/(1.0+alpha));
161
162 a0 = (double)(gain*inv*alpha);
163 a1 = 0.f;
164 a2 = (double)(-gain*inv*alpha);
165 b1 = (double)(-2*cs*inv);
166 b2 = (double)((1 - alpha)*inv);
167 }
168
169 // rbj's bandreject
170 inline void set_br_rbj(double fc, double q, double esr, double gain=1.0)
171 {
172 double omega=(double)(2*M_PI*fc/esr);
173 double sn=sin(omega);
174 double cs=cos(omega);
175 double alpha=(double)(sn/(2*q));
176
177 double inv=(double)(1.0/(1.0+alpha));
178
179 a0 = (gain*inv);
180 a1 = (-gain*inv*2.*cs);
181 a2 = (gain*inv);
182 b1 = (-2.*cs*inv);
183 b2 = ((1. - alpha)*inv);
184 }
185 // this is mine (and, I guess, it sucks/doesn't work)
186 void set_allpass(float freq, float pole_r, float sr)
187 {
188 double a=prewarp(freq, sr);
189 double q=pole_r;
190 set_bilinear(a*a+q*q, -2.0f*a, 1, a*a+q*q, 2.0f*a, 1);
191 }
192
193 static inline double prewarp(float freq, float sr)
194 {
195 if (freq>sr*0.49) freq=(float)(sr*0.49);
196 return (double)(tan(M_PI*freq/sr));
197 }
198
199 static inline double unwarp(float omega, float sr)
200 {
201 double T = 1.0 / sr;
202 return (2 / T) * atan(omega * T / 2);
203 }
204
205 static inline double unwarpf(float t, float sr)
206 {
207 // this is most likely broken and works by pure accident!
208 double omega = 1.0 / t;
209 omega = unwarp(omega, sr);
210 // I really don't know why does it have to be M_PI and not 2 * M_PI!
211 double f = M_PI / omega;
212 return f / sr;
213 }
214
215 void set_bilinear(double aa0, double aa1, double aa2, double ab0, double ab1, double ab2)
216 {
217 double q=(double)(1.0/(ab0+ab1+ab2));
218 a0 = (aa0+aa1+aa2)*q;
219 a1 = 2*(aa0-aa2)*q;
220 a2 = (aa0-aa1+aa2)*q;
221 b1 = 2*(ab0-ab2)*q;
222 b2 = (ab0-ab1+ab2)*q;
223 }
224
226 void set_bilinear_direct(double aa0, double aa1, double aa2, double ab1, double ab2)
227 {
228 a0 = aa0;
229 a1 = aa1;
230 a2 = aa2;
231 b1 = ab1;
232 b2 = ab2;
233 }
234
235
240 inline void set_peakeq_rbj(double freq, double q, double peak, double sr)
241 {
242 double A = sqrt(peak);
243 double w0 = freq * 2 * M_PI * (1.0 / sr);
244 double alpha = sin(w0) / (2 * q);
245 double ib0 = 1.0 / (1 + alpha/A);
246 a1 = b1 = -2*cos(w0) * ib0;
247 a0 = ib0 * (1 + alpha*A);
248 a2 = ib0 * (1 - alpha*A);
249 b2 = ib0 * (1 - alpha/A);
250 }
251
256 inline void set_lowshelf_rbj(float freq, float q, float peak, float sr)
257 {
258 double A = sqrt(peak);
259 double w0 = freq * 2 * M_PI * (1.0 / sr);
260 double alpha = sin(w0) / (2 * q);
261 double cw0 = cos(w0);
262 double tmp = 2 * sqrt(A) * alpha;
263 double b0 = 0.f, ib0 = 0.f;
264
265 a0 = A*( (A+1) - (A-1)*cw0 + tmp);
266 a1 = 2*A*( (A-1) - (A+1)*cw0);
267 a2 = A*( (A+1) - (A-1)*cw0 - tmp);
268 b0 = (A+1) + (A-1)*cw0 + tmp;
269 b1 = -2*( (A-1) + (A+1)*cw0);
270 b2 = (A+1) + (A-1)*cw0 - tmp;
271
272 ib0 = 1.0 / b0;
273 b1 *= ib0;
274 b2 *= ib0;
275 a0 *= ib0;
276 a1 *= ib0;
277 a2 *= ib0;
278 }
279
284 inline void set_highshelf_rbj(float freq, float q, float peak, float sr)
285 {
286 double A = sqrt(peak);
287 double w0 = freq * 2 * M_PI * (1.0 / sr);
288 double alpha = sin(w0) / (2 * q);
289 double cw0 = cos(w0);
290 double tmp = 2 * sqrt(A) * alpha;
291 double b0 = 0.f, ib0 = 0.f;
292
293 a0 = A*( (A+1) + (A-1)*cw0 + tmp);
294 a1 = -2*A*( (A-1) + (A+1)*cw0);
295 a2 = A*( (A+1) + (A-1)*cw0 - tmp);
296 b0 = (A+1) - (A-1)*cw0 + tmp;
297 b1 = 2*( (A-1) - (A+1)*cw0);
298 b2 = (A+1) - (A-1)*cw0 - tmp;
299
300 ib0 = 1.0 / b0;
301 b1 *= ib0;
302 b2 *= ib0;
303 a0 *= ib0;
304 a1 *= ib0;
305 a2 *= ib0;
306 }
307
309 inline void copy_coeffs(const biquad_coeffs &src)
310 {
311 a0 = src.a0;
312 a1 = src.a1;
313 a2 = src.a2;
314 b1 = src.b1;
315 b2 = src.b2;
316 }
317
321 float freq_gain(float freq, float sr) const
322 {
324 freq *= 2.0 * M_PI / sr;
325 cfloat z = 1.0 / exp(cfloat(0.0, freq));
326
327 return std::abs(h_z(z));
328 }
329
332 cfloat h_z(const cfloat &z) const
333 {
334
335 return (cfloat(a0) + double(a1) * z + double(a2) * z*z) / (cfloat(1.0) + double(b1) * z + double(b2) * z*z);
336 }
337
338};
339
346{
348 double x1;
350 double x2;
352 double y1;
354 double y2;
357 {
358 reset();
359 }
360
361 inline double process(double in)
362 {
363 double out = in * a0 + x1 * a1 + x2 * a2 - y1 * b1 - y2 * b2;
364 x2 = x1;
365 y2 = y1;
366 x1 = in;
367 y1 = out;
368 return out;
369 }
370
372 inline double process_zeroin()
373 {
374 double out = - y1 * b1 - y2 * b2;
375 y2 = y1;
376 y1 = out;
377 return out;
378 }
379
381 inline double process_lp(double in)
382 {
383 double out = a0*(in + x1 + x1 + x2) - y1 * b1 - y2 * b2;
384 x2 = x1;
385 y2 = y1;
386 x1 = in;
387 y1 = out;
388 return out;
389 }
390
391 inline double process_hp(double in)
392 {
393 double out = a0*(in - x1 - x1 + x2) - y1 * b1 - y2 * b2;
394 x2 = x1;
395 y2 = y1;
396 x1 = in;
397 y1 = out;
398 return out;
399 }
400
401 inline void sanitize()
402 {
407 }
408
409 inline void reset()
410 {
411 dsp::zero(x1);
412 dsp::zero(y1);
413 dsp::zero(x2);
414 dsp::zero(y2);
415 }
416 inline bool empty() const {
417 return (y1 == 0. && y2 == 0.);
418 }
419
420};
421
430{
432 double w1;
434 double w2;
437 {
438 reset();
439 }
440
441 inline double process(double in)
442 {
443 double n = in;
448
449 double tmp = n - w1 * b1 - w2 * b2;
450 double out = tmp * a0 + w1 * a1 + w2 * a2;
451 w2 = w1;
452 w1 = tmp;
453 return out;
454 }
455
456 // direct II form with two state variables, lowpass version
457 // interesting fact: this is actually slower than the general version!
458 inline double process_lp(double in)
459 {
460 double tmp = in - w1 * b1 - w2 * b2;
461 double out = (tmp + w2 + w1* 2) * a0;
462 w2 = w1;
463 w1 = tmp;
464 return out;
465 }
466
468 inline bool empty() const {
469 return (w1 == 0.f && w2 == 0.f);
470 }
471
472
474 inline void sanitize()
475 {
478 }
479
481 inline void reset()
482 {
483 dsp::zero(w1);
484 dsp::zero(w2);
485 }
486};
487
494{
498 double x1;
500 double x2;
502 double y1;
504 double y2;
507 {
508 reset();
509 }
510 #define _DO_COEFF(coeff) coeff##delta = (coeff - coeff##cur) * (frac)
511 void big_step(double frac)
512 {
513 _DO_COEFF(a0);
514 _DO_COEFF(a1);
515 _DO_COEFF(a2);
516 _DO_COEFF(b1);
517 _DO_COEFF(b2);
518 }
519 #undef _DO_COEFF
521 inline double process(double in)
522 {
523 double out = in * a0cur + x1 * a1cur + x2 * a2cur - y1 * b1cur - y2 * b2cur;
524 x2 = x1;
525 y2 = y1;
526 x1 = in;
527 y1 = out;
528 a0cur += a0delta;
529 a1cur += a1delta;
530 a2cur += a2delta;
531 b1cur += b1delta;
532 b2cur += b2delta;
533 return out;
534 }
535
537 inline double process_zeroin()
538 {
539 double out = - y1 * b1 - y2 * b2;
540 y2 = y1;
541 y1 = out;
542 b1cur += b1delta;
543 b2cur += b2delta;
544 return out;
545 }
546
548 inline double process_lp(double in)
549 {
550 double out = a0*(in + x1 + x1 + x2) - y1 * b1 - y2 * b2;
551 x2 = x1;
552 y2 = y1;
553 x1 = in;
554 y1 = out;
555 return out;
556 }
557
570
571 inline void reset()
572 {
573 dsp::zero(x1);
574 dsp::zero(y1);
575 dsp::zero(x2);
576 dsp::zero(y2);
582 }
583 inline bool empty() {
584 return (y1 == 0. && y2 == 0.);
585 }
586
587};
588
590template<class F1, class F2>
592public:
596public:
597 float process(float value) {
598 return f2.process(f1.process(value));
599 }
600
601 inline cfloat h_z(const cfloat &z) const {
602 return f1.h_z(z) * f2.h_z(z);
603 }
604
608 float freq_gain(float freq, float sr) const
609 {
611 freq *= 2.0 * M_PI / sr;
612 cfloat z = 1.0 / exp(cfloat(0.0, freq));
613
614 return std::abs(h_z(z));
615 }
616
617 void sanitize() {
618 f1.sanitize();
619 f2.sanitize();
620 }
621};
622
624template<class F1, class F2>
626public:
630public:
631 double process(double value) {
632 return f2.process(value) + f1.process(value);
633 }
634
635 inline cfloat h_z(const cfloat &z) const {
636 return f1.h_z(z) + f2.h_z(z);
637 }
638
642 float freq_gain(float freq, float sr) const
643 {
645 freq *= 2.0 * M_PI / sr;
646 cfloat z = 1.0 / exp(cfloat(0.0, freq));
647
648 return std::abs(h_z(z));
649 }
650
651 void sanitize() {
652 f1.sanitize();
653 f2.sanitize();
654 }
655};
656
657};
658
659#endif
uint8_t a
Definition Spc_Cpu.h:141
#define _DO_COEFF(coeff)
Definition biquad.h:510
void set_lowshelf_rbj(float freq, float q, float peak, float sr)
Definition biquad.h:256
biquad_coeffs()
Definition biquad.h:55
void set_lp_zoelzer(float fc, float q, float odsr, float gain=1.0)
Definition biquad.h:93
void set_br_rbj(double fc, double q, double esr, double gain=1.0)
Definition biquad.h:170
void set_bilinear(double aa0, double aa1, double aa2, double ab0, double ab1, double ab2)
set digital filter parameters based on given analog filter parameters
Definition biquad.h:215
void copy_coeffs(const biquad_coeffs &src)
copy coefficients from another biquad
Definition biquad.h:309
double b2
Definition biquad.h:52
double a0
Definition biquad.h:52
void set_peakeq_rbj(double freq, double q, double peak, double sr)
Definition biquad.h:240
static double prewarp(float freq, float sr)
prewarping for bilinear transform, maps given digital frequency to analog counterpart for analog filt...
Definition biquad.h:193
void set_lp_rbj(float fc, float q, float sr, float gain=1.0)
Definition biquad.h:74
void set_hp_rbj_optimized(float fc, float q, float esr, float gain=1.0)
Definition biquad.h:131
double a2
Definition biquad.h:52
cfloat h_z(const cfloat &z) const
Definition biquad.h:332
void set_hp_rbj(float fc, float q, float esr, float gain=1.0)
Definition biquad.h:114
void set_allpass(float freq, float pole_r, float sr)
Definition biquad.h:186
float freq_gain(float freq, float sr) const
Definition biquad.h:321
std::complex< double > cfloat
Definition biquad.h:53
void set_bp_rbj(double fc, double q, double esr, double gain=1.0)
Definition biquad.h:153
static double unwarp(float omega, float sr)
convert analog angular frequency value to digital
Definition biquad.h:199
double b1
Definition biquad.h:52
static double unwarpf(float t, float sr)
convert analog filter time constant to digital counterpart
Definition biquad.h:205
double a1
Definition biquad.h:52
void set_bilinear_direct(double aa0, double aa1, double aa2, double ab1, double ab2)
set digital filter parameters directly
Definition biquad.h:226
void set_null()
Definition biquad.h:60
void set_highshelf_rbj(float freq, float q, float peak, float sr)
Definition biquad.h:284
Compose two filters in series.
Definition biquad.h:591
std::complex< float > cfloat
Definition biquad.h:593
F2 f2
Definition biquad.h:595
float process(float value)
Definition biquad.h:597
float freq_gain(float freq, float sr) const
Definition biquad.h:608
void sanitize()
Definition biquad.h:617
F1 f1
Definition biquad.h:594
cfloat h_z(const cfloat &z) const
Definition biquad.h:601
Compose two filters in parallel.
Definition biquad.h:625
double process(double value)
Definition biquad.h:631
void sanitize()
Definition biquad.h:651
cfloat h_z(const cfloat &z) const
Definition biquad.h:635
std::complex< double > cfloat
Definition biquad.h:627
F1 f1
Definition biquad.h:628
F2 f2
Definition biquad.h:629
float freq_gain(float freq, float sr) const
Definition biquad.h:642
#define M_PI
Definition compat.h:149
unsigned z
Definition inflate.c:1589
struct huft * t
Definition inflate.c:943
unsigned f
Definition inflate.c:1572
static PuglViewHint int value
Definition pugl.h:1708
JHUFF_TBL long freq[]
Definition jchuff.h:50
#define A(x)
Definition lice_arc.cpp:13
float in
Definition lilv_test.c:1460
float out
Definition lilv_test.c:1461
#define F1(x, y, z)
Definition md5.c:40
#define F2(x, y, z)
Definition md5.c:41
Definition audio_fx.h:36
void zero(float &v)
Set a float to zero.
Definition primitives.h:41
void sanitize(float &value)
Definition primitives.h:354
void sanitize_denormal(float &value)
Definition primitives.h:374
void sanitize()
Sanitize (set to 0 if potentially denormal) filter state.
Definition biquad.h:558
double b1cur
Definition biquad.h:495
bool empty()
Definition biquad.h:583
double a2delta
Definition biquad.h:496
void big_step(double frac)
Definition biquad.h:511
double a2cur
Definition biquad.h:495
double y1
output[n-1]
Definition biquad.h:502
biquad_d1_lerp()
Constructor (initializes state to all zeros).
Definition biquad.h:506
double process_lp(double in)
simplified version for lowpass case with two zeros at -1
Definition biquad.h:548
double b1delta
Definition biquad.h:496
double a1delta
Definition biquad.h:496
double b2delta
Definition biquad.h:496
double a0cur
Definition biquad.h:495
double process(double in)
direct I form with four state variables
Definition biquad.h:521
double a0delta
Definition biquad.h:496
void reset()
Reset state variables.
Definition biquad.h:571
double process_zeroin()
direct I form with zero input
Definition biquad.h:537
double a1cur
Definition biquad.h:495
double y2
output[n-2]
Definition biquad.h:504
double x2
input[n-2]
Definition biquad.h:500
double b2cur
Definition biquad.h:495
double x1
input[n-1]
Definition biquad.h:498
double process_zeroin()
direct I form with zero input
Definition biquad.h:372
void sanitize()
Sanitize (set to 0 if potentially denormal) filter state.
Definition biquad.h:401
double x2
input[n-2]
Definition biquad.h:350
double process_lp(double in)
simplified version for lowpass case with two zeros at -1
Definition biquad.h:381
bool empty() const
Definition biquad.h:416
double process_hp(double in)
simplified version for highpass case with two zeros at 1
Definition biquad.h:391
double process(double in)
direct I form with four state variables
Definition biquad.h:361
double y1
output[n-1]
Definition biquad.h:352
double y2
output[n-2]
Definition biquad.h:354
double x1
input[n-1]
Definition biquad.h:348
biquad_d1()
Constructor (initializes state to all zeros).
Definition biquad.h:356
void reset()
Reset state variables.
Definition biquad.h:409
bool empty() const
Is the filter state completely silent? (i.e. set to 0 by sanitize function).
Definition biquad.h:468
biquad_d2()
Constructor (initializes state to all zeros).
Definition biquad.h:436
double w1
state[n-1]
Definition biquad.h:432
void reset()
Reset state variables.
Definition biquad.h:481
double process(double in)
direct II form with two state variables
Definition biquad.h:441
double process_lp(double in)
Definition biquad.h:458
double w2
state[n-2]
Definition biquad.h:434
void sanitize()
Sanitize (set to 0 if potentially denormal) filter state.
Definition biquad.h:474
Definition globals.h:33
int n
Definition crypt.c:458
register uch * q
Definition fileio.c:817