1 /* 2 dsp/RBJ.h 3 4 Copyright 5 1998 Robert Bristow-Johnson 6 2004-10 Tim Goetze <tim@quitte.de> 7 8 biquad prototypes according to the eq cookbook. easy-to-use, nice, 9 predictable filters. thanks rbj! 10 */ 11 /* 12 This program is free software; you can redistribute it and/or 13 modify it under the terms of the GNU General Public License 14 as published by the Free Software Foundation; either version 2 15 of the License, or (at your option) any later version. 16 17 This program is distributed in the hope that it will be useful, 18 but WITHOUT ANY WARRANTY; without even the implied warranty of 19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 GNU General Public License for more details. 21 22 You should have received a copy of the GNU General Public License 23 along with this program; if not, write to the Free Software 24 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 25 02111-1307, USA or point your web browser to http://www.gnu.org. 26 */ 27 28 #ifndef _DSP_RBJ_H_ 29 #define _DSP_RBJ_H_ 30 31 #include "BiQuad.h" 32 33 namespace DSP { 34 namespace RBJ { 35 36 /* base class, prepares common parameters */ 37 class RBJ 38 { 39 public: 40 double Q, alpha, sin, cos; 41 double a[3], b[3]; 42 43 public: RBJ(double f,double _Q)44 RBJ (double f, double _Q) 45 { 46 Q = _Q; 47 48 double w = 2 * M_PI * f; 49 50 sin = ::sin (w); 51 cos = ::cos (w); 52 53 alpha = sin / (2 * Q); 54 } 55 56 /* templated so we can set double and float coefficients from the same 57 * piece of code */ 58 template <class T> make_direct_I(T * ca,T * cb)59 void make_direct_I (T * ca, T * cb) 60 { 61 double a0i = 1 / a[0]; 62 63 ca[0] = b[0] * a0i; 64 ca[1] = b[1] * a0i; 65 ca[2] = b[2] * a0i; 66 67 /* our bi-quad implementation /adds/ b[i] * y[i] so we need to 68 * toggle the sign for the b[] coefficients. 69 */ 70 cb[0] = 0; 71 cb[1] = -a[1] * a0i; 72 cb[2] = -a[2] * a0i; 73 } 74 }; 75 76 /* now the individual prototypes. 77 * set-up is not optimal, i.e. does a lot of operations twice for readability. 78 */ 79 class LP 80 : public RBJ 81 { 82 public: LP(double f,double Q,BiQuad & bq)83 LP (double f, double Q, BiQuad & bq) : RBJ (f, Q) 84 { ab (bq.a, bq.b); } 85 86 template <class T> LP(double f,double Q,T * ca,T * cb)87 LP (double f, double Q, T * ca, T * cb) : RBJ (f, Q) 88 { ab (ca, cb); } 89 90 template <class T> ab(T * ca,T * cb)91 void ab (T * ca, T * cb) 92 { 93 b[0] = (1 - cos) * .5; 94 b[1] = (1 - cos); 95 b[2] = (1 - cos) * .5; 96 97 a[0] = 1 + alpha; 98 a[1] = -2 * cos; 99 a[2] = 1 - alpha; 100 101 make_direct_I (ca, cb); 102 } 103 }; 104 105 class BP 106 : public RBJ 107 { 108 public: BP(double f,double Q,BiQuad & bq)109 BP (double f, double Q, BiQuad & bq) : RBJ (f, Q) 110 { ab (bq.a, bq.b); } 111 112 template <class T> BP(double f,double Q,T * ca,T * cb)113 BP (double f, double Q, T * ca, T * cb) : RBJ (f, Q) 114 { ab (ca, cb); } 115 116 template <class T> ab(T * ca,T * cb)117 void ab (T * ca, T * cb) 118 { 119 b[0] = Q * alpha; 120 b[1] = 0; 121 b[2] = -Q * alpha; 122 123 a[0] = 1 + alpha; 124 a[1] = -2 * cos; 125 a[2] = 1 - alpha; 126 127 make_direct_I (ca, cb); 128 } 129 }; 130 131 class HP 132 : public RBJ 133 { 134 public: HP(double f,double Q,BiQuad & bq)135 HP (double f, double Q, BiQuad & bq) : RBJ (f, Q) 136 { ab (bq.a, bq.b); } 137 138 template <class T> HP(double f,double Q,T * ca,T * cb)139 HP (double f, double Q, T * ca, T * cb) : RBJ (f, Q) 140 { ab (ca, cb); } 141 142 template <class T> ab(T * ca,T * cb)143 void ab (T * ca, T * cb) 144 { 145 b[0] = (1 + cos) * .5; 146 b[1] = -(1 + cos); 147 b[2] = (1 + cos) * .5; 148 149 a[0] = 1 + alpha; 150 a[1] = -2 * cos; 151 a[2] = 1 - alpha; 152 153 make_direct_I (ca, cb); 154 } 155 }; 156 157 class Notch 158 : public RBJ 159 { 160 public: Notch(double f,double Q,BiQuad & bq)161 Notch (double f, double Q, BiQuad & bq) : RBJ (f, Q) 162 { ab (bq.a, bq.b); } 163 164 template <class T> Notch(double f,double Q,T * ca,T * cb)165 Notch (double f, double Q, T * ca, T * cb) : RBJ (f, Q) 166 { ab (ca, cb); } 167 168 template <class T> ab(T * ca,T * cb)169 void ab (T * ca, T * cb) 170 { 171 b[0] = 1; 172 b[1] = -2 * cos; 173 b[2] = 1; 174 175 a[0] = 1 + alpha; 176 a[1] = -2 * cos; 177 a[2] = 1 - alpha; 178 179 make_direct_I (ca, cb); 180 } 181 }; 182 183 /* shelving and peaking dept. ////////////////////////////////////////////// */ 184 185 class PeakShelve 186 : public RBJ 187 { 188 public: 189 double A, beta; 190 191 public: PeakShelve(double f,double Q,double dB)192 PeakShelve (double f, double Q, double dB) 193 : RBJ (f, Q) 194 { 195 A = pow (10, dB * .025); 196 double S = Q; /* slope */ 197 beta = sqrt ((A * A + 1) / S - (A - 1) * (A - 1)); 198 } 199 }; 200 201 class LoShelve 202 : public PeakShelve 203 { 204 public: LoShelve(double f,double Q,double dB,BiQuad & bq)205 LoShelve (double f, double Q, double dB, BiQuad & bq) 206 : PeakShelve (f, Q, dB) 207 { ab (bq.a, bq.b); } 208 209 template <class T> LoShelve(double f,double Q,double dB,T * ca,T * cb)210 LoShelve (double f, double Q, double dB, T * ca, T * cb) 211 : PeakShelve (f, Q, dB) 212 { ab (ca, cb); } 213 214 template <class T> ab(T * ca,T * cb)215 void ab (T * ca, T * cb) 216 { 217 double Ap1 = A + 1, Am1 = A - 1; 218 double beta_sin = beta * sin; 219 220 b[0] = A * (Ap1 - Am1 * cos + beta_sin); 221 b[1] = 2 * A * (Am1 - Ap1 * cos); 222 b[2] = A * (Ap1 - Am1 * cos - beta_sin); 223 224 a[0] = Ap1 + Am1 * cos + beta_sin; 225 a[1] = -2 * (Am1 + Ap1 * cos); 226 a[2] = Ap1 + Am1 * cos - beta_sin; 227 228 make_direct_I (ca, cb); 229 } 230 }; 231 232 class PeakingEQ 233 : public PeakShelve 234 { 235 public: PeakingEQ(double f,double Q,double dB,BiQuad & bq)236 PeakingEQ (double f, double Q, double dB, BiQuad & bq) 237 : PeakShelve (f, Q, dB) 238 { ab (bq.a, bq.b); } 239 240 template <class T> PeakingEQ(double f,double Q,double dB,T * ca,T * cb)241 PeakingEQ (double f, double Q, double dB, T * ca, T * cb) 242 : PeakShelve (f, Q, dB) 243 { ab (ca, cb); } 244 245 template <class T> ab(T * ca,T * cb)246 void ab (T * ca, T * cb) 247 { 248 b[0] = 1 + alpha * A; 249 b[1] = -2 * cos; 250 b[2] = 1 - alpha * A; 251 252 a[0] = 1 + alpha / A; 253 a[1] = -2 * cos; 254 a[2] = 1 - alpha / A; 255 256 make_direct_I (ca, cb); 257 } 258 }; 259 260 class HiShelve 261 : public PeakShelve 262 { 263 public: HiShelve(double f,double Q,double dB,BiQuad & bq)264 HiShelve (double f, double Q, double dB, BiQuad & bq) 265 : PeakShelve (f, Q, dB) 266 { ab (bq.a, bq.b); } 267 268 template <class T> HiShelve(double f,double Q,double dB,T * ca,T * cb)269 HiShelve (double f, double Q, double dB, T * ca, T * cb) 270 : PeakShelve (f, Q, dB) 271 { ab (ca, cb); } 272 273 template <class T> ab(T * ca,T * cb)274 void ab (T * ca, T * cb) 275 { 276 double Ap1 = A + 1, Am1 = A - 1; 277 double beta_sin = beta * sin; 278 279 b[0] = A * (Ap1 + Am1 * cos + beta_sin); 280 b[1] = -2 * A * (Am1 + Ap1 * cos); 281 b[2] = A * (Ap1 + Am1 * cos - beta_sin); 282 283 a[0] = Ap1 - Am1 * cos + beta_sin; 284 a[1] = 2 * (Am1 - Ap1 * cos); 285 a[2] = Ap1 - Am1 * cos - beta_sin; 286 287 make_direct_I (ca, cb); 288 } 289 }; 290 291 } /* ~namespace RBJ */ 292 } /* ~namespace DSP */ 293 294 #endif /* _DSP_RBJ_H_ */ 295