TestVCF.cpp (26645B)
1 2 #include "TestVCF.hpp" 3 4 #include <complex> 5 6 void TestVCF::LPFModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 7 resonance = std::max(0.1f, 10.0f * resonance); 8 _filter.setParams(APP->engine->getSampleRate(), cutoff, resonance); 9 } 10 11 float TestVCF::LPFModel::next(float sample) { 12 return _filter.next(sample); 13 } 14 15 void TestVCF::MultipoleModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 16 MultipoleFilter::Type type = mode == HIGHPASS_MODE ? MultipoleFilter::HP_TYPE : MultipoleFilter::LP_TYPE; 17 _filter.setParams(type, 2 * (1 + (int)poles), APP->engine->getSampleRate(), cutoff, topology * 0.29); 18 } 19 20 float TestVCF::MultipoleModel::next(float sample) { 21 return _filter.next(sample); 22 } 23 24 void TestVCF::ComplexModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 25 _pair1a.setComplexParams( 26 1.0f, 27 0.0f, 28 0.0f, 29 0.7f, 30 2.0f * M_PI * cutoff / APP->engine->getSampleRate() 31 ); 32 _pair1b.setComplexParams( 33 1.0f, 34 0.0f, 35 0.0f, 36 0.7f, 37 -2.0f * M_PI * cutoff / APP->engine->getSampleRate() 38 ); 39 } 40 41 float TestVCF::ComplexModel::next(float sample) { 42 return _pair1a.next(sample); // + _pair1b.next(sample); 43 } 44 45 void TestVCF::BookExampleModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 46 _poles = poles; 47 48 // _filter.setParams( 49 // 0.00473f, 50 // 0.00946f, 51 // 0.00473f, 52 // 1.0f, 53 // -1.8485f, 54 // 0.8674f 55 // ); 56 57 resonance = std::max(0.1f, resonance) * 10.0f; 58 float iq = 1.0f / resonance; 59 float wa = tanf(0.5f * (2.0f * M_PI * cutoff * APP->engine->getSampleTime())); 60 float wa2 = wa * wa; 61 if (mode == HIGHPASS_MODE) { 62 float a0 = 1.0f; 63 float a1 = -2.0f; 64 float a2 = 1.0f; 65 float b0 = 1.0f * wa2 + wa * iq + 1.0f; 66 float b1 = 2.0f * wa2 - 2.0f; 67 float b2 = 1.0f * wa2 - wa * iq + 1.0f; 68 _filter1.setParams(a0, a1, a2, b0, b1, b2); 69 _filter2.setParams(a0, a1, a2, b0, b1, b2); 70 _filter3.setParams(a0, a1, a2, b0, b1, b2); 71 _filter4.setParams(a0, a1, a2, b0, b1, b2); 72 } 73 else { 74 float a0 = wa2; 75 float a1 = 2.0f * wa2; 76 float a2 = wa2; 77 float b0 = wa2 + wa * iq + 1.0f; 78 float b1 = 2.0f * wa2 - 2.0f; 79 float b2 = wa2 - wa * iq + 1.0f; 80 _filter1.setParams(a0, a1, a2, b0, b1, b2); 81 _filter2.setParams(a0, a1, a2, b0, b1, b2); 82 _filter3.setParams(a0, a1, a2, b0, b1, b2); 83 _filter4.setParams(a0, a1, a2, b0, b1, b2); 84 85 // { 86 // iq = 0.7654f; 87 // float a0 = wa2; 88 // float a1 = 2.0f * wa2; 89 // float a2 = wa2; 90 // float b0 = wa2 + wa * iq + 1.0f; 91 // float b1 = 2.0f * wa2 - 2.0f; 92 // float b2 = wa2 - wa * iq + 1.0f; 93 // _filter1.setParams(a0, a1, a2, b0, b1, b2); 94 // } 95 // { 96 // iq = 1.847f; 97 // float a0 = wa2; 98 // float a1 = 2.0f * wa2; 99 // float a2 = wa2; 100 // float b0 = wa2 + wa * iq + 1.0f; 101 // float b1 = 2.0f * wa2 - 2.0f; 102 // float b2 = wa2 - wa * iq + 1.0f; 103 // _filter2.setParams(a0, a1, a2, b0, b1, b2); 104 // } 105 // // _filter3.setParams(a0, a1, a2, b0, b1, b2); 106 // // _filter4.setParams(a0, a1, a2, b0, b1, b2); 107 } 108 } 109 110 float TestVCF::BookExampleModel::next(float sample) { 111 float out = _filter1.next(sample); 112 switch (_poles) { 113 case POLES_2: { 114 break; 115 } 116 case POLES_4: { 117 out = _filter2.next(out); 118 break; 119 } 120 case POLES_6: { 121 out = _filter2.next(out); 122 out = _filter3.next(out); 123 break; 124 } 125 default: { 126 out = _filter2.next(out); 127 out = _filter3.next(out); 128 out = _filter4.next(out); 129 break; 130 } 131 } 132 return out; 133 } 134 135 void TestVCF::ButterworthModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 136 _nFilters = 1 + (int)poles; 137 assert(_nFilters <= maxPoles / 2); 138 139 cutoff = std::max(2.0f, cutoff); // FIXME: another way to avoid DC exploding near 0 hz? 140 // resonance = 1.0f + resonance * 20.0f / (2.0f * (float)_nFilters); // FIXME 141 // float iq = 1.0f / resonance; 142 float iq = 0.707 - 0.65 * resonance / (1.0f + std::pow(0.6f * std::log((float)_nFilters), 2.0)); 143 float wa = tanf(0.5f * (2.0f * M_PI * cutoff * APP->engine->getSampleTime())); 144 float wa2 = wa * wa; 145 if (mode == HIGHPASS_MODE) { 146 float a0 = 1.0f; 147 float a1 = -2.0f; 148 float a2 = 1.0f; 149 float b1 = 2.0f * wa2 - 2.0f; 150 float i2n = 1.0f / (4.0f * _nFilters); 151 for (int i = 0; i < _nFilters; ++i) { 152 float x = iq * 2.0f * cosf((float)i * M_PI * i2n); 153 float b0 = 1.0f * wa2 + wa * x + 1.0f; 154 float b2 = 1.0f * wa2 - wa * x + 1.0f; 155 _filters[i].setParams(a0, a1, a2, b0, b1, b2); 156 } 157 } 158 else { 159 float a0 = wa2; 160 float a1 = 2.0f * wa2; 161 float a2 = wa2; 162 float b1 = 2.0f * wa2 - 2.0f; 163 float i2n = 1.0f / (4.0f * _nFilters); 164 for (int i = 0; i < _nFilters; ++i) { 165 float x = iq * 2.0f * cosf((float)i * M_PI * i2n); 166 float b0 = wa2 + wa * x + 1.0f; 167 float b2 = wa2 - wa * x + 1.0f; 168 _filters[i].setParams(a0, a1, a2, b0, b1, b2); 169 } 170 } 171 } 172 173 float TestVCF::ButterworthModel::next(float sample) { 174 for (int i = 0; i < _nFilters; ++i) { 175 sample = _filters[i].next(sample); 176 } 177 return sample; 178 } 179 180 template<typename T> 181 void TestVCF::BPButterworthModel1<T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 182 _nFilters = 1 + (int)poles; 183 assert(_nFilters <= maxPoles / 2); 184 185 bandwidth = 0.1; 186 T span = std::max(1.0, bandwidth * 1000.0); 187 T wdl = std::max(1.0, cutoff - span); 188 T wdh = std::min((T)maxCutoff, cutoff + span); 189 T wal = std::tan(0.5 * (2.0 * M_PI * wdl * APP->engine->getSampleTime())); 190 T wah = std::tan(0.5 * (2.0 * M_PI * wdh * APP->engine->getSampleTime())); 191 T W = wah - wal; 192 T W2 = W * W; 193 T w02 = wah * wal; 194 195 resonance = 1.0 + resonance * 10.0 / (1.0 * (T)_nFilters); // FIXME 196 T iq = 1.0 / resonance; 197 198 T a0 = W2; 199 T a1 = W2; 200 T a2 = -W2; 201 T a3 = -W2; 202 203 T i2n = 1.0 / (2.0 * _nFilters); 204 for (int i = 0; i < _nFilters; ++i) { 205 T x = iq * 2.0 * std::cos((T)i * M_PI * i2n); 206 T w04etc = w02 * w02 + W * x * w02; 207 T b0 = 1.0 + W * x + W2 + 2.0 * w02 + w04etc; 208 T b1 = -3.0 - W * x + W2 + 2.0 * w02 + 3.0 * w04etc; 209 T b2 = 3.0 - W * x - W2 - 2.0 * w02 + 3.0 * w04etc; 210 T b3 = -1.0 + W * x - W2 - 2.0 * w02 + w04etc; 211 _filters[i].setParams(a0, a1, a2, a3, b0, b1, b2, b3); 212 } 213 } 214 215 template<typename T> 216 float TestVCF::BPButterworthModel1<T>::next(float sample) { 217 for (int i = 0; i < _nFilters; ++i) { 218 sample = _filters[i].next(sample); 219 } 220 return sample; 221 } 222 223 template<typename T> 224 void TestVCF::BandButterworthModel<T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 225 _nFilterPairs = 1 + (int)poles; 226 assert(_nFilterPairs <= maxPoles); 227 228 T span = std::max(1.0, (T)bandwidth / 2.0); 229 T wdl = std::max(1.0, cutoff - span); 230 T wdh = std::min((T)maxCutoff, cutoff + span); 231 T wal = std::tan(0.5 * (2.0 * M_PI * wdl * APP->engine->getSampleTime())); 232 T wah = std::tan(0.5 * (2.0 * M_PI * wdh * APP->engine->getSampleTime())); 233 T W = wah - wal; 234 T w02 = wah * wal; 235 const T iq = 1.0 / (0.5 * std::sqrt(2.0)); 236 237 if (mode == BAND_REJECT_MODE) { 238 T a0 = 1.0 + w02; 239 T a1 = 2.0 * w02 - 2.0; 240 T a2 = a0; 241 T i2n = 1.0 / (4.0 * _nFilterPairs); 242 for (int i = 0; i < _nFilterPairs; i += 2) { 243 T baseX = iq * 2.0 * std::cos((T)i * M_PI * i2n); 244 { 245 T x = baseX; 246 x = 0.5 * (-x + std::pow(std::max(0.0, x * x - 4.0), 0.5)); 247 T b0 = -x + W - x * w02; 248 T b1 = 2.0 * x - 2.0 * x * w02; 249 T b2 = -x - W - x * w02; 250 _filters[i].setParams(a0, a1, a2, b0, b1, b2); 251 } 252 { 253 T x = baseX; 254 x = 0.5 * (-x - std::pow(std::max(0.0, x * x - 4.0), 0.5)); 255 T b0 = -x + W - x * w02; 256 T b1 = 2.0 * x - 2.0 * x * w02; 257 T b2 = -x - W - x * w02; 258 _filters[i + 1].setParams(a0, a1, a2, b0, b1, b2); 259 } 260 } 261 } 262 else { 263 T a0 = W; 264 T a1 = 0.0; 265 T a2 = -W; 266 T i2n = 1.0 / (4.0 * _nFilterPairs); 267 for (int i = 0; i < _nFilterPairs; i += 2) { 268 T baseX = iq * 2.0 * std::cos((T)i * M_PI * i2n); 269 { 270 T x = baseX; 271 x = 0.5 * (-x + std::pow(std::max(0.0, x * x - 4.0), 0.5)); 272 T b0 = 1.0 - x * W + w02; 273 T b1 = -2.0 + 2.0 * w02; 274 T b2 = 1.0 + x * W + w02; 275 _filters[i].setParams(a0, a1, a2, b0, b1, b2); 276 } 277 { 278 T x = baseX; 279 x = 0.5 * (-x - std::pow(std::max(0.0, x * x - 4.0), 0.5)); 280 T b0 = 1.0 - x * W + w02; 281 T b1 = -2.0 + 2.0 * w02; 282 T b2 = 1.0 + x * W + w02; 283 _filters[i + 1].setParams(a0, a1, a2, b0, b1, b2); 284 } 285 } 286 } 287 } 288 289 template<typename T> 290 float TestVCF::BandButterworthModel<T>::next(float sample) { 291 for (int i = 0; i < _nFilterPairs; i += 2) { 292 sample = _filters[i].next(sample); 293 sample = _filters[i + 1].next(sample); 294 } 295 return sample; 296 } 297 298 template<typename T> 299 void TestVCF::QuarticBandButterworthModel<T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 300 _nFilters = 1 + (int)poles; 301 assert(_nFilters <= maxPoles / 2); 302 303 T span = std::max(1.0l, (T)bandwidth / 2.0); 304 T wdl = std::max(1.0l, cutoff - span); 305 T wdh = std::min((T)maxCutoff, cutoff + span); 306 T wal = std::tan(0.5 * (2.0 * M_PI * wdl * APP->engine->getSampleTime())); 307 T wah = std::tan(0.5 * (2.0 * M_PI * wdh * APP->engine->getSampleTime())); 308 T W = wah - wal; 309 T W2 = W * W; 310 T w02 = wah * wal; 311 T w04 = w02 * w02; 312 const T iq = 1.0 / (0.5 * std::sqrt(2.0)); 313 314 T a0 = W2; 315 T a1 = 0.0; 316 T a2 = -2.0 * W2; 317 T a3 = 0.0; 318 T a4 = W2; 319 320 T i2n = 1.0 / (4.0 * _nFilters); 321 for (int i = 0; i < _nFilters; ++i) { 322 T x = iq * 2.0 * std::cos((T)i * M_PI * i2n); 323 T xW = x * W; 324 T W2w02 = W2 + 2.0 * w02; 325 T xWw02 = xW * w02; 326 T b0 = +1.0 + +1.0 * xW + +1.0 * W2w02 + +1.0 * xWw02 + +1.0 * w04; 327 T b1 = -4.0 + -2.0 * xW + +0.0 * W2w02 + +2.0 * xWw02 + +4.0 * w04; 328 T b2 = +6.0 + +0.0 * xW + -2.0 * W2w02 + +0.0 * xWw02 + +6.0 * w04; 329 T b3 = -4.0 + +2.0 * xW + +0.0 * W2w02 + -2.0 * xWw02 + +4.0 * w04; 330 T b4 = +1.0 + +1.0 * xW + +1.0 * W2w02 + -1.0 * xWw02 + +1.0 * w04; 331 _filters[i].setParams(a0, a1, a2, a3, a4, b0, b1, b2, b3, b4); 332 } 333 } 334 335 template<typename T> 336 float TestVCF::QuarticBandButterworthModel<T>::next(float sample) { 337 for (int i = 0; i < _nFilters; ++i) { 338 sample = _filters[i].next(sample); 339 } 340 return sample; 341 } 342 343 void TestVCF::AllPassModel::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 344 float tq = std::tan(resonance * M_PI * APP->engine->getSampleTime()); 345 float alpha = (tq - 1.0f) / (tq + 1.0f); 346 float beta = -std::cos(2.0f * M_PI * cutoff * APP->engine->getSampleTime()); 347 float a1 = beta * (1.0f - alpha); 348 _filter.setParams( 349 -alpha, 350 a1, 351 1.0f, 352 1.0f, 353 a1, 354 -alpha 355 ); 356 } 357 358 float TestVCF::AllPassModel::next(float sample) { 359 return _filter.next(sample); 360 } 361 362 363 template<typename T> 364 void TestVCF::ChebyshevModel<T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 365 switch (mode) { 366 case BANDPASS_MODE: 367 case BAND_REJECT_MODE: { 368 setParamsBPBR(cutoff, bandwidth, resonance, mode, poles, topology); 369 break; 370 } 371 default: { 372 setParamsLPHP(cutoff, bandwidth, resonance, mode, poles, topology); 373 } 374 } 375 } 376 377 template<typename T> 378 void TestVCF::ChebyshevModel<T>::setParamsLPHP(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 379 int nf = 1 + (int)poles; 380 assert(nf <= maxPoles / 2); 381 for (int i = _nFilters; i < nf; ++i) { 382 _filters[i].reset(); 383 } 384 _nFilters = nf; 385 int nPoles = 2 * _nFilters; 386 387 cutoff = std::max(2.0f, cutoff); // FIXME: another way to avoid DC exploding near 0 hz? 388 T iq = (1.0 / std::sqrt(2.0)) - 0.65 * resonance; // / (1.0 + std::pow(0.6 * std::log((float)_nFilters), 2.0)); // FIXME 389 T wa = std::tan(0.5 * (2.0 * M_PI * cutoff * APP->engine->getSampleTime())); 390 391 T ripple = 3.0 + std::max(0.0, 12.0 * resonance); 392 if (topology >= 0.5) { 393 T e = ripple / 10.0; 394 e = std::pow(10.0, e); 395 e -= 1.0f; 396 e = std::sqrt(e); 397 T ef = std::asinh(1.0 / e) / (float)nPoles; 398 399 // _outGain = 1.0f / (std::pow(2.0, (T)(nPoles - 1)) * e); 400 _outGain = 1.0f / std::pow(2.0, (T)(nPoles - 1)); 401 402 for (int i = 0, fi = 0; i < _nFilters; ++i) { 403 int k = i + 1; 404 T a = ((T)(2 * k + nPoles - 1)) * M_PI / (T)(2 * nPoles); 405 T re = -std::sinh(ef) * std::sin(a); 406 T im = std::cosh(ef) * std::cos(a); 407 T x = 2.0 * re; 408 T y = re * re + im * im; 409 // fi += polesToFilters(mode, _filters + fi, x, y, wa, 0.0, 0.0); 410 polesToFilterLPHP(mode, _filters[fi], x, y, wa); 411 ++fi; 412 } 413 } 414 else { 415 _outGain = 1.0f; 416 417 for (int i = 0, fi = 0; i < _nFilters; ++i) { 418 int k = i + 1; 419 T a = ((T)(2 * k + nPoles - 1)) * M_PI / (T)(2 * nPoles); 420 T re = std::cos(a); 421 T im = std::sin(a); 422 T x = (i == _nFilters / 2 ? iq : 1.0) * 2.0 * re; 423 T y = re * re + im * im; 424 // fi += polesToFilters(mode, _filters + fi, x, y, wa, 0.0, 0.0); 425 polesToFilterLPHP(mode, _filters[fi], x, y, wa); 426 ++fi; 427 } 428 } 429 } 430 431 template<typename T> 432 void TestVCF::ChebyshevModel<T>::setParamsBPBR(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 433 int nf = 2 * (1 + (int)poles); 434 assert(nf <= maxPoles); 435 for (int i = _nFilters; i < nf; ++i) { 436 _filters[i].reset(); 437 } 438 _nFilters = nf; 439 int nPoles = _nFilters; 440 441 T span = std::max(1.0, (T)bandwidth / 2.0); 442 T wdl = std::max(1.0, cutoff - span); 443 T wdh = std::min((T)maxCutoff, cutoff + span); 444 T wal = std::tan(0.5 * (2.0 * M_PI * wdl * APP->engine->getSampleTime())); 445 T wah = std::tan(0.5 * (2.0 * M_PI * wdh * APP->engine->getSampleTime())); 446 T W = wah - wal; 447 T w02 = wah * wal; 448 // const T iq = 1.0 / (0.5 * std::sqrt(2.0)); 449 // const T iq = 0.707; 450 451 T ripple = 3.0; // + std::max(0.0, 12.0 * resonance); 452 if (topology >= 0.5) { 453 T e = ripple / 10.0; 454 e = std::pow(10.0, e); 455 e -= 1.0f; 456 e = std::sqrt(e); 457 T ef = std::asinh(1.0 / e) / (float)nPoles; 458 459 // _outGain = 1.0f / (std::pow(2.0, (T)(nPoles - 1)) * e); 460 _outGain = 1.0f / std::pow(2.0, (T)(nPoles - 1)); 461 462 for (int i = 0, fi = 0, n = _nFilters / 2; i < n; ++i) { 463 int k = i + 1; 464 T a = ((T)(2 * k + nPoles - 1)) * M_PI / (T)(2 * nPoles); 465 T re = -std::sinh(ef) * std::sin(a); 466 T im = std::cosh(ef) * std::cos(a); 467 // T x = 2.0 * re; 468 // T y = re * re + im * im; 469 // fi += polesToFilters(mode, _filters + fi, x, y, 0.0, W, w02); 470 polesToFiltersBPBR(mode, _filters[fi], _filters[fi + 1], re, im, W, w02); 471 fi += 2; 472 } 473 } 474 else { 475 _outGain = 1.0f; 476 477 for (int i = 0, fi = 0, n = _nFilters / 2; i < n; ++i) { 478 int k = i + 1; 479 T a = ((T)(2 * k + nPoles - 1)) * M_PI / (T)(2 * nPoles); 480 T re = std::cos(a); 481 T im = std::sin(a); 482 // T x = iq * 2.0 * re; 483 // T y = re * re + im * im; 484 // fi += polesToFilters(mode, _filters + fi, x, y, 0.0, W, w02); 485 polesToFiltersBPBR(mode, _filters[fi], _filters[fi + 1], re, im, W, w02); 486 fi += 2; 487 } 488 } 489 } 490 491 template<typename T> 492 int TestVCF::ChebyshevModel<T>::polesToFilters(Mode mode, BiquadFilter<T>* fs, T x, T y, T wa, T W, T w02) { 493 switch (mode) { 494 case BANDPASS_MODE: { 495 // y = 1.0; 496 x = -x; 497 T a0 = W; 498 T a1 = 0.0; 499 T a2 = -W; 500 // x = 0.5 * (-x + std::pow(std::max(0.0, x * x - 4.0), 0.5)); 501 T rt = std::sqrt(std::max(0.0, x * x - 4.0 * y)); 502 { 503 T xx = 0.5 * (-x + rt); 504 T b0 = 1.0 - xx * W + w02; 505 T b1 = -2.0 + 2.0 * w02; 506 T b2 = 1.0 + xx * W + w02; 507 fs[0].setParams(a0, a1, a2, b0, b1, b2); 508 } 509 { 510 T xx = 0.5 * (-x - rt); 511 T b0 = 1.0 - xx * W + w02; 512 T b1 = -2.0 + 2.0 * w02; 513 T b2 = 1.0 + xx * W + w02; 514 fs[1].setParams(a0, a1, a2, b0, b1, b2); 515 } 516 return 2; 517 } 518 519 case BAND_REJECT_MODE: { 520 x = -x; 521 T a0 = 1.0 + w02; 522 T a1 = 2.0 * w02 - 2.0; 523 T a2 = a0; 524 T rt = std::sqrt(std::max(0.0, x * x - 4.0 * y)); 525 { 526 T xx = 0.5 * (-x + rt); 527 T b0 = -xx + W - xx * w02; 528 T b1 = 2.0 * xx - 2.0 * xx * w02; 529 T b2 = -xx - W - xx * w02; 530 fs[0].setParams(a0, a1, a2, b0, b1, b2); 531 } 532 { 533 T xx = 0.5 * (-x + rt); 534 T b0 = -xx + W - xx * w02; 535 T b1 = 2.0 * xx - 2.0 * xx * w02; 536 T b2 = -xx - W - xx * w02; 537 fs[1].setParams(a0, a1, a2, b0, b1, b2); 538 } 539 return 2; 540 } 541 542 case HIGHPASS_MODE: { 543 T wa2 = wa * wa; 544 T a0 = 1.0; 545 T a1 = -2.0f; 546 T a2 = 1.0; 547 T b0 = wa2 - x * wa + y; 548 T b1 = 2.0 * wa2 - 2.0 * y; 549 T b2 = wa2 + x * wa + y; 550 fs[0].setParams(a0, a1, a2, b0, b1, b2); 551 return 1; 552 } 553 554 default: { 555 T wa2 = wa * wa; 556 T a0 = wa2; 557 T a1 = 2.0f * wa2; 558 T a2 = wa2; 559 T b0 = 1.0 - x * wa + y * wa2; 560 T b1 = -2.0 + 2.0 * y * wa2; 561 T b2 = 1.0 + x * wa + y * wa2; 562 fs[0].setParams(a0, a1, a2, b0, b1, b2); 563 return 1; 564 } 565 } 566 } 567 568 template<typename T> 569 void TestVCF::ChebyshevModel<T>::polesToFilterLPHP(Mode mode, BiquadFilter<T>& f, T x, T y, T wa) { 570 switch (mode) { 571 case LOWPASS_MODE: { 572 T wa2 = wa * wa; 573 T a0 = wa2; 574 T a1 = 2.0f * wa2; 575 T a2 = wa2; 576 T b0 = 1.0 - x * wa + y * wa2; 577 T b1 = -2.0 + 2.0 * y * wa2; 578 T b2 = 1.0 + x * wa + y * wa2; 579 f.setParams(a0, a1, a2, b0, b1, b2); 580 break; 581 } 582 583 case HIGHPASS_MODE: { 584 T wa2 = wa * wa; 585 T a0 = 1.0; 586 T a1 = -2.0f; 587 T a2 = 1.0; 588 T b0 = wa2 - x * wa + y; 589 T b1 = 2.0 * wa2 - 2.0 * y; 590 T b2 = wa2 + x * wa + y; 591 f.setParams(a0, a1, a2, b0, b1, b2); 592 break; 593 } 594 595 default: { 596 assert(false); 597 } 598 } 599 } 600 601 template<typename T> 602 void TestVCF::ChebyshevModel<T>::polesToFiltersBPBR(Mode mode, BiquadFilter<T>& f0, BiquadFilter<T>& f1, T re, T im, T W, T w02) { 603 typedef std::complex<T> TC; 604 switch (mode) { 605 case BANDPASS_MODE: { 606 // TC pole(-re, im); 607 // TC poleW2 = pole * W * 0.5; 608 // T R = std::abs(poleW2); 609 // T r = std::arg(poleW2); 610 // TC X = pole * pole; 611 // X *= W * W; 612 // X -= 4.0 * w02; 613 // X = std::sqrt(X); 614 // X *= 0.5; 615 // T Q = std::abs(X); 616 // T q = std::arg(X); 617 // T f = 2.0 * Q * std::cos(q); 618 // T F1a = 2.0 * R * std::cos(r); 619 // T F1b = F1a + f; 620 // F1a -= f; 621 // f = 2.0 * R * Q * std::cos(r - q); 622 // T F2a = R * R + Q * Q; 623 // T F2b = F2a + f; 624 // F2a -= f; 625 TC P(-re, im); 626 TC PC = std::conj(P); 627 TC X = P * P; 628 X *= W * W; 629 X -= 4.0 * w02; 630 X = std::sqrt(X); 631 TC XC = std::conj(X); 632 TC Y1 = (X - W * P) * 0.5; 633 TC Y1C = (XC - W * PC) * 0.5; 634 TC Y2 = (-X - W * P) * 0.5; 635 TC Y2C = (-XC - W * PC) * 0.5; 636 TC cF1a = -(Y1 + Y1C); 637 TC cF2a = Y1 * Y1C; 638 TC cF1b = -(Y2 + Y2C); 639 TC cF2b = Y2 * Y2C; 640 T F1a = std::real(cF1a); 641 T F1b = std::real(cF1b); 642 T F2a = std::real(cF2a); 643 T F2b = std::real(cF2b); 644 645 T a0 = W; 646 T a1 = 0.0; 647 T a2 = -W; 648 { 649 T b0 = 1.0 + F1a + F2a; 650 T b1 = -2.0 + 2.0 * F2a; 651 T b2 = 1.0 - F1a + F2a; 652 f0.setParams(a0, a1, a2, b0, b1, b2); 653 } 654 { 655 T b0 = 1.0 + F1b + F2b; 656 T b1 = -2.0 + 2.0 * F2b; 657 T b2 = 1.0 - F1b + F2b; 658 f1.setParams(a0, a1, a2, b0, b1, b2); 659 } 660 break; 661 } 662 663 case BAND_REJECT_MODE: { 664 TC P(-re, im); 665 TC PC = std::conj(P); 666 T R = std::abs(P); 667 TC X = P * P; 668 X *= -4.0 * w02; 669 X += W * W; 670 X = std::sqrt(X); 671 TC XC = std::conj(X); 672 TC Y1 = (X - W) / (2.0 * P); 673 TC Y1C = (XC - W) / (2.0 * PC); 674 TC Y2 = (-X - W) / (2.0 * P); 675 TC Y2C = (-XC - W) / (2.0 * PC); 676 TC cF1a = -R * (Y1 + Y1C); 677 TC cF2a = R * Y1 * Y1C; 678 TC cF1b = -R * (Y2 + Y2C); 679 TC cF2b = R * Y2 * Y2C; 680 T F1a = std::real(cF1a); 681 T F1b = std::real(cF1b); 682 T F2a = std::real(cF2a); 683 T F2b = std::real(cF2b); 684 685 T a0 = 1.0 + w02; 686 T a1 = -2.0 + 2.0 * w02; 687 T a2 = 1.0 + w02; 688 { 689 T b0 = R + F1a + F2a; 690 T b1 = -2.0 * R + 2.0 * F2a; 691 T b2 = R - F1a + F2a; 692 f0.setParams(a0, a1, a2, b0, b1, b2); 693 } 694 { 695 T b0 = R + F1b + F2b; 696 T b1 = -2.0 * R + 2.0 * F2b; 697 T b2 = R - F1b + F2b; 698 f1.setParams(a0, a1, a2, b0, b1, b2); 699 } 700 break; 701 } 702 703 default: { 704 assert(false); 705 } 706 } 707 } 708 709 template<typename T> 710 float TestVCF::ChebyshevModel<T>::next(float sample) { 711 for (int i = 0; i < _nFilters; ++i) { 712 sample = _filters[i].next(sample); 713 } 714 return _outGain * sample; 715 } 716 717 template<typename T> 718 void TestVCF::TwoPoleResonatorModel<T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 719 // T wa = std::tan(0.5 * (2.0 * M_PI * cutoff * APP->engine->getSampleTime())); 720 T wa = 2.0 * M_PI * cutoff * APP->engine->getSampleTime(); 721 T r = std::max(0.1f, 1.0f * resonance); 722 _filter.setParams(1.0, 0.0, -1.0 * r, 1.0, -2.0 * r * std::cos(wa), r * r); 723 _outGain = 1.0; // * (1.0 - r * r); 724 } 725 726 template<typename T> 727 float TestVCF::TwoPoleResonatorModel<T>::next(float sample) { 728 return _filter.next(sample) * _outGain; 729 } 730 731 template<typename M, int FACTOR> 732 void TestVCF::OversamplingModel<M, FACTOR>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 733 _model.setParams(cutoff / (float)FACTOR, bandwidth / (float)FACTOR, resonance, mode, poles, topology); 734 _interpolator.setParams(APP->engine->getSampleRate(), FACTOR); 735 _decimator.setParams(APP->engine->getSampleRate(), FACTOR); 736 } 737 738 template<typename M, int FACTOR> 739 float TestVCF::OversamplingModel<M, FACTOR>::next(float sample) { 740 float buf[FACTOR]; 741 _interpolator.next(sample, buf); 742 for (int i = 0; i < FACTOR; ++i) { 743 buf[i] = _model.next(buf[i]); 744 } 745 return _decimator.next(buf); 746 } 747 748 template<typename M> 749 void TestVCF::FeedbackModel<M>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 750 _q = resonance; 751 _model.setParams(cutoff, bandwidth, 0.0f, mode, poles, topology); 752 } 753 754 template<typename M> 755 float TestVCF::FeedbackModel<M>::next(float sample) { 756 return _last = _model.next(sample - _q * _last); 757 } 758 759 template<typename M, typename T> 760 void TestVCF::AddResonanceModel<M, T>::setParams(float cutoff, float bandwidth, float resonance, Mode mode, Poles poles, float topology) { 761 _model.setParams(cutoff, bandwidth, 0.0f, mode, poles, topology); 762 _resonator.setParams(cutoff, bandwidth, resonance * (1.0 / std::sqrt(2.0)), mode, poles, topology); 763 } 764 765 template<typename M, typename T> 766 float TestVCF::AddResonanceModel<M, T>::next(float sample) { 767 return _model.next(_resonator.next(sample)); 768 } 769 770 void TestVCF::modulate() { 771 float cutoff = maxCutoff * clamp(params[CUTOFF_PARAM].getValue(), 0.0f, 1.0f); 772 float q = clamp(params[Q_PARAM].getValue(), 0.0f, 1.0f); 773 float bandwidth = q * 10000.0f; 774 _mode = (Mode)clamp((int)params[MODE_PARAM].getValue(), 0, 3); 775 _poles = (Poles)clamp((int)params[POLES_PARAM].getValue(), 0, 5); 776 float topology = clamp(params[TOPOLOGY_PARAM].getValue(), 0.0f, 1.0f); 777 778 if (_model) { 779 _model->setParams( 780 cutoff, 781 bandwidth, 782 q, 783 _mode, 784 _poles, 785 topology 786 ); 787 } 788 if (_model2) { 789 _model2->setParams( 790 cutoff, 791 bandwidth, 792 q, 793 _mode, 794 _poles, 795 topology 796 ); 797 } 798 799 _amplifier.setLevel(Amplifier::maxDecibels * clamp(params[DRIVE_PARAM].getValue(), 0.0f, 1.0f)); 800 } 801 802 void TestVCF::processAll(const ProcessArgs& args) { 803 lights[LOWPASS_LIGHT].value = _mode == LOWPASS_MODE; 804 lights[HIGHPASS_LIGHT].value = _mode == HIGHPASS_MODE; 805 lights[BANDPASS_LIGHT].value = _mode == BANDPASS_MODE; 806 lights[BAND_REJECT_LIGHT].value = _mode == BAND_REJECT_MODE; 807 808 lights[POLES_2_LIGHT].value = _poles == POLES_2; 809 lights[POLES_4_LIGHT].value = _poles == POLES_4; 810 lights[POLES_6_LIGHT].value = _poles == POLES_6; 811 lights[POLES_8_LIGHT].value = _poles == POLES_8; 812 lights[POLES_10_LIGHT].value = _poles == POLES_10; 813 lights[POLES_12_LIGHT].value = _poles == POLES_12; 814 815 float in = inputs[IN_INPUT].getVoltage(); 816 in = _amplifier.next(in); 817 if (_model) { 818 float out = _model->next(in); 819 out = _saturator.next(out); 820 outputs[OUT_OUTPUT].setVoltage(out); 821 } 822 if (_model2) { 823 float out = _model2->next(in); 824 out = _saturator2.next(out); 825 outputs[OUT_B_OUTPUT].setVoltage(out); 826 } 827 } 828 829 struct TestVCFWidget : BGModuleWidget { 830 static constexpr int hp = 12; 831 832 TestVCFWidget(TestVCF* module) { 833 setModule(module); 834 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 835 setPanel(box.size, "TestVCF"); 836 createScrews(); 837 838 // generated by svg_widgets.rb 839 auto cutoffParamPosition = Vec(40.0, 50.0); 840 auto qParamPosition = Vec(40.0, 120.0); 841 auto driveParamPosition = Vec(40.0, 190.0); 842 auto topologyParamPosition = Vec(40.0, 260.0); 843 auto modeParamPosition = Vec(145.0, 77.0); 844 auto polesParamPosition = Vec(145.0, 156.0); 845 846 auto inInputPosition = Vec(47.5, 318.0); 847 848 auto outOutputPosition = Vec(76.5, 318.0); 849 auto outBOutputPosition = Vec(105.5, 318.0); 850 851 auto lowpassLightPosition = Vec(130.0, 58.0); 852 auto highpassLightPosition = Vec(151.0, 58.0); 853 auto bandpassLightPosition = Vec(130.0, 68.0); 854 auto bandRejectLightPosition = Vec(151.0, 68.0); 855 auto poles2LightPosition = Vec(130.0, 127.0); 856 auto poles4LightPosition = Vec(151.0, 127.0); 857 auto poles6LightPosition = Vec(130.0, 137.0); 858 auto poles8LightPosition = Vec(151.0, 137.0); 859 auto poles10LightPosition = Vec(130.0, 147.0); 860 auto poles12LightPosition = Vec(151.0, 147.0); 861 // end generated by svg_widgets.rb 862 863 addParam(createParam<Knob38>(cutoffParamPosition, module, TestVCF::CUTOFF_PARAM)); 864 addParam(createParam<Knob38>(qParamPosition, module, TestVCF::Q_PARAM)); 865 addParam(createParam<Knob38>(driveParamPosition, module, TestVCF::DRIVE_PARAM)); 866 addParam(createParam<Knob38>(topologyParamPosition, module, TestVCF::TOPOLOGY_PARAM)); 867 addParam(createParam<StatefulButton9>(modeParamPosition, module, TestVCF::MODE_PARAM)); 868 addParam(createParam<StatefulButton9>(polesParamPosition, module, TestVCF::POLES_PARAM)); 869 870 addInput(createInput<Port24>(inInputPosition, module, TestVCF::IN_INPUT)); 871 872 addOutput(createOutput<Port24>(outOutputPosition, module, TestVCF::OUT_OUTPUT)); 873 addOutput(createOutput<Port24>(outBOutputPosition, module, TestVCF::OUT_B_OUTPUT)); 874 875 addChild(createLight<BGSmallLight<GreenLight>>(lowpassLightPosition, module, TestVCF::LOWPASS_LIGHT)); 876 addChild(createLight<BGSmallLight<GreenLight>>(highpassLightPosition, module, TestVCF::HIGHPASS_LIGHT)); 877 addChild(createLight<BGSmallLight<GreenLight>>(bandpassLightPosition, module, TestVCF::BANDPASS_LIGHT)); 878 addChild(createLight<BGSmallLight<GreenLight>>(bandRejectLightPosition, module, TestVCF::BAND_REJECT_LIGHT)); 879 addChild(createLight<BGSmallLight<GreenLight>>(poles2LightPosition, module, TestVCF::POLES_2_LIGHT)); 880 addChild(createLight<BGSmallLight<GreenLight>>(poles4LightPosition, module, TestVCF::POLES_4_LIGHT)); 881 addChild(createLight<BGSmallLight<GreenLight>>(poles6LightPosition, module, TestVCF::POLES_6_LIGHT)); 882 addChild(createLight<BGSmallLight<GreenLight>>(poles8LightPosition, module, TestVCF::POLES_8_LIGHT)); 883 addChild(createLight<BGSmallLight<GreenLight>>(poles10LightPosition, module, TestVCF::POLES_10_LIGHT)); 884 addChild(createLight<BGSmallLight<GreenLight>>(poles12LightPosition, module, TestVCF::POLES_12_LIGHT)); 885 } 886 }; 887 888 Model* modelTestVCF = createModel<TestVCF, TestVCFWidget>("Bogaudio-TestVCF", "TestVCF", "Test VCF");