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