OpenWareLaboratory
BiquadFilter.h
Go to the documentation of this file.
1 #ifndef __BiquadFilter_h__
2 #define __BiquadFilter_h__
3 
4 #include <string.h> // for memcpy
5 #include "FloatArray.h"
6 #include "SignalProcessor.h"
7 
8 class FilterStage {
9 public:
12  static constexpr float BESSEL_Q = 0.57735026919f; // 1/sqrt(3)
13  static constexpr float SALLEN_KEY_Q = 0.5f; // 1/2
14  static constexpr float BUTTERWORTH_Q = M_SQRT1_2; // 1/sqrt(2)
15 
17 
18  void setLowPass(float fc, float q, float sr){
19  setLowPass(coefficients, fc*M_PI/sr, q);
20  }
21 
22  void setHighPass(float fc, float q, float sr){
23  setHighPass(coefficients, fc*M_PI/sr, q);
24  }
25 
26  void setBandPass(float fc, float q, float sr){
27  setBandPass(coefficients, fc*M_PI/sr, q);
28  }
29 
30  void setAllPass(float fc, float q, float sr){
31  setAllPass(coefficients, fc*M_PI/sr, q);
32  }
33 
34  void setNotch(float fc, float q, float sr){
35  setNotch(coefficients, fc*M_PI/sr, q);
36  }
37 
38  void setPeak(float fc, float q, float gain, float sr){
39  setPeak(coefficients, fc*M_PI/sr, q, gain);
40  }
41  void setLowShelf(float fc, float gain, float sr){
42  setLowShelf(coefficients, fc*M_PI/sr, gain);
43  }
44  void setHighShelf(float fc, float gain, float sr){
45  setHighShelf(coefficients, fc*M_PI/sr, gain);
46  }
47  void copyCoefficients(FloatArray newCoefficients){
48  ASSERT(coefficients.getSize()==newCoefficients.getSize(), "wrong size");
49  coefficients.copyFrom(newCoefficients);
50  }
51 
53  return coefficients;
54  }
56  return state;
57  }
58 
59  static void setLowPass(float* coefficients, float omega, float q){
60  float K = tanf(omega);
61  float norm = 1 / (1 + K / q + K * K);
62  coefficients[0] = K * K * norm;
63  coefficients[1] = 2 * coefficients[0];
64  coefficients[2] = coefficients[0];
65  coefficients[3] = - 2 * (K * K - 1) * norm;
66  coefficients[4] = - (1 - K / q + K * K) * norm;
67  }
68 
69  static void setHighPass(float* coefficients, float omega, float q){
70  float K = tanf(omega);
71  float norm = 1 / (1 + K / q + K * K);
72  coefficients[0] = 1 * norm;
73  coefficients[1] = -2 * coefficients[0];
74  coefficients[2] = coefficients[0];
75  coefficients[3] = - 2 * (K * K - 1) * norm;
76  coefficients[4] = - (1 - K / q + K * K) * norm;
77  }
78 
79  static void setBandPass(float* coefficients, float omega, float q){
80  float K = tanf(omega);
81  float norm = 1 / (1 + K / q + K * K);
82  coefficients[0] = K / q * norm;
83  coefficients[1] = 0;
84  coefficients[2] = -coefficients[0];
85  coefficients[3] = - 2 * (K * K - 1) * norm;
86  coefficients[4] = - (1 - K / q + K * K) * norm;
87  }
88 
89  static void setAllPass(float* coefficients, float omega, float q){
90  float K = tanf(omega);
91  float norm = 1 / (1 + K / q + K * K);
92  coefficients[0] = (1 - K / q + K * K) * norm;
93  coefficients[1] = 2 * (K * K - 1) * norm;
94  coefficients[2] = 1;
95  coefficients[3] = coefficients[1];
96  coefficients[4] = coefficients[0];
97  }
98 
99  static void setNotch(float* coefficients, float omega, float q){
100  float K = tanf(omega);
101  float norm = 1 / (1 + K / q + K * K);
102  coefficients[0] = (1 + K * K) * norm;
103  coefficients[1] = 2 * (K * K - 1) * norm;
104  coefficients[2] = coefficients[0];
105  coefficients[3] = - coefficients[1];
106  coefficients[4] = - (1 - K / q + K * K) * norm;
107  }
108 
109  static void setPeak(float* coefficients, float omega, float q, float gain){
110  float K = tanf(omega);
111  float V = exp10f(fabsf(gain)/20);
112  float norm;
113  if (gain >= 0) {
114  norm = 1 / (1 + 1/q * K + K * K);
115  coefficients[0] = (1 + V/q * K + K * K) * norm;
116  coefficients[1] = 2 * (K * K - 1) * norm;
117  coefficients[2] = (1 - V/q * K + K * K) * norm;
118  coefficients[3] = - coefficients[1];
119  coefficients[4] = - (1 - 1/q * K + K * K) * norm;
120  }
121  else {
122  norm = 1 / (1 + V/q * K + K * K);
123  coefficients[0] = (1 + 1/q * K + K * K) * norm;
124  coefficients[1] = 2 * (K * K - 1) * norm;
125  coefficients[2] = (1 - 1/q * K + K * K) * norm;
126  coefficients[3] = - coefficients[1];
127  coefficients[4] = - (1 - V/q * K + K * K) * norm;
128  }
129  }
130 
131  static void setLowShelf(float* coefficients, float omega, float gain){
132  float K = tanf(omega);
133  float V = exp10f(fabsf(gain)/20);
134  float norm;
135  if(gain >= 0) {
136  norm = 1 / (1 + M_SQRT2 * K + K * K);
137  coefficients[0] = (1 + sqrtf(2*V) * K + V * K * K) * norm;
138  coefficients[1] = 2 * (V * K * K - 1) * norm;
139  coefficients[2] = (1 - sqrtf(2*V) * K + V * K * K) * norm;
140  coefficients[3] = - 2 * (K * K - 1) * norm;
141  coefficients[4] = - (1 - M_SQRT2 * K + K * K) * norm;
142  } else {
143  norm = 1 / (1 + sqrtf(2*V) * K + V * K * K);
144  coefficients[0] = (1 + M_SQRT2 * K + K * K) * norm;
145  coefficients[1] = 2 * (K * K - 1) * norm;
146  coefficients[2] = (1 - M_SQRT2 * K + K * K) * norm;
147  coefficients[3] = - 2 * (V * K * K - 1) * norm;
148  coefficients[4] = - (1 - sqrtf(2*V) * K + V * K * K) * norm;
149  }
150  }
151 
152  static void setHighShelf(float* coefficients, float omega, float gain){
153  float K = tanf(omega);
154  float V = exp10f(fabsf(gain)/20);
155  float norm;
156  if(gain >= 0) {
157  norm = 1 / (1 + M_SQRT2 * K + K * K);
158  coefficients[0] = (V + sqrtf(2*V) * K + K * K) * norm;
159  coefficients[1] = 2 * (K * K - V) * norm;
160  coefficients[2] = (V - sqrtf(2*V) * K + K * K) * norm;
161  coefficients[3] = - 2 * (K * K - 1) * norm;
162  coefficients[4] = - (1 - M_SQRT2 * K + K * K) * norm;
163  } else {
164  norm = 1 / (V + sqrtf(2*V) * K + K * K);
165  coefficients[0] = (1 + M_SQRT2 * K + K * K) * norm;
166  coefficients[1] = 2 * (K * K - 1) * norm;
167  coefficients[2] = (1 - M_SQRT2 * K + K * K) * norm;
168  coefficients[3] = - 2 * (K * K - V) * norm;
169  coefficients[4] = - (V - sqrtf(2*V) * K + K * K) * norm;
170  }
171  }
172 };
173 
179 #define BIQUAD_COEFFICIENTS_PER_STAGE 5
180 #define BIQUAD_STATE_VARIABLES_PER_STAGE 2 // 4 for df1, 2 for df2
182 private:
183  float pioversr;
184 #ifdef ARM_CORTEX
185  // arm_biquad_casd_df1_inst_f32 df1;
186  arm_biquad_cascade_df2T_instance_f32 df2;
187 #endif /* ARM_CORTEX */
188 protected:
189  float* coefficients; // stages*5
190  float* state; // stages*4 for df1, stages*2 for df2
191  size_t stages;
192  /*
193  * The coefficients are stored in the array <code>coefficients</code> in the following order:
194  * <pre>
195  * {b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}
196  * </pre>
197  * where <code>b1x</code> and <code>a1x</code> are the coefficients for the first stage,
198  * <code>b2x</code> and <code>a2x</code> are the coefficients for the second stage,
199  * and so on. The <code>coeffs</code> array must contain a total of <code>5*stages</code> values.
200  */
202  for(size_t i=1; i<stages; ++i)
204  }
205  void init(){
206 #ifdef ARM_CORTEX
207  // arm_biquad_cascade_df1_init_f32(&df1, stages, coefficients, state);
208  arm_biquad_cascade_df2T_init_f32(&df2, stages, coefficients, state);
209 #else
210  if(state)
211  memset(state, 0, stages*BIQUAD_STATE_VARIABLES_PER_STAGE*sizeof(float));
212 #endif /* ARM_CORTEX */
213  }
214 public:
216  : pioversr(0), coefficients(NULL), state(NULL), stages(0) {}
217 
218  BiquadFilter(float sr, float* coefs, float* ste, size_t sgs) :
219  pioversr(M_PI/sr), coefficients(coefs), state(ste), stages(sgs) {
220  init();
221  }
222  virtual ~BiquadFilter(){}
223 
224  void setSampleRate(float sr){
225  pioversr = M_PI/sr;
226  }
227 
228  float getSampleRate(){
229  return M_PI / pioversr;
230  }
231 
232  size_t getStages(){
233  return stages;
234  }
235 
236  void setStages(size_t newStages){
237  stages = newStages;
238  }
239 
240  static size_t getCoefficientsPerStage(){
242  }
243 
246  }
247 
250  }
251 
255  void setState(FloatArray newState){
256  ASSERT(BIQUAD_STATE_VARIABLES_PER_STAGE*stages == newState.getSize(), "wrong size");
257  state = newState.getData();
258  }
259 
263  void copyState(FloatArray newState){
264  ASSERT(newState.getSize() == stages*BIQUAD_STATE_VARIABLES_PER_STAGE, "wrong size");
265  getState().copyFrom(newState);
266  }
267 
269  ASSERT(stage < stages, "Invalid filter stage index");
272  return FilterStage(c, s);
273  }
274 
275  /* process into output, leaving input intact */
276  void process(float* input, float* output, size_t size){
277 #ifdef ARM_CORTEX
278  // arm_biquad_cascade_df1_f32(&df1, input, output, size);
279  arm_biquad_cascade_df2T_f32(&df2, input, output, size);
280 #else
281  for(size_t k=0; k<stages; k++){
282  float* coeffs = getFilterStage(k).getCoefficients();
283  float b0 = *coeffs++;
284  float b1 = *coeffs++;
285  float b2 = *coeffs++;
286  float a1 = *coeffs++;
287  float a2 = *coeffs++;
289  float d2 = state[k*BIQUAD_STATE_VARIABLES_PER_STAGE+1];
290  for(size_t n=0; n<size; n++){ //manually apply filter, one stage
291  float out=b0 * input[n] + d1;
292  d1 = b1 * input[n] + a1 * out + d2;
293  d2 = b2 * input[n] + a2 * out;
294  output[n]=out;
297  }
298  }
299 #endif /* ARM_CORTEX */
300  }
301 
302  /* perform in-place processing */
303  void process(FloatArray in){
304  process(in, in, in.getSize());
305  }
306 
308  ASSERT(out.getSize() >= in.getSize(), "output array must be at least as long as input");
309  process(in, out, in.getSize());
310  }
311 
312  void processLowPass(FloatArray in, FloatArray fc, float q, FloatArray out){
313  for(size_t i = 0; i < in.getSize(); i++){
314  setLowPass(fc[i], q);
315  out[i] = process(in[i]);
316  }
317  }
318 
319  void processHighPass(FloatArray in, FloatArray fc, float q, FloatArray out){
320  for(size_t i = 0; i < in.getSize(); i++){
321  setHighPass(fc[i], q);
322  out[i] = process(in[i]);
323  }
324  }
325 
326  void processBandPass(FloatArray in, FloatArray fc, float q, FloatArray out){
327  for(size_t i = 0; i < in.getSize(); i++){
328  setBandPass(fc[i], q);
329  out[i] = process(in[i]);
330  }
331  }
332 
333  void processAllPass(FloatArray in, FloatArray fc, float q, FloatArray out){
334  for(size_t i = 0; i < in.getSize(); i++){
335  setAllPass(fc[i], q);
336  out[i] = process(in[i]);
337  }
338  }
339 
340  /* process a single sample and return the result */
341  float process(float input){
342  float output;
343  process(&input, &output, 1);
344  return output;
345  }
346 
347  void setLowPass(float fc, float q){
348  FilterStage::setLowPass(coefficients, fc*pioversr, q);
350  }
351 
352  void setHighPass(float fc, float q){
353  FilterStage::setHighPass(coefficients, fc*pioversr, q);
355  }
356 
357  void setBandPass(float fc, float q){
358  FilterStage::setBandPass(coefficients, fc*pioversr, q);
360  }
361 
362  void setAllPass(float fc, float q){
363  FilterStage::setAllPass(coefficients, fc*pioversr, q);
365  }
366 
367  void setNotch(float fc, float q){
368  FilterStage::setNotch(coefficients, fc*pioversr, q);
370  }
371 
376  void setPeak(float fc, float q, float gain){
377  FilterStage::setPeak(coefficients, fc*pioversr, q, gain);
379  }
380 
385  void setLowShelf(float fc, float gain){
386  FilterStage::setLowShelf(coefficients, fc*pioversr, gain);
388  }
389 
394  void setHighShelf(float fc, float gain){
395  FilterStage::setHighShelf(coefficients, fc*pioversr, gain);
397  }
398 
402  void setCoefficients(FloatArray newCoefficients){
403  ASSERT(BIQUAD_COEFFICIENTS_PER_STAGE*stages==newCoefficients.getSize(), "wrong size");
404  coefficients = newCoefficients.getData();
405  init();
406  }
407 
411  void copyCoefficients(FloatArray newCoefficients){
412  ASSERT(newCoefficients.getSize()==BIQUAD_COEFFICIENTS_PER_STAGE, "wrong size");
413  getFilterStage(0).copyCoefficients(newCoefficients);
414  copyCoefficients(); //set all the other stages
415  }
416 
417  static BiquadFilter* create(float sr, size_t stages=1){
419  }
420 
421  static void destroy(BiquadFilter* filter){
422  delete[] filter->coefficients;
423  delete[] filter->state;
424  delete filter;
425  }
426 };
427 
429 private:
430  BiquadFilter* filters;
431  size_t channels;
432 protected:
433 public:
434  MultiBiquadFilter(float sr, float* coefs, float* states, size_t stages, BiquadFilter* filters, size_t len) :
435  BiquadFilter(sr, coefs, states, stages), filters(filters), channels(len){}
436  virtual ~MultiBiquadFilter(){}
437  static MultiBiquadFilter* create(float sr, size_t channels, size_t stages=1){
438  BiquadFilter* filters = new BiquadFilter[channels-1];
439  float* coefs = new float[stages*BIQUAD_COEFFICIENTS_PER_STAGE];
440  float* states = new float[stages*BIQUAD_STATE_VARIABLES_PER_STAGE*channels];
442  float* mystate = states;
443  for(size_t ch=1; ch<channels; ++ch){
445  filters[ch-1].setSampleRate(sr);
446  filters[ch-1].setStages(stages);
448  filters[ch-1].setCoefficients(coefficients); // shared coefficients
449  }
450  return new MultiBiquadFilter(sr, coefs, mystate, stages, filters, channels);
451  }
452  static void destroy(MultiBiquadFilter* filter){
453  delete[] filter->coefficients;
454  delete[] filter->state;
455  delete[] filter->filters;
456  delete filter;
457  }
458  BiquadFilter* getFilter(size_t channel){
459  if(channel == 0)
460  return this;
461  if(channel < channels)
462  return &filters[channel-1];
463  return NULL;
464  }
465  void process(AudioBuffer &input, AudioBuffer &output){
466  size_t len = min((int)channels, min(input.getChannels(), output.getChannels()));
467  BiquadFilter::process(input.getSamples(0), output.getSamples(0));
468  for(size_t ch=1; ch<len; ++ch)
469  filters[ch-1].process(input.getSamples(ch), output.getSamples(ch));
470  }
471 };
472 
474 public:
475  StereoBiquadFilter(float sr, float* coefs, float* states, size_t stages, BiquadFilter* filters) :
476  MultiBiquadFilter(sr, coefs, states, stages, filters, 2) {}
477  static StereoBiquadFilter* create(float sr, size_t stages=1){
478  size_t channels = 2;
479  BiquadFilter* filters = new BiquadFilter[channels-1];
480  float* coefs = new float[stages*BIQUAD_COEFFICIENTS_PER_STAGE];
481  float* states = new float[stages*BIQUAD_STATE_VARIABLES_PER_STAGE*channels];
483  float* mystate = states;
484  for(size_t ch=1; ch<channels; ++ch){
486  filters[ch-1].setSampleRate(sr);
487  filters[ch-1].setStages(stages);
489  filters[ch-1].setCoefficients(coefficients); // shared coefficients
490  }
491  return new StereoBiquadFilter(sr, coefs, mystate, stages, filters);
492  }
493  static void destroy(StereoBiquadFilter* filter){
495  }
496 };
497 
498 #endif // __BiquadFilter_h__
#define BIQUAD_COEFFICIENTS_PER_STAGE
Cascaded Biquad Filter.
Definition: BiquadFilter.h:179
#define BIQUAD_STATE_VARIABLES_PER_STAGE
Definition: BiquadFilter.h:180
#define M_SQRT2
Definition: basicmaths.h:55
#define min(a, b)
Definition: basicmaths.h:38
#define M_PI
Definition: basicmaths.h:52
virtual int getChannels()=0
virtual FloatArray getSamples(int channel)=0
void setState(FloatArray newState)
Sets state to point to a different set of values.
Definition: BiquadFilter.h:255
void setHighShelf(float fc, float gain)
Configure a high shelf filter with variable gain.
Definition: BiquadFilter.h:394
void setHighPass(float fc, float q)
Definition: BiquadFilter.h:352
void setStages(size_t newStages)
Definition: BiquadFilter.h:236
BiquadFilter(float sr, float *coefs, float *ste, size_t sgs)
Definition: BiquadFilter.h:218
float * coefficients
Definition: BiquadFilter.h:189
void setLowShelf(float fc, float gain)
Configure a low shelf filter with variable gain.
Definition: BiquadFilter.h:385
size_t getStages()
Definition: BiquadFilter.h:232
float * state
Definition: BiquadFilter.h:190
void processLowPass(FloatArray in, FloatArray fc, float q, FloatArray out)
Definition: BiquadFilter.h:312
void processBandPass(FloatArray in, FloatArray fc, float q, FloatArray out)
Definition: BiquadFilter.h:326
void processAllPass(FloatArray in, FloatArray fc, float q, FloatArray out)
Definition: BiquadFilter.h:333
void setAllPass(float fc, float q)
Definition: BiquadFilter.h:362
FloatArray getState()
Definition: BiquadFilter.h:248
void setPeak(float fc, float q, float gain)
Configure a peaking filter with resonance and variable gain.
Definition: BiquadFilter.h:376
void setCoefficients(FloatArray newCoefficients)
Sets coefficients to point to a different set of values.
Definition: BiquadFilter.h:402
void setLowPass(float fc, float q)
Definition: BiquadFilter.h:347
void processHighPass(FloatArray in, FloatArray fc, float q, FloatArray out)
Definition: BiquadFilter.h:319
static BiquadFilter * create(float sr, size_t stages=1)
Definition: BiquadFilter.h:417
void process(FloatArray in)
Definition: BiquadFilter.h:303
void copyCoefficients(FloatArray newCoefficients)
Copies coefficient values from an array.
Definition: BiquadFilter.h:411
void copyCoefficients()
Definition: BiquadFilter.h:201
float process(float input)
Definition: BiquadFilter.h:341
static size_t getCoefficientsPerStage()
Definition: BiquadFilter.h:240
static void destroy(BiquadFilter *filter)
Definition: BiquadFilter.h:421
void setNotch(float fc, float q)
Definition: BiquadFilter.h:367
virtual ~BiquadFilter()
Definition: BiquadFilter.h:222
FloatArray getCoefficients()
Definition: BiquadFilter.h:244
FilterStage getFilterStage(size_t stage)
Definition: BiquadFilter.h:268
void setBandPass(float fc, float q)
Definition: BiquadFilter.h:357
void process(FloatArray in, FloatArray out)
Definition: BiquadFilter.h:307
void copyState(FloatArray newState)
Copies state values from an array.
Definition: BiquadFilter.h:263
float getSampleRate()
Definition: BiquadFilter.h:228
void process(float *input, float *output, size_t size)
Definition: BiquadFilter.h:276
void setSampleRate(float sr)
Definition: BiquadFilter.h:224
void setAllPass(float fc, float q, float sr)
Definition: BiquadFilter.h:30
void setHighShelf(float fc, float gain, float sr)
Definition: BiquadFilter.h:44
static void setHighPass(float *coefficients, float omega, float q)
Definition: BiquadFilter.h:69
static void setNotch(float *coefficients, float omega, float q)
Definition: BiquadFilter.h:99
static void setHighShelf(float *coefficients, float omega, float gain)
Definition: BiquadFilter.h:152
void setBandPass(float fc, float q, float sr)
Definition: BiquadFilter.h:26
void setLowPass(float fc, float q, float sr)
Definition: BiquadFilter.h:18
void setNotch(float fc, float q, float sr)
Definition: BiquadFilter.h:34
static void setLowPass(float *coefficients, float omega, float q)
Definition: BiquadFilter.h:59
static void setAllPass(float *coefficients, float omega, float q)
Definition: BiquadFilter.h:89
FloatArray coefficients
Definition: BiquadFilter.h:10
void setPeak(float fc, float q, float gain, float sr)
Definition: BiquadFilter.h:38
static constexpr float SALLEN_KEY_Q
Definition: BiquadFilter.h:13
FloatArray getCoefficients()
Definition: BiquadFilter.h:52
static constexpr float BESSEL_Q
Definition: BiquadFilter.h:12
void setHighPass(float fc, float q, float sr)
Definition: BiquadFilter.h:22
static void setPeak(float *coefficients, float omega, float q, float gain)
Definition: BiquadFilter.h:109
static void setBandPass(float *coefficients, float omega, float q)
Definition: BiquadFilter.h:79
FloatArray state
Definition: BiquadFilter.h:11
static constexpr float BUTTERWORTH_Q
Definition: BiquadFilter.h:14
FloatArray getState()
Definition: BiquadFilter.h:55
void copyCoefficients(FloatArray newCoefficients)
Definition: BiquadFilter.h:47
FilterStage(FloatArray co, FloatArray st)
Definition: BiquadFilter.h:16
static void setLowShelf(float *coefficients, float omega, float gain)
Definition: BiquadFilter.h:131
void setLowShelf(float fc, float gain, float sr)
Definition: BiquadFilter.h:41
This class contains useful methods for manipulating arrays of floats.
Definition: FloatArray.h:12
void process(AudioBuffer &input, AudioBuffer &output)
Definition: BiquadFilter.h:465
BiquadFilter * getFilter(size_t channel)
Definition: BiquadFilter.h:458
static void destroy(MultiBiquadFilter *filter)
Definition: BiquadFilter.h:452
MultiBiquadFilter(float sr, float *coefs, float *states, size_t stages, BiquadFilter *filters, size_t len)
Definition: BiquadFilter.h:434
static MultiBiquadFilter * create(float sr, size_t channels, size_t stages=1)
Definition: BiquadFilter.h:437
virtual ~MultiBiquadFilter()
Definition: BiquadFilter.h:436
Base class for signal processors such as Filters.
void copyFrom(SimpleArray< T > source)
Copies the content of another array into this array.
Definition: SimpleArray.h:86
size_t getSize() const
Definition: SimpleArray.h:31
T * getData()
Get the data stored in the Array.
Definition: SimpleArray.h:27
static StereoBiquadFilter * create(float sr, size_t stages=1)
Definition: BiquadFilter.h:477
static void destroy(StereoBiquadFilter *filter)
Definition: BiquadFilter.h:493
StereoBiquadFilter(float sr, float *coefs, float *states, size_t stages, BiquadFilter *filters)
Definition: BiquadFilter.h:475
#define ASSERT(cond, msg)
Definition: message.h:16