shithub: leaf

Download patch

ref: b6dc19e8bc75816be562478e06d94b9f4fd8031f
parent: ef901ea9042b8d353fe6f976bbc04ced54b7d87a
parent: 44f28dded14ffd0e328fc6329e86f0f4c071e8c5
author: spiricom <jeff@snyderphonics.com>
date: Tue Jul 21 10:31:40 EDT 2020

fixed a few float/double issues found by setting more agressive warning flags

--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@
 tCycle mySine;
 
 
-//also, create a memory pool array where you can store the data for the LEAF objects. It should be an array of chars. Note that you can also define multiple mempool objects in different memory locations in you want to, and initialize different LEAF objects in different places. However, LEAF needs at least one mempool, so the one you pass into the LEAF_init function is considered the default location for any LEAF-related memory, unless you specifically put something elsewhere by using an initToPool(), freeFromPool() function instead of init() or free(). 
+//also, create a memory pool array where you can store the data for the LEAF objects. It should be an array of chars. Note that you can also define multiple mempool objects in different memory locations in you want to, and initialize different LEAF objects in different places. However, LEAF needs at least one mempool, so the one you pass into the LEAF_init function is considered the default location for any LEAF-related memory, unless you specifically put something elsewhere by using an initToPool() function instead of init(). LEAF object store a pointer to which mempool they are in, so if you initToPool it will remember where you put it and the free() function will free it from the correct location.
 
 #define MEM_SIZE 500000
 char myMemory[MEM_SIZE];
--- 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 = fmaxf(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,11 @@
     z->_size = pow(2.0, ceil(log2((double)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 (uint 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 +1075,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 +1113,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 (int)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 fmaxf(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 +1198,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 +1210,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 +1228,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 +1249,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 +1477,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 +1496,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 +1517,7 @@
 {
     _tPeriodDetector* p = *detector;
     
-    tZeroCrossings_free(&p->_zc);
+    tZeroCrossingCollector_free(&p->_zc);
     tBitset_free(&p->_bits);
     tBACF_free(&p->_bacf);
     
@@ -1527,8 +1529,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 +1538,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 +1594,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 +1623,7 @@
 {
     _tPeriodDetector* p = *detector;
     
-    return tZeroCrossings_isReady(&p->_zc);
+    return tZeroCrossingCollector_isReady(&p->_zc);
 }
 
 static inline void set_bitstream(tPeriodDetector* const detector)
@@ -1628,13 +1630,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 +1650,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 +1720,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 / (float)collector->_zc->_window_size;
@@ -1733,9 +1735,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));
     
     /*! @} */