commit 2714c5952da83932b5122d6dabe0e28964f84f26
parent 9b381cc5ce72caaffe4b73626e2304221ea235c4
Author: Jonathan Moore Liles <j.liles@unix.net>
Date: Thu, 10 Dec 2020 19:38:46 -0800
SVFilter: Use Value_Smoothing_Filter to smooth cutoff frequency changes.
Also, add include guard to Value_Smoothing_Filter.
Also, cleanup some unused properties.
Diffstat:
7 files changed, 51 insertions(+), 91 deletions(-)
diff --git a/src/DSP/AnalogFilter.cpp b/src/DSP/AnalogFilter.cpp
@@ -32,18 +32,14 @@ AnalogFilter::AnalogFilter(unsigned char Ftype,
stages(Fstages),
freq(Ffreq),
q(Fq),
- gain(1.0),
- abovenq(false),
- oldabovenq(false)
+ gain(1.0)
{
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;
freq_smoothing.sample_rate(samplerate_f);
@@ -62,7 +58,6 @@ void AnalogFilter::cleanup()
history[i].y2 = 0.0f;
oldHistory[i] = history[i];
}
- needsinterpolation = false;
}
AnalogFilter::Coeff AnalogFilter::computeCoeff(int type, float cutoff, float q,
@@ -277,14 +272,8 @@ void AnalogFilter::setfreq(float frequency)
if(rap < 1.0f)
rap = 1.0f / rap;
- oldabovenq = abovenq;
- abovenq = frequency > (halfsamplerate_f - 500.0f);
-
- bool nyquistthresh = (abovenq ^ oldabovenq);
-
freq = frequency;
computefiltercoefs();
- firsttime = false;
}
void AnalogFilter::setfreq_and_q(float frequency, float q_)
diff --git a/src/DSP/AnalogFilter.h b/src/DSP/AnalogFilter.h
@@ -74,13 +74,6 @@ class AnalogFilter:public Filter
int order; //the order of the filter (number of poles)
- bool needsinterpolation, //Interpolation between coeff changes
- firsttime; //First Iteration of filter
- bool abovenq, //if the frequency is above the nyquist
- oldabovenq; //if the last time was above nyquist
- //(used to see if it needs interpolation)
-
-
Value_Smoothing_Filter freq_smoothing; /* for smoothing freq modulations to avoid zipper effect */
};
diff --git a/src/DSP/SVFilter.cpp b/src/DSP/SVFilter.cpp
@@ -26,12 +26,6 @@
namespace zyn {
-enum FilterInterpolationType {
- INTERPOLATE_EXTREME = 0x01,
- INTERPOLATE_NON_ZERO,
- INTERPOLATE_NONE
-};
-
SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq,
unsigned char Fstages, unsigned int srate, int bufsize)
:Filter(srate, bufsize),
@@ -39,15 +33,15 @@ SVFilter::SVFilter(unsigned char Ftype, float Ffreq, float Fq,
stages(Fstages),
freq(Ffreq),
q(Fq),
- gain(1.0f),
- needsinterpolation(INTERPOLATE_NONE),
- firsttime(true)
+ gain(1.0f)
{
if(stages >= MAX_FILTER_STAGES)
stages = MAX_FILTER_STAGES;
outgain = 1.0f;
cleanup();
setfreq_and_q(Ffreq, Fq);
+ freq_smoothing.reset(Ffreq);
+ freq_smoothing.sample_rate(bufsize);
}
SVFilter::~SVFilter()
@@ -57,8 +51,6 @@ void SVFilter::cleanup()
{
for(int i = 0; i < MAX_FILTER_STAGES + 1; ++i)
st[i].low = st[i].high = st[i].band = st[i].notch = 0.0f;
- oldabovenq = false;
- abovenq = false;
}
SVFilter::response::response(float b0, float b1, float b2,
@@ -127,26 +119,8 @@ void SVFilter::setfreq(float frequency)
if(rap < 1.0f)
rap = 1.0f / rap;
- oldabovenq = abovenq;
- abovenq = frequency > (samplerate_f / 2 - 500.0f);
-
- bool nyquistthresh = (abovenq ^ oldabovenq);
-
- //if the frequency is changed fast, it needs interpolation
- if((rap > 3.0f) || nyquistthresh) { //(now, filter and coefficients backup)
- if(!firsttime)
- needsinterpolation = INTERPOLATE_EXTREME;
- ipar = par;
- } else if(rap != 1.0) {
- if (!firsttime)
- needsinterpolation = INTERPOLATE_NON_ZERO;
- ipar = par;
- } else {
- needsinterpolation = INTERPOLATE_NONE;
- }
freq = frequency;
computefiltercoefs();
- firsttime = false;
}
void SVFilter::setfreq_and_q(float frequency, float q_)
@@ -204,21 +178,6 @@ float *SVFilter::getfilteroutfortype(SVFilter::fstage &x) {
return out;
}
-void SVFilter::singlefilterout_with_par_interpolation(float *smp, fstage &x, parameters &par1, parameters &par2)
-{
- float *out = getfilteroutfortype(x);
- for(int i = 0; i < buffersize; ++i) {
- float p = i / buffersize_f;
- float f = par1.f + (par2.f - par1.f) * p;
- float q = par1.q + (par2.q - par1.q) * p;
- float q_sqrt = sqrtf(q);
- x.low = x.low + f * x.band;
- x.high = q_sqrt * smp[i] - x.low - q * x.band;
- x.band = f * x.high + x.band;
- x.notch = x.high + x.low;
- smp[i] = *out;
- }
-}
// simplifying the responses
// xl = xl*z(-1) + pf*xb*z(-1)
@@ -232,7 +191,7 @@ void SVFilter::singlefilterout_with_par_interpolation(float *smp, fstage &x, par
-void SVFilter::singlefilterout(float *smp, SVFilter::fstage &x, SVFilter::parameters &par)
+void SVFilter::singlefilterout(float *smp, SVFilter::fstage &x, SVFilter::parameters &par, int buffersize )
{
float *out = getfilteroutfortype(x);
for(int i = 0; i < buffersize; ++i) {
@@ -246,24 +205,28 @@ void SVFilter::singlefilterout(float *smp, SVFilter::fstage &x, SVFilter::parame
void SVFilter::filterout(float *smp)
{
- if (needsinterpolation == INTERPOLATE_EXTREME) {
- float ismp[buffersize];
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(smp, st[i], par);
- memcpy(ismp, smp, bufferbytes);
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(ismp, st[i], ipar);
- for(int i = 0; i < buffersize; ++i) {
- float x = i / buffersize_f;
- smp[i] = ismp[i] * (1.0f - x) + smp[i] * x;
- }
- } else if (needsinterpolation == INTERPOLATE_NON_ZERO) {
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout_with_par_interpolation(smp, st[i], ipar, par);
- } else {
- for(int i = 0; i < stages + 1; ++i)
- singlefilterout(smp, st[i], par);
+ assert((buffersize % 8) == 0);
+
+ float freqbuf[buffersize];
+
+ if ( freq_smoothing.apply( freqbuf, buffersize, freq ) )
+ {
+ /* 8 sample chunks seems to work OK for AnalogFilter, so do that here too. */
+ for ( int i = 0; i < buffersize; i += 8 )
+ {
+ freq = freqbuf[i];
+ computefiltercoefs();
+
+ for(int j = 0; j < stages + 1; ++j)
+ singlefilterout(smp + i, st[j], par, 8 );
+ }
+
+ freq = freqbuf[buffersize - 1];
+ computefiltercoefs();
}
+ else
+ for(int i = 0; i < stages + 1; ++i)
+ singlefilterout(smp, st[i], par, buffersize );
for(int i = 0; i < buffersize; ++i)
smp[i] *= outgain;
diff --git a/src/DSP/SVFilter.h b/src/DSP/SVFilter.h
@@ -16,6 +16,7 @@
#include "../globals.h"
#include "Filter.h"
+#include "Value_Smoothing_Filter.h"
namespace zyn {
@@ -57,19 +58,16 @@ class SVFilter:public Filter
} par, ipar;
float *getfilteroutfortype(SVFilter::fstage &x);
- void singlefilterout(float *smp, fstage &x, parameters &par);
- void singlefilterout_with_par_interpolation(float *smp, fstage &x, parameters &par1, parameters &par2);
- void computefiltercoefs(void);
+ void singlefilterout(float *smp, fstage &x, parameters &par, int buffersize );
+
+ void computefiltercoefs(void);
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 abovenq, //if the frequency is above the nyquist
- oldabovenq;
- int needsinterpolation;
- bool firsttime;
+ Value_Smoothing_Filter freq_smoothing;
};
}
diff --git a/src/DSP/Value_Smoothing_Filter.cpp b/src/DSP/Value_Smoothing_Filter.cpp
@@ -32,6 +32,13 @@ Value_Smoothing_Filter::sample_rate ( nframes_t n )
bool
Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, float gt )
{
+ if ( _reset_on_next_apply )
+ {
+ reset( gt );
+ _reset_on_next_apply = false;
+ return false;
+ }
+
if ( target_reached(gt) )
return false;
diff --git a/src/DSP/Value_Smoothing_Filter.h b/src/DSP/Value_Smoothing_Filter.h
@@ -17,6 +17,9 @@
/* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/*******************************************************************************/
+#ifndef VALUE_SMOOTHING_FILTER_H
+#define VALUE_SMOOTHING_FILTER_H
+
typedef unsigned long nframes_t;
typedef float sample_t;
@@ -26,14 +29,20 @@ class Value_Smoothing_Filter
float _cutoff;
+ bool _reset_on_next_apply;
+
public:
Value_Smoothing_Filter ( )
{
g1 = g2 = 0;
_cutoff = 10.0f;
+ _reset_on_next_apply = false;
}
+
+ void reset_on_next_apply ( bool v ) { _reset_on_next_apply = v; }
+
void cutoff ( float v ) { _cutoff = v; }
void reset ( float v ) { g2 = g1 = v; }
@@ -45,3 +54,4 @@ public:
bool apply( sample_t * __restrict__ dst, nframes_t nframes, float gt );
};
+#endif
diff --git a/src/Misc/Master.cpp b/src/Misc/Master.cpp
@@ -785,13 +785,13 @@ Master::Master(const SYNTH_T &synth_, Config* config)
config->cfg.Interpolation, µtonal, fft, &watcher,
(ss+"/part"+npart+"/").c_str);
smoothing_part_l[npart].sample_rate( synth.samplerate );
- smoothing_part_l[npart].reset( 1.0f );
+ smoothing_part_l[npart].reset_on_next_apply( true ); /* necessary to make CI tests happy, otherwise of no practical use */
smoothing_part_r[npart].sample_rate( synth.samplerate );
- smoothing_part_r[npart].reset( 0.992126f ); /* curious default, must be a bug in panning formula. */
+ smoothing_part_r[npart].reset_on_next_apply( true ); /* necessary to make CI tests happy, otherwise of no practical use */
}
smoothing.sample_rate( synth.samplerate );
- smoothing.reset( 0.464159f ); /* master volume has this odd default for some reason, just go with it. */
+ smoothing.reset_on_next_apply( true ); /* necessary to make CI tests happy, otherwise of no practical use */
//Insertion Effects init
for(int nefx = 0; nefx < NUM_INS_EFX; ++nefx)