shithub: leaf

Download patch

ref: 1a26f591471711b6ba36625a296d485a7b5702d6
parent: f98d24f939182df6a21177b8dde5937d160c8996
author: spiricom <jeff@snyderphonics.com>
date: Thu May 7 21:34:57 EDT 2020

added setfreqandbandwidth to vzfilter

binary files a/LEAF/.DS_Store b/LEAF/.DS_Store differ
--- a/LEAF/Inc/leaf-filters.h
+++ b/LEAF/Inc/leaf-filters.h
@@ -386,61 +386,47 @@
 
 	//Vadim Zavalishin style from VA book (from implementation in RSlib posted to kvr forum)
 
-    typedef enum VZFilterType
-    {
-    	Highpass = 0,
-        Lowpass,
-        BandpassSkirt,
-		BandpassPeak,
-		BandReject,
-        Bell,
-		Lowshelf,
-		Highshelf,
-		Morph,
-		Bypass,
-		Allpass
-    } VZFilterType;
+        typedef struct _tVZFilter
+        {
+            VZFilterType type;
+            // state:
+            float s1, s2;
 
+            // filter coefficients:
+            float g;          // embedded integrator gain
+            float R2;         // twice the damping coefficient (R2 == 2*R == 1/Q)
+            float h;          // factor for feedback (== 1/(1+2*R*g+g*g))
+            float cL, cB, cH; // coefficients for low-, band-, and highpass signals
 
-	typedef struct _tVZFilter
-	    {
-			VZFilterType type;
-			// state:
-			float s1, s2;
+            // parameters:
+            float fs;    // sample-rate
+            float fc;    // characteristic frequency
+            float G;     // gain
+            float invG;     //1/gain
+            float B;     // bandwidth (in octaves)
+            float m;     // morph parameter (0...1)
 
-			// filter coefficients:
-			float g;          // embedded integrator gain
-			float R2;         // twice the damping coefficient (R2 == 2*R == 1/Q)
-			float h;          // factor for feedback (== 1/(1+2*R*g+g*g))
-			float cL, cB, cH; // coefficients for low-, band-, and highpass signals
+            float sr;    //local sampling rate of filter (may be different from leaf sr if oversampled)
+            float inv_sr;
 
-			// parameters:
-			float fs;    // sample-rate
-			float fc;    // characteristic frequency
-			float G;     // gain
-			float invG;		//1/gain
-			float B;     // bandwidth (in octaves)
-			float m;     // morph parameter (0...1)
+        } _tVZFilter;
 
-			float sr;    //local sampling rate of filter (may be different from leaf sr if oversampled)
-			float inv_sr;
+        typedef _tVZFilter* tVZFilter;
 
-	    } _tVZFilter;
-
-	    typedef _tVZFilter* tVZFilter;
-
-	    void    tVZFilter_init           (tVZFilter* const, VZFilterType type, float freq, float Q);
-		void    tVZFilter_free           (tVZFilter* const);
-		void    tVZFilter_initToPool     (tVZFilter* const, VZFilterType type, float freq, float Q, tMempool* const);
-		void    tVZFilter_freeFromPool   (tVZFilter* const, tMempool* const);
-		void 	tVZFilter_setSampleRate  (tVZFilter* const, float sampleRate);
-		float   tVZFilter_tick           	(tVZFilter* const, float input);
-		void   tVZFilter_calcCoeffs           (tVZFilter* const);
-		void   tVZFilter_setBandwidth        	(tVZFilter* const, float bandWidth);
-		void   tVZFilter_setFreq           (tVZFilter* const, float freq);
-		void   tVZFilter_setGain          		(tVZFilter* const, float gain);
-		void   tVZFilter_setType          		(tVZFilter* const, VZFilterType type);
-		float 	tVZFilter_BandwidthToR		(tVZFilter* const vf, float B);
+        void    tVZFilter_init           (tVZFilter* const, VZFilterType type, float freq, float Q);
+        void    tVZFilter_free           (tVZFilter* const);
+        void    tVZFilter_initToPool     (tVZFilter* const, VZFilterType type, float freq, float Q, tMempool* const);
+        void    tVZFilter_freeFromPool   (tVZFilter* const, tMempool* const);
+        void    tVZFilter_setSampleRate  (tVZFilter* const, float sampleRate);
+        float   tVZFilter_tick              (tVZFilter* const, float input);
+        float   tVZFilter_tickEfficient             (tVZFilter* const vf, float in);
+        void   tVZFilter_calcCoeffs           (tVZFilter* const);
+        void   tVZFilter_setBandwidth           (tVZFilter* const, float bandWidth);
+        void   tVZFilter_setFreq           (tVZFilter* const, float freq);
+        void   tVZFilter_setFreqAndBandwidth    (tVZFilter* const vf, float freq, float bw);
+        void   tVZFilter_setGain                (tVZFilter* const, float gain);
+        void   tVZFilter_setType                (tVZFilter* const, VZFilterType type);
+        float   tVZFilter_BandwidthToR      (tVZFilter* const vf, float B);
 
 
 
