minilogue xd SDK  v1.1-0
biquad.hpp
Go to the documentation of this file.
1 #pragma once
2 /*
3  BSD 3-Clause License
4 
5  Copyright (c) 2018, KORG INC.
6  All rights reserved.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  * Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 
14  * Redistributions in binary form must reproduce the above copyright notice,
15  this list of conditions and the following disclaimer in the documentation
16  and/or other materials provided with the distribution.
17 
18  * Neither the name of the copyright holder nor the names of its
19  contributors may be used to endorse or promote products derived from
20  this software without specific prior written permission.
21 
22  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 //*/
34 
44 #include "float_math.h"
45 
49 namespace dsp {
50 
54  struct BiQuad {
55 
56  // Transposed Form 2
57 
58  /*=====================================================================*/
59  /* Types and Data Structures. */
60  /*=====================================================================*/
61 
65  typedef struct Coeffs {
66  float ff0;
67  float ff1;
68  float ff2;
69  float fb1;
70  float fb2;
71 
75  Coeffs() :
76  ff0(0), ff1(0), ff2(0),
77  fb1(0), fb2(0)
78  { }
79 
80  // -- Pre-calculations -------------------
81 
88  static inline __attribute__((optimize("Ofast"),always_inline))
89  float wc(const float fc, const float fsrecip) {
90  return fc * fsrecip;
91  }
92 
93  // -- Filter types -----------------------
94 
100  inline __attribute__((optimize("Ofast"),always_inline))
101  void setPoleLP(const float pole) {
102  ff0 = 1.f - pole;
103  fb1 = -pole;
104  fb2 = ff2 = ff1 = 0.f;
105  }
106 
112  inline __attribute__((optimize("Ofast"),always_inline))
113  void setPoleHP(const float pole) {
114  ff0 = 1.f - pole;
115  fb1 = pole;
116  fb2 = ff2 = ff1 = 0.f;
117  }
118 
124  inline __attribute__((optimize("Ofast"),always_inline))
125  void setFODC(const float pole) {
126  ff0 = 1.f;
127  ff1 = -1.f;
128  fb1 = -pole;
129  fb2 = ff2 = 0.f;
130  }
131 
137  inline __attribute__((optimize("Ofast"),always_inline))
138  void setFOLP(const float k) {
139  const float kp1 = k+1.f;
140  const float km1 = k-1.f;
141  ff0 = ff1 = k / kp1;
142  fb1 = km1 / kp1;
143  fb2 = ff2 = 0.f;
144  }
145 
151  inline __attribute__((optimize("Ofast"),always_inline))
152  void setFOHP(const float k) {
153  // k = tan(pi*wc)
154  const float kp1 = k+1.f;
155  const float km1 = k-1.f;
156  ff0 = 1.f / kp1;
157  ff1 = -ff0;
158  fb1 = km1 / kp1;
159  fb2 = ff2 = 0.f;
160  }
161 
167  inline __attribute__((optimize("Ofast"),always_inline))
168  void setFOAP(const float k) {
169  // k = tan(pi*wc)
170  const float kp1 = k+1.f;
171  const float km1 = k-1.f;
172  ff0 = fb1 = km1 / kp1;
173  ff1 = 1.f;
174  fb2 = ff2 = 0.f;
175  }
176 
184  inline __attribute__((optimize("Ofast"),always_inline))
185  void setFOAP2(const float wc) {
186  // Note: alternative implementation for use in phasers
187  const float g1 = 1.f - wc;
188  ff0 = g1;
189  ff1 = -1;
190  fb1 = -g1;
191  fb2 = ff2 = 0.f;
192  }
193 
199  inline __attribute__((optimize("Ofast"),always_inline))
200  void setSODC(const float pole) {
201  ff0 = ff2 = 1.f;
202  ff1 = 2.f;
203  fb1 = -2.f * pole;
204  fb2 = pole * pole;
205  }
206 
213  inline __attribute__((optimize("Ofast"),always_inline))
214  void setSOLP(const float k, const float q) {
215  // k = tan(pi*wc)
216  // flat response at q = sqrt(2)
217  const float qk2 = q * k * k;
218  const float qk2_k_q_r = 1.f / (qk2 + k + q);
219  ff0 = ff2 = qk2 * qk2_k_q_r;
220  ff1 = 2.f * ff0;
221  fb1 = 2.f * (qk2 - q) * qk2_k_q_r;
222  fb2 = (qk2 - k + q) * qk2_k_q_r;
223  }
224 
231  inline __attribute__((optimize("Ofast"),always_inline))
232  void setSOHP(const float k, const float q) {
233  // k = tan(pi*wc)
234  // flat response at q = sqrt(2)
235  const float qk2 = q * k * k;
236  const float qk2_k_q_r = 1.f / (qk2 + k + q);
237  ff0 = ff2 = q * qk2_k_q_r;
238  ff1 = -2.f * ff0;
239  fb1 = 2.f * (qk2 - q) * qk2_k_q_r;
240  fb2 = (qk2 - k + q) * qk2_k_q_r;
241  }
242 
249  inline __attribute__((optimize("Ofast"),always_inline))
250  void setSOBP(const float k, const float q) {
251  // k = tan(pi*wc)
252  // q is inverse of relative bandwidth (Fc / Fb)
253  const float qk2 = q * k * k;
254  const float qk2_k_q_r = 1.f / (qk2 + k + q);
255  ff0 = k * qk2_k_q_r;
256  ff1 = 0.f;
257  ff2 = -ff0;
258  fb1 = 2.f * (qk2 - q) * qk2_k_q_r;
259  fb2 = (qk2 - k + q) * qk2_k_q_r;
260  }
261 
268  inline __attribute__((optimize("Ofast"),always_inline))
269  void setSOBR(const float k, const float q) {
270  // k = tan(pi*wc)
271  // q is inverse of relative bandwidth (Fc / Fb)
272  const float qk2 = q * k * k;
273  const float qk2_k_q_r = 1.f / (qk2 + k + q);
274  ff0 = ff2 = (qk2 + q) * qk2_k_q_r;
275  ff1 = fb1 = 2.f * (qk2 - q) * qk2_k_q_r;
276  fb2 = (qk2 - k + q) * qk2_k_q_r;
277  }
278 
285  inline __attribute__((optimize("Ofast"),always_inline))
286  void setSOAP1(const float k, const float q) {
287  // k = tan(pi*wc)
288  // q is inverse of relative bandwidth (Fc / Fb)
289  const float qk2 = q * k * k;
290  const float qk2_k_q_r = 1.f / (qk2 + k + q);
291  ff0 = fb2 = (qk2 - k + q) * qk2_k_q_r;
292  ff1 = fb1 = 2.f * (qk2 - q) * qk2_k_q_r;
293  ff2 = 1.f;
294  }
295 
305  inline __attribute__((optimize("Ofast"),always_inline))
306  void setSOAP2(const float delta, const float gamma) {
307  // Note: Alternative implementation .. so called "tunable" in DAFX.
308  // delta = cos(2pi*wc)
309  const float c = (gamma - 1.f) / (gamma + 1.f);
310  const float d = -delta;
311  ff0 = fb2 = -c;
312  ff1 = fb1 = d * (1.f - c);
313  ff2 = 1.f;
314  }
315 
324  inline __attribute__((optimize("Ofast"),always_inline))
325  void setSOAP3(const float delta, const float radius) {
326  // Note: alternative implementation for use in phasers
327  // delta = cos(2pi * wc)
328  const float a1 = -2.f * radius * delta;
329  const float a2 = radius * radius;
330  ff0 = fb2 = a2;
331  ff1 = fb1 = a1;
332  ff2 = 1.f;
333  }
334 
335  } Coeffs;
336 
337  /*=====================================================================*/
338  /* Constructor / Destructor. */
339  /*=====================================================================*/
340 
344  BiQuad(void) : mZ1(0), mZ2(0)
345  { }
346 
347  /*=====================================================================*/
348  /* Public Methods. */
349  /*=====================================================================*/
350 
354  inline __attribute__((optimize("Ofast"),always_inline))
355  void flush(void) {
356  mZ1 = mZ2 = 0;
357  }
358 
366  inline __attribute__((optimize("Ofast"),always_inline))
367  float process_so(const float xn) {
368  float acc = mCoeffs.ff0 * xn + mZ1;
369  mZ1 = mCoeffs.ff1 * xn + mZ2;
370  mZ2 = mCoeffs.ff2 * xn;
371  mZ1 -= mCoeffs.fb1 * acc;
372  mZ2 -= mCoeffs.fb2 * acc;
373  return acc;
374  }
375 
383  inline __attribute__((optimize("Ofast"),always_inline))
384  float process_fo(const float xn) {
385  float acc = mCoeffs.ff0 * xn + mZ1;
386  mZ1 = mCoeffs.ff1 * xn;
387  mZ1 -= mCoeffs.fb1 * acc;
388  return acc;
389  }
390 
398  inline __attribute__((optimize("Ofast"),always_inline))
399  float process(const float xn) {
400  return process_so(xn);
401  }
402 
403  /*=====================================================================*/
404  /* Member Variables. */
405  /*=====================================================================*/
406 
409  float mZ1, mZ2;
410  };
411 
415  struct ExtBiQuad {
416  // Extended BiQuad structure
417 
418  /*=====================================================================*/
419  /* Types and Data Structures. */
420  /*=====================================================================*/
421 
422  /*=====================================================================*/
423  /* Constructor / Destructor. */
424  /*=====================================================================*/
425 
429  ExtBiQuad(void) :
430  mZ1(0), mZ2(0),
431  mD0(0), mD1(0),
432  mW0(0), mW1(0)
433  { }
434 
435  /*=====================================================================*/
436  /* Public Methods. */
437  /*=====================================================================*/
438 
442  inline __attribute__((optimize("Ofast"),always_inline))
443  void flush(void) {
444  mZ1 = mZ2 = 0;
445  }
446 
454  inline __attribute__((optimize("Ofast"),always_inline))
455  float process_so(const float xn) {
456  float acc = mCoeffs.ff0 * xn + mZ1;
457  mZ1 = mCoeffs.ff1 * xn + mZ2;
458  mZ2 = mCoeffs.ff2 * xn;
459  mZ1 -= mCoeffs.fb1 * acc;
460  mZ2 -= mCoeffs.fb2 * acc;
461  return mW1 * (mW0 * acc + mD0 * xn) + mD1 * xn;
462  }
463 
471  inline __attribute__((optimize("Ofast"),always_inline))
472  float process_fo(const float xn) {
473  float acc = mCoeffs.ff0 * xn + mZ1;
474  mZ1 = mCoeffs.ff1 * xn;
475  mZ1 -= mCoeffs.fb1 * acc;
476  return mW1 * (mW0 * acc + mD0 * xn) + mD1 * xn;
477  }
478 
486  inline __attribute__((optimize("Ofast"),always_inline))
487  float process(const float xn) {
488  return process_so(xn);
489  }
490 
491  // -- Invertable All-Pass based Low/High Pass -------
492 
498  inline __attribute__((optimize("Ofast"),always_inline))
499  void setFOAPLP(const float k) {
500  // k = tan(pi*wc)
501  mCoeffs.setFOAP(k);
502  mD0 = mW0 = 0.5f;
503  mD1 = 0.f;
504  mW1 = 1.f;
505  }
506 
512  inline __attribute__((optimize("Ofast"),always_inline))
513  void setFOAPHP(const float k) {
514  // k = tan(pi*wc)
515  mCoeffs.setFOAP(k);
516  mD0 = 0.5f;
517  mW0 = -0.5f;
518  mD1 = 0.f;
519  mW1 = 1.f;
520  }
521 
525  inline __attribute__((optimize("Ofast"),always_inline))
526  void toggleFOLPHP(void) {
527  mW0 = -mW0;
528  }
529 
535  inline __attribute__((optimize("Ofast"),always_inline))
536  void updateFOLPHP(const float k) {
537  mCoeffs.setFOAP(k);
538  }
539 
540  // -- All-Pass based Low/High Shelf -----------------
541 
548  inline __attribute__((optimize("Ofast"),always_inline))
549  void setFOLS(const float k, const float gain) {
550  // k = tan(pi*wc)
551  // gain = raw amplitude (pre converted from dB)
552  const float h = gain - 1.f;
553  const float g = (gain >= 1.f) ? 1.f : gain;
554  mCoeffs.ff0 = mCoeffs.fb1 = (k - g) / (k + g);
555  mCoeffs.ff1 = 1.f;
556  mCoeffs.fb2 = mCoeffs.ff2 = 0.f;
557 
558  mW0 = 1.f;
559  mD0 = 1.f;
560 
561  mW1 = 0.5f * h;
562  mD1 = 1.f;
563  }
564 
571  inline __attribute__((optimize("Ofast"),always_inline))
572  void setFOHS(const float k, const float gain) {
573  // k = tan(pi*wc)
574  // gain = raw amplitude (pre converted from dB)
575  const float h = gain - 1.f;
576  const float gk = (gain >= 1.f) ? k : gain*k;
577  mCoeffs.ff0 = mCoeffs.fb1 = (gk - 1.f) / (gk + 1);
578  mCoeffs.ff1 = 1.f;
579  mCoeffs.fb2 = mCoeffs.ff2 = 0.f;
580 
581  mW0 = -1.f;
582  mD0 = 1.f;
583 
584  mW1 = 0.5f * h;
585  mD1 = 1.f;
586  }
587 
588  // TODO: second order shelves
589 
590  // -- All-Pass based Band Pass/Reject -------------
599  inline __attribute__((optimize("Ofast"),always_inline))
600  void setSOAPBR2(const float delta, const float gamma) {
601  // Alternative implementation based on second order tunable all pass
602  // delta = cos(2pi*wc)
603  mCoeffs.setSOAP2(delta, gamma);
604 
605  mW0 = 1.f;
606  mD0 = 1.f;
607 
608  mW1 = 0.5f;
609  mD1 = 0.f;
610  }
611 
620  inline __attribute__((optimize("Ofast"),always_inline))
621  void setSOAPBP2(const float delta, const float gamma) {
622  // Alternative implementation based on second order tunable all pass
623  // delta = cos(2pi*wc)
624  mCoeffs.setSOAP2(delta, gamma);
625 
626  mW0 = -1.f;
627  mD0 = 1.f;
628 
629  mW1 = 0.5f;
630  mD1 = 0.f;
631  }
632 
633  // -- All-Pass based Peak/Notch -------------
643  inline __attribute__((optimize("Ofast"),always_inline))
644  void setSOAPPN2(const float delta, const float gamma, const float gain) {
645  // Alternative implementation based on second order tunable all pass
646  // delta = cos(2pi*wc)
647 
648  const float h = gain - 1.f;
649  const float g = (gain >= 1.f) ? 1.f : gain;
650 
651  const float c = (gamma - g) / (gamma + g);
652  const float d = -delta;
653 
654  mCoeffs.ff0 = mCoeffs.fb2 = -c;
655  mCoeffs.ff1 = mCoeffs.fb1 = d * (1.f - c);
656  mCoeffs.ff2 = 1.f;
657 
658  mW0 = -1.f;
659  mD0 = 1.f;
660 
661  mW1 = 0.5f * h;
662  mD1 = 1.f;
663  }
664 
665  /*=====================================================================*/
666  /* Member Variables. */
667  /*=====================================================================*/
668 
671  float mD0, mD1, mW0, mW1;
672  float mZ1, mZ2;
673  };
674 }
675 
dsp::BiQuad::Coeffs
struct dsp::BiQuad::Coeffs Coeffs
Filter coefficients.
dsp::ExtBiQuad
Extended transposed form 2 Bi-Quad construct.
Definition: biquad.hpp:415
dsp::ExtBiQuad::process_so
float process_so(const float xn)
Second order processing of one sample.
Definition: biquad.hpp:455
dsp::ExtBiQuad::mCoeffs
BiQuad::Coeffs mCoeffs
Coefficients for the Bi-Quad construct.
Definition: biquad.hpp:670
dsp::ExtBiQuad::setSOAPPN2
void setSOAPPN2(const float delta, const float gamma, const float gain)
Calculate coefficients for second order all pass based peak/notch filter.
Definition: biquad.hpp:644
dsp::BiQuad::Coeffs
Filter coefficients.
Definition: biquad.hpp:65
dsp::BiQuad::Coeffs::setFOAP2
void setFOAP2(const float wc)
Calculate coefficients for first order all pass filter.
Definition: biquad.hpp:185
dsp::BiQuad::Coeffs::setSOAP2
void setSOAP2(const float delta, const float gamma)
Calculate coefficients for second order all pass filter.
Definition: biquad.hpp:306
dsp::BiQuad::Coeffs::setSOBR
void setSOBR(const float k, const float q)
Calculate coefficients for second order band reject filter.
Definition: biquad.hpp:269
float_math.h
Floating Point Math Utilities.
dsp::BiQuad::Coeffs::setSODC
void setSODC(const float pole)
Calculate coefficients for second order DC filter.
Definition: biquad.hpp:200
dsp::ExtBiQuad::setSOAPBP2
void setSOAPBP2(const float delta, const float gamma)
Calculate coefficients for second order all pass based band pass filter.
Definition: biquad.hpp:621
dsp::BiQuad::Coeffs::setSOLP
void setSOLP(const float k, const float q)
Calculate coefficients for second order low pass filter.
Definition: biquad.hpp:214
dsp::BiQuad::process_fo
float process_fo(const float xn)
First order processing of one sample.
Definition: biquad.hpp:384
dsp::ExtBiQuad::setFOHS
void setFOHS(const float k, const float gain)
Calculate coefficients for first order all pass based high shelf filter.
Definition: biquad.hpp:572
dsp::BiQuad::Coeffs::wc
static float wc(const float fc, const float fsrecip)
Convert Hz frequency to radians.
Definition: biquad.hpp:89
dsp::BiQuad::Coeffs::setFOLP
void setFOLP(const float k)
Calculate coefficients for first order low pass filter.
Definition: biquad.hpp:138
dsp::ExtBiQuad::setSOAPBR2
void setSOAPBR2(const float delta, const float gamma)
Calculate coefficients for second order all pass based band reject filter.
Definition: biquad.hpp:600
dsp::BiQuad::Coeffs::Coeffs
Coeffs()
Default constructor.
Definition: biquad.hpp:75
dsp::BiQuad::Coeffs::setSOHP
void setSOHP(const float k, const float q)
Calculate coefficients for second order high pass filter.
Definition: biquad.hpp:232
dsp::BiQuad::process_so
float process_so(const float xn)
Second order processing of one sample.
Definition: biquad.hpp:367
dsp::BiQuad::mCoeffs
Coeffs mCoeffs
Coefficients for the Bi-Quad construct.
Definition: biquad.hpp:408
dsp::ExtBiQuad::setFOAPLP
void setFOAPLP(const float k)
Calculate coefficients for "invertable" all pass based low pass filter.
Definition: biquad.hpp:499
dsp::ExtBiQuad::flush
void flush(void)
Flush internal delays.
Definition: biquad.hpp:443
dsp::BiQuad::Coeffs::setSOAP3
void setSOAP3(const float delta, const float radius)
Calculate coefficients for second order all pass filter.
Definition: biquad.hpp:325
dsp::ExtBiQuad::process
float process(const float xn)
Default processing function (second order)
Definition: biquad.hpp:487
dsp::BiQuad::Coeffs::setFOHP
void setFOHP(const float k)
Calculate coefficients for first order high pass filter.
Definition: biquad.hpp:152
dsp::BiQuad::Coeffs::setPoleHP
void setPoleHP(const float pole)
Calculate coefficients for single pole high pass filter.
Definition: biquad.hpp:113
dsp::ExtBiQuad::toggleFOLPHP
void toggleFOLPHP(void)
Toggle "invertable" all pass based low/high pass filter to opposite mode.
Definition: biquad.hpp:526
dsp::ExtBiQuad::updateFOLPHP
void updateFOLPHP(const float k)
Update "invertable" all pass based low/high pass filter coefficients.
Definition: biquad.hpp:536
dsp::BiQuad::flush
void flush(void)
Flush internal delays.
Definition: biquad.hpp:355
dsp::ExtBiQuad::ExtBiQuad
ExtBiQuad(void)
Default constructor.
Definition: biquad.hpp:429
dsp::BiQuad::Coeffs::setPoleLP
void setPoleLP(const float pole)
Calculate coefficients for single pole low pass filter.
Definition: biquad.hpp:101
dsp::BiQuad::BiQuad
BiQuad(void)
Default constructor.
Definition: biquad.hpp:344
dsp
Common DSP Utilities.
Definition: biquad.hpp:49
dsp::BiQuad::process
float process(const float xn)
Default processing function (second order)
Definition: biquad.hpp:399
dsp::ExtBiQuad::setFOLS
void setFOLS(const float k, const float gain)
Calculate coefficients for first order all pass based low shelf filter.
Definition: biquad.hpp:549
dsp::BiQuad
Transposed form 2 Bi-Quad construct for FIR/IIR filters.
Definition: biquad.hpp:54
dsp::BiQuad::Coeffs::setSOBP
void setSOBP(const float k, const float q)
Calculate coefficients for second order band pass filter.
Definition: biquad.hpp:250
dsp::BiQuad::Coeffs::setFOAP
void setFOAP(const float k)
Calculate coefficients for first order all pass filter.
Definition: biquad.hpp:168
dsp::ExtBiQuad::process_fo
float process_fo(const float xn)
First order processing of one sample.
Definition: biquad.hpp:472
dsp::BiQuad::Coeffs::setSOAP1
void setSOAP1(const float k, const float q)
Calculate coefficients for second order all pass filter.
Definition: biquad.hpp:286
dsp::BiQuad::Coeffs::setFODC
void setFODC(const float pole)
Calculate coefficients for single pole DC filter.
Definition: biquad.hpp:125
dsp::ExtBiQuad::setFOAPHP
void setFOAPHP(const float k)
Calculate coefficients for "invertable" all pass based high pass filter.
Definition: biquad.hpp:513