|
- /*
- ZynAddSubFX - a software synthesizer
-
- AnalogFilter.cpp - Several analog filters (lowpass, highpass...)
- Copyright (C) 2002-2005 Nasca Octavian Paul
- Copyright (C) 2010-2010 Mark McCurry
- Author: Nasca Octavian Paul
- Mark McCurry
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <cstring> //memcpy
- #include <cmath>
- #include <cassert>
-
- #include "../Misc/Util.h"
- #include "AnalogFilter.h"
-
- namespace zyncarla {
-
- AnalogFilter::AnalogFilter(unsigned char Ftype,
- float Ffreq,
- float Fq,
- unsigned char Fstages,
- unsigned int srate, int bufsize)
- :Filter(srate, bufsize),
- type(Ftype),
- stages(Fstages),
- freq(Ffreq),
- q(Fq),
- gain(1.0),
- abovenq(false),
- oldabovenq(false)
- {
- for(int i = 0; i < 3; ++i)
- coeff.c[i] = coeff.d[i] = oldCoeff.c[i] = oldCoeff.d[i] = 0.0f;
- if(stages >= MAX_FILTER_STAGES)
- stages = MAX_FILTER_STAGES;
- cleanup();
- firsttime = false;
- setfreq_and_q(Ffreq, Fq);
- firsttime = true;
- coeff.d[0] = 0; //this is not used
- outgain = 1.0f;
- }
-
- AnalogFilter::~AnalogFilter()
- {}
-
- void AnalogFilter::cleanup()
- {
- for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i) {
- history[i].x1 = 0.0f;
- history[i].x2 = 0.0f;
- history[i].y1 = 0.0f;
- history[i].y2 = 0.0f;
- oldHistory[i] = history[i];
- }
- needsinterpolation = false;
- }
-
- AnalogFilter::Coeff AnalogFilter::computeCoeff(int type, float cutoff, float q,
- int stages, float gain, float fs, int &order)
- {
- AnalogFilter::Coeff coeff;
- bool zerocoefs = false; //this is used if the freq is too high
-
- const float samplerate_f = fs;
- const float halfsamplerate_f = fs/2;
-
- //do not allow frequencies bigger than samplerate/2
- float freq = cutoff;
- if(freq > (halfsamplerate_f - 500.0f)) {
- freq = halfsamplerate_f - 500.0f;
- zerocoefs = true;
- }
-
- if(freq < 0.1f)
- freq = 0.1f;
-
- //do not allow bogus Q
- if(q < 0.0f)
- q = 0.0f;
-
-
- float tmpq, tmpgain;
- if(stages == 0) {
- tmpq = q;
- tmpgain = gain;
- } else {
- tmpq = (q > 1.0f) ? powf(q, 1.0f / (stages + 1)) : q;
- tmpgain = powf(gain, 1.0f / (stages + 1));
- }
-
- //Alias Terms
- float *c = coeff.c;
- float *d = coeff.d;
-
- //General Constants
- const float omega = 2 * PI * freq / samplerate_f;
- const float sn = sinf(omega), cs = cosf(omega);
- float alpha, beta;
-
- //most of theese are implementations of
- //the "Cookbook formulae for audio EQ" by Robert Bristow-Johnson
- //The original location of the Cookbook is:
- //http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt
- float tmp;
- float tgp1;
- float tgm1;
- switch(type) {
- case 0: //LPF 1 pole
- if(!zerocoefs)
- tmp = expf(-2.0f * PI * freq / samplerate_f);
- else
- tmp = 0.0f;
- c[0] = 1.0f - tmp;
- c[1] = 0.0f;
- c[2] = 0.0f;
- d[1] = tmp;
- d[2] = 0.0f;
- order = 1;
- break;
- case 1: //HPF 1 pole
- if(!zerocoefs)
- tmp = expf(-2.0f * PI * freq / samplerate_f);
- else
- tmp = 0.0f;
- c[0] = (1.0f + tmp) / 2.0f;
- c[1] = -(1.0f + tmp) / 2.0f;
- c[2] = 0.0f;
- d[1] = tmp;
- d[2] = 0.0f;
- order = 1;
- break;
- case 2: //LPF 2 poles
- if(!zerocoefs) {
- alpha = sn / (2.0f * tmpq);
- tmp = 1 + alpha;
- c[1] = (1.0f - cs) / tmp;
- c[0] = c[2] = c[1] / 2.0f;
- d[1] = -2.0f * cs / tmp * -1.0f;
- d[2] = (1.0f - alpha) / tmp * -1.0f;
- }
- else {
- c[0] = 1.0f;
- c[1] = c[2] = d[1] = d[2] = 0.0f;
- }
- order = 2;
- break;
- case 3: //HPF 2 poles
- if(!zerocoefs) {
- alpha = sn / (2.0f * tmpq);
- tmp = 1 + alpha;
- c[0] = (1.0f + cs) / 2.0f / tmp;
- c[1] = -(1.0f + cs) / tmp;
- c[2] = (1.0f + cs) / 2.0f / tmp;
- d[1] = -2.0f * cs / tmp * -1.0f;
- d[2] = (1.0f - alpha) / tmp * -1.0f;
- }
- else
- c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f;
- order = 2;
- break;
- case 4: //BPF 2 poles
- if(!zerocoefs) {
- alpha = sn / (2.0f * tmpq);
- tmp = 1.0f + alpha;
- c[0] = alpha / tmp *sqrtf(tmpq + 1.0f);
- c[1] = 0.0f;
- c[2] = -alpha / tmp *sqrtf(tmpq + 1.0f);
- d[1] = -2.0f * cs / tmp * -1.0f;
- d[2] = (1.0f - alpha) / tmp * -1.0f;
- }
- else
- c[0] = c[1] = c[2] = d[1] = d[2] = 0.0f;
- order = 2;
- break;
- case 5: //NOTCH 2 poles
- if(!zerocoefs) {
- alpha = sn / (2.0f * sqrtf(tmpq));
- tmp = 1.0f + alpha;
- c[0] = 1.0f / tmp;
- c[1] = -2.0f * cs / tmp;
- c[2] = 1.0f / tmp;
- d[1] = -2.0f * cs / tmp * -1.0f;
- d[2] = (1.0f - alpha) / tmp * -1.0f;
- }
- else {
- c[0] = 1.0f;
- c[1] = c[2] = d[1] = d[2] = 0.0f;
- }
- order = 2;
- break;
- case 6: //PEAK (2 poles)
- if(!zerocoefs) {
- tmpq *= 3.0f;
- alpha = sn / (2.0f * tmpq);
- tmp = 1.0f + alpha / tmpgain;
- c[0] = (1.0f + alpha * tmpgain) / tmp;
- c[1] = (-2.0f * cs) / tmp;
- c[2] = (1.0f - alpha * tmpgain) / tmp;
- d[1] = -2.0f * cs / tmp * -1.0f;
- d[2] = (1.0f - alpha / tmpgain) / tmp * -1.0f;
- }
- else {
- c[0] = 1.0f;
- c[1] = c[2] = d[1] = d[2] = 0.0f;
- }
- order = 2;
- break;
- case 7: //Low Shelf - 2 poles
- if(!zerocoefs) {
- tmpq = sqrtf(tmpq);
- beta = sqrtf(tmpgain) / tmpq;
- tgp1 = tmpgain + 1.0f;
- tgm1 = tmpgain - 1.0f;
- tmp = tgp1 + tgm1 * cs + beta * sn;
-
- c[0] = tmpgain * (tgp1 - tgm1 * cs + beta * sn) / tmp;
- c[1] = 2.0f * tmpgain * (tgm1 - tgp1 * cs) / tmp;
- c[2] = tmpgain * (tgp1 - tgm1 * cs - beta * sn) / tmp;
- d[1] = -2.0f * (tgm1 + tgp1 * cs) / tmp * -1.0f;
- d[2] = (tgp1 + tgm1 * cs - beta * sn) / tmp * -1.0f;
- }
- else {
- c[0] = tmpgain;
- c[1] = c[2] = d[1] = d[2] = 0.0f;
- }
- order = 2;
- break;
- case 8: //High Shelf - 2 poles
- if(!zerocoefs) {
- tmpq = sqrtf(tmpq);
- beta = sqrtf(tmpgain) / tmpq;
- tgp1 = tmpgain + 1.0f;
- tgm1 = tmpgain - 1.0f;
- tmp = tgp1 - tgm1 * cs + beta * sn;
-
- c[0] = tmpgain * (tgp1 + tgm1 * cs + beta * sn) / tmp;
- c[1] = -2.0f * tmpgain * (tgm1 + tgp1 * cs) / tmp;
- c[2] = tmpgain * (tgp1 + tgm1 * cs - beta * sn) / tmp;
- d[1] = 2.0f * (tgm1 - tgp1 * cs) / tmp * -1.0f;
- d[2] = (tgp1 - tgm1 * cs - beta * sn) / tmp * -1.0f;
- }
- else {
- c[0] = 1.0f;
- c[1] = c[2] = d[1] = d[2] = 0.0f;
- }
- order = 2;
- break;
- default: //wrong type
- assert(false && "wrong type for a filter");
- break;
- }
- return coeff;
- }
-
- void AnalogFilter::computefiltercoefs(void)
- {
- coeff = AnalogFilter::computeCoeff(type, freq, q, stages, gain,
- samplerate_f, order);
- }
-
-
- void AnalogFilter::setfreq(float frequency)
- {
- if(frequency < 0.1f)
- frequency = 0.1f;
- float rap = freq / frequency;
- if(rap < 1.0f)
- rap = 1.0f / rap;
-
- oldabovenq = abovenq;
- abovenq = frequency > (halfsamplerate_f - 500.0f);
-
- bool nyquistthresh = (abovenq ^ oldabovenq);
-
-
- //if the frequency is changed fast, it needs interpolation
- if((rap > 3.0f) || nyquistthresh) { //(now, filter and coeficients backup)
- oldCoeff = coeff;
- for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i)
- oldHistory[i] = history[i];
- if(!firsttime)
- needsinterpolation = true;
- }
- freq = frequency;
- computefiltercoefs();
- firsttime = false;
- }
-
- void AnalogFilter::setfreq_and_q(float frequency, float q_)
- {
- q = q_;
- setfreq(frequency);
- }
-
- void AnalogFilter::setq(float q_)
- {
- q = q_;
- computefiltercoefs();
- }
-
- void AnalogFilter::settype(int type_)
- {
- type = type_;
- computefiltercoefs();
- }
-
- void AnalogFilter::setgain(float dBgain)
- {
- gain = dB2rap(dBgain);
- computefiltercoefs();
- }
-
- void AnalogFilter::setstages(int stages_)
- {
- if(stages_ >= MAX_FILTER_STAGES)
- stages_ = MAX_FILTER_STAGES - 1;
- if(stages_ != stages) {
- stages = stages_;
- cleanup();
- computefiltercoefs();
- }
- }
-
- inline void AnalogBiquadFilterA(const float coeff[5], float &src, float work[4])
- {
- work[3] = src*coeff[0]
- + work[0]*coeff[1]
- + work[1]*coeff[2]
- + work[2]*coeff[3]
- + work[3]*coeff[4];
- work[1] = src;
- src = work[3];
- }
-
- inline void AnalogBiquadFilterB(const float coeff[5], float &src, float work[4])
- {
- work[2] = src*coeff[0]
- + work[1]*coeff[1]
- + work[0]*coeff[2]
- + work[3]*coeff[3]
- + work[2]*coeff[4];
- work[0] = src;
- src = work[2];
- }
-
- void AnalogFilter::singlefilterout(float *smp, fstage &hist,
- const Coeff &coeff)
- {
- assert((buffersize % 8) == 0);
- if(order == 1) { //First order filter
- for(int i = 0; i < buffersize; ++i) {
- float y0 = smp[i] * coeff.c[0] + hist.x1 * coeff.c[1]
- + hist.y1 * coeff.d[1];
- hist.y1 = y0;
- hist.x1 = smp[i];
- smp[i] = y0;
- }
- } else if(order == 2) {//Second order filter
- const float coeff_[5] = {coeff.c[0], coeff.c[1], coeff.c[2], coeff.d[1], coeff.d[2]};
- float work[4] = {hist.x1, hist.x2, hist.y1, hist.y2};
- for(int i = 0; i < buffersize; i+=8) {
- AnalogBiquadFilterA(coeff_, smp[i + 0], work);
- AnalogBiquadFilterB(coeff_, smp[i + 1], work);
- AnalogBiquadFilterA(coeff_, smp[i + 2], work);
- AnalogBiquadFilterB(coeff_, smp[i + 3], work);
- AnalogBiquadFilterA(coeff_, smp[i + 4], work);
- AnalogBiquadFilterB(coeff_, smp[i + 5], work);
- AnalogBiquadFilterA(coeff_, smp[i + 6], work);
- AnalogBiquadFilterB(coeff_, smp[i + 7], work);
- }
- hist.x1 = work[0];
- hist.x2 = work[1];
- hist.y1 = work[2];
- hist.y2 = work[3];
- }
- }
-
- void AnalogFilter::filterout(float *smp)
- {
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(smp, history[i], coeff);
-
- if(needsinterpolation) {
- //Merge Filter at old coeff with new coeff
- float ismp[buffersize];
- memcpy(ismp, smp, bufferbytes);
-
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(ismp, oldHistory[i], oldCoeff);
-
- for(int i = 0; i < buffersize; ++i) {
- float x = (float)i / buffersize_f;
- smp[i] = ismp[i] * (1.0f - x) + smp[i] * x;
- }
- needsinterpolation = false;
- }
-
- for(int i = 0; i < buffersize; ++i)
- smp[i] *= outgain;
- }
-
- float AnalogFilter::H(float freq)
- {
- float fr = freq / samplerate_f * PI * 2.0f;
- float x = coeff.c[0], y = 0.0f;
- for(int n = 1; n < 3; ++n) {
- x += cosf(n * fr) * coeff.c[n];
- y -= sinf(n * fr) * coeff.c[n];
- }
- float h = x * x + y * y;
- x = 1.0f;
- y = 0.0f;
- for(int n = 1; n < 3; ++n) {
- x -= cosf(n * fr) * coeff.d[n];
- y += sinf(n * fr) * coeff.d[n];
- }
- h = h / (x * x + y * y);
- return powf(h, (stages + 1.0f) / 2.0f);
- }
-
- }
|