--- a/LEAF/Src/leaf-filters.c
+++ b/LEAF/Src/leaf-filters.c
@@ -1366,229 +1366,271 @@
 }
 
 
+/////
+
 void    tVZFilter_init           (tVZFilter* const vf, VZFilterType type, float freq, float bandWidth)
 {
-	tVZFilter_initToPool(vf, type, freq, bandWidth, &leaf.mempool);
+    tVZFilter_initToPool(vf, type, freq, bandWidth, &leaf.mempool);
 }
 
 void    tVZFilter_free           (tVZFilter* const vf)
 {
-	tVZFilter_freeFromPool(vf, &leaf.mempool);
+    tVZFilter_freeFromPool(vf, &leaf.mempool);
 }
 void    tVZFilter_initToPool     (tVZFilter* const vf, VZFilterType type, float freq, float bandWidth, tMempool* const mp)
 {
 
-	 _tMempool* m = *mp;
-	 _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
-	f->fc   = freq;
-	f->type = type;
-	f->G    = ONE_OVER_SQRT2;
-	f->B    = bandWidth;
-	f->m    = 0.0f;
-	f->s1 = 0.0f;
-	f->s2 = 0.0f;
-	f->sr = leaf.sampleRate;
-	f->inv_sr = leaf.invSampleRate;
-	tVZFilter_calcCoeffs(vf);
+     _tMempool* m = *mp;
+     _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
+    f->fc   = freq;
+    f->type = type;
+    f->G    = ONE_OVER_SQRT2;
+    f->invG    = 1.0f/ONE_OVER_SQRT2;
+    f->B    = bandWidth;
+    f->m    = 0.0f;
+    f->s1 = 0.0f;
+    f->s2 = 0.0f;
+    f->sr = leaf.sampleRate;
+    f->inv_sr = leaf.invSampleRate;
+    tVZFilter_calcCoeffs(vf);
 
 
 }
 void    tVZFilter_freeFromPool   (tVZFilter* const vf, tMempool* const mp)
 {
-	 _tMempool* m = *mp;
-		 _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
-		 mpool_free(f, m);
+     _tMempool* m = *mp;
+         _tVZFilter* f = *vf = (_tVZFilter*) mpool_alloc(sizeof(_tVZFilter), m);
+         mpool_free(f, m);
 }
 
-void 	tVZFilter_setSampleRate  (tVZFilter* const vf, float sampleRate)
+void    tVZFilter_setSampleRate  (tVZFilter* const vf, float sampleRate)
 {
-	_tVZFilter* f = *vf;
-	f->sr = sampleRate;
-	f->inv_sr = 1.0f/sampleRate;
+    _tVZFilter* f = *vf;
+    f->sr = sampleRate;
+    f->inv_sr = 1.0f/sampleRate;
 }
 
-float   tVZFilter_tick           	(tVZFilter* const vf, float in)
+float   tVZFilter_tick              (tVZFilter* const vf, float in)
 {
-	_tVZFilter* f = *vf;
+    _tVZFilter* f = *vf;
 
-	float yL, yB, yH;
+    float yL, yB, yH;
 
-	// compute highpass output via Eq. 5.1:
-	yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
+    // compute highpass output via Eq. 5.1:
+    yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
 
-	// compute bandpass output by applying 1st integrator to highpass output:
-	yB = tanhf(f->g*yH) + f->s1;
-	f->s1 = f->g*yH + yB; // state update in 1st integrator
+    // compute bandpass output by applying 1st integrator to highpass output:
+    yB = tanhf(f->g*yH) + f->s1;
+    f->s1 = f->g*yH + yB; // state update in 1st integrator
 
-	// compute lowpass output by applying 2nd integrator to bandpass output:
-	yL = tanhf(f->g*yB) + f->s2;
-	f->s2 = f->g*yB + yL; // state update in 2nd integrator
+    // compute lowpass output by applying 2nd integrator to bandpass output:
+    yL = tanhf(f->g*yB) + f->s2;
+    f->s2 = f->g*yB + yL; // state update in 2nd integrator
 
-	//according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
-	//
-	//seems like that might look like this:
+    //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
+    //
+    //seems like that might look like this:
     // y = tanh(g*x) + s; // output computation
     // s = g*x + y; // state update
 
-	//instead of this:
+    //instead of this:
     // y = g*x + s; // output computation
     // s = g*x + y; // state update
 
-	return f->cL*yL + f->cB*yB + f->cH*yH;
+    return f->cL*yL + f->cB*yB + f->cH*yH;
 
 }
 
