commit 2642e82dc7597d241802f79ffd976b765ea2f8ca
parent c880db1a67e4af83bfe46257951840f7536015d1
Author: Jonathan Moore Liles <j.liles@unix.net>
Date: Wed, 23 Dec 2020 17:31:45 -0800
AnalogFilter: Improve performance of cutoff change, enforce some sanity limits on upper frequency and resolution.
Diffstat:
2 files changed, 51 insertions(+), 21 deletions(-)
diff --git a/src/DSP/AnalogFilter.cpp b/src/DSP/AnalogFilter.cpp
@@ -20,6 +20,10 @@
#include "../Misc/Util.h"
#include "AnalogFilter.h"
+
+const float MAX_FREQ = 20000.0f;
+const float MAX_FREQ_CO = 1.0f / MAX_FREQ;
+
namespace zyn {
AnalogFilter::AnalogFilter(unsigned char Ftype,
@@ -32,7 +36,8 @@ AnalogFilter::AnalogFilter(unsigned char Ftype,
stages(Fstages),
freq(Ffreq),
q(Fq),
- gain(1.0)
+ gain(1.0),
+ recompute(true)
{
for(int i = 0; i < 3; ++i)
coeff.c[i] = coeff.d[i] = oldCoeff.c[i] = oldCoeff.d[i] = 0.0f;
@@ -43,7 +48,7 @@ AnalogFilter::AnalogFilter(unsigned char Ftype,
coeff.d[0] = 0; //this is not used
outgain = 1.0f;
freq_smoothing.sample_rate(samplerate_f);
- freq_smoothing.reset( freq );
+ freq_smoothing.reset( freq * MAX_FREQ_CO );
}
AnalogFilter::~AnalogFilter()
@@ -257,7 +262,7 @@ AnalogFilter::Coeff AnalogFilter::computeCoeff(int type, float cutoff, float q,
return coeff;
}
-void AnalogFilter::computefiltercoefs(void)
+void AnalogFilter::computefiltercoefs(float freq, float q)
{
coeff = AnalogFilter::computeCoeff(type, freq, q, stages, gain,
samplerate_f, order);
@@ -268,12 +273,24 @@ void AnalogFilter::setfreq(float frequency)
{
if(frequency < 0.1f)
frequency = 0.1f;
+ else if ( frequency > MAX_FREQ )
+ frequency = MAX_FREQ;
+
float rap = freq / frequency;
if(rap < 1.0f)
rap = 1.0f / rap;
- freq = frequency;
- computefiltercoefs();
+ frequency = ceilf(frequency);/* fractional Hz changes are not
+ * likely to be audible and waste CPU,
+ * esp since we're already smoothing
+ * changes, so round it */
+
+ if ( fabsf( frequency - freq ) >= 1.0f )
+ {
+ /* only perform computation if absolutely necessary */
+ freq = frequency;
+ recompute = true;
+ }
}
void AnalogFilter::setfreq_and_q(float frequency, float q_)
@@ -285,19 +302,19 @@ void AnalogFilter::setfreq_and_q(float frequency, float q_)
void AnalogFilter::setq(float q_)
{
q = q_;
- computefiltercoefs();
+ computefiltercoefs(freq,q);
}
void AnalogFilter::settype(int type_)
{
type = type_;
- computefiltercoefs();
+ computefiltercoefs(freq,q);
}
void AnalogFilter::setgain(float dBgain)
{
gain = dB2rap(dBgain);
- computefiltercoefs();
+ computefiltercoefs(freq,q);
}
void AnalogFilter::setstages(int stages_)
@@ -307,7 +324,7 @@ void AnalogFilter::setstages(int stages_)
if(stages_ != stages) {
stages = stages_;
cleanup();
- computefiltercoefs();
+ computefiltercoefs(freq,q);
}
}
@@ -333,10 +350,16 @@ inline void AnalogBiquadFilterB(const float coeff[5], float &src, float work[4])
src = work[2];
}
-void AnalogFilter::singlefilterout(float *smp, fstage &hist,
- const Coeff &coeff)
+void AnalogFilter::singlefilterout(float *smp, fstage &hist)
{
assert((buffersize % 8) == 0);
+
+ if ( recompute )
+ {
+ computefiltercoefs(freq,q);
+ recompute = false;
+ }
+
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]
@@ -365,17 +388,25 @@ void AnalogFilter::singlefilterout(float *smp, fstage &hist,
}
}
-
void AnalogFilter::singlefilterout_freqbuf(float *smp, fstage &hist,
float *freqbuf)
{
assert((buffersize % 8) == 0);
+ float frequency = -1.0f;
+
for ( int i = 0; i < buffersize; i += 8 )
{
/* recompute coeffs for each 8 samples */
- freq = freqbuf[i];
- computefiltercoefs();
+
+ const float f = ceilf(freqbuf[i] * MAX_FREQ);
+
+ if ( fabsf( f - frequency ) >= 1.0f )
+ {
+ /* don't perform computation more often than necessary */
+ computefiltercoefs(f,q);
+ frequency = f;
+ }
if(order == 1) { //First order filter
for ( int j = 0; j < 8; j++ )
@@ -407,15 +438,14 @@ void AnalogFilter::singlefilterout_freqbuf(float *smp, fstage &hist,
}
}
- freq = freqbuf[buffersize-1];
- computefiltercoefs();
+ recompute = true;
}
void AnalogFilter::filterout(float *smp)
{
float freqbuf[buffersize];
- if ( freq_smoothing.apply( freqbuf, buffersize, freq ) )
+ if ( freq_smoothing.apply( freqbuf, buffersize, freq * MAX_FREQ_CO ) )
{
/* in transition, need to do fine grained interpolation */
for(int i = 0; i < stages + 1; ++i)
@@ -425,7 +455,7 @@ void AnalogFilter::filterout(float *smp)
{
/* stable state, just use one coeff */
for(int i = 0; i < stages + 1; ++i)
- singlefilterout(smp, history[i], coeff);
+ singlefilterout(smp, history[i]);
}
for(int i = 0; i < buffersize; ++i)
diff --git a/src/DSP/AnalogFilter.h b/src/DSP/AnalogFilter.h
@@ -61,17 +61,17 @@ class AnalogFilter:public Filter
//old coeffs are used for interpolation when parameters change quickly
//Apply IIR filter to Samples, with coefficients, and past history
- void singlefilterout(float *smp, fstage &hist, const Coeff &coeff);
+ void singlefilterout(float *smp, fstage &hist);// const Coeff &coeff);
void singlefilterout_freqbuf(float *smp, fstage &hist, float *freqbuf);
//Update coeff and order
- void computefiltercoefs(void);
+ void computefiltercoefs(float freq, float q);
int type; //The type of the filter (LPF1,HPF1,LPF2,HPF2...)
int stages; //how many times the filter is applied (0->1,1->2,etc.)
float freq; //Frequency given in Hz
float q; //Q factor (resonance or Q factor)
float gain; //the gain of the filter (if are shelf/peak) filters
-
+ bool recompute; // need to recompute coeff.
int order; //the order of the filter (number of poles)
Value_Smoothing_Filter freq_smoothing; /* for smoothing freq modulations to avoid zipper effect */