shithub: leaf

Download patch

ref: af9f02fa0616c2d0001fb9d8c8b65f151de34ff8
parent: 249e21c4a352ebbf990f72e8e4e760eece755989
author: spiricom <jeff@snyderphonics.com>
date: Wed May 6 20:34:52 EDT 2020

fixed SVF bandpass issue, added zero crossing detector in analysis.h

binary files a/.DS_Store b/.DS_Store differ
binary files a/LEAF/.DS_Store b/LEAF/.DS_Store differ
--- a/LEAF/Inc/leaf-analysis.h
+++ b/LEAF/Inc/leaf-analysis.h
@@ -52,6 +52,30 @@
     int     tEnvelopeFollower_attackThresh  (tEnvelopeFollower* const, float attackThresh);
     
     // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+    /* Zero Crossing Detector */
+    typedef struct _tZeroCrossing {
+        int count;
+        int maxWindowSize;
+        int currentWindowSize;
+        float invCurrentWindowSize;
+        float* inBuffer;
+        uint16_t* countBuffer;
+        int prevPosition;
+        int position;
+    } _tZeroCrossing;
+
+    typedef _tZeroCrossing* tZeroCrossing;
+
+    void    tZeroCrossing_init         (tZeroCrossing* const, int maxWindowSize);
+    void    tZeroCrossing_free         (tZeroCrossing* const);
+    void    tZeroCrossing_initToPool   (tZeroCrossing* const, int maxWindowSize, tMempool* const);
+    void    tZeroCrossing_freeFromPool (tZeroCrossing* const, tMempool* const);
+
+    float   tZeroCrossing_tick         (tZeroCrossing* const, float input);
+    void    tZeroCrossing_setWindow        (tZeroCrossing* const, float windowSize);
+
+    // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
     
     /* PowerEnvelopeFollower */
     typedef struct _tPowerFollower {
--- a/LEAF/Src/leaf-analysis.c
+++ b/LEAF/Src/leaf-analysis.c
@@ -86,6 +86,99 @@
 }
 
 
+
+
+
+// zero crossing detector
+
+void    tZeroCrossing_init         (tZeroCrossing* const zc, int maxWindowSize)
+{
+    tZeroCrossing_initToPool   (zc, maxWindowSize, &leaf.mempool);
+}
+void    tZeroCrossing_free         (tZeroCrossing* const zc)
+{
+    tZeroCrossing_freeFromPool   (zc, &leaf.mempool);
+}
+void    tZeroCrossing_initToPool   (tZeroCrossing* const zc, int maxWindowSize, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tZeroCrossing* z = *zc = (_tZeroCrossing*) mpool_alloc(sizeof(_tZeroCrossing), m);
+
+    z->count = 0;
+    z->maxWindowSize = maxWindowSize;
+    z->currentWindowSize = maxWindowSize;
+    z->invCurrentWindowSize = 1.0f / maxWindowSize;
+    z->position = 0;
+    z->prevPosition = maxWindowSize;
+    z->inBuffer = (float*) mpool_calloc(sizeof(float) * maxWindowSize, m);
+    z->countBuffer = (uint16_t*) mpool_calloc(sizeof(uint16_t) * maxWindowSize, m);
+}
+void    tZeroCrossing_freeFromPool (tZeroCrossing* const zc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tZeroCrossing* z = *zc;
+
+    mpool_free(z, m);
+}
+
+//returns proportion of zero crossings within window size (0.0 would be none in window, 1.0 would be all zero crossings)
+float   tZeroCrossing_tick         (tZeroCrossing* const zc, float input)
+{
+    _tZeroCrossing* z = *zc;
+
+    z->inBuffer[z->position] = input;
+    int futurePosition = ((z->position + 1) % z->currentWindowSize);
+    float output = 0.0f;
+
+    //add new value to count
+    if ((z->inBuffer[z->position] * z->inBuffer[z->prevPosition]) < 0.0f)
+    {
+        //zero crossing happened, add it to the count array
+        z->countBuffer[z->position] = 1;
+        z->count++;
+    }
+    else
+    {
+        z->countBuffer[z->position] = 0;
+    }
+
+    //remove oldest value from count
+    if (z->countBuffer[futurePosition] > 0)
+    {
+        z->count--;
+        if (z->count < 0)
+        {
+            z->count = 0;
+        }
+    }
+
+    z->prevPosition = z->position;
+    z->position = futurePosition;
+
+    output = z->count * z->invCurrentWindowSize;
+
+    return output;
+}
+
+
+void    tZeroCrossing_setWindow        (tZeroCrossing* const zc, float windowSize)
+{
+    _tZeroCrossing* z = *zc;
+    if (windowSize <= z->maxWindowSize)
+        {
+            z->currentWindowSize = windowSize;
+        }
+    else
+    {
+        z->currentWindowSize = z->maxWindowSize;
+    }
+    z->invCurrentWindowSize = 1.0f / z->currentWindowSize;
+}
+
+
+
+
+
 //===========================================================================
 /* Power Follower */
 //===========================================================================
