shithub: leaf

Download patch

ref: 3d29bd8ccc57b5059130828c74dd32d6519b05f6
parent: 386e144a520324e83dd92262913b8d1a86a1fbde
author: Matthew Wang <mjw7@princeton.edu>
date: Tue Jul 21 09:37:48 EDT 2020

improve error reporting structure, use function pointer that can be set by the user instead of weak attribute

--- a/TestPlugin/Source/PluginProcessor.cpp
+++ b/TestPlugin/Source/PluginProcessor.cpp
@@ -94,7 +94,7 @@
     
     for (int samp = 0; samp < buffer.getNumSamples(); ++samp)
     {
-        outPointerL[samp] = LEAFTest_tick( (inPointerL[samp] ));
+        outPointerL[samp] = LEAFTest_tick( (inPointerL[samp] + inPointerR[samp]) * 0.5f );
         outPointerR[samp] = outPointerL[samp];
     }
 }
--- a/leaf/Inc/leaf-analysis.h
+++ b/leaf/Inc/leaf-analysis.h
@@ -536,7 +536,7 @@
     
     // Maybe keep these up to PeriodDetector internal?
     
-    typedef struct _tZeroCrossing2
+    typedef struct _tZeroCrossingInfo
     {
         tMempool mempool;
         
@@ -547,21 +547,21 @@
         int               _leading_edge;// = undefined_edge; int_min
         int               _trailing_edge;// = undefined_edge;
         float             _width;// = 0.0f;
-    } _tZeroCrossing2;
+    } _tZeroCrossingInfo;
     
-    typedef _tZeroCrossing2* tZeroCrossing2;
+    typedef _tZeroCrossingInfo* tZeroCrossingInfo;
     
-    void    tZeroCrossing2_init  (tZeroCrossing2* const);
-    void    tZeroCrossing2_initToPool    (tZeroCrossing2* const, tMempool* const);
-    void    tZeroCrossing2_free  (tZeroCrossing2* const);
+    void    tZeroCrossingInfo_init  (tZeroCrossingInfo* const);
+    void    tZeroCrossingInfo_initToPool    (tZeroCrossingInfo* const, tMempool* const);
+    void    tZeroCrossingInfo_free  (tZeroCrossingInfo* 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);
+    int     tZeroCrossingInfo_tick(tZeroCrossingInfo* const, float s);
+    int     tZeroCrossingInfo_getState(tZeroCrossingInfo* const);
+    void    tZeroCrossingInfo_updatePeak(tZeroCrossingInfo* const, float s, int pos);
+    int     tZeroCrossingInfo_period(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
+    float   tZeroCrossingInfo_fractionalPeriod(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
+    int     tZeroCrossingInfo_getWidth(tZeroCrossingInfo* const);
+    int     tZeroCrossingInfo_isSimilar(tZeroCrossingInfo* const, tZeroCrossingInfo* const next);
     
     //==============================================================================
     
@@ -568,11 +568,11 @@
 #define PULSE_HEIGHT_DIFF 0.8
 #define PULSE_WIDTH_DIFF 0.85
     
-    typedef struct _tZeroCrossings
+    typedef struct _tZeroCrossingCollector
     {
         tMempool mempool;
         
-        tZeroCrossing2* _info;
+        tZeroCrossingInfo* _info;
         unsigned int _size;
         unsigned int _pos;
         unsigned int _mask;
@@ -586,27 +586,27 @@
         int                  _ready;// = false;
         float                _peak_update;// = 0.0f;
         float                _peak;// = 0.0f;
-    } _tZeroCrossings;
+    } _tZeroCrossingCollector;
     
-    typedef _tZeroCrossings* tZeroCrossings;
+    typedef _tZeroCrossingCollector* tZeroCrossingCollector;
     
-    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);
+    void    tZeroCrossingCollector_init  (tZeroCrossingCollector* const, int windowSize, float hysteresis);
+    void    tZeroCrossingCollector_initToPool    (tZeroCrossingCollector* const, int windowSize, float hysteresis, tMempool* const);
+    void    tZeroCrossingCollector_free  (tZeroCrossingCollector* const);
     
