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;