zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit 11a8031753a4743f3a1e5a7510e6d7f79407f696
parent 9fd44013b620e423ce80beec2a3e7f6f0ec6f33f
Author: friedolino78 <34608315+friedolino78@users.noreply.github.com>
Date:   Thu, 16 Sep 2021 22:09:47 +0200

fix of the AnalogFilter Punch (#136)

* fix of the AnalogFilter Punch

Co-authored-by: Friedolino <mkirchn@freenet.de>
Diffstat:
Msrc/DSP/AnalogFilter.cpp | 87++++++++++++++++++++-----------------------------------------------------------
Msrc/DSP/AnalogFilter.h | 5+++--
Msrc/DSP/Value_Smoothing_Filter.cpp | 2+-
Msrc/DSP/Value_Smoothing_Filter.h | 4+++-
Msrc/Tests/AdNoteTest.cpp | 8++++----
Msrc/Tests/PadNoteTest.cpp | 10+++++-----
Msrc/Tests/SubNoteTest.cpp | 8++++----
Msrc/Tests/UnisonTest.cpp | 30+++++++++++++++---------------
8 files changed, 57 insertions(+), 97 deletions(-)

diff --git a/src/DSP/AnalogFilter.cpp b/src/DSP/AnalogFilter.cpp @@ -22,7 +22,6 @@ const float MAX_FREQ = 20000.0f; -const float MAX_FREQ_CO = 1.0f / MAX_FREQ; namespace zyn { @@ -37,7 +36,8 @@ AnalogFilter::AnalogFilter(unsigned char Ftype, freq(Ffreq), q(Fq), gain(1.0), - recompute(true) + recompute(true), + freqbufsize(bufsize/8) { for(int i = 0; i < 3; ++i) coeff.c[i] = coeff.d[i] = oldCoeff.c[i] = oldCoeff.d[i] = 0.0f; @@ -47,8 +47,9 @@ AnalogFilter::AnalogFilter(unsigned char Ftype, setfreq_and_q(Ffreq, Fq); coeff.d[0] = 0; //this is not used outgain = 1.0f; - freq_smoothing.sample_rate(samplerate_f); - freq_smoothing.reset( freq * MAX_FREQ_CO ); + freq_smoothing.sample_rate(samplerate_f/8); + freq_smoothing.thresh(2.0f); // 2Hz + beforeFirstTick=true; } AnalogFilter::~AnalogFilter() @@ -291,6 +292,11 @@ void AnalogFilter::setfreq(float frequency) freq = frequency; recompute = true; } + + if (beforeFirstTick) { + freq_smoothing.reset( freq ); + beforeFirstTick=false; + } } void AnalogFilter::setfreq_and_q(float frequency, float q_) @@ -350,18 +356,18 @@ inline void AnalogBiquadFilterB(const float coeff[5], float &src, float work[4]) src = work[2]; } -void AnalogFilter::singlefilterout(float *smp, fstage &hist) +void AnalogFilter::singlefilterout(float *smp, fstage &hist, float f, unsigned int bufsize) { assert((buffersize % 8) == 0); if ( recompute ) { - computefiltercoefs(freq,q); + computefiltercoefs(f,q); recompute = false; } if(order == 1) { //First order filter - for(int i = 0; i < buffersize; ++i) { + for(unsigned int i = 0; i < bufsize; ++i) { float y0 = smp[i] * coeff.c[0] + hist.x1 * coeff.c[1] + hist.y1 * coeff.d[1]; hist.y1 = y0; @@ -371,7 +377,7 @@ void AnalogFilter::singlefilterout(float *smp, fstage &hist) } 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) { + for(unsigned int i = 0; i < bufsize; i+=8) { AnalogBiquadFilterA(coeff_, smp[i + 0], work); AnalogBiquadFilterB(coeff_, smp[i + 1], work); AnalogBiquadFilterA(coeff_, smp[i + 2], work); @@ -388,74 +394,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 */ - - 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++ ) - { - float y0 = smp[i+j] * coeff.c[0] + hist.x1 * coeff.c[1] - + hist.y1 * coeff.d[1]; - hist.y1 = y0; - hist.x1 = smp[i+j]; - smp[i+j] = 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}; - - 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]; - } - } - - recompute = true; -} - void AnalogFilter::filterout(float *smp) { - float freqbuf[buffersize]; + float freqbuf[freqbufsize]; - if ( freq_smoothing.apply( freqbuf, buffersize, freq * MAX_FREQ_CO ) ) + if ( freq_smoothing.apply( freqbuf, freqbufsize, freq ) ) { /* in transition, need to do fine grained interpolation */ for(int i = 0; i < stages + 1; ++i) - singlefilterout_freqbuf(smp, history[i], freqbuf); + for(int j = 0; j < freqbufsize; ++j) + { + recompute = true; + singlefilterout(&smp[j*8], history[i], freqbuf[j], 8); + } } else { /* stable state, just use one coeff */ for(int i = 0; i < stages + 1; ++i) - singlefilterout(smp, history[i]); + singlefilterout(smp, history[i], freq, buffersize); } for(int i = 0; i < buffersize; ++i) diff --git a/src/DSP/AnalogFilter.h b/src/DSP/AnalogFilter.h @@ -61,8 +61,7 @@ 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_freqbuf(float *smp, fstage &hist, float *freqbuf); + void singlefilterout(float *smp, fstage &hist, float f, unsigned int bufsize);// const Coeff &coeff); //Update coeff and order void computefiltercoefs(float freq, float q); @@ -74,7 +73,9 @@ class AnalogFilter:public Filter bool recompute; // need to recompute coeff. int order; //the order of the filter (number of poles) + int freqbufsize; Value_Smoothing_Filter freq_smoothing; /* for smoothing freq modulations to avoid zipper effect */ + bool beforeFirstTick; // reset the smoothing at first Tick }; } diff --git a/src/DSP/Value_Smoothing_Filter.cpp b/src/DSP/Value_Smoothing_Filter.cpp @@ -64,7 +64,7 @@ Value_Smoothing_Filter::apply( sample_t * __restrict__ dst, nframes_t nframes, f g2 += 1e-10f; /* denormal protection */ - if ( fabsf( gt - g2 ) < 0.0001f ) + if ( fabsf( gt - g2 ) < t ) g2 = gt; this->g1 = g1; diff --git a/src/DSP/Value_Smoothing_Filter.h b/src/DSP/Value_Smoothing_Filter.h @@ -25,7 +25,7 @@ typedef float sample_t; class Value_Smoothing_Filter { - float w, g1, g2; + float w, g1, g2, t; float _cutoff; @@ -37,12 +37,14 @@ public: { g1 = g2 = 0; _cutoff = 10.0f; + t = 0.0001f; _reset_on_next_apply = false; } void reset_on_next_apply ( bool v ) { _reset_on_next_apply = v; } void cutoff ( float v ) { _cutoff = v; } + void thresh ( float t_ ) { t = t_; } void reset ( float v ) { g2 = g1 = v; } diff --git a/src/Tests/AdNoteTest.cpp b/src/Tests/AdNoteTest.cpp @@ -171,25 +171,25 @@ class AdNoteTest #endif sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1924f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.25552f, 0.0001f); note->releasekey(); TS_ASSERT(!tr->hasNext()); w->add_watch("noteout/be4_mix"); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.4717f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.46883f, 0.0001f); w->tick(); TS_ASSERT(tr->hasNext()); note->noteout(outL, outR); sampleCount += synth->buffersize; w->tick(); - TS_ASSERT_DELTA(outL[255], 0.0646f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.06695f, 0.0001f); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1183f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.11621f, 0.0001f); w->tick(); note->noteout(outL, outR); sampleCount += synth->buffersize; diff --git a/src/Tests/PadNoteTest.cpp b/src/Tests/PadNoteTest.cpp @@ -152,7 +152,7 @@ class PadNoteTest #endif sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.3950, 0.0005f); + TS_ASSERT_DELTA(outL[255], -0.0555f, 0.0005f); note->releasekey(); @@ -161,21 +161,21 @@ class PadNoteTest w->add_watch("noteout"); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.2305f, 0.0005f); + TS_ASSERT_DELTA(outL[255], -0.0726f, 0.0005f); w->tick(); TS_ASSERT(!tr->hasNext()); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.1164f, 0.0005f); + TS_ASSERT_DELTA(outL[255], -0.0516f, 0.0005f); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.1079, 0.0005f); + TS_ASSERT_DELTA(outL[255], 0.0529f, 0.0005f); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.0841f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.0525f, 0.0001f); while(!note->finished()) { note->noteout(outL, outR); diff --git a/src/Tests/SubNoteTest.cpp b/src/Tests/SubNoteTest.cpp @@ -117,7 +117,7 @@ class SubNoteTest #endif sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.0010f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0009f, 0.0001f); note->releasekey(); @@ -126,12 +126,12 @@ class SubNoteTest note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], 0.0114f, 0.0001f); + TS_ASSERT_DELTA(outL[255], 0.0026f, 0.0001f); w->tick(); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.0014f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0011f, 0.0001f); w->tick(); TS_ASSERT(tr->hasNext()); @@ -141,7 +141,7 @@ class SubNoteTest w->add_watch("noteout/amp_int"); note->noteout(outL, outR); sampleCount += synth->buffersize; - TS_ASSERT_DELTA(outL[255], -0.0031f, 0.0001f); + TS_ASSERT_DELTA(outL[255], -0.0023f, 0.0001f); w->tick(); note->noteout(outL, outR); diff --git a/src/Tests/UnisonTest.cpp b/src/Tests/UnisonTest.cpp @@ -116,21 +116,21 @@ class UnisonTest sprng(0xbeef); float data[][4] = { - {0.125972,0.029887,0.000000,0.138013}, - {-0.095414,-0.083965,-0.000000,0.009048}, - {-0.077587,-0.001760,-0.021463,-0.013995}, - {0.041240,-0.008561,-0.000000,-0.099298}, - {-0.098969,-0.048030,-0.000052,-0.087053}, - {0.104913,-0.081452,-0.017700,0.000978}, - {0.041270,0.003788,0.006064,0.002436}, - {-0.030791,-0.036072,-0.007964,-0.015141}, - {0.009218,0.015333,-0.007500,0.083076}, - {0.058909,0.064450,-0.002517,0.041595}, - {-0.007731,-0.009040,-0.068033,-0.016573}, - {-0.047286,-0.002355,-0.049196,0.016222}, - {0.014014,-0.002635,0.006542,0.050710}, - {-0.054877,-0.027135,0.040211,0.031927}, - {-0.048367,0.022010,0.018224,0.032846}, + {-0.034547,0.034349,-0.000000,0.138284}, + {0.016801,-0.084991,0.000000,0.009240}, + {0.020383,-0.002424,-0.012952,-0.014037}, + {-0.041653,0.002287,0.000000,-0.098181}, + {-0.009189,-0.049860,0.000268,-0.084941}, + {0.056976,-0.084627,-0.018144,0.000666}, + {-0.015588,0.003690,0.003994,0.002435}, + {0.023178,-0.024961,0.004433,-0.015144}, + {0.042007,-0.006559,-0.005887,0.083685}, + {0.007638,0.057870,-0.014244,0.041457}, + {-0.018006,-0.017846,-0.063624,-0.016378}, + {0.004914,-0.001756,-0.046715,0.015975}, + {0.004341,-0.014575,0.000560,0.050902}, + {0.000470,-0.036961,0.038622,0.031383}, + {-0.045796,0.000262,0.009858,0.031958}, }; int freq_spread[15];