+float   tVZFilter_tickEfficient             (tVZFilter* const vf, float in)
+{
+    _tVZFilter* f = *vf;
+
+    float yL, yB, yH;
+
+    // compute highpass output via Eq. 5.1:
+    yH = (in - f->R2*f->s1 - f->g*f->s1 - f->s2) * f->h;
+
+    // compute bandpass output by applying 1st integrator to highpass output:
+    yB = (f->g*yH) + f->s1;
+    f->s1 = f->g*yH + yB; // state update in 1st integrator
+
+    // compute lowpass output by applying 2nd integrator to bandpass output:
+    yL = (f->g*yB) + f->s2;
+    f->s2 = f->g*yB + yL; // state update in 2nd integrator
+
+    //according to the Vadim paper, we could add saturation to this model by adding a tanh in the integration stage.
+    //
+    //seems like that might look like this:
+    // y = tanh(g*x) + s; // output computation
+    // s = g*x + y; // state update
+
+    //instead of this:
+    // y = g*x + s; // output computation
+    // s = g*x + y; // state update
+
+    return f->cL*yL + f->cB*yB + f->cH*yH;
+
+}
+
+
 void   tVZFilter_calcCoeffs           (tVZFilter* const vf)
 {
 
-	_tVZFilter* f = *vf;
-	f->g = tanf(PI * f->fc * f->inv_sr);  // embedded integrator gain (Fig 3.11)
+    _tVZFilter* f = *vf;
+    f->g = tanf(PI * f->fc * f->inv_sr);  // embedded integrator gain (Fig 3.11)
 
-	  switch( f->type )
-	  {
-	  case Bypass:
-		{
-		  f->R2 = f->invG;  // can we use an arbitrary value here, for example R2 = 1?
-		  f->cL = 1.0f;
-		  f->cB = f->R2;
-		  f->cH = 1.0f;
-		}
-		break;
-	  case Lowpass:
-		{
-			f->R2 = f->invG;
-			f->cL = 1.0f; f->cB = 0.0f; f->cH = 0.0f;
-		}
-		break;
-	  case Highpass:
-		{
-			f->R2 = f->invG;
-			f->cL = 0.0f; f->cB = 0.0f; f->cH = 1.0f;
-		}
-		break;
-	  case BandpassSkirt:
-		{
-			f->R2 = f->invG;
-			f->cL = 0.0f; f->cB = 1.0f; f->cH = 0.0f;
-		}
-		break;
-	  case BandpassPeak:
-		{
-			f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
-			f->cL = 0.0f; f->cB = f->R2; f->cH = 0.0f;
-		}
-		break;
-	  case BandReject:
-		{
-			f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
-			f->cL = 1.0f; f->cB = 0.0f; f->cH = 1.0f;
-		}
-		break;
-	  case Bell:
-		{
-			float fl = f->fc*powf(2.0f, (-f->B)*0.5f); // lower bandedge frequency (in Hz)
-			float wl = tanf(PI*fl*f->inv_sr);   // warped radian lower bandedge frequency /(2*fs)
-			float r  = f->g/wl;
-			r *= r;    // warped frequency ratio wu/wl == (wc/wl)^2 where wu is the
-									   // warped upper bandedge, wc the center
-			f->R2 = 2.0f*sqrtf(((r*r+1.0f)/r-2.0f)/(4.0f*f->G));
-			f->cL = 1.0f; f->cB = f->R2*f->G; f->cH = 1.0f;
-		}
-		break;
-	  case Lowshelf:
-		{
-			float A = sqrtf(f->G);
-		  f->g /= sqrtf(A);               // scale SVF-cutoff frequency for shelvers
-		  f->R2 = 2*sinhf(f->B*logf(2.0f)*0.5f);
-		  f->cL = f->G; f->cB = f->R2*A; f->cH = 1.0f;
-		}
-		break;
-	  case Highshelf:
-		{
-		  float A = sqrtf(f->G);
-		  f->g *= sqrtf(A);               // scale SVF-cutoff frequency for shelvers
-		  f->R2 = 2.0f*sinhf(f->B*logf(2.0f)*0.5f);
-		  f->cL = 1.0f; f->cB = f->R2*A; f->cH = f->G;
-		}
-		break;
-	  case Allpass:
-		{
-			f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
-			f->cL = 1.0f; f->cB = -f->R2; f->cH = 1.0f;
-		}
-		break;
+      switch( f->type )
+      {
+      case Bypass:
+        {
+          f->R2 = f->invG;  // can we use an arbitrary value here, for example R2 = 1?
+          f->cL = 1.0f;
+          f->cB = f->R2;
+          f->cH = 1.0f;
+        }
+        break;
+      case Lowpass:
+        {
+            f->R2 = f->invG;
+            f->cL = 1.0f; f->cB = 0.0f; f->cH = 0.0f;
+        }
+        break;
+      case Highpass:
+        {
+            f->R2 = f->invG;
+            f->cL = 0.0f; f->cB = 0.0f; f->cH = 1.0f;
+        }
+        break;
+      case BandpassSkirt:
+        {
+            f->R2 = f->invG;
+            f->cL = 0.0f; f->cB = 1.0f; f->cH = 0.0f;
+        }
+        break;
+      case BandpassPeak:
+        {
+            f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
+            f->cL = 0.0f; f->cB = f->R2; f->cH = 0.0f;
+        }
+        break;
+      case BandReject:
+        {
+            f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
+            f->cL = 1.0f; f->cB = 0.0f; f->cH = 1.0f;
+        }
+        break;
+      case Bell:
+        {
+            float fl = f->fc*powf(2.0f, (-f->B)*0.5f); // lower bandedge frequency (in Hz)
+            float wl = tanf(PI*fl*f->inv_sr);   // warped radian lower bandedge frequency /(2*fs)
+            float r  = f->g/wl;
+            r *= r;    // warped frequency ratio wu/wl == (wc/wl)^2 where wu is the
+                                       // warped upper bandedge, wc the center
+            f->R2 = 2.0f*sqrtf(((r*r+1.0f)/r-2.0f)/(4.0f*f->G));
+            f->cL = 1.0f; f->cB = f->R2*f->G; f->cH = 1.0f;
+        }
+        break;
+      case Lowshelf:
+        {
+            float A = sqrtf(f->G);
+          f->g /= sqrtf(A);               // scale SVF-cutoff frequency for shelvers
+          f->R2 = 2*sinhf(f->B*logf(2.0f)*0.5f);
+          f->cL = f->G; f->cB = f->R2*A; f->cH = 1.0f;
+        }
+        break;
+      case Highshelf:
+        {
+          float A = sqrtf(f->G);
+          f->g *= sqrtf(A);               // scale SVF-cutoff frequency for shelvers
+          f->R2 = 2.0f*sinhf(f->B*logf(2.0f)*0.5f);
+          f->cL = 1.0f; f->cB = f->R2*A; f->cH = f->G;
+        }
+        break;
+      case Allpass:
+        {
+            f->R2 = 2.0f*tVZFilter_BandwidthToR(vf, f->B);
+            f->cL = 1.0f; f->cB = -f->R2; f->cH = 1.0f;
+        }
+        break;
 
-		// experimental - maybe we must find better curves for cL, cB, cH:
-	  case Morph:
-		{
-			f->R2 = f->invG;
-		  float x  = 2.0f*f->m-1.0f;
+        // experimental - maybe we must find better curves for cL, cB, cH:
+      case Morph:
+        {
+            f->R2 = f->invG;
+          float x  = 2.0f*f->m-1.0f;
 
-		  f->cL = maximum(-x, 0.0f); /*cL *= cL;*/
-		  f->cH = minimum( x, 0.0f); /*cH *= cH;*/
-		  f->cB = 1.0f-x*x;
+          f->cL = maximum(-x, 0.0f); /*cL *= cL;*/
+          f->cH = minimum( x, 0.0f); /*cH *= cH;*/
+          f->cB = 1.0f-x*x;
 
-			// bottom line: we need to test different versions for how they feel when tweaking the
-			// morph parameter
+            // bottom line: we need to test different versions for how they feel when tweaking the
+            // morph parameter
 
-		  // this scaling ensures constant magnitude at the cutoff point (we divide the coefficients by
-		  // the magnitude response value at the cutoff frequency and scale back by the gain):
-		  float s = f->G * sqrtf((f->R2*f->R2) / (f->cL*f->cL + f->cB*f->cB + f->cH*f->cH - 2.0f*f->cL*f->cH));
-		  f->cL *= s; f->cB *= s; f->cH *= s;
-		}
-		break;
+          // this scaling ensures constant magnitude at the cutoff point (we divide the coefficients by
+          // the magnitude response value at the cutoff frequency and scale back by the gain):
+          float s = f->G * sqrtf((f->R2*f->R2) / (f->cL*f->cL + f->cB*f->cB + f->cH*f->cH - 2.0f*f->cL*f->cH));
+          f->cL *= s; f->cB *= s; f->cH *= s;
+        }
+        break;
 
-	  }
+      }
 
-	  f->h = 1.0f / (1.0f + f->R2*f->g + f->g*f->g);  // factor for feedback precomputation
+      f->h = 1.0f / (1.0f + f->R2*f->g + f->g*f->g);  // factor for feedback precomputation
 }
 
 
