ref: f504bc437e406429f2d0ae8fa745c4e2d3babce2
parent: 654405de9bc9c636558211aadd707cba8a05f541
author: Matthew Wang <mjw7@princeton.edu>
date: Tue Jul 7 13:26:19 EDT 2020
wip on bitstream auto correlation
--- a/leaf/Inc/leaf-analysis.h
+++ b/leaf/Inc/leaf-analysis.h
@@ -639,6 +639,124 @@
//==============================================================================
+ typedef struct _tZeroCrossing2
+ {
+ tMempool mempool;
+
+ float _before_crossing;
+ float _after_crossing;
+
+ float _peak;
+ int _leading_edge;// = undefined_edge; int_min
+ int _trailing_edge;// = undefined_edge;
+ float _width;// = 0.0f;
+ } _tZeroCrossing2;
+
+ typedef _tZeroCrossing2* tZeroCrossing2;
+
+ void tZeroCrossing2_init (tZeroCrossing2* const);
+ void tZeroCrossing2_initToPool (tZeroCrossing2* const, tMempool* const);
+ void tZeroCrossing2_free (tZeroCrossing2* const);
+
+ int tZeroCrossing2_tick(tZeroCrossing2* const, float s);
+ int tZeroCrossing2_getState(tZeroCrossing2* const);
+ void tZeroCrossing2_updatePeak(tZeroCrossing2* const, float s, int pos);
+ int tZeroCrossing2_period(tZeroCrossing2* const, tZeroCrossing2* const next);
+ float tZeroCrossing2_fractionalPeriod(tZeroCrossing2* const, tZeroCrossing2* const next);
+ int tZeroCrossing2_getWidth(tZeroCrossing2* const);
+ int tZeroCrossing2_isSimilar(tZeroCrossing2* const, tZeroCrossing2* const next);
+
+ //==============================================================================
+
+#define PULSE_HEIGHT_DIFF 0.8
+#define PULSE_WIDTH_DIFF 0.85
+
+ typedef struct _tZeroCrossings
+ {
+ tMempool mempool;
+
+ _tZeroCrossing2* _info;
+
+ int index;
+
+ float _prev;// = 0.0f;
+ float _hysteresis;
+ bool _state;// = false;
+ int _num_edges;// = 0;
+ int _window_size;
+ int _frame;// = 0;
+ bool _ready;// = false;
+ float _peak_update;// = 0.0f;
+ float _peak;// = 0.0f;
+ } _tZeroCrossings;
+
+ typedef _tZeroCrossings* tZeroCrossings;
+
+ void tZeroCrossings_init (tZeroCrossings* const, int windowSize, float hysteresis);
+ void tZeroCrossings_initToPool (tZeroCrossings* const, int windowSize, float hysteresis, tMempool* const);
+ void tZeroCrossings_free (tZeroCrossings* const);
+
+ int tZeroCrossings_tick(tZeroCrossings* const, float s);
+ int tZeroCrossings_getState(tZeroCrossings* const);
+
+ int tZeroCrossings_getNumEdges(tZeroCrossings* const zc);
+ int tZeroCrossings_getCapacity(tZeroCrossings* const zc);
+ int tZeroCrossings_getFrame(tZeroCrossings* const zc);
+ int tZeroCrossings_getWindowSize(tZeroCrossings* const zc);
+
+ int tZeroCrossings_isReady(tZeroCrossings* const zc);
+ float tZeroCrossings_getPeak(tZeroCrossings* const zc);
+ int tZeroCrossings_isReset(tZeroCrossings* const zc);
+
+ tZeroCrossing2* const tZeroCrossings_getCrossing(int index);
+
+ //==============================================================================
+
+ typedef struct _tBitset
+ {
+ tMempool mempool;
+
+ unsigned int* _bits;
+ } _tBitset;
+
+ typedef _tBitset* tBitset;
+
+ void tBitset_init (tBitset* const bitset, int numBits);
+ void tBitset_initToPool (tBitset* const bitset, int numBits, tMempool* const mempool);
+ void tBitset_free (tBitset* const bitset);
+
+ int tBitset_getSize (tBitset* const bitset);
+// bitset& operator=(bitset const& rhs) = default;
+// bitset& operator=(bitset&& rhs) = default;
+//
+// std::size_t size() const;
+// void clear();
+// void set(std::size_t i, bool val);
+// void set(std::size_t i, std::size_t n, bool val);
+// bool get(std::size_t i) const;
+//
+// T* data();
+// T const* data() const;
+
+ //==============================================================================
+
+ typedef struct _tBACF
+ {
+ tMempool mempool;
+
+ int windowSize;
+
+
+ } _tBACF;
+
+ typedef _tBACF* tBACF;
+
+ void tBACF_init (tBACF* const, int windowSize);
+ void tBACF_initToPool (tBACF* const, int windowSize, tMempool* const);
+ void tBACF_free (tBACF* const);
+
+
+
#ifdef __cplusplus
}
#endif
--- a/leaf/Inc/leaf-math.h
+++ b/leaf/Inc/leaf-math.h
@@ -17,6 +17,7 @@
#include "math.h"
#include "stdint.h"
#include "stdlib.h"
+#include "limits.h"
//==============================================================================
--- a/leaf/Src/leaf-analysis.c
+++ b/leaf/Src/leaf-analysis.c
@@ -950,3 +950,261 @@
if (tolerance < 0.0f) p->tolerance = 0.0f;
else p->tolerance = tolerance;
}
+
+
+void tZeroCrossing2_init (tZeroCrossing2* const zc)
+{
+ tZeroCrossing2_initToPool(zc, &leaf.mempool);
+}
+
+void tZeroCrossing2_initToPool (tZeroCrossing2* const zc, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tZeroCrossing2* z = *zc = (_tZeroCrossing2*) mpool_alloc(sizeof(_tZeroCrossing2), m);
+ z->mempool = m;
+
+ z->_leading_edge = INT_MIN;
+ z->_trailing_edge = INT_MIN;
+ z->_width = 0.0f;
+}
+
+void tZeroCrossing2_free (tZeroCrossing2* const zc)
+{
+ _tZeroCrossing2* z = *zc;
+
+ mpool_free((char*)z, z->mempool);
+}
+
+void tZeroCrossing2_updatePeak(tZeroCrossing2* const zc, float s, int pos)
+{
+ _tZeroCrossing2* z = *zc;
+
+ z->_peak = fmax(s, z->_peak);
+ if ((z->_width == 0.0f) && (s < (z->_peak * 0.3f)))
+ z->_width = pos - z->_leading_edge;
+}
+
+int tZeroCrossing2_period(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+{
+ _tZeroCrossing2* z = *zc;
+ _tZeroCrossing2* n = *next;
+
+ return n->_leading_edge - z->_leading_edge;
+}
+
+float tZeroCrossing2_fractionalPeriod(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+{
+ _tZeroCrossing2* z = *zc;
+ _tZeroCrossing2* n = *next;
+
+ // Get the start edge
+ float prev1 = z->_before_crossing;
+ float curr1 = z->_after_crossing;
+ float dy1 = curr1 - prev1;
+ float dx1 = -prev1 / dy1;
+
+ // Get the next edge
+ float prev2 = n->_before_crossing;
+ float curr2 = n->_after_crossing;
+ float dy2 = curr2 - prev2;
+ float dx2 = -prev2 / dy2;
+
+ // Calculate the fractional period
+ float result = n->_leading_edge - z->_leading_edge;
+ return result + (dx2 - dx1);
+}
+
+int tZeroCrossing2_getWidth(tZeroCrossing2* const zc)
+{
+ _tZeroCrossing2* z = *zc;
+
+ return z->_width;
+}
+
+int tZeroCrossing2_isSimilar(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+{
+ _tZeroCrossing2* z = *zc;
+ _tZeroCrossing2* n = *next;
+
+ int similarPeak = fabs(z->_peak - n->_peak) <= ((1.0f - PULSE_HEIGHT_DIFF) * fmax(fabs(z->_peak), fabs(n->_peak)));
+
+ int similarWidth = fabs(z->_width - n->_width) <= ((1.0f - PULSE_WIDTH_DIFF) * fmax(fabs(z->_width), fabs(n->_width)));
+
+ return similarPeak && similarWidth;
+}
+
+
+static void update_state(tZeroCrossings* const zc, float s);
+static void shift(tZeroCrossings* const zc, int n);
+static void reset(tZeroCrossings* const zc);
+
+void tZeroCrossings_init (tZeroCrossings* const zc, int windowSize, float hysteresis)
+{
+ tZeroCrossings_initToPool(zc, windowSize, hysteresis, &leaf.mempool);
+}
+
+void tZeroCrossings_initToPool (tZeroCrossings* const zc, int windowSize, float hysteresis, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tZeroCrossings* z = *zc = (_tZeroCrossings*) mpool_alloc(sizeof(_tZeroCrossings), m);
+ z->mempool = m;
+
+ z->_hysteresis = hysteresis;
+ int bits = CHAR_BIT * sizeof(unsigned int);
+ z->_window_size = fmax(2, (windowSize + bits - 1) / bits) * bits;
+
+ // The current ring buffer and indexing implementation for this is less efficient than the original source
+ // May be worth porting over the ring buffer class from https://github.com/cycfi/q/tree/develop
+ z->_info = (_tZeroCrossing2*) mpool_alloc(sizeof(_tZeroCrossing2) * (z->_window_size / 2), m);
+ z->index = -1;
+}
+
+void tZeroCrossings_free (tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ mpool_free((char*)z, z->mempool);
+}
+
+int tZeroCrossings_tick(tZeroCrossings* const zc, float s)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_state;
+}
+
+int tZeroCrossings_getState(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_state;
+}
+
+int tZeroCrossings_getNumEdges(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_num_edges;
+}
+
+int tZeroCrossings_getCapacity(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_window_size / 2;
+}
+
+int tZeroCrossings_getFrame(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_frame;
+}
+
+int tZeroCrossings_getWindowSize(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_window_size;
+}
+
+int tZeroCrossings_isReady(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_ready;
+}
+
+float tZeroCrossings_getPeak(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return fmax(z->_peak, z->_peak_update);
+}
+
+int tZeroCrossings_isReset(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ return z->_frame == 0;
+}
+
+static void update_state(tZeroCrossings* const zc, float s)
+{
+ _tZeroCrossings* z = *zc;
+
+ int capacity = z->_window_size / 2;
+ if (z->_ready)
+ {
+ shift(zc, capacity);
+ z->_ready = 0;
+ z->_peak = z->_peak_update;
+ z->_peak_update = 0.0f;
+ }
+
+ if (z->_num_edges >= capacity)
+ reset(zc);
+
+ if (s > 0.0f)
+ {
+ if (!z->_state)
+ {
+ ++z->index;
+ _tZeroCrossing2 crossing = z->_info[z->index];
+ crossing._before_crossing = z->_prev;
+ crossing._after_crossing = s;
+ crossing._peak = s;
+ crossing._leading_edge = (int) z->_frame;
+ ++z->_num_edges;
+ z->_state = 1;
+ }
+ else
+ {
+ tZeroCrossing2 ptr = &z->_info[z->index];
+ tZeroCrossing2_updatePeak(&ptr, s, z->_frame);
+ }
+ if (s > z->_peak_update)
+ {
+ z->_peak_update = s;
+ }
+ }
+ else if (z->_state && (s < z->_hysteresis))
+ {
+ z->_state = 0;
+ z->_info[z->index]._trailing_edge = z->_frame;
+ if (z->_peak == 0.0f)
+ z->_peak = z->_peak_update;
+ }
+
+ z->_prev = s;
+}
+
+static void shift(tZeroCrossings* const zc, int n)
+{
+ _tZeroCrossings* z = *zc;
+
+ _tZeroCrossing2 crossing = z->_info[z->index];
+
+ crossing._leading_edge -= n;
+ if (!z->_state)
+ crossing._trailing_edge -= n;
+ int i = 1;
+ for (; i != z->_num_edges; ++i)
+ {
+ int idx = (z->index + i) % (z->_window_size / 2);
+ z->_info[idx]._leading_edge -= n;
+ int edge = (z->_info[idx]._trailing_edge -= n);
+ if (edge < 0.0f)
+ break;
+ }
+ z->_num_edges = i;
+}
+
+static void reset(tZeroCrossings* const zc)
+{
+ _tZeroCrossings* z = *zc;
+
+ z->_num_edges = 0;
+ z->_state = 0;
+ z->_frame = 0;
+}