robert@464
|
1 //
|
robert@464
|
2 // Biquad.cpp
|
robert@464
|
3 //
|
robert@464
|
4 // Created by Nigel Redmon on 11/24/12
|
robert@464
|
5 // EarLevel Engineering: earlevel.com
|
robert@464
|
6 // Copyright 2012 Nigel Redmon
|
robert@464
|
7 //
|
robert@464
|
8 // For a complete explanation of the Biquad code:
|
robert@464
|
9 // http://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
|
robert@464
|
10 //
|
robert@464
|
11 // License:
|
robert@464
|
12 //
|
robert@464
|
13 // This source code is provided as is, without warranty.
|
robert@464
|
14 // You may copy and distribute verbatim copies of this document.
|
robert@464
|
15 // You may modify and use this source code to create binary code
|
robert@464
|
16 // for your own purposes, free or commercial.
|
robert@464
|
17 //
|
robert@464
|
18
|
robert@464
|
19 #include <math.h>
|
robert@464
|
20 #include "Biquad.h"
|
robert@464
|
21 #include <iostream>
|
robert@464
|
22
|
robert@464
|
23 Biquad::Biquad() {
|
robert@464
|
24 type = bq_type_lowpass;
|
robert@464
|
25 a0 = 1.0;
|
robert@464
|
26 a1 = a2 = b1 = b2 = 0.0;
|
robert@464
|
27 Fc = 0.50;
|
robert@464
|
28 Q = 0.707;
|
robert@464
|
29 peakGain = 0.0;
|
robert@464
|
30 z1 = z2 = 0.0;
|
robert@464
|
31 }
|
robert@464
|
32
|
robert@464
|
33 Biquad::Biquad(int type, double Fc, double Q, double peakGainDB) {
|
robert@464
|
34 setBiquad(type, Fc, Q, peakGainDB);
|
robert@464
|
35 z1 = z2 = 0.0;
|
robert@464
|
36 }
|
robert@464
|
37
|
robert@464
|
38 Biquad::~Biquad() {
|
robert@464
|
39 }
|
robert@464
|
40
|
robert@464
|
41 void Biquad::setType(int type) {
|
robert@464
|
42 this->type = type;
|
robert@464
|
43 calcBiquad();
|
robert@464
|
44 }
|
robert@464
|
45
|
robert@464
|
46 void Biquad::setQ(double Q) {
|
robert@464
|
47 this->Q = Q;
|
robert@464
|
48 calcBiquad();
|
robert@464
|
49 }
|
robert@464
|
50
|
robert@464
|
51 void Biquad::setFc(double Fc) {
|
robert@464
|
52 this->Fc = Fc;
|
robert@464
|
53 calcBiquad();
|
robert@464
|
54 }
|
robert@464
|
55
|
robert@464
|
56 void Biquad::setPeakGain(double peakGainDB) {
|
robert@464
|
57 this->peakGain = peakGainDB;
|
robert@464
|
58 calcBiquad();
|
robert@464
|
59 }
|
robert@464
|
60
|
robert@464
|
61 void Biquad::setBiquad(int type, double Fc, double Q, double peakGainDB) {
|
robert@464
|
62 this->type = type;
|
robert@464
|
63 this->Q = Q;
|
robert@464
|
64 this->Fc = Fc;
|
robert@464
|
65 startFc = Fc;
|
robert@464
|
66 startQ = Q;
|
robert@464
|
67 startPeakGain = peakGainDB;
|
robert@464
|
68 setPeakGain(peakGainDB);
|
robert@464
|
69 }
|
robert@464
|
70
|
robert@464
|
71 void Biquad::calcBiquad(void) {
|
robert@464
|
72 double norm;
|
robert@464
|
73 double V = pow(10, fabs(peakGain) / 20.0);
|
robert@464
|
74 double K = tan(M_PI * Fc);
|
robert@464
|
75 switch (this->type) {
|
robert@464
|
76 case bq_type_lowpass:
|
robert@464
|
77 norm = 1 / (1 + K / Q + K * K);
|
robert@464
|
78 a0 = K * K * norm;
|
robert@464
|
79 a1 = 2 * a0;
|
robert@464
|
80 a2 = a0;
|
robert@464
|
81 b1 = 2 * (K * K - 1) * norm;
|
robert@464
|
82 b2 = (1 - K / Q + K * K) * norm;
|
robert@464
|
83 break;
|
robert@464
|
84
|
robert@464
|
85 case bq_type_highpass:
|
robert@464
|
86 norm = 1 / (1 + K / Q + K * K);
|
robert@464
|
87 a0 = 1 * norm;
|
robert@464
|
88 a1 = -2 * a0;
|
robert@464
|
89 a2 = a0;
|
robert@464
|
90 b1 = 2 * (K * K - 1) * norm;
|
robert@464
|
91 b2 = (1 - K / Q + K * K) * norm;
|
robert@464
|
92 break;
|
robert@464
|
93
|
robert@464
|
94 case bq_type_bandpass:
|
robert@464
|
95 norm = 1 / (1 + K / Q + K * K);
|
robert@464
|
96 a0 = K / Q * norm;
|
robert@464
|
97 a1 = 0;
|
robert@464
|
98 a2 = -a0;
|
robert@464
|
99 b1 = 2 * (K * K - 1) * norm;
|
robert@464
|
100 b2 = (1 - K / Q + K * K) * norm;
|
robert@464
|
101 break;
|
robert@464
|
102
|
robert@464
|
103 case bq_type_notch:
|
robert@464
|
104 norm = 1 / (1 + K / Q + K * K);
|
robert@464
|
105 a0 = (1 + K * K) * norm;
|
robert@464
|
106 a1 = 2 * (K * K - 1) * norm;
|
robert@464
|
107 a2 = a0;
|
robert@464
|
108 b1 = a1;
|
robert@464
|
109 b2 = (1 - K / Q + K * K) * norm;
|
robert@464
|
110 break;
|
robert@464
|
111
|
robert@464
|
112 case bq_type_peak:
|
robert@464
|
113 if (peakGain >= 0) { // boost
|
robert@464
|
114 norm = 1 / (1 + 1/Q * K + K * K);
|
robert@464
|
115 a0 = (1 + V/Q * K + K * K) * norm;
|
robert@464
|
116 a1 = 2 * (K * K - 1) * norm;
|
robert@464
|
117 a2 = (1 - V/Q * K + K * K) * norm;
|
robert@464
|
118 b1 = a1;
|
robert@464
|
119 b2 = (1 - 1/Q * K + K * K) * norm;
|
robert@464
|
120 }
|
robert@464
|
121 else { // cut
|
robert@464
|
122 norm = 1 / (1 + V/Q * K + K * K);
|
robert@464
|
123 a0 = (1 + 1/Q * K + K * K) * norm;
|
robert@464
|
124 a1 = 2 * (K * K - 1) * norm;
|
robert@464
|
125 a2 = (1 - 1/Q * K + K * K) * norm;
|
robert@464
|
126 b1 = a1;
|
robert@464
|
127 b2 = (1 - V/Q * K + K * K) * norm;
|
robert@464
|
128 }
|
robert@464
|
129 break;
|
robert@464
|
130 case bq_type_lowshelf:
|
robert@464
|
131 if (peakGain >= 0) { // boost
|
robert@464
|
132 norm = 1 / (1 + sqrt(2) * K + K * K);
|
robert@464
|
133 a0 = (1 + sqrt(2*V) * K + V * K * K) * norm;
|
robert@464
|
134 a1 = 2 * (V * K * K - 1) * norm;
|
robert@464
|
135 a2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
|
robert@464
|
136 b1 = 2 * (K * K - 1) * norm;
|
robert@464
|
137 b2 = (1 - sqrt(2) * K + K * K) * norm;
|
robert@464
|
138 }
|
robert@464
|
139 else { // cut
|
robert@464
|
140 norm = 1 / (1 + sqrt(2*V) * K + V * K * K);
|
robert@464
|
141 a0 = (1 + sqrt(2) * K + K * K) * norm;
|
robert@464
|
142 a1 = 2 * (K * K - 1) * norm;
|
robert@464
|
143 a2 = (1 - sqrt(2) * K + K * K) * norm;
|
robert@464
|
144 b1 = 2 * (V * K * K - 1) * norm;
|
robert@464
|
145 b2 = (1 - sqrt(2*V) * K + V * K * K) * norm;
|
robert@464
|
146 }
|
robert@464
|
147 break;
|
robert@464
|
148 case bq_type_highshelf:
|
robert@464
|
149 if (peakGain >= 0) { // boost
|
robert@464
|
150 norm = 1 / (1 + sqrt(2) * K + K * K);
|
robert@464
|
151 a0 = (V + sqrt(2*V) * K + K * K) * norm;
|
robert@464
|
152 a1 = 2 * (K * K - V) * norm;
|
robert@464
|
153 a2 = (V - sqrt(2*V) * K + K * K) * norm;
|
robert@464
|
154 b1 = 2 * (K * K - 1) * norm;
|
robert@464
|
155 b2 = (1 - sqrt(2) * K + K * K) * norm;
|
robert@464
|
156 }
|
robert@464
|
157 else { // cut
|
robert@464
|
158 norm = 1 / (V + sqrt(2*V) * K + K * K);
|
robert@464
|
159 a0 = (1 + sqrt(2) * K + K * K) * norm;
|
robert@464
|
160 a1 = 2 * (K * K - 1) * norm;
|
robert@464
|
161 a2 = (1 - sqrt(2) * K + K * K) * norm;
|
robert@464
|
162 b1 = 2 * (K * K - V) * norm;
|
robert@464
|
163 b2 = (V - sqrt(2*V) * K + K * K) * norm;
|
robert@464
|
164 }
|
robert@464
|
165 break;
|
robert@464
|
166 }
|
robert@464
|
167
|
robert@464
|
168 return;
|
robert@464
|
169 }
|