-    int     tZeroCrossings_tick(tZeroCrossings* const, float s);
-    int     tZeroCrossings_getState(tZeroCrossings* const);
+    int     tZeroCrossingCollector_tick(tZeroCrossingCollector* const, float s);
+    int     tZeroCrossingCollector_getState(tZeroCrossingCollector* 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     tZeroCrossingCollector_getNumEdges(tZeroCrossingCollector* const zc);
+    int     tZeroCrossingCollector_getCapacity(tZeroCrossingCollector* const zc);
+    int     tZeroCrossingCollector_getFrame(tZeroCrossingCollector* const zc);
+    int     tZeroCrossingCollector_getWindowSize(tZeroCrossingCollector* const zc);
     
-    int     tZeroCrossings_isReady(tZeroCrossings* const zc);
-    float   tZeroCrossings_getPeak(tZeroCrossings* const zc);
-    int     tZeroCrossings_isReset(tZeroCrossings* const zc);
+    int     tZeroCrossingCollector_isReady(tZeroCrossingCollector* const zc);
+    float   tZeroCrossingCollector_getPeak(tZeroCrossingCollector* const zc);
+    int     tZeroCrossingCollector_isReset(tZeroCrossingCollector* const zc);
     
-    tZeroCrossing2 const tZeroCrossings_getCrossing(tZeroCrossings* const zc, int index);
+    tZeroCrossingInfo const tZeroCrossingCollector_getCrossing(tZeroCrossingCollector* const zc, int index);
     
     //==============================================================================
     
@@ -723,7 +723,7 @@
         _auto_correlation_info _fundamental;
         
         // passed in, not initialized
-        tZeroCrossings    _zc;
+        tZeroCrossingCollector    _zc;
         
         float             _harmonic_threshold;
         float             _periodicity_diff_threshold;
@@ -734,7 +734,7 @@
     {
         tMempool mempool;
         
-        tZeroCrossings          _zc;
+        tZeroCrossingCollector          _zc;
         float                   _period_info[2]; // i0 is period, i1 is periodicity
         unsigned int            _min_period;
         int                     _range;
--- a/leaf/Inc/leaf-global.h
+++ b/leaf/Inc/leaf-global.h
@@ -31,8 +31,11 @@
         float   (*random)(void); //!< A pointer to the random() function provided on initialization.
         int     clearOnAllocation; //!< A flag that determines whether memory allocated from the LEAF memory pool will be cleared.
         tMempool mempool; //!< The default LEAF mempool object.
-        _tMempool _mempool;
+        _tMempool _internal_mempool;
         size_t header_size; //!< The size in bytes of memory region headers within mempools.
+        void (*errorCallback)(LEAFErrorType); //!< A pointer to the callback function for LEAF errors. Can be set by the user.
+        int     errorState[LEAFErrorNil]; //!< An array of flags that indicate which errors have occurred.
+        
         ///@}
     };
     typedef struct LEAF LEAF;
--- a/leaf/Inc/leaf-mempool.h
+++ b/leaf/Inc/leaf-mempool.h
@@ -54,6 +54,14 @@
     
     //#define size_t unsigned long
     
+    typedef enum LEAFErrorType
+    {
+        LEAFMempoolOverrun = 0,
+        LEAFMempoolFragmentation,
+        LEAFInvalidFree,
+        LEAFErrorNil
+    } LEAFErrorType;
+    
     /*!
      * @defgroup tmempool tMempool
      * @ingroup mempool
@@ -145,8 +153,6 @@
     size_t leaf_pool_get_used(void);
     
     char* leaf_pool_get_pool(void);
-    
-    void leaf_mempool_overrun(void);
     
 #ifdef __cplusplus
 }
--- a/leaf/Src/leaf-analysis.c
+++ b/leaf/Src/leaf-analysis.c
@@ -952,15 +952,15 @@
 }
 
 
-void    tZeroCrossing2_init  (tZeroCrossing2* const zc)
+void    tZeroCrossingInfo_init  (tZeroCrossingInfo* const zc)
 {
-    tZeroCrossing2_initToPool(zc, &leaf.mempool);
+    tZeroCrossingInfo_initToPool(zc, &leaf.mempool);
 }
 
-void    tZeroCrossing2_initToPool    (tZeroCrossing2* const zc, tMempool* const mp)
+void    tZeroCrossingInfo_initToPool    (tZeroCrossingInfo* const zc, tMempool* const mp)
 {
     _tMempool* m = *mp;
-    _tZeroCrossing2* z = *zc = (_tZeroCrossing2*) mpool_alloc(sizeof(_tZeroCrossing2), m);
+    _tZeroCrossingInfo* z = *zc = (_tZeroCrossingInfo*) mpool_alloc(sizeof(_tZeroCrossingInfo), m);
     z->mempool = m;
 
     z->_leading_edge = INT_MIN;
@@ -968,16 +968,16 @@
     z->_width = 0.0f;
 }
 
-void    tZeroCrossing2_free  (tZeroCrossing2* const zc)
+void    tZeroCrossingInfo_free  (tZeroCrossingInfo* const zc)
 {
-    _tZeroCrossing2* z = *zc;
+    _tZeroCrossingInfo* z = *zc;
     
     mpool_free((char*)z, z->mempool);
 }
 
-void    tZeroCrossing2_updatePeak(tZeroCrossing2* const zc, float s, int pos)
+void    tZeroCrossingInfo_updatePeak(tZeroCrossingInfo* const zc, float s, int pos)
 {
-    _tZeroCrossing2* z = *zc;
+    _tZeroCrossingInfo* z = *zc;
     
     z->_peak = fmax(s, z->_peak);
     if ((z->_width == 0.0f) && (s < (z->_peak * 0.3f)))
@@ -984,18 +984,18 @@
         z->_width = pos - z->_leading_edge;
 }
 
-int     tZeroCrossing2_period(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+int     tZeroCrossingInfo_period(tZeroCrossingInfo* const zc, tZeroCrossingInfo* const next)
 {
-    _tZeroCrossing2* z = *zc;
-    _tZeroCrossing2* n = *next;
+    _tZeroCrossingInfo* z = *zc;
+    _tZeroCrossingInfo* n = *next;
     
     return n->_leading_edge - z->_leading_edge;
 }
 
-float   tZeroCrossing2_fractionalPeriod(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+float   tZeroCrossingInfo_fractionalPeriod(tZeroCrossingInfo* const zc, tZeroCrossingInfo* const next)
 {
-    _tZeroCrossing2* z = *zc;
-    _tZeroCrossing2* n = *next;
+    _tZeroCrossingInfo* z = *zc;
+    _tZeroCrossingInfo* n = *next;
     
     // Get the start edge
     float prev1 = z->_before_crossing;
@@ -1014,17 +1014,17 @@
     return result + (dx2 - dx1);
 }
 
-int     tZeroCrossing2_getWidth(tZeroCrossing2* const zc)
+int     tZeroCrossingInfo_getWidth(tZeroCrossingInfo* const zc)
 {
-    _tZeroCrossing2* z = *zc;
+    _tZeroCrossingInfo* z = *zc;
     
     return z->_width;
 }
 
-int     tZeroCrossing2_isSimilar(tZeroCrossing2* const zc, tZeroCrossing2* const next)
+int     tZeroCrossingInfo_isSimilar(tZeroCrossingInfo* const zc, tZeroCrossingInfo* const next)
 {
-    _tZeroCrossing2* z = *zc;
-    _tZeroCrossing2* n = *next;
+    _tZeroCrossingInfo* z = *zc;
+    _tZeroCrossingInfo* n = *next;
     
     int similarPeak = fabs(z->_peak - n->_peak) <= ((1.0f - PULSE_HEIGHT_DIFF) * fmax(fabs(z->_peak), fabs(n->_peak)));
     
@@ -1034,19 +1034,19 @@
 }
 
 
-static inline void update_state(tZeroCrossings* const zc, float s);
-static inline void shift(tZeroCrossings* const zc, int n);
-static inline void reset(tZeroCrossings* const zc);
+static inline void update_state(tZeroCrossingCollector* const zc, float s);
+static inline void shift(tZeroCrossingCollector* const zc, int n);
+static inline void reset(tZeroCrossingCollector* const zc);
 
-void    tZeroCrossings_init  (tZeroCrossings* const zc, int windowSize, float hysteresis)
+void    tZeroCrossingCollector_init  (tZeroCrossingCollector* const zc, int windowSize, float hysteresis)
 {
-    tZeroCrossings_initToPool(zc, windowSize, hysteresis, &leaf.mempool);
+    tZeroCrossingCollector_initToPool(zc, windowSize, hysteresis, &leaf.mempool);
 }
 
-void    tZeroCrossings_initToPool    (tZeroCrossings* const zc, int windowSize, float hysteresis, tMempool* const mp)
+void    tZeroCrossingCollector_initToPool    (tZeroCrossingCollector* const zc, int windowSize, float hysteresis, tMempool* const mp)
 {
     _tMempool* m = *mp;
-    _tZeroCrossings* z = *zc = (_tZeroCrossings*) mpool_alloc(sizeof(_tZeroCrossings), m);
+    _tZeroCrossingCollector* z = *zc = (_tZeroCrossingCollector*) mpool_alloc(sizeof(_tZeroCrossingCollector), m);
     z->mempool = m;
     
     z->_hysteresis = -hysteresis;
@@ -1059,9 +1059,9 @@
     z->_size = pow(2, ceil(log2(size)));
     z->_mask = z->_size - 1;
 
-    z->_info = (tZeroCrossing2*) mpool_alloc(sizeof(tZeroCrossing2) * z->_size, m);
+    z->_info = (tZeroCrossingInfo*) mpool_alloc(sizeof(tZeroCrossingInfo) * z->_size, m);
     for (int i = 0; i < z->_size; i++)
-        tZeroCrossing2_initToPool(&z->_info[i], mp);
+        tZeroCrossingInfo_initToPool(&z->_info[i], mp);
     z->_pos = 0;
     
     z->_prev = 0.0f;
@@ -1073,16 +1073,16 @@
     z->_peak = 0.0f;
 }
 
-void    tZeroCrossings_free  (tZeroCrossings* const zc)
+void    tZeroCrossingCollector_free  (tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     mpool_free((char*)z, z->mempool);
 }
 
-int     tZeroCrossings_tick(tZeroCrossings* const zc, float s)
+int     tZeroCrossingCollector_tick(tZeroCrossingCollector* const zc, float s)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     // Offset s by half of hysteresis, so that zero cross detection is
     // centered on the actual zero.
@@ -1111,73 +1111,73 @@
     return z->_state;
 }
 
-int     tZeroCrossings_getState(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_getState(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_state;
 }
 
-tZeroCrossing2 const tZeroCrossings_getCrossing(tZeroCrossings* const zc, int index)
+tZeroCrossingInfo const tZeroCrossingCollector_getCrossing(tZeroCrossingCollector* const zc, int index)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     int i = (z->_num_edges - 1) - index;
     return z->_info[(z->_pos + i) & z->_mask];
 }
 
-int     tZeroCrossings_getNumEdges(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_getNumEdges(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_num_edges;
 }
 
-int     tZeroCrossings_getCapacity(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_getCapacity(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_size;
 }
 
-int     tZeroCrossings_getFrame(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_getFrame(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_frame;
 }
 
-int     tZeroCrossings_getWindowSize(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_getWindowSize(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_window_size;
 }
 
-int     tZeroCrossings_isReady(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_isReady(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_ready;
 }
 
-float   tZeroCrossings_getPeak(tZeroCrossings* const zc)
+float   tZeroCrossingCollector_getPeak(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return fmax(z->_peak, z->_peak_update);
 }
 
-int     tZeroCrossings_isReset(tZeroCrossings* const zc)
+int     tZeroCrossingCollector_isReset(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     return z->_frame == 0;
 }
 
-static inline void update_state(tZeroCrossings* const zc, float s)
+static inline void update_state(tZeroCrossingCollector* const zc, float s)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     if (z->_ready)
     {
@@ -1196,7 +1196,7 @@
         {
             --z->_pos;
             z->_pos &= z->_mask;
-            tZeroCrossing2 crossing = z->_info[z->_pos];
+            tZeroCrossingInfo crossing = z->_info[z->_pos];
             crossing->_before_crossing = z->_prev;
             crossing->_after_crossing = s;
             crossing->_peak = s;
@@ -1208,7 +1208,7 @@
         }
         else
         {
-            tZeroCrossing2_updatePeak(&z->_info[z->_pos], s, z->_frame);
+            tZeroCrossingInfo_updatePeak(&z->_info[z->_pos], s, z->_frame);
         }
         if (s > z->_peak_update)
         {
@@ -1226,11 +1226,11 @@
     z->_prev = s;
 }
 
-static inline void shift(tZeroCrossings* const zc, int n)
+static inline void shift(tZeroCrossingCollector* const zc, int n)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
-    tZeroCrossing2 crossing = z->_info[z->_pos];
+    tZeroCrossingInfo crossing = z->_info[z->_pos];
     
     crossing->_leading_edge -= n;
     if (!z->_state)
@@ -1247,9 +1247,9 @@
     z->_num_edges = i;
 }
 
-static inline void reset(tZeroCrossings* const zc)
+static inline void reset(tZeroCrossingCollector* const zc)
 {
-    _tZeroCrossings* z = *zc;
+    _tZeroCrossingCollector* z = *zc;
     
     z->_num_edges = 0;
     z->_state = 0;
@@ -1475,7 +1475,7 @@
 static inline void set_bitstream(tPeriodDetector* const detector);
 static inline void autocorrelate(tPeriodDetector* const detector);
 
-static inline void sub_collector_init(_sub_collector* collector, tZeroCrossings* const crossings, float pdt, int range);
+static inline void sub_collector_init(_sub_collector* collector, tZeroCrossingCollector* const crossings, float pdt, int range);
 static inline float sub_collector_period_of(_sub_collector* collector, _auto_correlation_info info);
 static inline void sub_collector_save(_sub_collector* collector, _auto_correlation_info info);
 static inline int sub_collector_try_sub_harmonic(_sub_collector* collector, int harmonic, _auto_correlation_info info);
@@ -1494,11 +1494,11 @@
     _tPeriodDetector* p = *detector = (_tPeriodDetector*) mpool_alloc(sizeof(_tPeriodDetector), m);
     p->mempool = m;
     
-    tZeroCrossings_initToPool(&p->_zc, (1.0f / lowestFreq) * leaf.sampleRate * 2.0f, hysteresis, mempool);
+    tZeroCrossingCollector_initToPool(&p->_zc, (1.0f / lowestFreq) * leaf.sampleRate * 2.0f, hysteresis, mempool);
     p->_min_period = (1.0f / highestFreq) * leaf.sampleRate;
     p->_range = highestFreq / lowestFreq;
     
-    int windowSize = tZeroCrossings_getWindowSize(&p->_zc);
+    int windowSize = tZeroCrossingCollector_getWindowSize(&p->_zc);
     tBitset_initToPool(&p->_bits, windowSize, mempool);
     p->_weight = 2.0f / windowSize;
     p->_mid_point = windowSize / 2;
@@ -1515,7 +1515,7 @@
 {
     _tPeriodDetector* p = *detector;
     
-    tZeroCrossings_free(&p->_zc);
+    tZeroCrossingCollector_free(&p->_zc);
     tBitset_free(&p->_bits);
     tBACF_free(&p->_bacf);
     
@@ -1527,8 +1527,8 @@
     _tPeriodDetector* p = *detector;
     
     // Zero crossing
-    int prev = tZeroCrossings_getState(&p->_zc);
-    int zc = tZeroCrossings_tick(&p->_zc, s);
+    int prev = tZeroCrossingCollector_getState(&p->_zc);
+    int zc = tZeroCrossingCollector_tick(&p->_zc, s);
     
     if (!zc && prev != zc)
     {
@@ -1536,13 +1536,13 @@
         p->_predicted_period = -1.0f;
     }
     
-    if (tZeroCrossings_isReset(&p->_zc))
+    if (tZeroCrossingCollector_isReset(&p->_zc))
     {
         p->_period_info[0] = -1.0f;
         p->_period_info[1] = 0.0f;
     }
     
-    if (tZeroCrossings_isReady(&p->_zc))
+    if (tZeroCrossingCollector_isReady(&p->_zc))
     {
         set_bitstream(detector);
         autocorrelate(detector);
@@ -1592,21 +1592,21 @@
     if (p->_predicted_period == -1.0f && p->_edge_mark != p->_predict_edge)
     {
         p->_predict_edge = p->_edge_mark;
-        int n = tZeroCrossings_getNumEdges(&p->_zc);
+        int n = tZeroCrossingCollector_getNumEdges(&p->_zc);
         if (n > 1)
         {
-            float threshold = tZeroCrossings_getPeak(&p->_zc) * PULSE_THRESHOLD;
+            float threshold = tZeroCrossingCollector_getPeak(&p->_zc) * PULSE_THRESHOLD;
             for (int i = n - 1; i > 0; --i)
             {
-                tZeroCrossing2 edge2 = tZeroCrossings_getCrossing(&p->_zc, i);
+                tZeroCrossingInfo edge2 = tZeroCrossingCollector_getCrossing(&p->_zc, i);
                 if (edge2->_peak >= threshold)
                 {
                     for (int j = i-1; j >= 0; --j)
                     {
-                        tZeroCrossing2 edge1 = tZeroCrossings_getCrossing(&p->_zc, j);
-                        if (tZeroCrossing2_isSimilar(&edge1, &edge2))
+                        tZeroCrossingInfo edge1 = tZeroCrossingCollector_getCrossing(&p->_zc, j);
+                        if (tZeroCrossingInfo_isSimilar(&edge1, &edge2))
                         {
-                            p->_predicted_period = tZeroCrossing2_fractionalPeriod(&edge1, &edge2);
+                            p->_predicted_period = tZeroCrossingInfo_fractionalPeriod(&edge1, &edge2);
                             return p->_predicted_period;
                         }
                     }
@@ -1621,7 +1621,7 @@
 {
     _tPeriodDetector* p = *detector;
     
-    return tZeroCrossings_isReady(&p->_zc);
+    return tZeroCrossingCollector_isReady(&p->_zc);
 }
 
 static inline void set_bitstream(tPeriodDetector* const detector)
@@ -1628,13 +1628,13 @@
 {
     _tPeriodDetector* p = *detector;
     
-    float threshold = tZeroCrossings_getPeak(&p->_zc) * PULSE_THRESHOLD;
+    float threshold = tZeroCrossingCollector_getPeak(&p->_zc) * PULSE_THRESHOLD;
     
     tBitset_clear(&p->_bits);
 
-    for (int i = 0; i != tZeroCrossings_getNumEdges(&p->_zc); ++i)
+    for (int i = 0; i != tZeroCrossingCollector_getNumEdges(&p->_zc); ++i)
     {
-        tZeroCrossing2 info = tZeroCrossings_getCrossing(&p->_zc, i);
+        tZeroCrossingInfo info = tZeroCrossingCollector_getCrossing(&p->_zc, i);
         if (info->_peak >= threshold)
         {
             int pos = fmax(info->_leading_edge, 0);
@@ -1648,24 +1648,24 @@
 {
     _tPeriodDetector* p = *detector;
     
-    float threshold = tZeroCrossings_getPeak(&p->_zc) * PULSE_THRESHOLD;
+    float threshold = tZeroCrossingCollector_getPeak(&p->_zc) * PULSE_THRESHOLD;
     
     _sub_collector collect;
     sub_collector_init(&collect, &p->_zc, p->_periodicity_diff_threshold, p->_range);
     
     int shouldBreak = 0;
-    int n = tZeroCrossings_getNumEdges(&p->_zc);
+    int n = tZeroCrossingCollector_getNumEdges(&p->_zc);
     for (int i = 0; i != n - 1; ++i)
     {
-        tZeroCrossing2 first = tZeroCrossings_getCrossing(&p->_zc, i);
+        tZeroCrossingInfo first = tZeroCrossingCollector_getCrossing(&p->_zc, i);
         if (first->_peak >= threshold)
         {
             for (int j = i + 1; j != n; ++j)
             {
-                tZeroCrossing2 next = tZeroCrossings_getCrossing(&p->_zc, j);
+                tZeroCrossingInfo next = tZeroCrossingCollector_getCrossing(&p->_zc, j);
                 if (next->_peak >= threshold)
                 {
-                    int period = tZeroCrossing2_period(&first, &next);
+                    int period = tZeroCrossingInfo_period(&first, &next);
                     if (period > p->_mid_point)
                         break;
                     if (period >= p->_min_period)
@@ -1718,7 +1718,7 @@
     sub_collector_get(&collect, collect._fundamental, p->_period_info);
 }
 
-static inline void sub_collector_init(_sub_collector* collector, tZeroCrossings* const crossings, float pdt, int range)
+static inline void sub_collector_init(_sub_collector* collector, tZeroCrossingCollector* const crossings, float pdt, int range)
 {
     collector->_zc = *crossings;
     collector->_harmonic_threshold = HARMONIC_PERIODICITY_FACTOR * 2.0f / collector->_zc->_window_size;
@@ -1733,9 +1733,9 @@
 
 static inline float sub_collector_period_of(_sub_collector* collector, _auto_correlation_info info)
 {
-    tZeroCrossing2 first = tZeroCrossings_getCrossing(&collector->_zc, info._i1);
-    tZeroCrossing2 next = tZeroCrossings_getCrossing(&collector->_zc, info._i2);
-    return tZeroCrossing2_fractionalPeriod(&first, &next);
+    tZeroCrossingInfo first = tZeroCrossingCollector_getCrossing(&collector->_zc, info._i1);
+    tZeroCrossingInfo next = tZeroCrossingCollector_getCrossing(&collector->_zc, info._i2);
+    return tZeroCrossingInfo_fractionalPeriod(&first, &next);
 }
 
 static inline void sub_collector_save(_sub_collector* collector, _auto_correlation_info info)
--- a/leaf/Src/leaf-mempool.c
+++ b/leaf/Src/leaf-mempool.c
@@ -79,9 +79,9 @@
 
 void leaf_pool_init(char* memory, size_t size)
 {
-    mpool_create(memory, size, &leaf._mempool);
+    mpool_create(memory, size, &leaf._internal_mempool);
     
-    leaf.mempool = &leaf._mempool;
+    leaf.mempool = &leaf._internal_mempool;
 }
 
 /**
@@ -92,7 +92,14 @@
     // If the head is NULL, the mempool is full
     if (pool->head == NULL)
     {
-        leaf_mempool_overrun();
+        if ((pool->msize - pool->usize) > asize)
+        {
+            LEAF_internalErrorCallback(LEAFMempoolFragmentation);
+        }
+        else
+        {
+            LEAF_internalErrorCallback(LEAFMempoolOverrun);
+        }
         return NULL;
     }
     
@@ -109,7 +116,14 @@
         // are no blocks large enough, return NULL
         if (node_to_alloc == NULL)
         {
-            leaf_mempool_overrun();
+            if ((pool->msize - pool->usize) > asize)
+            {
+                LEAF_internalErrorCallback(LEAFMempoolFragmentation);
+            }
+            else
+            {
+                LEAF_internalErrorCallback(LEAFMempoolOverrun);
+            }
             return NULL;
         }
     }
@@ -166,7 +180,14 @@
     // If the head is NULL, the mempool is full
     if (pool->head == NULL)
     {
-        leaf_mempool_overrun();
+        if ((pool->msize - pool->usize) > asize)
+        {
+            LEAF_internalErrorCallback(LEAFMempoolFragmentation);
+        }
+        else
+        {
+            LEAF_internalErrorCallback(LEAFMempoolOverrun);
+        }
         return NULL;
     }
     
@@ -183,7 +204,14 @@
         // are no blocks large enough, return NULL
         if (node_to_alloc == NULL)
         {
-            leaf_mempool_overrun();
+            if ((pool->msize - pool->usize) > asize)
+            {
+                LEAF_internalErrorCallback(LEAFMempoolFragmentation);
+            }
+            else
+            {
+                LEAF_internalErrorCallback(LEAFMempoolOverrun);
+            }
             return NULL;
         }
     }
@@ -230,10 +258,8 @@
 char* leaf_alloc(size_t size)
 {
     //printf("alloc %i\n", size);
-    char* block = mpool_alloc(size, &leaf._mempool);
+    char* block = mpool_alloc(size, &leaf._internal_mempool);
     
-    if (block == NULL) leaf_mempool_overrun();
-    
     return block;
 }
 
@@ -240,11 +266,8 @@
 char* leaf_calloc(size_t size)
 {
     //printf("alloc %i\n", size);
-    char* block = mpool_calloc(size, &leaf._mempool);
-    
-    if (block == NULL) leaf_mempool_overrun();
-    
-    
+    char* block = mpool_calloc(size, &leaf._internal_mempool);
+
     return block;
 }
 
@@ -264,7 +287,7 @@
         if ((long) other_node < (long) pool->mpool ||
             (long) other_node >= (((long) pool->mpool) + pool->msize))
         {
-            LEAF_error(2);
+            LEAF_internalErrorCallback(LEAFInvalidFree);
             return;
         }
         next_node = other_node->next;
@@ -318,7 +341,7 @@
 
 void leaf_free(char* ptr)
 {
-    mpool_free(ptr, &leaf._mempool);
+    mpool_free(ptr, &leaf._internal_mempool);
 }
 
 size_t mpool_get_size(_tMempool* pool)
@@ -333,17 +356,17 @@
 
 size_t leaf_pool_get_size(void)
 {
-    return mpool_get_size(&leaf._mempool);
+    return mpool_get_size(&leaf._internal_mempool);
 }
 
 size_t leaf_pool_get_used(void)
 {
-    return mpool_get_used(&leaf._mempool);
+    return mpool_get_used(&leaf._internal_mempool);
 }
 
 char* leaf_pool_get_pool(void)
 {
-    char* buff = leaf._mempool.mpool;
+    char* buff = leaf._internal_mempool.mpool;
     
     return buff;
 }
@@ -383,12 +406,6 @@
     
     node->next = NULL;
     node->prev = NULL;
-}
-
-void leaf_mempool_overrun(void)
-{
-    LEAF_error(1);
-    //TODO: we should make a set of real error codes that are in an enum type
 }
 
 void tMempool_init(tMempool* const mp, char* memory, size_t size)
--- a/leaf/Src/leaf.c
+++ b/leaf/Src/leaf.c
@@ -36,6 +36,11 @@
     leaf.random = random;
     
     leaf.clearOnAllocation = 0;
+    
+    leaf.errorCallback = &LEAF_defaultErrorCallback;
+    
+    for (int i = 0; i < LEAFErrorNil; ++i)
+        leaf.errorState[i] = 0;
 }
 
 
@@ -52,10 +57,19 @@
     return leaf.sampleRate;
 }
 
+void LEAF_defaultErrorCallback(LEAFErrorType whichone)
+{
+    // Not sure what this should do if anything
+    // Maybe fine as a placeholder
+}
 
-//implement a function called this in your user code to catch errors
-//__attribute__((weak))
-uint8_t LEAF_error(uint8_t whichone)
+void LEAF_internalErrorCallback(LEAFErrorType whichone)
 {
-    return whichone;
+    leaf.errorState[whichone] = 1;
+    leaf.errorCallback(whichone);
+}
+
+void LEAF_setErrorCallback(void (*callback)(LEAFErrorType))
+{
+    leaf.errorCallback = callback;
 }
--- a/leaf/leaf.h
+++ b/leaf/leaf.h
@@ -140,9 +140,19 @@
      */
     float       LEAF_getSampleRate   (void);
     
-
-//    __attribute__((weak))
-    uint8_t LEAF_error(uint8_t whichone);
+    //! The default callback function for LEAF errors.
+    /*!
+     @param errorType The type of the error that has occurred.
+     */
+    void        LEAF_defaultErrorCallback(LEAFErrorType errorType);
+    
+    void        LEAF_internalErrorCallback(LEAFErrorType whichone);
+    
+    //! Set the callback function for LEAF errors.
+    /*!
+     @param callback A pointer to the callback function.
+     */
+    void LEAF_setErrorCallback(void (*callback)(LEAFErrorType))
     
     /*! @} */