History

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

spiricom committed 6 years ago

Commit af9f02f1 parent 249e21c5 files · +164 −58Browse files

Unified · Split

5 files
  1. .DS_Store +0 −0
  2. LEAF/.DS_Store +0 −0
  3. LEAF/Inc/leaf-analysis.h +24 −0
  4. LEAF/Src/leaf-analysis.c +93 −0
  5. LEAF/Src/leaf-filters.c +49 −60
.DS_Store+0−0

Binary file not shown.

LEAF/.DS_Store+0−0

Binary file not shown.

LEAF/Inc/leaf-analysis.h+24−0
@@ -51,6 +51,30 @@ extern "C" { · 50 unmodified lines
5151 int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
5252 int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh);
5353
54+ // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
55+
56+ /* Zero Crossing Detector */
57+ typedef struct _tZeroCrossing {
58+ int count;
59+ int maxWindowSize;
60+ int currentWindowSize;
61+ float invCurrentWindowSize;
62+ float* inBuffer;
63+ uint16_t* countBuffer;
64+ int prevPosition;
65+ int position;
66+ } _tZeroCrossing;
67+
68+ typedef _tZeroCrossing* tZeroCrossing;
69+
70+ void tZeroCrossing_init (tZeroCrossing* const, int maxWindowSize);
71+ void tZeroCrossing_free (tZeroCrossing* const);
72+ void tZeroCrossing_initToPool (tZeroCrossing* const, int maxWindowSize, tMempool* const);
73+ void tZeroCrossing_freeFromPool (tZeroCrossing* const, tMempool* const);
74+
75+ float tZeroCrossing_tick (tZeroCrossing* const, float input);
76+ void tZeroCrossing_setWindow (tZeroCrossing* const, float windowSize);
77+
5478 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
5579
5680 /* PowerEnvelopeFollower */
LEAF/Src/leaf-analysis.c+93−0
@@ -86,6 +86,99 @@ int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attack · 85 unmodified lines
8686 }
8787
8888
89+
90+
91+
92+// zero crossing detector
93+
94+void tZeroCrossing_init (tZeroCrossing* const zc, int maxWindowSize)
95+{
96+ tZeroCrossing_initToPool (zc, maxWindowSize, &leaf.mempool);
97+}
98+void tZeroCrossing_free (tZeroCrossing* const zc)
99+{
100+ tZeroCrossing_freeFromPool (zc, &leaf.mempool);
101+}
102+void tZeroCrossing_initToPool (tZeroCrossing* const zc, int maxWindowSize, tMempool* const mp)
103+{
104+ _tMempool* m = *mp;
105+ _tZeroCrossing* z = *zc = (_tZeroCrossing*) mpool_alloc(sizeof(_tZeroCrossing), m);
106+
107+ z->count = 0;
108+ z->maxWindowSize = maxWindowSize;
109+ z->currentWindowSize = maxWindowSize;
110+ z->invCurrentWindowSize = 1.0f / maxWindowSize;
111+ z->position = 0;
112+ z->prevPosition = maxWindowSize;
113+ z->inBuffer = (float*) mpool_calloc(sizeof(float) * maxWindowSize, m);
114+ z->countBuffer = (uint16_t*) mpool_calloc(sizeof(uint16_t) * maxWindowSize, m);
115+}
116+void tZeroCrossing_freeFromPool (tZeroCrossing* const zc, tMempool* const mp)
117+{
118+ _tMempool* m = *mp;
119+ _tZeroCrossing* z = *zc;
120+
121+ mpool_free(z, m);
122+}
123+
124+//returns proportion of zero crossings within window size (0.0 would be none in window, 1.0 would be all zero crossings)
125+float tZeroCrossing_tick (tZeroCrossing* const zc, float input)
126+{
127+ _tZeroCrossing* z = *zc;
128+
129+ z->inBuffer[z->position] = input;
130+ int futurePosition = ((z->position + 1) % z->currentWindowSize);
131+ float output = 0.0f;
132+
133+ //add new value to count
134+ if ((z->inBuffer[z->position] * z->inBuffer[z->prevPosition]) < 0.0f)
135+ {
136+ //zero crossing happened, add it to the count array
137+ z->countBuffer[z->position] = 1;
138+ z->count++;
139+ }
140+ else
141+ {
142+ z->countBuffer[z->position] = 0;
143+ }
144+
145+ //remove oldest value from count
146+ if (z->countBuffer[futurePosition] > 0)
147+ {
148+ z->count--;
149+ if (z->count < 0)
150+ {
151+ z->count = 0;
152+ }
153+ }
154+
155+ z->prevPosition = z->position;
156+ z->position = futurePosition;
157+
158+ output = z->count * z->invCurrentWindowSize;
159+
160+ return output;
161+}
162+
163+
164+void tZeroCrossing_setWindow (tZeroCrossing* const zc, float windowSize)
165+{
166+ _tZeroCrossing* z = *zc;
167+ if (windowSize <= z->maxWindowSize)
168+ {
169+ z->currentWindowSize = windowSize;
170+ }
171+ else
172+ {
173+ z->currentWindowSize = z->maxWindowSize;
174+ }
175+ z->invCurrentWindowSize = 1.0f / z->currentWindowSize;
176+}
177+
178+
179+
180+
181+
89182 //===========================================================================
90183 /* Power Follower */
91184 //===========================================================================
LEAF/Src/leaf-filters.c+49−60
@@ -843,90 +843,79 @@ void tBiQuadSampleRateChanged(tBiQuad* const ft) · 842 unmodified lines
843843 // is calculated when frequency changes.
844844 void tSVF_init(tSVF* const svff, SVFType type, float freq, float Q)
845845 {
846− _tSVF* svf = *svff = (_tSVF*) leaf_alloc(sizeof(_tSVF));
847−
846+ tSVF_initToPool (svff, type, freq, Q, &leaf.mempool);
847+
848+ // or maybe this?
849+ /*
850+ * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1
851+ */
852+
853+}
854+
855+void tSVF_free(tSVF* const svff)
856+{
857+ tSVF_freeFromPool (svff, &leaf.mempool);
858+}
859+
860+void tSVF_initToPool (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp)
861+{
862+ _tMempool* m = *mp;
863+ _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m);
864+
848865 svf->type = type;
849−
866+
850867 svf->ic1eq = 0;
851868 svf->ic2eq = 0;
852−
869+ svf->Q = Q;
870+ svf->cutoff = freq;
853871 svf->g = tanf(PI * freq * leaf.invSampleRate);
854872 svf->k = 1.0f/Q;
855873 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
856874 svf->a2 = svf->g*svf->a1;
857875 svf->a3 = svf->g*svf->a2;
876+ svf->cH = 0.0f;
877+ svf->cB = 0.0f;
878+ svf->cL = 1.0f;
858879
859880 if (type == SVFTypeLowpass)
860881 {
861− svf->cH = 0.0f;
862− svf->cB = 0.0f;
863− svf->kAmount = 0.0f;
864− svf->cL = 1.0f;
882+ svf->cH = 0.0f;
883+ svf->cB = 0.0f;
884+ svf->cBK = 0.0f;
885+ svf->cL = 1.0f;
865886 }
866887 else if (type == SVFTypeBandpass)
867888 {
868− svf->cH = 0.0f;
869− svf->cB = 1.0f;
870− svf->kAmount = 0.0f;
871− svf->cL = 0.0f;
889+ svf->cH = 0.0f;
890+ svf->cB = 1.0f;
891+ svf->cBK = 0.0f;
892+ svf->cL = 0.0f;
872893 }
873894
874895 else if (type == SVFTypeHighpass)
875896 {
876− svf->cH = 1.0f;
877− svf->cB = svf->k * -1.0f;
878− svf->kAmount = 1.0f;
879− svf->cL = -1.0f;
897+ svf->cH = 1.0f;
898+ svf->cB = 0.0f;
899+ svf->cBK = -1.0f;
900+ svf->cL = -1.0f;
880901 }
881902
882903 else if (type == SVFTypeNotch)
883904 {
884− svf->cH = 1.0f;
885− svf->cB = svf->k * -1.0f;
886− svf->kAmount = 1.0f;
887− svf->cL = 0.0f;
905+ svf->cH = 1.0f;
906+ svf->cB = 0.0f;
907+ svf->cBK = -1.0f;
908+ svf->cL = 0.0f;
888909 }
889910
890911
891912 else if (type == SVFTypePeak)
892913 {
893− svf->cH = 1.0f;
894− svf->cB = svf->k * -1.0f;
895− svf->kAmount = 1.0f;
896− svf->cL = -2.0f;
914+ svf->cH = 1.0f;
915+ svf->cB = 0.0f;
916+ svf->cBK = -1.0f;
917+ svf->cL = -2.0f;
897918 }
898− // or maybe this?
899− /*
900− * hp=1 bp=A/Q (where A is 10^(G/40) and G is gain in decibels) and lp = 1
901− */
902−
903−}
904−
905−void tSVF_free(tSVF* const svff)
906−{
907− _tSVF* svf = *svff;
908−
909− leaf_free(svf);
910−}
911−
912−void tSVF_initToPool (tSVF* const svff, SVFType type, float freq, float Q, tMempool* const mp)
913−{
914− _tMempool* m = *mp;
915− _tSVF* svf = *svff = (_tSVF*) mpool_alloc(sizeof(_tSVF), m);
916−
917− svf->type = type;
918−
919− svf->ic1eq = 0;
920− svf->ic2eq = 0;
921−
922− svf->g = tanf(PI * freq * leaf.invSampleRate);
923− svf->k = 1.0f/Q;
924− svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
925− svf->a2 = svf->g*svf->a1;
926− svf->a3 = svf->g*svf->a2;
927− svf->cH = 0.0f;
928− svf->cB = 0.0f;
929− svf->cL = 1.0f;
930919 }
931920
932921 void tSVF_freeFromPool (tSVF* const svff, tMempool* const mp)
@@ -948,13 +937,13 @@ float tSVF_tick(tSVF* const svff, float v0) · 15 unmodified lines
948937 svf->ic1eq = (2.0f * v1) - svf->ic1eq;
949938 svf->ic2eq = (2.0f * v2) - svf->ic2eq;
950939
951− return (v0 * svf->cH) + (svf->kAmount * svf->k * v1 * svf->cB) + (v2 * svf->cL);
940+ return (v0 * svf->cH) + (v1 * svf->cB) + (svf->k * v1 * svf->cBK) + (v2 * svf->cL);
952941 }
953942
954943 void tSVF_setFreq(tSVF* const svff, float freq)
955944 {
956945 _tSVF* svf = *svff;
957−
946+ svf->cutoff = freq;
958947 svf->g = tanf(PI * freq * leaf.invSampleRate);
959948 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
960949 svf->a2 = svf->g * svf->a1;
@@ -964,7 +953,7 @@ void tSVF_setFreq(tSVF* const svff, float freq) · 3 unmodified lines
964953 void tSVF_setQ(tSVF* const svff, float Q)
965954 {
966955 _tSVF* svf = *svff;
967−
956+ svf->Q = Q;
968957 svf->k = 1.0f/Q;
969958
970959 svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
@@ -972,7 +961,7 @@ void tSVF_setQ(tSVF* const svff, float Q) · 1 unmodified line
972961 svf->a3 = svf->g * svf->a2;
973962 }
974963
975−void tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q)
964+void tSVF_setFreqAndQ(tSVF* const svff, float freq, float Q)
976965 {
977966 _tSVF* svf = *svff;
978967 svf->k = 1.0f/Q;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t