--- a/LEAF/Src/leaf-filters.c
+++ b/LEAF/Src/leaf-filters.c
@@ -843,92 +843,81 @@
 // is calculated when frequency changes.
 void tSVF_init(tSVF* const svff, SVFType type, float freq, float Q)
 {
-    _tSVF* svf = *svff = (_tSVF*) leaf_alloc(sizeof(_tSVF));
-    
+    tSVF_initToPool     (svff, type, freq, Q, &leaf.mempool);
+
+    // or maybe this?
+    /*
+     * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1
+     */
+
+}
+
+void tSVF_free(tSVF* const svff)
+{
+    tSVF_freeFromPool     (svff, &leaf.mempool);
+}
+
+void    tSVF_initToPool     (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m);
+
     svf->type = type;
-    
+
     svf->ic1eq = 0;
     svf->ic2eq = 0;
-    
+    svf->Q = Q;
+    svf->cutoff = freq;
     svf->g = tanf(PI * freq * leaf.invSampleRate);
     svf->k = 1.0f/Q;
     svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
     svf->a2 = svf->g*svf->a1;
     svf->a3 = svf->g*svf->a2;
+    svf->cH = 0.0f;
+    svf->cB = 0.0f;
+    svf->cL = 1.0f;
 
     if (type == SVFTypeLowpass)
     {
-		svf->cH = 0.0f;
-		svf->cB = 0.0f;
-		svf->kAmount = 0.0f;
-		svf->cL = 1.0f;
+        svf->cH = 0.0f;
+        svf->cB = 0.0f;
+        svf->cBK = 0.0f;
+        svf->cL = 1.0f;
     }
     else if (type == SVFTypeBandpass)
     {
-		svf->cH = 0.0f;
-		svf->cB = 1.0f;
-		svf->kAmount = 0.0f;
-		svf->cL = 0.0f;
+        svf->cH = 0.0f;
+        svf->cB = 1.0f;
+        svf->cBK = 0.0f;
+        svf->cL = 0.0f;
     }
 
     else if (type == SVFTypeHighpass)
     {
-		svf->cH = 1.0f;
-		svf->cB = svf->k * -1.0f;
-		svf->kAmount = 1.0f;
-		svf->cL = -1.0f;
+        svf->cH = 1.0f;
+        svf->cB = 0.0f;
+        svf->cBK = -1.0f;
+        svf->cL = -1.0f;
     }
 
     else if (type == SVFTypeNotch)
     {
-		svf->cH = 1.0f;
-		svf->cB = svf->k * -1.0f;
-		svf->kAmount = 1.0f;
-		svf->cL = 0.0f;
+        svf->cH = 1.0f;
+        svf->cB = 0.0f;
+        svf->cBK = -1.0f;
+        svf->cL = 0.0f;
     }
 
 
     else if (type == SVFTypePeak)
     {
-		svf->cH = 1.0f;
-		svf->cB = svf->k * -1.0f;
-		svf->kAmount = 1.0f;
-		svf->cL = -2.0f;
+        svf->cH = 1.0f;
+        svf->cB = 0.0f;
+        svf->cBK = -1.0f;
+        svf->cL = -2.0f;
     }
-    // or maybe this?
-    /*
-     * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1
-     */
-
 }
 
-void tSVF_free(tSVF* const svff)
-{
-    _tSVF* svf = *svff;
-    
-    leaf_free(svf);
-}
-
-void    tSVF_initToPool     (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp)
-{
-    _tMempool* m = *mp;
-    _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m);
-    
-    svf->type = type;
-    
-    svf->ic1eq = 0;
-    svf->ic2eq = 0;
-    
-    svf->g = tanf(PI * freq * leaf.invSampleRate);
-    svf->k = 1.0f/Q;
-    svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
-    svf->a2 = svf->g*svf->a1;
-    svf->a3 = svf->g*svf->a2;
-    svf->cH = 0.0f;
-    svf->cB = 0.0f;
-    svf->cL = 1.0f;
-}
-
 void    tSVF_freeFromPool   (tSVF* const svff, tMempool* const mp)
 {
     _tMempool* m = *mp;
@@ -948,13 +937,13 @@
     svf->ic1eq = (2.0f * v1) - svf->ic1eq;
     svf->ic2eq = (2.0f * v2) - svf->ic2eq;
     
-    return (v0 * svf->cH) + (svf->kAmount * svf->k * v1 * svf->cB) + (v2 * svf->cL);
+    return (v0 * svf->cH) + (v1 * svf->cB) + (svf->k * v1 * svf->cBK) + (v2 * svf->cL);
 }
 
 void     tSVF_setFreq(tSVF* const svff, float freq)
 {
     _tSVF* svf = *svff;
-    
+    svf->cutoff = freq;
     svf->g = tanf(PI * freq * leaf.invSampleRate);
     svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
     svf->a2 = svf->g * svf->a1;
@@ -964,7 +953,7 @@
 void     tSVF_setQ(tSVF* const svff, float Q)
 {
     _tSVF* svf = *svff;
-    
+    svf->Q = Q;
     svf->k = 1.0f/Q;
 
     svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
@@ -972,7 +961,7 @@
     svf->a3 = svf->g * svf->a2;
 }
 
-void 	tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q)
+void    tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q)
 {
     _tSVF* svf = *svff;
     svf->k = 1.0f/Q;