CSL  6.0
Filters.cpp
Go to the documentation of this file.
1 //
2 // Filters.cpp -- implementation of the base Filter class and its standard subclasses
3 //
4 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
5 //
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <math.h>
10 
11 #include "Filters.h"
12 
13 using namespace csl;
14 
15 // FrequencyAmount -- Constructors
16 
18 #ifdef CSL_DEBUG
19  logMsg("FrequencyAmount::add null inputs");
20 #endif
21 }
22 
23 FrequencyAmount::~FrequencyAmount() { /* no-op for now */ }
24 
25 // FrequencyAmount -- Accessors
26 
28  this->addInput(CSL_FILTER_FREQUENCY, frequency);
29 #ifdef CSL_DEBUG
30  logMsg("FrequencyAmount::set scale input UG");
31 #endif
32 }
33 
34 void FrequencyAmount::setFrequency(float frequency) {
35  this->addInput(CSL_FILTER_FREQUENCY, frequency);
36 #ifdef CSL_DEBUG
37  logMsg("FrequencyAmount::set scale input value");
38 #endif
39 }
40 
42  return(getPort(CSL_FILTER_FREQUENCY)->nextValue());
43 }
44 
46  this->addInput(CSL_FILTER_AMOUNT, amount);
47 #ifdef CSL_DEBUG
48  logMsg("FrequencyAmount::set offset input UG");
49 #endif
50 }
51 
52 void FrequencyAmount::setAmount(float amount) {
53  this->addInput(CSL_FILTER_AMOUNT, amount);
54 #ifdef CSL_DEBUG
55  logMsg("FrequencyAmount::set offset input value");
56 #endif
57 }
58 
59 /// Generic Filter class with scalable order and generic next_buffer method
60 /// that implememnts the canonical filter diference equation.
61 /// Subclasses must supply filter order and override the setupCoeffs() method.
62 
63 /// Default constructor generates a zeroth order "do-nothing" filter
64 Filter::Filter () : Effect(), Scalable(1.f,0.f) {
65  init(1,1);
66 };
67 
68 
69 Filter::Filter(unsigned num_b, unsigned num_a) : Effect(), Scalable(1.f,0.f) {
70  init(num_a, num_b);
71 }
72 
73 Filter::Filter(UnitGenerator & in, unsigned num_b, unsigned num_a) : Effect(in), Scalable(1.f,0.f) {
74  init(num_a, num_b);
75 };
76 
77 /// This constructor takes arrays of coefficients and constructs the filter accordingly.
78 Filter::Filter(UnitGenerator & in, SampleBuffer bCoeffs, SampleBuffer aCoeffs, unsigned num_b, unsigned num_a)
79  : Effect(in), Scalable(1.f,0.f) {
80  init(num_a, num_b);
81  setupCoeffs(bCoeffs, aCoeffs, num_b, num_a);
82 };
83 
84 void Filter::init(unsigned a, unsigned b) {
85  mBNum = b;
86  mANum = a;
87  mBCoeff[0] = 1.f;
88  mACoeff[0] = 1.f;
89  mPrevOutputs = new Buffer(1, mANum);
90  mPrevInputs = new Buffer(1, mBNum);
94 }
95 
96 /// Filter destructor frees temp memory
97 
98 Filter::~Filter (void) {
99  if (mPrevOutputs) delete mPrevOutputs;
100  if (mPrevInputs) delete mPrevInputs;
101 };
102 
103 // This version does in-place filtering
104 
105 void Filter::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
106 #ifdef CSL_DEBUG
107  logMsg("Filter nextBuffer");
108 #endif
109  SampleBuffer out = outputBuffer.buffer(outBufNum); // get ptr to output channel
110  unsigned numFrames = outputBuffer.mNumFrames; // get buffer length
111  SampleBuffer prevOuts = mPrevOutputs->buffer(0);
112  SampleBuffer prevIns = mPrevInputs->buffer(0);
113  SampleBuffer inputPtr;
114 
115  DECLARE_SCALABLE_CONTROLS; // declare the scale/offset buffers and values
116  DECLARE_FILTER_CONTROLS; // declare the freq/bw buffers and values
119 
120  bool isDynamic = false;
121  if ((freqPort && ( ! freqPort->isFixed())) || (bwPort && ( ! bwPort->isFixed())))
122  isDynamic = true;
123 
124  if (! isInline) {
125  Effect::pullInput(numFrames); // get some input
126  inputPtr = mInputPtr; // get a pointer to the input samples
127  } else
128  inputPtr = out;
129 
130  SampleBuffer prevOPtr = prevOuts;
131  SampleBuffer prevIPtr = prevIns;
132 
133  for (unsigned i = 0; i < numFrames; i++) { // here's the canonical N-quad filter loop
134  if (isDynamic)
135  this->setupCoeffs(); // calculate new coefficients for next sample
136  *prevOPtr = 0.f;
137  *prevIPtr = scaleValue * *inputPtr++ + offsetValue; // get next input sample, scale & offset
138  for (unsigned j = mBNum - 1; j > 0; j--) {
139  *prevOPtr += mBCoeff[j] * prevIns[j]; // prevIns or prevOuts?
140  prevIns[j] = prevIns[j-1];
141  }
142  *prevOPtr += mBCoeff[0] * prevIns[0];
143  for (unsigned j = mANum - 1; j > 0; j--) {
144  *prevOPtr += -mACoeff[j] * prevOuts[j];
145  prevOuts[j] = prevOuts[j-1];
146  }
147  // put current output in the buffer and increment
148  *out++ = (*prevOPtr * scaleValue) + offsetValue;
149 
150  UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
151  }
152 }
153 
154 /// this version is to be inherited by the subclasses. provides a way to directly supply the filter info
155 
156 void Filter::setupCoeffs(SampleBuffer bCoeffs, SampleBuffer aCoeffs, unsigned num_b, unsigned num_a ) {
157  for (unsigned i = 0; i < num_b; i++)
158  mBCoeff[i] = bCoeffs[i];
159  for (unsigned i = 0; i < num_a; i++)
160  mACoeff[i] = aCoeffs[i];
161 }
162 
163 void Filter::clear(void) {
166 }
167 
168 /// log information about myself
169 void Filter::dump() {
170  logMsg("a Filter");
171  Scalable::dump();
173 
174  fprintf(stderr, "A coefficients ");
175  for (unsigned i=0;i<mANum;i++) {
176  fprintf(stderr, "%.2f, ",mACoeff[i]);
177  }
178  fprintf(stderr, "\n");
179  fprintf(stderr, "B coefficients ");
180  for (unsigned i=0;i<mBNum;i++) {
181  fprintf(stderr, "%.2f, ",mBCoeff[i]);
182  }
183  fprintf(stderr, "\n");
184 }
185 
186 #pragma mark Butter
187 
188 /// Butterworth IIR (2nd order recursive) filter.
189 /// This operates upon a buffer of frames of amplitude samples by applying the following equation
190 /// y(n) = a0*x(n) + mACoeff[1] *x(n-1) + mACoeff[2] *x(n-2) - b1*y(n-1) - b2*y(n-2) where x is an amplitude sample.
191 /// It has constructors that can calculate the coefficients from a given cutoff frequency.
192 
194 
195 Butter::Butter (FilterType type, float cutoff) : Filter(3,3) {
196  mFilterType = type;
197  setFrequency(cutoff);
198  setAmount(cutoff / 10.0);
199  setupCoeffs();
200  clear();
201 }
202 
203 Butter::Butter (UnitGenerator & in, FilterType type, float cutoff) : Filter(in,3,3) {
204  mFilterType = type;
205  setFrequency(cutoff);
206  setAmount(cutoff / 10.0);
207  setupCoeffs();
208  clear();
209 }
210 
211 Butter::Butter (UnitGenerator & in, FilterType type, UnitGenerator & cutoff) : Filter(in,3,3) {
212  mFilterType = type;
213  setFrequency(cutoff);
214  setAmount(100);
215  setupCoeffs();
216  clear();
217 }
218 
219 // constructor for dual filter parameters (i.e. band pass and reject)
220 
221 Butter::Butter (FilterType type, float center, float bandwidth) : Filter(3,3) {
222  mFilterType = type;
223  setFrequency(center);
224  setAmount(bandwidth);
225  setupCoeffs();
226  clear();
227 }
228 
229 Butter::Butter (UnitGenerator & in, FilterType type, float center, float bandwidth)
230  : Filter(in,3,3) {
231  mFilterType = type;
232  setFrequency(center);
233  setAmount(bandwidth);
234  setupCoeffs();
235  clear();
236 }
237 
239  : Filter(in,3,3) {
240  mFilterType = type;
241  setFrequency(center);
242  setAmount(bandwidth);
243  setupCoeffs();
244  clear();
245 }
246 
247 // Calculate the filter coefficients based on the frequency characteristics
248 
250  float C, D; // handy intermediate variables
251  float centreFreq = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
252  float bandwidth = mInputs[CSL_FILTER_AMOUNT]->nextValue();
253 
254  mACoeff[0] = 0.f;
255  switch (mFilterType) { // These are the Butterworth equations
256  case BW_LOW_PASS :
257  C = 1 / (tanf (CSL_PI * (centreFreq/mFrameRate)) );
258  mBCoeff[0] = 1 / (1 + (CSL_SQRT_TWO * C) + (C * C) );
259  mBCoeff[1] = 2 * mBCoeff[0];
260  mBCoeff[2] = mBCoeff[0];
261  mACoeff[1] = 2 * mBCoeff[0] * (1 - (C * C));
262  mACoeff[2] = mBCoeff[0] * (1 - (CSL_SQRT_TWO * C) + (C * C) );
263  break;
264  case BW_HIGH_PASS :
265  C = tanf (CSL_PI * centreFreq / mFrameRate);
266  mBCoeff[0] = 1 / (1 + (CSL_SQRT_TWO * C) + (C * C) );
267  mBCoeff[1] = -2 * mBCoeff[0];
268  mBCoeff[2] = mBCoeff[0];
269  mACoeff[1] = 2 * mBCoeff[0] * ((C * C) - 1);
270  mACoeff[2] = mBCoeff[0] * (1 - (CSL_SQRT_TWO * C) + (C * C) );
271  break;
272  case BW_BAND_PASS :
273  C = 1 / (tanf (CSL_PI * bandwidth / mFrameRate) );
274  D = 2 * cos (2 * CSL_PI * centreFreq / mFrameRate);
275  mBCoeff[0] = 1 / (1 + C);
276  mBCoeff[1] = 0;
277  mBCoeff[2] = -1 * mBCoeff[0];
278  mACoeff[1] = -1 * mBCoeff[0] * C * D;
279  mACoeff[2] = mBCoeff[0] * (C - 1);
280  break;
281  case BW_BAND_STOP :
282  C = tanf (CSL_PI * bandwidth / mFrameRate);
283  D = 2 * cos (2 * CSL_PI * centreFreq / mFrameRate);
284  mBCoeff[0] = 1 / (1 + C);
285  mBCoeff[1] = -1 * mBCoeff[0] * D;
286  mBCoeff[2] = mBCoeff[0];
287  mACoeff[1] = -1 * mBCoeff[0] * D;
288  mACoeff[2] = mBCoeff[0] * (1 - C);
289  break;
290  } // switch
291 }
292 
293 #pragma mark Biquad
294 
296 
297 Biquad::Biquad (FilterType type, float freq, float q, float d) : Filter(3,3) {
298  mFilterType = type;
299 // setFrequency(freq);
300 // setAmount(dB);
301  Fc = freq / CGestalt::frameRateF();
302  Q = q;
303  dB = d;
304  setupCoeffs();
305  clear();
306 }
307 
308 Biquad::Biquad (UnitGenerator & in, FilterType type, float freq, float q, float d)
309  : Filter(in,3,3) {
310  mFilterType = type;
311 // setFrequency(freq);
312 // setAmount(dB);
313  Fc = freq / CGestalt::frameRateF();
314  Q = q;
315  dB = d;
316  setupCoeffs();
317  clear();
318 }
319 
320 // Calculate the filter coefficients based on the frequency characteristics
321 // https://stackoverflow.com/questions/52547218/how-to-caculate-biquad-filter-coefficient
322 
323 #ifdef OLD_BQ
324 
325 void Biquad::setupCoeffs() {
326  float C, D; // handy intermediate variables
327  float centreFreq = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
328  float dB = mInputs[CSL_FILTER_AMOUNT]->nextValue();
329  float FS = CGestalt::frameRateF();
330  float w0 = 2.0f * (float) M_PI * (centreFreq / FS);
331  float cosW = cosf(w0);
332  float sinW = sinf(w0);
333  float A = pow(10.0f, (dB / 40.0f));
334  float alpha = sinW / (2.0f * Q);
335  float beta = pow(A, 0.5f) / Q;
336 
337  // http://shepazu.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html
338 
339  switch (mFilterType) { // These are the std. biquad equations
340  case BW_LOW_PASS :
341  mBCoeff[0] = (1.0f - cosW) / 2.0f;
342  mBCoeff[1] = 1.0f - cosW;
343  mBCoeff[2] = (1.0f - cosW) / 2.0f;
344  mACoeff[0] = 1.0f + alpha;
345  mACoeff[1] = -2.0f * cosW;
346  mACoeff[2] = 1.0f - alpha;
347  break;
348  case BW_HIGH_PASS :
349  mBCoeff[0] = (1.0f + cosW)/2.0f;
350  mBCoeff[1] = -(1.0f + cosW);
351  mBCoeff[2] = (1.0f + cosW)/2.0f;
352  mACoeff[0] = (1.0f + alpha);
353  mACoeff[1] = -2.0f * cosW;
354  mACoeff[2] = 1.0f - alpha;
355  break;
356  case BW_BAND_PASS :
357  mBCoeff[0] = sinW / 2.0f;
358  mBCoeff[1] = 0;
359  mBCoeff[2] = -sinW / 2.0f;
360  mACoeff[0] = 1.0f + alpha;
361  mACoeff[1] = -2.0f * cosW;
362  mACoeff[2] = 1.0f - alpha;
363  break;
364  case BW_BAND_STOP :
365  mBCoeff[0] = 1.0f;
366  mBCoeff[1] = -2.0f * cosW;
367  mBCoeff[2] = 1.0f;
368  mACoeff[0] = 1.0f + alpha;
369  mACoeff[1] = -2.0f * cosW;
370  mACoeff[2] = 1.0f - alpha;
371  break;
372  case BW_LOW_SHELF :
373  mBCoeff[0] = A* ((A + 1.0f) - ((A -1.0f) * cosW) + beta * sinW);
374  mBCoeff[1] = 2.0f * A * ((A - 1.0f) - ((A + 1.0f) * cosW));
375  mBCoeff[2] = A * ((A + 1.0f) - (A - 1.0f) * cosW - beta * sinW);
376  mACoeff[0] = ((A + 1.0f) + (A - 1.0f) * cosW + beta * sinW);
377  mACoeff[1] = -2.0f * ((A - 1.0f) + (A + 1.0f) * cosW);
378  mACoeff[2] = ((A + 1.0f) + (A - 1.0f) * cosW - (beta * sinW));
379  break;
380  case BW_HIGH_SHELF :
381  mBCoeff[0] = A * ((A + 1.0f) + (A - 1.0f) * cosW + beta * sinW);
382  mBCoeff[1] = -2.0f * A * ((A - 1.0f) + (A + 1.0f) * cosW);
383  mBCoeff[2] = A * ((A + 1.0f) + (A - 1.0f) * cosW - beta * sinW);
384  mACoeff[0] = ((A + 1.0f) - (A - 1.0f) * cosW + beta * sinW);
385  mACoeff[1] = 2.0f * ((A - 1.0f) - (A + 1.0f) * cosW);
386  mACoeff[2] = ((A + 1.0f) - (A - 1.0f) * cosW - beta * sinW);
387  break;
388  case PEAKING :
389  mBCoeff[0] = 1.0f + (alpha * A);
390  mBCoeff[1] = -2.0f * cosW;
391  mBCoeff[2] = 1.0f - (alpha * A);
392  mACoeff[0] = 1.0f + (alpha / A);
393  mACoeff[1] = -2.0f * cosW;
394  mACoeff[2] = 1.0f - (alpha / A);
395  break;
396  } // switch
397 }
398 
399 #else
400 // https://www.earlevel.com/main/2012/11/26/biquad-c-source-code/
401 
403  float norm = 0.0f;
404  float V = powf(10.0f, fabs(dB) / 20.0f);
405  float K = tanf((float) M_PI * Fc);
406  a0 = a1 = a2 = b1 = b2 = z1 = z2 = 0.0f;
407 
408  switch (mFilterType) { // These are the std. biquad equations
409  case BW_LOW_PASS:
410  norm = 1.0f / (1.0f + K / Q + K * K);
411  a0 = K * K * norm;
412  a1 = 2.0f * a0;
413  a2 = a0;
414  b1 = 2.0f * (K * K - 1.0f) * norm;
415  b2 = (1.0f - K / Q + K * K) * norm;
416  break;
417  case BW_HIGH_PASS:
418  norm = 1.0f / (1.0f + K / Q + K * K);
419  a0 = 1.0f * norm;
420  a1 = -2.0f * a0;
421  a2 = a0;
422  b1 = 2.0f * (K * K - 1.0f) * norm;
423  b2 = (1.0f - K / Q + K * K) * norm;
424  break;
425  case BW_BAND_PASS:
426  norm = 1.0f / (1.0f + K / Q + K * K);
427  a0 = K / Q * norm;
428  a1 = 0;
429  a2 = -a0;
430  b1 = 2.0f * (K * K - 1.0f) * norm;
431  b2 = (1.0f - K / Q + K * K) * norm;
432  break;
433  case BW_BAND_STOP:
434  norm = 1.0f / (1.0f + K / Q + K * K);
435  a0 = (1.0f + K * K) * norm;
436  a1 = 2.0f * (K * K - 1.0f) * norm;
437  a2 = a0;
438  b1 = a1;
439  b2 = (1.0f - K / Q + K * K) * norm;
440  break;
441  case PEAKING:
442  if (dB >= 0.0f) { // boost
443  norm = 1.0f / (1.0f + 1.0f / Q * K + K * K);
444  a0 = (1.0f + V / Q * K + K * K) * norm;
445  a1 = 2.0f * (K * K - 1.0f) * norm;
446  a2 = (1.0f - V / Q * K + K * K) * norm;
447  b1 = a1;
448  b2 = (1.0f - 1.0f / Q * K + K * K) * norm;
449  } else { // cut
450  norm = 1.0f / (1.0f + V / Q * K + K * K);
451  a0 = (1.0f + 1.0f / Q * K + K * K) * norm;
452  a1 = 2.0f * (K * K - 1) * norm;
453  a2 = (1.0f - 1.0f / Q * K + K * K) * norm;
454  b1 = a1;
455  b2 = (1.0f - V / Q * K + K * K) * norm;
456  }
457  break;
458  case BW_LOW_SHELF:
459  if (dB >= 0.0f) { // boost
460  norm = 1.0f / (1.0f + sqrtf(2.0f) * K + K * K);
461  a0 = (1.0f + sqrtf(2.0f * V) * K + V * K * K) * norm;
462  a1 = 2.0f * (V * K * K - 1.0f) * norm;
463  a2 = (1.0f - sqrtf(2.0f * V) * K + V * K * K) * norm;
464  b1 = 2.0f * (K * K - 1.0f) * norm;
465  b2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
466  } else { // cut
467  norm = 1.0f / (1.0f + sqrtf(2.0f * V) * K + V * K * K);
468  a0 = (1.0f + sqrtf(2.0f) * K + K * K) * norm;
469  a1 = 2.0f * (K * K - 1.0f) * norm;
470  a2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
471  b1 = 2.0f * (V * K * K - 1.0f) * norm;
472  b2 = (1.0f - sqrtf(2.0f * V) * K + V * K * K) * norm;
473  }
474  break;
475  case BW_HIGH_SHELF:
476  if (dB >= 0.0f) { // boost
477  norm = 1.0f / (1.0f + sqrtf(2.0f) * K + K * K);
478  a0 = (V + sqrtf(2.0f * V) * K + K * K) * norm;
479  a1 = 2.0f * (K * K - V) * norm;
480  a2 = (V - sqrtf(2.0f * V) * K + K * K) * norm;
481  b1 = 2.0f * (K * K - 1.0f) * norm;
482  b2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
483  } else { // cut
484  norm = 1.0f / (V + sqrtf(2.0f * V) * K + K * K);
485  a0 = (1.0f + sqrtf(2.0f) * K + K * K) * norm;
486  a1 = 2.0f * (K * K - 1.0f) * norm;
487  a2 = (1.0f - sqrtf(2.0f) * K + K * K) * norm;
488  b1 = 2.0f * (K * K - V) * norm;
489  b2 = (V - sqrtf(2.0f * V) * K + K * K) * norm;
490  }
491  } // switch
492 }
493 
494 #endif
495 
496 void Biquad::setQ(float q) {
497  Q = q;
498  setupCoeffs();
499 }
500 
501 void Biquad::setFrq(float f) {
502  mInputs[CSL_FILTER_FREQUENCY]->mValue = f;
503  setupCoeffs();
504 }
505 
506 void Biquad::incrFrq(float f) {
507  mInputs[CSL_FILTER_FREQUENCY]->mValue = f;
508  setupCoeffs();
509 }
510 
511 void Biquad::setBoost(float f) {
512  mInputs[CSL_FILTER_AMOUNT]->mValue = f;
513  setupCoeffs();
514 }
515 
516 void Biquad::incrBoost(float f) {
517  mInputs[CSL_FILTER_AMOUNT]->mValue = f;
518  setupCoeffs();
519 }
520 
521 void Biquad::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
522  SampleBuffer out = outputBuffer.buffer(outBufNum); // get ptr to output channel
523  unsigned numFrames = outputBuffer.mNumFrames; // get buffer length
524  SampleBuffer inP;
525  if (isInline) {
526  inP = out;
527  } else {
528  Effect::pullInput(numFrames); // get some input
529  inP = mInputPtr; // get a pointer to the input samples
530  }
531  for (unsigned i = 0; i < numFrames; i++) { // here's a minimal bi-quad filter loop
532  float inV = *inP++; // no variable controls or scalable inputs
533  float samp = inV * a0 + z1; // uses inst vars rather than arrays for coefficients
534  z1 = inV * a1 + z2 - b1 * samp;
535  z2 = inV * a2 - b2 * samp;
536  *out++ = samp;
537  }
538 }
539 
540 #pragma mark Formant
541 
542 Formant::Formant (UnitGenerator & in, float cutoff, float radius) : Filter (in, 3,3) {
543  mNormalize = true;
544  setFrequency(cutoff);
545  setAmount(radius);
546  setupCoeffs();
547  clear();
548 }
549 
550 Formant::Formant (UnitGenerator & in, UnitGenerator & cutoff, float radius) : Filter (in, 3,3) {
551  mNormalize = true;
552  setFrequency(cutoff);
553  setAmount(radius);
554  setupCoeffs();
555  clear();
556 }
557 
558 void Formant::setNormalize(bool normalize) {
559  mNormalize = normalize;
560  setupCoeffs();
561 };
562 
563 // Calculate the filter coefficients based on the frequency characteristics
564 // to be done every sample for dynamic controls
565 
567  float centreFreq = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
568  float radius = mInputs[CSL_FILTER_AMOUNT]->nextValue();
569 
570  mACoeff[0] = 1.0F;
571  mACoeff[1] = cos(CSL_TWOPI * centreFreq * 1.f / mFrameRate ) * (-2.0F) * radius;
572  mACoeff[2] = radius * radius;
573  if (mNormalize ) { // Use zeros at +- 1 and normalize the filter peak gain.
574  mBCoeff[0] = 0.5 - 0.5 * mACoeff[2];
575  mBCoeff[1] = 0.0;
576  mBCoeff[2] = -mBCoeff[0];
577  } else {
578  mBCoeff[0] = 1.0F;
579  mBCoeff[1] = 0.0F;
580  mBCoeff[2] = -1.0F;
581  }
582 }
583 
584 Notch::Notch (UnitGenerator & in, float cutoff, float radius) : Filter (in,3,3) {
585  setFrequency(cutoff);
586  setAmount(radius);
587  clear();
588 }
589 
590 Notch::Notch (UnitGenerator & in, UnitGenerator & cutoff, float radius) : Filter(in,3,3) {
591  setFrequency(cutoff);
592  setAmount(radius);
593  clear();
594 }
595 
596 // Calculate the filter coefficients based on the frequency characteristics
598  float centreFreq = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
599  float radius = mInputs[CSL_FILTER_AMOUNT]->nextValue();
600 
601  //coeff's similar to formant but opposite
602  mBCoeff[0] = 1.0F;
603  mBCoeff[1] = cos(CSL_TWOPI * centreFreq * 1.0f / mFrameRate ) * (-2.0F) * radius;
604  mBCoeff[2] = radius * radius;
605  mACoeff[0] = 1.0F;
606  mACoeff[1] = 0.0F;
607  mACoeff[2] = 0.0F;
608 }
609 
610 // the Frequency input of FrequencyAmount is used as the Allpass coefficient
611 Allpass::Allpass (UnitGenerator & in, float coeff) : Filter(in,2,2) { // 1st order 1-pole 1-zero filter
612  setFrequency(coeff);
613  setAmount(1);
614  clear();
615 }
616 
618  setFrequency(coeff);
619  setAmount(1);
620  clear();
621 }
622 
623 
624 // Calculate the filter coefficients based on supplied coeffs
626  float coefficient = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
627 
628  mACoeff[0] = mBCoeff[1] = 1.0;
629  mBCoeff[0] = mACoeff[1] = coefficient;
630 }
631 
632 // Moog VCF Methods
633 
635  setFrequency(500.0);
636  setAmount(0.99);
637  y1 = y2 = y3 = y4 = oldy1 = oldy2 = oldy3 = x = oldx = 0.f;
638 }
639 
641  setFrequency(cutoff);
642  setAmount(0.99);
643  y1 = y2 = y3 = y4 = oldy1 = oldy2 = oldy3 = x = oldx = 0.f;
644 }
645 
646 Moog::Moog (UnitGenerator & in, UnitGenerator & cutoff, UnitGenerator & resonance) : Filter(in) {
647  setFrequency(cutoff);
648  setAmount(resonance);
649  y1 = y2 = y3 = y4 = oldy1 = oldy2 = oldy3 = x = oldx = 0.f;
650 }
651 
652 Moog::Moog (UnitGenerator & in, float cutoff) : Filter(in) {
653  setFrequency(cutoff);
654  setAmount(0.5);
655  y1 = y2 = y3 = y4 = oldy1 = oldy2 = oldy3 = x = oldx = 0.f;
656 }
657 
658 Moog::Moog (UnitGenerator & in, float cutoff, float resonance) : Filter(in) {
659  setFrequency(cutoff);
660  setAmount(resonance);
661  y1 = y2 = y3 = y4 = oldy1 = oldy2 = oldy3 = x = oldx = 0.f;
662 }
663 
664 // Filter the next buffer of the input -- adapted from moog filter at music.dsp source code archive
665 
666 void Moog::nextBuffer(Buffer & outputBuffer, unsigned outBufNum) throw (CException) {
667 #ifdef CSL_DEBUG
668  logMsg("Moog Filter nextBuffer");
669 #endif
670  sample* out = outputBuffer.buffer(outBufNum); // get ptr to output channel
671  unsigned numFrames = outputBuffer.mNumFrames; // get buffer length
672  SampleBuffer inputPtr = mInputs[CSL_INPUT]->mBuffer->buffer(outBufNum);
673  DECLARE_SCALABLE_CONTROLS; // declare the scale/offset buffers and values
674  DECLARE_FILTER_CONTROLS; // declare the freq/bw buffers and values
677  this->setupCoeffs();
678 
679  for (unsigned i = 0; i < numFrames; i++) {
680 // this->setupCoeffs();
681  // --Inverted feed back for corner peaking
682  x = *inputPtr++ - r * y4;
683  // Four cascaded onepole filters (bilinear transform)
684  y1 = x * p + oldx * p - k * y1;
685  y2 = y1 * p + oldy1 * p - k * y2;
686  y3 = y2 * p + oldy2 * p - k * y3;
687  y4 = y3 * p + oldy3 * p - k * y4;
688  // Clipper band limited sigmoid
689  y4 = y4 - (y4*y4*y4) / 6;
690  oldx = x;
691  oldy1 = y1;
692  oldy2 = y2;
693  oldy3 = y3;
694  *out++ = y4;
695  UPDATE_SCALABLE_CONTROLS; // update the dynamic scale/offset
696  }
697 }
698 
699 // Calculate the filter coefficients based on the frequency characteristics
700 
702  float centreFreq = mInputs[CSL_FILTER_FREQUENCY]->nextValue();
703  float resonance = mInputs[CSL_FILTER_AMOUNT]->nextValue();
704 
705  float f, scale;
706  f = 2 * centreFreq / mFrameRate; //[0 - 1]
707  k = 3.6 * f - 1.6 * f * f - 1; //(Empirical tunning)
708  p = (k + 1 ) * 0.5;
709  scale = exp((1 - p ) * 1.386249 );
710  r = resonance * scale;
711 }
sample * SampleBuffer
1-channel buffer data type, vector of (sample)
Definition: CSL_Types.h:194
#define UPDATE_SCALABLE_CONTROLS
Definition: CSL_Core.h:444
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
Buffer * mPrevInputs
arrays of past input and output samples
Definition: Filters.h:124
float a0
Definition: Filters.h:178
void pullInput(Buffer &outputBuffer)
Definition: CSL_Core.cpp:1122
unsigned mBNum
number of coeffs in b
Definition: Filters.h:122
#define CSL_FILTER_FREQUENCY
Definition: CSL_Types.h:283
virtual void setupCoeffs()
Definition: Filters.h:109
float x
Definition: Filters.h:260
float mBCoeff[FILTER_MAX_COEFFICIENTS]
array of numerator coeffs
Definition: Filters.h:120
Buffer * mPrevOutputs
Definition: Filters.h:125
void setupCoeffs()
Definition: Filters.cpp:402
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
Effect – mix-in for classes that have unit generators as inputs (like filters).
Definition: CSL_Core.h:466
void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
really compute the next buffer given an offset base channel; this is called by nextBuffer, possibly multiple times
Definition: Filters.cpp:521
void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
really compute the next buffer given an offset base channel; this is called by nextBuffer, possibly multiple times
Definition: Filters.cpp:666
float a2
Definition: Filters.h:178
Notch(UnitGenerator &in, float center_freq, float radius)
constructors & destructor
Definition: Filters.cpp:584
float z1
Definition: Filters.h:179
float p
Definition: Filters.h:259
unsigned mFrameRate
trigger ignored here
Definition: CSL_Core.h:288
void setupCoeffs()
Definition: Filters.cpp:625
#define PEAKING
Definition: Filters.h:57
#define DECLARE_FILTER_CONTROLS
Declare the pointer to freq/bw buffers (if used) and current scale/offset values. ...
Definition: Filters.h:64
void setupCoeffs()
Definition: Filters.cpp:249
Formant(UnitGenerator &in, float center_freq, float radius)
constructors & destructor
Definition: Filters.cpp:542
void setBoost(float d)
Definition: Filters.cpp:511
void incrBoost(float d)
Definition: Filters.cpp:516
void setAmount(UnitGenerator &amount)
set the receiver's amount to a UGen or a float
Definition: Filters.cpp:45
float y2
Definition: Filters.h:261
int mFilterType
Definition: Filters.h:152
#define BW_LOW_SHELF
Definition: Filters.h:55
#define BW_HIGH_SHELF
Definition: Filters.h:56
void incrFrq(float f)
Definition: Filters.cpp:506
Filter: the canonical-form n-pole/m-zero filter class.
Definition: Filters.h:99
static float frameRateF()
default frame rate as a float
Definition: CGestalt.cpp:52
float Q
ctr frq (Hz), peak (dB), Q(uality) factor
Definition: Filters.h:177
float oldx
Definition: Filters.h:260
void zeroBuffers()
fill all data with 0
Definition: CSL_Core.cpp:173
float Fc
Definition: Filters.h:177
void setQ(float q)
Definition: Filters.cpp:496
virtual void dump()
pretty-print the receiver
Definition: CSL_Core.cpp:693
float dB
Definition: Filters.h:177
#define BW_LOW_PASS
Definition: Filters.h:51
~FrequencyAmount()
Destructor.
Definition: Filters.cpp:23
void dump()
log information about myself
Definition: Filters.cpp:169
Scalable – mix-in class with scale and offset control inputs (may be constants or generators)...
Definition: CSL_Core.h:403
#define CSL_PI
Definition: CSL_Types.h:334
#define LOAD_FILTER_CONTROLS
Load the freq/bw-related values at the start.
Definition: Filters.h:70
int mFilterType
flag as to what kind of filter I am
Definition: Filters.h:176
#define BW_BAND_PASS
Definition: Filters.h:53
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
float a1
Definition: Filters.h:178
#define CSL_INPUT
Definition: CSL_Types.h:275
static unsigned frameRate()
default frame rate
Definition: CGestalt.cpp:51
float k
Definition: Filters.h:259
float y1
Definition: Filters.h:261
float b2
coefficients
Definition: Filters.h:178
FrequencyAmount()
Constructors.
Definition: Filters.cpp:17
void setupCoeffs()
Definition: Filters.cpp:597
#define BW_HIGH_PASS
Definition: Filters.h:52
void setFrq(float f)
Definition: Filters.cpp:501
unsigned mANum
number of coeffs in a
Definition: Filters.h:123
#define CSL_FILTER_AMOUNT
Definition: CSL_Types.h:284
float getFrequency()
Definition: Filters.cpp:41
float oldy3
Definition: Filters.h:261
Filter()
Generic Filter class with scalable order and generic next_buffer method that implememnts the canonica...
Definition: Filters.cpp:64
float b1
Definition: Filters.h:178
#define CSL_TWOPI
Definition: CSL_Types.h:336
float y3
Definition: Filters.h:261
void setFrequency(UnitGenerator &frequency)
set the receiver's frequency to a UGen or a float
Definition: Filters.cpp:27
#define LOAD_SCALABLE_CONTROLS
Load the scale/offset-related values at the start.
Definition: CSL_Core.h:436
#define CSL_SQRT_TWO
Definition: CSL_Types.h:338
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
int FilterType
Definition: Filters.h:59
float oldy2
Definition: Filters.h:261
~Filter()
Filter destructor frees temp memory.
Definition: Filters.cpp:98
Port * getPort(CSL_MAP_KEY name)
Definition: CSL_Core.cpp:920
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
float z2
past outputs
Definition: Filters.h:179
float r
Definition: Filters.h:259
void addInput(CSL_MAP_KEY name, UnitGenerator &ugen)
Plug in a unit generator to the named input slot.
Definition: CSL_Core.cpp:894
#define BW_BAND_STOP
Definition: Filters.h:54
PortMap mInputs
the map of my inputs or controls (used by the mix-in classes)
Definition: CSL_Core.h:378
float oldy1
Definition: Filters.h:261
forward declaration
Definition: CSL_Core.h:241
Allpass(UnitGenerator &in, float coeff)
Definition: Filters.cpp:611
float mACoeff[FILTER_MAX_COEFFICIENTS]
array of denominator coeffs
Definition: Filters.h:121
virtual void nextBuffer(Buffer &outputBuffer, unsigned outBufNum)
really compute the next buffer given an offset base channel; this is called by nextBuffer, possibly multiple times
Definition: Filters.cpp:105
bool mNormalize
Definition: Filters.h:203
void clear(void)
clears the input/output buffers
Definition: Filters.cpp:163
void init(unsigned a, unsigned b)
shared initialization function
Definition: Filters.cpp:84
void setupCoeffs()
Definition: Filters.cpp:701
virtual void dump()
pretty-print the receiver's input/controls map
Definition: CSL_Core.cpp:926
void setNormalize(bool normalize)
Definition: Filters.cpp:558
float y4
Definition: Filters.h:261
Butter()
Butterworth IIR (2nd order recursive) filter. This operates upon a buffer of frames of amplitude samp...
Definition: Filters.cpp:193
Base class of CSL exceptions (written upper-case). Has a string message.
void setupCoeffs()
Filtering methods.
Definition: Filters.cpp:566
#define DECLARE_SCALABLE_CONTROLS
Macros for all the Scalable UnitGenerators (note that these don't end with ";")
Definition: CSL_Core.h:429
Moog(UnitGenerator &in)
Definition: Filters.cpp:634