-void   tVZFilter_setBandwidth           	(tVZFilter* const vf, float B)
+void   tVZFilter_setBandwidth               (tVZFilter* const vf, float B)
 {
-	_tVZFilter* f = *vf;
-	f->B = LEAF_clip(0.0f, B, 100.0f);
-	tVZFilter_calcCoeffs(vf);
+    _tVZFilter* f = *vf;
+    f->B = LEAF_clip(0.0f, B, 100.0f);
+    tVZFilter_calcCoeffs(vf);
 }
 void   tVZFilter_setFreq           (tVZFilter* const vf, float freq)
 {
-	_tVZFilter* f = *vf;
-	f->fc = LEAF_clip(0.0f, freq, 0.5f*leaf.sampleRate);
-	tVZFilter_calcCoeffs(vf);
+    _tVZFilter* f = *vf;
+    f->fc = LEAF_clip(0.0f, freq, 0.5f*leaf.sampleRate);
+    tVZFilter_calcCoeffs(vf);
 }
-void   tVZFilter_setGain          		(tVZFilter* const vf, float gain)
+void   tVZFilter_setFreqAndBandwidth           (tVZFilter* const vf, float freq, float bw)
 {
-	_tVZFilter* f = *vf;
-	f->G = LEAF_clip(0.000001f, gain, 100.0f);
-	f->invG = 1.0f/f->G;
-	tVZFilter_calcCoeffs(vf);
+    _tVZFilter* f = *vf;
+    f->B = LEAF_clip(0.0f,bw, 100.0f);
+    f->fc = LEAF_clip(0.0f, freq, 0.5f*leaf.sampleRate);
+    tVZFilter_calcCoeffs(vf);
 }
 
