1 // Copyright 2014 Emilie Gillet. 2 // 3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com) 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 // 23 // See http://creativecommons.org/licenses/MIT/ for more information. 24 // 25 // ----------------------------------------------------------------------------- 26 // 27 // Zero-delay-feedback filters (one pole and SVF). 28 // Naive SVF. 29 30 #ifndef STMLIB_DSP_FILTER_H_ 31 #define STMLIB_DSP_FILTER_H_ 32 33 #include "stmlib/stmlib.h" 34 35 #include <cmath> 36 #include <algorithm> 37 38 namespace stmlib { 39 40 enum FilterMode { 41 FILTER_MODE_LOW_PASS, 42 FILTER_MODE_BAND_PASS, 43 FILTER_MODE_BAND_PASS_NORMALIZED, 44 FILTER_MODE_HIGH_PASS 45 }; 46 47 enum FrequencyApproximation { 48 FREQUENCY_EXACT, 49 FREQUENCY_ACCURATE, 50 FREQUENCY_FAST, 51 FREQUENCY_DIRTY 52 }; 53 54 #define M_PI_F float(M_PI) 55 #define M_PI_POW_2 M_PI * M_PI 56 #define M_PI_POW_3 M_PI_POW_2 * M_PI 57 #define M_PI_POW_5 M_PI_POW_3 * M_PI_POW_2 58 #define M_PI_POW_7 M_PI_POW_5 * M_PI_POW_2 59 #define M_PI_POW_9 M_PI_POW_7 * M_PI_POW_2 60 #define M_PI_POW_11 M_PI_POW_9 * M_PI_POW_2 61 62 class DCBlocker { 63 public: DCBlocker()64 DCBlocker() { } ~DCBlocker()65 ~DCBlocker() { } 66 Init(float pole)67 void Init(float pole) { 68 x_ = 0.0f; 69 y_ = 0.0f; 70 pole_ = pole; 71 } 72 Process(float * in_out,size_t size)73 inline void Process(float* in_out, size_t size) { 74 float x = x_; 75 float y = y_; 76 const float pole = pole_; 77 while (size--) { 78 float old_x = x; 79 x = *in_out; 80 *in_out++ = y = y * pole + x - old_x; 81 } 82 x_ = x; 83 y_ = y; 84 } 85 86 private: 87 float pole_; 88 float x_; 89 float y_; 90 }; 91 92 class OnePole { 93 public: OnePole()94 OnePole() { } ~OnePole()95 ~OnePole() { } 96 Init()97 void Init() { 98 set_f<FREQUENCY_DIRTY>(0.01f); 99 Reset(); 100 } 101 Reset()102 void Reset() { 103 state_ = 0.0f; 104 } 105 106 template<FrequencyApproximation approximation> tan(float f)107 static inline float tan(float f) { 108 if (approximation == FREQUENCY_EXACT) { 109 // Clip coefficient to about 100. 110 f = f < 0.497f ? f : 0.497f; 111 return tanf(M_PI * f); 112 } else if (approximation == FREQUENCY_DIRTY) { 113 // Optimized for frequencies below 8kHz. 114 const float a = 3.736e-01 * M_PI_POW_3; 115 return f * (M_PI_F + a * f * f); 116 } else if (approximation == FREQUENCY_FAST) { 117 // The usual tangent approximation uses 3.1755e-01 and 2.033e-01, but 118 // the coefficients used here are optimized to minimize error for the 119 // 16Hz to 16kHz range, with a sample rate of 48kHz. 120 const float a = 3.260e-01 * M_PI_POW_3; 121 const float b = 1.823e-01 * M_PI_POW_5; 122 float f2 = f * f; 123 return f * (M_PI_F + f2 * (a + b * f2)); 124 } else if (approximation == FREQUENCY_ACCURATE) { 125 // These coefficients don't need to be tweaked for the audio range. 126 const float a = 3.333314036e-01 * M_PI_POW_3; 127 const float b = 1.333923995e-01 * M_PI_POW_5; 128 const float c = 5.33740603e-02 * M_PI_POW_7; 129 const float d = 2.900525e-03 * M_PI_POW_9; 130 const float e = 9.5168091e-03 * M_PI_POW_11; 131 float f2 = f * f; 132 return f * (M_PI_F + f2 * (a + f2 * (b + f2 * (c + f2 * (d + f2 * e))))); 133 } 134 } 135 136 // Set frequency and resonance from true units. Various approximations 137 // are available to avoid the cost of tanf. 138 template<FrequencyApproximation approximation> set_f(float f)139 inline void set_f(float f) { 140 g_ = tan<approximation>(f); 141 gi_ = 1.0f / (1.0f + g_); 142 } 143 144 template<FilterMode mode> Process(float in)145 inline float Process(float in) { 146 float lp; 147 lp = (g_ * in + state_) * gi_; 148 state_ = g_ * (in - lp) + lp; 149 150 if (mode == FILTER_MODE_LOW_PASS) { 151 return lp; 152 } else if (mode == FILTER_MODE_HIGH_PASS) { 153 return in - lp; 154 } else { 155 return 0.0f; 156 } 157 } 158 159 template<FilterMode mode> Process(float * in_out,size_t size)160 inline void Process(float* in_out, size_t size) { 161 while (size--) { 162 *in_out = Process<mode>(*in_out); 163 ++in_out; 164 } 165 } 166 167 private: 168 float g_; 169 float gi_; 170 float state_; 171 172 DISALLOW_COPY_AND_ASSIGN(OnePole); 173 }; 174 175 176 177 class Svf { 178 public: Svf()179 Svf() { } ~Svf()180 ~Svf() { } 181 Init()182 void Init() { 183 set_f_q<FREQUENCY_DIRTY>(0.01f, 100.0f); 184 Reset(); 185 } 186 Reset()187 void Reset() { 188 state_1_ = state_2_ = 0.0f; 189 } 190 191 // Copy settings from another filter. set(const Svf & f)192 inline void set(const Svf& f) { 193 g_ = f.g(); 194 r_ = f.r(); 195 h_ = f.h(); 196 } 197 198 // Set all parameters from LUT. set_g_r_h(float g,float r,float h)199 inline void set_g_r_h(float g, float r, float h) { 200 g_ = g; 201 r_ = r; 202 h_ = h; 203 } 204 205 // Set frequency and resonance coefficients from LUT, adjust remaining 206 // parameter. set_g_r(float g,float r)207 inline void set_g_r(float g, float r) { 208 g_ = g; 209 r_ = r; 210 h_ = 1.0f / (1.0f + r_ * g_ + g_ * g_); 211 } 212 213 // Set frequency from LUT, resonance in true units, adjust the rest. set_g_q(float g,float resonance)214 inline void set_g_q(float g, float resonance) { 215 g_ = g; 216 r_ = 1.0f / resonance; 217 h_ = 1.0f / (1.0f + r_ * g_ + g_ * g_); 218 } 219 220 // Set frequency and resonance from true units. Various approximations 221 // are available to avoid the cost of tanf. 222 template<FrequencyApproximation approximation> set_f_q(float f,float resonance)223 inline void set_f_q(float f, float resonance) { 224 g_ = OnePole::tan<approximation>(f); 225 r_ = 1.0f / resonance; 226 h_ = 1.0f / (1.0f + r_ * g_ + g_ * g_); 227 } 228 229 template<FilterMode mode> Process(float in)230 inline float Process(float in) { 231 float hp, bp, lp; 232 hp = (in - r_ * state_1_ - g_ * state_1_ - state_2_) * h_; 233 bp = g_ * hp + state_1_; 234 state_1_ = g_ * hp + bp; 235 lp = g_ * bp + state_2_; 236 state_2_ = g_ * bp + lp; 237 238 if (mode == FILTER_MODE_LOW_PASS) { 239 return lp; 240 } else if (mode == FILTER_MODE_BAND_PASS) { 241 return bp; 242 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 243 return bp * r_; 244 } else if (mode == FILTER_MODE_HIGH_PASS) { 245 return hp; 246 } 247 } 248 249 template<FilterMode mode_1, FilterMode mode_2> Process(float in,float * out_1,float * out_2)250 inline void Process(float in, float* out_1, float* out_2) { 251 float hp, bp, lp; 252 hp = (in - r_ * state_1_ - g_ * state_1_ - state_2_) * h_; 253 bp = g_ * hp + state_1_; 254 state_1_ = g_ * hp + bp; 255 lp = g_ * bp + state_2_; 256 state_2_ = g_ * bp + lp; 257 258 if (mode_1 == FILTER_MODE_LOW_PASS) { 259 *out_1 = lp; 260 } else if (mode_1 == FILTER_MODE_BAND_PASS) { 261 *out_1 = bp; 262 } else if (mode_1 == FILTER_MODE_BAND_PASS_NORMALIZED) { 263 *out_1 = bp * r_; 264 } else if (mode_1 == FILTER_MODE_HIGH_PASS) { 265 *out_1 = hp; 266 } 267 268 if (mode_2 == FILTER_MODE_LOW_PASS) { 269 *out_2 = lp; 270 } else if (mode_2 == FILTER_MODE_BAND_PASS) { 271 *out_2 = bp; 272 } else if (mode_2 == FILTER_MODE_BAND_PASS_NORMALIZED) { 273 *out_2 = bp * r_; 274 } else if (mode_2 == FILTER_MODE_HIGH_PASS) { 275 *out_2 = hp; 276 } 277 } 278 279 template<FilterMode mode> Process(const float * in,float * out,size_t size)280 inline void Process(const float* in, float* out, size_t size) { 281 float hp, bp, lp; 282 float state_1 = state_1_; 283 float state_2 = state_2_; 284 285 while (size--) { 286 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 287 bp = g_ * hp + state_1; 288 state_1 = g_ * hp + bp; 289 lp = g_ * bp + state_2; 290 state_2 = g_ * bp + lp; 291 292 float value; 293 if (mode == FILTER_MODE_LOW_PASS) { 294 value = lp; 295 } else if (mode == FILTER_MODE_BAND_PASS) { 296 value = bp; 297 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 298 value = bp * r_; 299 } else if (mode == FILTER_MODE_HIGH_PASS) { 300 value = hp; 301 } 302 303 *out = value; 304 ++out; 305 ++in; 306 } 307 state_1_ = state_1; 308 state_2_ = state_2; 309 } 310 311 template<FilterMode mode> ProcessAdd(const float * in,float * out,size_t size,float gain)312 inline void ProcessAdd(const float* in, float* out, size_t size, float gain) { 313 float hp, bp, lp; 314 float state_1 = state_1_; 315 float state_2 = state_2_; 316 317 while (size--) { 318 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 319 bp = g_ * hp + state_1; 320 state_1 = g_ * hp + bp; 321 lp = g_ * bp + state_2; 322 state_2 = g_ * bp + lp; 323 324 float value; 325 if (mode == FILTER_MODE_LOW_PASS) { 326 value = lp; 327 } else if (mode == FILTER_MODE_BAND_PASS) { 328 value = bp; 329 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 330 value = bp * r_; 331 } else if (mode == FILTER_MODE_HIGH_PASS) { 332 value = hp; 333 } 334 335 *out += gain * value; 336 ++out; 337 ++in; 338 } 339 state_1_ = state_1; 340 state_2_ = state_2; 341 } 342 343 template<FilterMode mode> Process(const float * in,float * out,size_t size,size_t stride)344 inline void Process(const float* in, float* out, size_t size, size_t stride) { 345 float hp, bp, lp; 346 float state_1 = state_1_; 347 float state_2 = state_2_; 348 349 while (size--) { 350 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 351 bp = g_ * hp + state_1; 352 state_1 = g_ * hp + bp; 353 lp = g_ * bp + state_2; 354 state_2 = g_ * bp + lp; 355 356 float value; 357 if (mode == FILTER_MODE_LOW_PASS) { 358 value = lp; 359 } else if (mode == FILTER_MODE_BAND_PASS) { 360 value = bp; 361 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 362 value = bp * r_; 363 } else if (mode == FILTER_MODE_HIGH_PASS) { 364 value = hp; 365 } 366 367 *out = value; 368 out += stride; 369 in += stride; 370 } 371 state_1_ = state_1; 372 state_2_ = state_2; 373 } 374 ProcessMultimode(const float * in,float * out,size_t size,float mode)375 inline void ProcessMultimode( 376 const float* in, 377 float* out, 378 size_t size, 379 float mode) { 380 float hp, bp, lp; 381 float state_1 = state_1_; 382 float state_2 = state_2_; 383 float hp_gain = mode < 0.5f ? -mode * 2.0f : -2.0f + mode * 2.0f; 384 float lp_gain = mode < 0.5f ? 1.0f - mode * 2.0f : 0.0f; 385 float bp_gain = mode < 0.5f ? 0.0f : mode * 2.0f - 1.0f; 386 while (size--) { 387 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 388 bp = g_ * hp + state_1; 389 state_1 = g_ * hp + bp; 390 lp = g_ * bp + state_2; 391 state_2 = g_ * bp + lp; 392 *out = hp_gain * hp + bp_gain * bp + lp_gain * lp; 393 ++in; 394 ++out; 395 } 396 state_1_ = state_1; 397 state_2_ = state_2; 398 } 399 ProcessMultimodeLPtoHP(const float * in,float * out,size_t size,float mode)400 inline void ProcessMultimodeLPtoHP( 401 const float* in, 402 float* out, 403 size_t size, 404 float mode) { 405 float hp, bp, lp; 406 float state_1 = state_1_; 407 float state_2 = state_2_; 408 float hp_gain = std::min(-mode * 2.0f + 1.0f, 0.0f); 409 float bp_gain = 1.0f - 2.0f * fabsf(mode - 0.5f); 410 float lp_gain = std::max(1.0f - mode * 2.0f, 0.0f); 411 while (size--) { 412 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 413 bp = g_ * hp + state_1; 414 state_1 = g_ * hp + bp; 415 lp = g_ * bp + state_2; 416 state_2 = g_ * bp + lp; 417 *out = hp_gain * hp + bp_gain * bp + lp_gain * lp; 418 ++in; 419 ++out; 420 } 421 state_1_ = state_1; 422 state_2_ = state_2; 423 } 424 425 template<FilterMode mode> Process(const float * in,float * out_1,float * out_2,size_t size,float gain_1,float gain_2)426 inline void Process( 427 const float* in, float* out_1, float* out_2, size_t size, 428 float gain_1, float gain_2) { 429 float hp, bp, lp; 430 float state_1 = state_1_; 431 float state_2 = state_2_; 432 433 while (size--) { 434 hp = (*in - r_ * state_1 - g_ * state_1 - state_2) * h_; 435 bp = g_ * hp + state_1; 436 state_1 = g_ * hp + bp; 437 lp = g_ * bp + state_2; 438 state_2 = g_ * bp + lp; 439 440 float value; 441 if (mode == FILTER_MODE_LOW_PASS) { 442 value = lp; 443 } else if (mode == FILTER_MODE_BAND_PASS) { 444 value = bp; 445 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 446 value = bp * r_; 447 } else if (mode == FILTER_MODE_HIGH_PASS) { 448 value = hp; 449 } 450 451 *out_1 += value * gain_1; 452 *out_2 += value * gain_2; 453 ++out_1; 454 ++out_2; 455 ++in; 456 } 457 state_1_ = state_1; 458 state_2_ = state_2; 459 } 460 g()461 inline float g() const { return g_; } r()462 inline float r() const { return r_; } h()463 inline float h() const { return h_; } 464 465 private: 466 float g_; 467 float r_; 468 float h_; 469 470 float state_1_; 471 float state_2_; 472 473 DISALLOW_COPY_AND_ASSIGN(Svf); 474 }; 475 476 477 478 // Naive Chamberlin SVF. 479 class NaiveSvf { 480 public: NaiveSvf()481 NaiveSvf() { } ~NaiveSvf()482 ~NaiveSvf() { } 483 Init()484 void Init() { 485 set_f_q<FREQUENCY_DIRTY>(0.01f, 100.0f); 486 Reset(); 487 } 488 Reset()489 void Reset() { 490 lp_ = bp_ = 0.0f; 491 } 492 493 // Set frequency and resonance from true units. Various approximations 494 // are available to avoid the cost of sinf. 495 template<FrequencyApproximation approximation> set_f_q(float f,float resonance)496 inline void set_f_q(float f, float resonance) { 497 f = f < 0.497f ? f : 0.497f; 498 if (approximation == FREQUENCY_EXACT) { 499 f_ = 2.0f * sinf(M_PI_F * f); 500 } else { 501 f_ = 2.0f * M_PI_F * f; 502 } 503 damp_ = 1.0f / resonance; 504 } 505 506 template<FilterMode mode> Process(float in)507 inline float Process(float in) { 508 float hp, notch, bp_normalized; 509 bp_normalized = bp_ * damp_; 510 notch = in - bp_normalized; 511 lp_ += f_ * bp_; 512 hp = notch - lp_; 513 bp_ += f_ * hp; 514 515 if (mode == FILTER_MODE_LOW_PASS) { 516 return lp_; 517 } else if (mode == FILTER_MODE_BAND_PASS) { 518 return bp_; 519 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 520 return bp_normalized; 521 } else if (mode == FILTER_MODE_HIGH_PASS) { 522 return hp; 523 } 524 } 525 lp()526 inline float lp() const { return lp_; } bp()527 inline float bp() const { return bp_; } 528 529 template<FilterMode mode> Process(const float * in,float * out,size_t size)530 inline void Process(const float* in, float* out, size_t size) { 531 float hp, notch, bp_normalized; 532 float lp = lp_; 533 float bp = bp_; 534 while (size--) { 535 bp_normalized = bp * damp_; 536 notch = *in++ - bp_normalized; 537 lp += f_ * bp; 538 hp = notch - lp; 539 bp += f_ * hp; 540 541 if (mode == FILTER_MODE_LOW_PASS) { 542 *out++ = lp; 543 } else if (mode == FILTER_MODE_BAND_PASS) { 544 *out++ = bp; 545 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 546 *out++ = bp_normalized; 547 } else if (mode == FILTER_MODE_HIGH_PASS) { 548 *out++ = hp; 549 } 550 } 551 lp_ = lp; 552 bp_ = bp; 553 } 554 Split(const float * in,float * low,float * high,size_t size)555 inline void Split(const float* in, float* low, float* high, size_t size) { 556 float hp, notch, bp_normalized; 557 float lp = lp_; 558 float bp = bp_; 559 while (size--) { 560 bp_normalized = bp * damp_; 561 notch = *in++ - bp_normalized; 562 lp += f_ * bp; 563 hp = notch - lp; 564 bp += f_ * hp; 565 *low++ = lp; 566 *high++ = hp; 567 } 568 lp_ = lp; 569 bp_ = bp; 570 } 571 572 template<FilterMode mode> Process(const float * in,float * out,size_t size,size_t decimate)573 inline void Process(const float* in, float* out, size_t size, size_t decimate) { 574 float hp, notch, bp_normalized; 575 float lp = lp_; 576 float bp = bp_; 577 size_t n = decimate - 1; 578 while (size--) { 579 bp_normalized = bp * damp_; 580 notch = *in++ - bp_normalized; 581 lp += f_ * bp; 582 hp = notch - lp; 583 bp += f_ * hp; 584 585 ++n; 586 if (n == decimate) { 587 if (mode == FILTER_MODE_LOW_PASS) { 588 *out++ = lp; 589 } else if (mode == FILTER_MODE_BAND_PASS) { 590 *out++ = bp; 591 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 592 *out++ = bp_normalized; 593 } else if (mode == FILTER_MODE_HIGH_PASS) { 594 *out++ = hp; 595 } 596 n = 0; 597 } 598 } 599 lp_ = lp; 600 bp_ = bp; 601 } 602 603 private: 604 float f_; 605 float damp_; 606 float lp_; 607 float bp_; 608 609 DISALLOW_COPY_AND_ASSIGN(NaiveSvf); 610 }; 611 612 613 614 // Modified Chamberlin SVF (Duane K. Wise) 615 // http://www.dafx.ca/proceedings/papers/p_053.pdf 616 class ModifiedSvf { 617 public: ModifiedSvf()618 ModifiedSvf() { } ~ModifiedSvf()619 ~ModifiedSvf() { } 620 Init()621 void Init() { 622 Reset(); 623 } 624 Reset()625 void Reset() { 626 lp_ = bp_ = 0.0f; 627 } 628 set_f_fq(float f,float fq)629 inline void set_f_fq(float f, float fq) { 630 f_ = f; 631 fq_ = fq; 632 x_ = 0.0f; 633 } 634 635 template<FilterMode mode> Process(const float * in,float * out,size_t size)636 inline void Process(const float* in, float* out, size_t size) { 637 float lp = lp_; 638 float bp = bp_; 639 float x = x_; 640 const float fq = fq_; 641 const float f = f_; 642 while (size--) { 643 lp += f * bp; 644 bp += -fq * bp -f * lp + *in; 645 if (mode == FILTER_MODE_BAND_PASS || 646 mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 647 bp += x; 648 } 649 x = *in++; 650 651 if (mode == FILTER_MODE_LOW_PASS) { 652 *out++ = lp * f; 653 } else if (mode == FILTER_MODE_BAND_PASS) { 654 *out++ = bp * f; 655 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 656 *out++ = bp * fq; 657 } else if (mode == FILTER_MODE_HIGH_PASS) { 658 *out++ = x - lp * f - bp * fq; 659 } 660 } 661 lp_ = lp; 662 bp_ = bp; 663 x_ = x; 664 } 665 666 private: 667 float f_; 668 float fq_; 669 float x_; 670 float lp_; 671 float bp_; 672 673 DISALLOW_COPY_AND_ASSIGN(ModifiedSvf); 674 }; 675 676 677 678 // Two passes of modified Chamberlin SVF with the same coefficients - 679 // to implement Linkwitz–Riley (Butterworth squared) crossover filters. 680 class CrossoverSvf { 681 public: CrossoverSvf()682 CrossoverSvf() { } ~CrossoverSvf()683 ~CrossoverSvf() { } 684 Init()685 void Init() { 686 Reset(); 687 } 688 Reset()689 void Reset() { 690 lp_[0] = bp_[0] = lp_[1] = bp_[1] = 0.0f; 691 x_[0] = 0.0f; 692 x_[1] = 0.0f; 693 } 694 set_f_fq(float f,float fq)695 inline void set_f_fq(float f, float fq) { 696 f_ = f; 697 fq_ = fq; 698 } 699 700 template<FilterMode mode> Process(const float * in,float * out,size_t size)701 inline void Process(const float* in, float* out, size_t size) { 702 float lp_1 = lp_[0]; 703 float bp_1 = bp_[0]; 704 float lp_2 = lp_[1]; 705 float bp_2 = bp_[1]; 706 float x_1 = x_[0]; 707 float x_2 = x_[1]; 708 const float fq = fq_; 709 const float f = f_; 710 while (size--) { 711 lp_1 += f * bp_1; 712 bp_1 += -fq * bp_1 -f * lp_1 + *in; 713 if (mode == FILTER_MODE_BAND_PASS || 714 mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 715 bp_1 += x_1; 716 } 717 x_1 = *in++; 718 719 float y; 720 if (mode == FILTER_MODE_LOW_PASS) { 721 y = lp_1 * f; 722 } else if (mode == FILTER_MODE_BAND_PASS) { 723 y = bp_1 * f; 724 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 725 y = bp_1 * fq; 726 } else if (mode == FILTER_MODE_HIGH_PASS) { 727 y = x_1 - lp_1 * f - bp_1 * fq; 728 } 729 730 lp_2 += f * bp_2; 731 bp_2 += -fq * bp_2 -f * lp_2 + y; 732 if (mode == FILTER_MODE_BAND_PASS || 733 mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 734 bp_2 += x_2; 735 } 736 x_2 = y; 737 738 if (mode == FILTER_MODE_LOW_PASS) { 739 *out++ = lp_2 * f; 740 } else if (mode == FILTER_MODE_BAND_PASS) { 741 *out++ = bp_2 * f; 742 } else if (mode == FILTER_MODE_BAND_PASS_NORMALIZED) { 743 *out++ = bp_2 * fq; 744 } else if (mode == FILTER_MODE_HIGH_PASS) { 745 *out++ = x_2 - lp_2 * f - bp_2 * fq; 746 } 747 } 748 lp_[0] = lp_1; 749 bp_[0] = bp_1; 750 lp_[1] = lp_2; 751 bp_[1] = bp_2; 752 x_[0] = x_1; 753 x_[1] = x_2; 754 } 755 756 private: 757 float f_; 758 float fq_; 759 float x_[2]; 760 float lp_[2]; 761 float bp_[2]; 762 763 DISALLOW_COPY_AND_ASSIGN(CrossoverSvf); 764 }; 765 766 } // namespace stmlib 767 768 #endif // STMLIB_DSP_FILTER_H_ 769