-void   tVZFilter_setMorph          		(tVZFilter* const vf, float morph)
+void   tVZFilter_setGain                (tVZFilter* const vf, float gain)
 {
-	_tVZFilter* f = *vf;
-	f->m = LEAF_clip(0.0f, morph, 1.0f);
-	tVZFilter_calcCoeffs(vf);
+    _tVZFilter* f = *vf;
+    f->G = LEAF_clip(0.000001f, gain, 100.0f);
+    f->invG = 1.0f/f->G;
+    tVZFilter_calcCoeffs(vf);
 }
 
-void tVZFilter_setType         		(tVZFilter* const vf, VZFilterType type)
+void   tVZFilter_setMorph               (tVZFilter* const vf, float morph)
 {
-	_tVZFilter* f = *vf;
-	f->type = type;
-	tVZFilter_calcCoeffs(vf);
+    _tVZFilter* f = *vf;
+    f->m = LEAF_clip(0.0f, morph, 1.0f);
+    tVZFilter_calcCoeffs(vf);
 }
 
+void tVZFilter_setType              (tVZFilter* const vf, VZFilterType type)
+{
+    _tVZFilter* f = *vf;
+    f->type = type;
+    tVZFilter_calcCoeffs(vf);
+}
+
 float tVZFilter_BandwidthToR(tVZFilter* const vf, float B)
 {
-	_tVZFilter* f = *vf;
+    _tVZFilter* f = *vf;
   float fl = f->fc*powf(2.0f, -B*0.5f); // lower bandedge frequency (in Hz)
   float gl = tanf(PI*fl*f->inv_sr);   // warped radian lower bandedge frequency /(2*fs)
   float r  = gl/f->g;            // ratio between warped lower bandedge- and center-frequencies
-							   // unwarped: r = pow(2, -B/2) -> approximation for low
-							   // center-frequencies
+                               // unwarped: r = pow(2, -B/2) -> approximation for low
+                               // center-frequencies
   return sqrtf((1.0f-r*r)*(1.0f-r*r)/(4.0f*r*r));
 }
-
 
 
 void    tDiodeFilter_init           (tDiodeFilter* const vf, float cutoff, float resonance)