shithub: leaf

Download patch

ref: 482f07c8138ec548f0d371bedebc560dd5f9b5d3
parent: a98552ba09ba07ed88553aae41b503870ad56140
author: Matthew Wang <mjw7@princeton.edu>
date: Tue May 19 18:56:25 EDT 2020

minblep oscillators and start to hard sync

--- a/LEAF/Inc/leaf-effects.h
+++ b/LEAF/Inc/leaf-effects.h
@@ -130,11 +130,11 @@
 
 	float   tRosenbergGlottalPulse_tick           (tRosenbergGlottalPulse* const);
 
-	float   tRosenbergGlottalPulse_setFreq           (tRosenbergGlottalPulse* const, float freq);
+	void   tRosenbergGlottalPulse_setFreq           (tRosenbergGlottalPulse* const, float freq);
 
-	float   tRosenbergGlottalPulse_setOpenLength           (tRosenbergGlottalPulse* const, float openLength);
+	void   tRosenbergGlottalPulse_setOpenLength           (tRosenbergGlottalPulse* const, float openLength);
 
-	float   tRosenbergGlottalPulse_setPulseLength           (tRosenbergGlottalPulse* const, float pulseLength);
+	void   tRosenbergGlottalPulse_setPulseLength           (tRosenbergGlottalPulse* const, float pulseLength);
     
     //==============================================================================
     
--- a/LEAF/Inc/leaf-oscillators.h
+++ b/LEAF/Inc/leaf-oscillators.h
@@ -902,9 +902,9 @@
     
     typedef _tMinBLEP* tMinBLEP;
     
-    void    tMinBLEP_init           (tMinBLEP* const minblep);
+    void    tMinBLEP_init           (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio);
     void    tMinBLEP_free           (tMinBLEP* const minblep);
-    void    tMinBLEP_initToPool     (tMinBLEP* const minblep, tMempool* const pool);
+    void    tMinBLEP_initToPool     (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio, tMempool* const pool);
     void    tMinBLEP_freeFromPool   (tMinBLEP* const minblep, tMempool* const pool);
     
     // pass in audio, identify discontinuities and return the audio with minbleps inserted
@@ -914,6 +914,224 @@
     
     void    tMinBLEP_setOversamplingRatio   (tMinBLEP* const minblep, float ratio);
     void    tMinBLEP_setNumZeroCrossings    (tMinBLEP* const minblep, int numCrossings);
+    
+    //==============================================================================
+    
+    /* tMBTriangle: Anti-aliased Triangle waveform using wavetable interpolation. */
+    typedef struct _tMBTriangle
+    {
+        float phase;
+        float inc,freq;
+        float skew;
+        float lastOut;
+        
+        tMinBLEP minBlep;
+        tHighpass dcBlock;
+    } _tMBTriangle;
+    
+    typedef _tMBTriangle* tMBTriangle;
+    
+    /*!
+     * @defgroup tMBTriangle tMBTriangle
+     * @ingroup oscillators
+     * @brief An anti-aliased triangle waveform oscillator.
+     * @{
+     */
+    
+    //! Initialize a tMBTriangle to the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBTriangle to be initialized.
+     */
+    void    tMBTriangle_init          (tMBTriangle* const osc);
+    
+    
+    //! Free a tMBTriangle from the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBTriangle to be freed.
+     */
+    void    tMBTriangle_free          (tMBTriangle* const osc);
+    
+    
+    //! Initialize a tMBTriangle to a specified mempool.
+    /*!
+     @param osc A pointer to the tMBTriangle to be initialized.
+     @param pool A pointer to the tMempool to which the tMBTriangle should be initialized.
+     */
+    void    tMBTriangle_initToPool    (tMBTriangle* const osc, tMempool* const pool);
+    
+    
+    //! Free a tMBTriangle from a specified mempool.
+    /*!
+     @param osc A pointer to the tMBTriangle to be freed.
+     @param pool A pointer to the tMempool from which the tMBTriangle should be freed.
+     */
+    void    tMBTriangle_freeFromPool  (tMBTriangle* const osc, tMempool* const pool);
+    
+    
+    //! Tick a tMBTriangle oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBTriangle.
+     @return The ticked sample as a float from -1 to 1.
+     */
+    float   tMBTriangle_tick          (tMBTriangle* const osc);
+    
+    
+    //! Set the frequency of a tMBTriangle oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBTriangleangle.
+     @param freq The frequency to set the oscillator to.
+     */
+    void    tMBTriangle_setFreq       (tMBTriangle* const osc, float freq);
+    
+    void    tMBTriangle_setSkew       (tMBTriangle* const osc, float skew);
+    
+    void    tMBTriangle_sync          (tMBTriangle* const osc, float phase);
+    
+    /*! @} */
+    
+    //==============================================================================
+    
+    /* tMBPulse: Anti-aliased Square waveform. */
+    typedef struct _tMBPulse
+    {
+        float phase;
+        float inc,freq;
+        float width;
+        
+        tMinBLEP minBlep;
+        tHighpass dcBlock;
+    } _tMBPulse;
+    
+    typedef _tMBPulse* tMBPulse;
+    
+    /*!
+     * @defgroup tMBPulse tMBPulse
+     * @ingroup oscillators
+     * @brief An anti-aliased pulse waveform oscillator with changeable pulse width.
+     * @{
+     */
+    
+    //! Initialize a tMBPulse to the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBPulse to be initialized.
+     */
+    void    tMBPulse_init        (tMBPulse* const osc);
+    
+    
+    //! Free a tMBPulse from the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBPulse to be freed.
+     */
+    void    tMBPulse_free        (tMBPulse* const osc);
+    
+    
+    //! Initialize a tMBPulse to a specified mempool.
+    /*!
+     @param osc A pointer to the tMBPulse to be initialized.
+     @param pool A pointer to the tMempool to which the tMBPulse should be initialized.
+     */
+    void    tMBPulse_initToPool  (tMBPulse* const osc, tMempool* const);
+    
+    
+    //! Free a tMBPulse from a specified mempool.
+    /*!
+     @param osc A pointer to the tMBPulse to be freed.
+     @param pool A pointer to the tMempool from which the tMBPulse should be freed.
+     */
+    void    tMBPulse_freeFromPool(tMBPulse* const osc, tMempool* const);
+    
+    
+    //! Tick a tMBPulse oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBPulse.
+     @return The ticked sample as a float from -1 to 1.
+     */
+    float   tMBPulse_tick        (tMBPulse* const osc);
+    
+    
+    //! Set the frequency of a tMBPulse oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBPulse.
+     @param freq The frequency to set the oscillator to.
+     */
+    void    tMBPulse_setFreq     (tMBPulse* const osc, float freq);
+    
+    void    tMBPulse_setWidth    (tMBPulse* const osc, float width);
+    
+    void    tMBPulse_sync          (tMBPulse* const osc, float phase);
+    
+    
+    /*! @} */
+    
+    //==============================================================================
+    
+    /* tMBSawtooth: Anti-aliased Sawtooth waveform. */
+    typedef struct _tMBSaw
+    {
+        float phase;
+        float inc,freq;
+        
+        tMinBLEP minBlep;
+        tHighpass dcBlock;
+    } _tMBSaw;
+    
+    typedef _tMBSaw* tMBSaw;
+    
+    /*!
+     * @defgroup tMBSaw tMBSaw
+     * @ingroup oscillators
+     * @brief An anti-aliased sawtooth waveform oscillator. Uses wavetable synthesis.
+     * @{
+     */
+    
+    //! Initialize a tMBSaw to the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBSaw to be initialized.
+     */
+    void    tMBSaw_init          (tMBSaw* const osc);
+    
+    
+    //! Free a tMBSaw from the default LEAF mempool.
+    /*!
+     @param osc A pointer to the tMBSaw to be freed.
+     */
+    void    tMBSaw_free          (tMBSaw* const osc);
+    
+    
+    //! Initialize a tMBSaw to a specified mempool.
+    /*!
+     @param osc A pointer to the tMBSaw to be initialized.
+     @param pool A pointer to the tMempool to which the tMBSaw should be initialized.
+     */
+    void    tMBSaw_initToPool    (tMBSaw* const osc, tMempool* const pool);
+    
+    
+    //! Free a tMBSaw from a specified mempool.
+    /*!
+     @param osc A pointer to the tMBSaw to be freed.
+     @param pool A pointer to the tMempool from which the tMBSaw should be freed.
+     */
+    void    tMBSaw_freeFromPool  (tMBSaw* const osc, tMempool* const pool);
+    
+    
+    //! Tick a tMBSaw oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBSaw.
+     @return The ticked sample as a float from -1 to 1.
+     */
+    float   tMBSaw_tick          (tMBSaw* const osc);
+    
+    
+    //! Set the frequency of a tMBSaw oscillator.
+    /*!
+     @param osc A pointer to the relevant tMBSaw.
+     @param freq The frequency to set the oscillator to.
+     */
+    void    tMBSaw_setFreq       (tMBSaw* const osc, float freq);
+    
+    void    tMBSaw_sync          (tMBSaw* const osc, float phase);
+    
+    /*! @} */
     
 #ifdef __cplusplus
 }
--- a/LEAF/Inc/leaf-sampling.h
+++ b/LEAF/Inc/leaf-sampling.h
@@ -139,9 +139,7 @@
     void    tSampler_setEnd             (tSampler* const, int32_t end);
     void    tSampler_setLength             (tSampler* const, int32_t length);
     
-    static void handleStartEndChange    (tSampler* const sp);
-    
-    void     tSampler_setCrossfadeLength (tSampler* const sp, uint32_t length);
+    void    tSampler_setCrossfadeLength (tSampler* const sp, uint32_t length);
     
     void    tSampler_setRate            (tSampler* const, float rate);
     
--- a/LEAF/Src/leaf-effects.c
+++ b/LEAF/Src/leaf-effects.c
@@ -622,7 +622,7 @@
 	return output;
 }
 
-float   tRosenbergGlottalPulse_setFreq           (tRosenbergGlottalPulse* const gp, float freq)
+void   tRosenbergGlottalPulse_setFreq           (tRosenbergGlottalPulse* const gp, float freq)
 {
 	_tRosenbergGlottalPulse* g = *gp;
 	g->freq = freq;
@@ -629,13 +629,13 @@
 	g->inc = freq * leaf.invSampleRate;
 }
 
-float   tRosenbergGlottalPulse_setOpenLength           (tRosenbergGlottalPulse* const gp, float openLength)
+void   tRosenbergGlottalPulse_setOpenLength           (tRosenbergGlottalPulse* const gp, float openLength)
 {
 	_tRosenbergGlottalPulse* g = *gp;
 	g->openLength = openLength;
 }
 
-float   tRosenbergGlottalPulse_setPulseLength           (tRosenbergGlottalPulse* const gp, float pulseLength)
+void   tRosenbergGlottalPulse_setPulseLength           (tRosenbergGlottalPulse* const gp, float pulseLength)
 {
 	_tRosenbergGlottalPulse* g = *gp;
 	g->pulseLength = pulseLength;
--- a/LEAF/Src/leaf-filters.c
+++ b/LEAF/Src/leaf-filters.c
@@ -17,7 +17,7 @@
 #include "../Inc/leaf-filters.h"
 #include "../Inc/leaf-tables.h"
 #include "../leaf.h"
-#include "tim.h"
+//#include "tim.h"
 #endif
 
 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
@@ -1728,24 +1728,24 @@
 
 	// This formula gives the result for y3 thanks to MATLAB
 	float y3 = (f->s2 + f->s3 + t2*(f->s1 + f->s2 + f->s3 + t1*(f->s0 + f->s1 + f->s2 + f->s3 + t0*in)) + t1*(2.0f*f->s2 + 2.0f*f->s3))*t3 + f->s3 + 2.0f*f->s3*t1 + t2*(2.0f*f->s3 + 3.0f*f->s3*t1);
-	if (isnan(y3))
-	{
-		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-	}
+//    if (isnan(y3))
+//    {
+//        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
+//    }
 	float tempy3denom = (t4 + t1*(2.0f*t4 + 4.0f) + t2*(t4 + t1*(t4 + f->r*t0 + 4.0f) + 3.0f) + 2.0f)*t3 + t4 + t1*(2.0f*t4 + 2.0f) + t2*(2.0f*t4 + t1*(3.0f*t4 + 3.0f) + 2.0f) + 1.0f;
-	if (isnan(tempy3denom))
-	{
-		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-	}
+//    if (isnan(tempy3denom))
+//    {
+//        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
+//    }
 	if (tempy3denom == 0.0f)
 	{
 		tempy3denom = 0.000001f;
 	}
 	y3 = y3 / tempy3denom;
-	if (isnan(y3))
-	{
-		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-	}
+//    if (isnan(y3))
+//    {
+//        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
+//    }
 	if (t1 == 0.0f)
 	{
 		t1 = 0.000001f;
@@ -1766,15 +1766,15 @@
 
 	// update state
 	f->s0 += 2.0f * (t0*xx + t1*(y1-y0));
-	if (isnan(f->s0))
-	{
-		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-	}
+//    if (isnan(f->s0))
+//    {
+//        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
+//    }
 
-	if (isinf(f->s0))
-	{
-		__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
-	}
+//    if (isinf(f->s0))
+//    {
+//        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, 400);
+//    }
 	f->s1 += 2.0f * (t2*(y2-y1) - t1*(y1-y0));
 	f->s2 += 2.0f * (t3*(y3-y2) - t2*(y2-y1));
 	f->s3 += 2.0f * (-t4*(y3) - t3*(y3-y2));
--- a/LEAF/Src/leaf-oscillators.c
+++ b/LEAF/Src/leaf-oscillators.c
@@ -925,9 +925,9 @@
 
 
 
-void    tMinBLEP_init           (tMinBLEP* const minblep)
+void    tMinBLEP_init           (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio)
 {
-    tMinBLEP_initToPool(minblep, &leaf.mempool);
+    tMinBLEP_initToPool(minblep, zeroCrossings, oversamplerRatio, &leaf.mempool);
 }
 
 void    tMinBLEP_free           (tMinBLEP* const minblep)
@@ -935,15 +935,15 @@
     tMinBLEP_freeFromPool(minblep, &leaf.mempool);
 }
 
-void    tMinBLEP_initToPool     (tMinBLEP* const minblep, tMempool* const mp)
+void    tMinBLEP_initToPool     (tMinBLEP* const minblep, int zeroCrossings, int oversamplerRatio, tMempool* const mp)
 {
     _tMempool* m = *mp;
     _tMinBLEP* mb = *minblep = (_tMinBLEP*) mpool_alloc(sizeof(_tMinBLEP), m);
     
-    mb->overSamplingRatio = 64;
-    mb->zeroCrossings = 32;
+    mb->overSamplingRatio = zeroCrossings;
+    mb->zeroCrossings = oversamplerRatio;
     mb->returnDerivative = 0;
-    mb->proportionalBlepFreq = 0.5; // defaults to NyQuist ....
+    mb->proportionalBlepFreq = (float) mb->zeroCrossings / (float) mb->overSamplingRatio; // defaults to NyQuist ....
     
     mb->lastValue = 0;
     mb->lastDelta = 0;
@@ -963,8 +963,10 @@
     mb->blepIndex = 0;
     mb->numActiveBleps = 0;
     //currentActiveBlepOffsets;
+    
+    // These probably don't need to be this large
     mb->offset = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
-    mb->freqMultiple = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
+//    mb->freqMultiple = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
     mb->pos_change_magnitude = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
     mb->vel_change_magnitude = (float*) mpool_alloc(sizeof(float) * mb->minBlepSize, m);
     
@@ -979,7 +981,14 @@
     _tMempool* m = *mp;
     _tMinBLEP* mb = *minblep;
     
+    mpool_free(mb->offset, m);
+//    mpool_free(mb->freqMultiple, m);
+    mpool_free(mb->pos_change_magnitude, m);
+    mpool_free(mb->vel_change_magnitude, m);
     
+    mpool_free(mb->minBlepArray, m);
+    mpool_free(mb->minBlepDerivArray, m);
+    
     mpool_free(mb, m);
 }
 
@@ -1236,7 +1245,7 @@
     int n = m->minBlepSize;
     
     m->offset[m->blepIndex] = offset;
-    m->freqMultiple[m->blepIndex] = m->overSamplingRatio*m->proportionalBlepFreq;
+//    m->freqMultiple[m->blepIndex] = m->overSamplingRatio*m->proportionalBlepFreq;
     m->pos_change_magnitude[m->blepIndex] = posChange;
     m->vel_change_magnitude[m->blepIndex] = velChange;
     
@@ -1259,7 +1268,7 @@
     for (int blep = 1; blep <= m->numActiveBleps; blep++)
     {
         int i = (m->blepIndex - blep + n) % n;
-        float adjusted_Freq = m->freqMultiple[i];
+        float adjusted_Freq = m->overSamplingRatio*m->proportionalBlepFreq;//m->freqMultiple[i];
         float exactPosition = m->offset[i];
         
         double blepPosExact = adjusted_Freq*(exactPosition + 1); // +1 because this needs to trigger on the LOW SAMPLE
@@ -1336,4 +1345,293 @@
         }
     }
     return sample;
+}
+
+//==============================================================================
+
+/* tMBTriangle: Anti-aliased Triangle waveform. */
+void    tMBTriangle_init          (tMBTriangle* const osc)
+{
+    tMBTriangle_initToPool(osc, &leaf.mempool);
+}
+
+void    tMBTriangle_free          (tMBTriangle* const osc)
+{
+    tMBTriangle_freeFromPool(osc, &leaf.mempool);
+}
+
+void    tMBTriangle_initToPool    (tMBTriangle* const osc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBTriangle* c = *osc = (_tMBTriangle*) mpool_alloc(sizeof(_tMBTriangle), m);
+    
+    c->inc      =  0.0f;
+    c->phase    =  0.0f;
+    c->skew     =  0.5f;
+    c->lastOut  =  0.0f;
+    
+    tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
+    tHighpass_initToPool(&c->dcBlock, 10.0f, mp);
+}
+
+void    tMBTriangle_freeFromPool  (tMBTriangle* const cy, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBTriangle* c = *cy;
+    
+    tMinBLEP_freeFromPool(&c->minBlep, mp);
+    tHighpass_freeFromPool(&c->dcBlock, mp);
+    
+    mpool_free(c, m);
+}
+
+float   tMBTriangle_tick          (tMBTriangle* const osc)
+{
+    _tMBTriangle* c = *osc;
+    
+    float out;
+    
+    c->phase += c->inc;
+    if (c->phase >= 1.0f)
+    {
+        c->phase -= 1.0f;
+        float offset = 1.0f - ((c->inc - c->phase) / c->inc);
+        tMinBLEP_addBLEP(&c->minBlep, offset, -2, 0.0f);
+    }
+    if (c->skew <= c->phase && c->phase < c->skew + c->inc)
+    {
+        float offset = 1.0f - ((c->inc - c->phase + c->skew) / c->inc);
+        tMinBLEP_addBLEP(&c->minBlep, offset, 2, 0.0f);
+    }
+    
+    if (c->phase < c->skew)
+    {
+        out = (1.0f - c->skew) * 2.0f;
+    }
+    else
+    {
+        out = -c->skew * 2.0f;
+    }
+    
+    out = tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));// - phasor->inc * 2.0f;
+    
+//    out = tMinBLEP_tick(&c->minBlep, out) - c->inc * 2.0f;
+    
+    out = (c->inc * out) + ((1 - c->inc) * c->lastOut);
+    c->lastOut = out;
+    
+    return out;
+}
+
+void    tMBTriangle_setFreq       (tMBTriangle* const osc, float freq)
+{
+    _tMBTriangle* c = *osc;
+    
+    c->freq  = freq;
+    c->inc = freq * leaf.invSampleRate;
+    
+//    tHighpass_setFreq(&c->dcBlock, freq*0.5);
+}
+
+void    tMBTriangle_setSkew       (tMBTriangle* const osc, float skew)
+{
+    _tMBTriangle* c = *osc;
+    c->skew = (skew + 1.0f) * 0.5f;
+}
+
+void    tMBTriangle_sync          (tMBTriangle* const osc, float phase)
+{
+    _tMBTriangle* c = *osc;
+    LEAF_clip(0.0f, phase, 1.0f);
+    
+    float last, next;
+    
+    if (c->phase < c->skew) last = (1.0f - c->skew - c->phase) * 2.0f;
+    else last = -(c->phase - c->skew) * 2.0f;
+
+    if (phase < c->skew) next = (1.0f - c->skew - phase) * 2.0f;
+    else next = -(phase - c->skew) * 2.0f;
+
+    c->phase = phase;
+
+    float offset = 1.0f - ((c->inc - c->phase) / c->inc);
+    tMinBLEP_addBLEP(&c->minBlep, offset, last - next, 0.0f);
+    
+//    c->lastOut = 0.0f;
+}
+
+//==============================================================================
+
+/* tMBPulse: Anti-aliased pulse waveform. */
+void    tMBPulse_init        (tMBPulse* const osc)
+{
+    tMBPulse_initToPool(osc, &leaf.mempool);
+}
+
+void    tMBPulse_free        (tMBPulse* const osc)
+{
+    tMBPulse_freeFromPool(osc, &leaf.mempool);
+}
+
+void    tMBPulse_initToPool  (tMBPulse* const osc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBPulse* c = *osc = (_tMBPulse*) mpool_alloc(sizeof(_tMBPulse), m);
+    
+    c->inc      =  0.0f;
+    c->phase    =  0.0f;
+    c->width     =  0.5f;
+    
+    tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
+    tHighpass_initToPool(&c->dcBlock, 10.0f, mp);
+}
+
+void    tMBPulse_freeFromPool(tMBPulse* const osc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBPulse* c = *osc;
+    
+    tMinBLEP_freeFromPool(&c->minBlep, mp);
+    tHighpass_freeFromPool(&c->dcBlock, mp);
+    
+    mpool_free(c, m);
+}
+
+float   tMBPulse_tick        (tMBPulse* const osc)
+{
+    _tMBPulse* c = *osc;
+    
+
+    
+    c->phase += c->inc;
+    if (c->phase >= 1.0f)
+    {
+        c->phase -= 1.0f;
+        float offset = 1.0f - ((c->inc - c->phase) / c->inc);
+        tMinBLEP_addBLEP(&c->minBlep, offset, -2, 0.0f);
+    }
+    if (c->width <= c->phase && c->phase < c->width + c->inc)
+    {
+        float offset = 1.0f - ((c->inc - c->phase + c->width) / c->inc);
+        tMinBLEP_addBLEP(&c->minBlep, offset, 2, 0.0f);
+    }
+    
+    float out;
+    if (c->phase < c->width) out = 1.0f;
+    else out = -1.0f;
+    
+    return tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));// - phasor->inc * 2.0f;
+    
+    
+    
+    return out;
+}
+
+void    tMBPulse_setFreq     (tMBPulse* const osc, float freq)
+{
+    _tMBPulse* c = *osc;
+    
+    c->freq  = freq;
+    c->inc = freq * leaf.invSampleRate;
+}
+
+void    tMBPulse_setWidth    (tMBPulse* const osc, float width)
+{
+    _tMBPulse* c = *osc;
+    c->width = width;
+}
+
+void    tMBPulse_sync          (tMBPulse* const osc, float phase)
+{
+    _tMBPulse* c = *osc;
+    LEAF_clip(0.0f, phase, 1.0f);
+    
+    float last, next;
+    
+    if (c->phase < c->width) last = 1.0f;
+    else last = -1.0f;
+    
+    if (phase < c->width) next = 1.0;
+    else next = -1.0f;
+    
+    c->phase = phase;
+    
+    float offset = 1.0f - ((c->inc - c->phase) / c->inc);
+    tMinBLEP_addBLEP(&c->minBlep, offset, last - next, 0.0f);
+}
+
+
+//==============================================================================
+
+/* tMBSawtooth: Anti-aliased Sawtooth waveform. */
+void    tMBSaw_init          (tMBSaw* const osc)
+{
+    tMBSaw_initToPool(osc, &leaf.mempool);
+}
+
+void    tMBSaw_free          (tMBSaw* const osc)
+{
+    tMBSaw_freeFromPool(osc, &leaf.mempool);
+}
+
+void    tMBSaw_initToPool    (tMBSaw* const osc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBSaw* c = *osc = (_tMBSaw*) mpool_alloc(sizeof(_tMBSaw), m);
+    
+    c->inc      =  0.0f;
+    c->phase    =  0.0f;
+    
+    tMinBLEP_initToPool(&c->minBlep, 16, 32, mp);
+    tHighpass_initToPool(&c->dcBlock, 10.0f, mp);
+}
+
+void    tMBSaw_freeFromPool  (tMBSaw* const osc, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tMBSaw* c = *osc;
+    
+    tMinBLEP_freeFromPool(&c->minBlep, mp);
+    tHighpass_freeFromPool(&c->dcBlock, mp);
+    
+    mpool_free(c, m);
+}
+
+float   tMBSaw_tick          (tMBSaw* const osc)
+{
+    _tMBSaw* c = *osc;
+    
+    c->phase += c->inc;
+    if (c->phase >= 1.0f)
+    {
+        c->phase -= 1.0f;
+        float offset = 1.0f - ((c->inc - c->phase) / c->inc);
+        tMinBLEP_addBLEP(&c->minBlep, offset, 2, 0.0f);
+    }
+    
+    float out = (c->phase * 2.0f) - 1.0f;
+    
+    return tHighpass_tick(&c->dcBlock, tMinBLEP_tick(&c->minBlep, out));// - phasor->inc * 2.0f;
+    
+//    return tMinBLEP_tick(&c->minBlep, out) - c->inc * 2.0f;
+}
+
+void    tMBSaw_setFreq       (tMBSaw* const osc, float freq)
+{
+    _tMBSaw* c = *osc;
+    
+    c->freq  = freq;
+    
+    c->inc = freq * leaf.invSampleRate;
+}
+
+void    tMBSaw_sync          (tMBSaw* const osc, float phase)
+{
+    _tMBSaw* c = *osc;
+    LEAF_clip(0.0f, phase, 1.0f);
+    
+    float offset = 1.0f - ((c->inc - phase) / c->inc);
+    tMinBLEP_addBLEP(&c->minBlep, offset, c->phase * 2.0f, 0.0f);
+    
+    c->phase = phase;
 }
--- a/LEAF/Src/leaf-sampling.c
+++ b/LEAF/Src/leaf-sampling.c
@@ -609,7 +609,7 @@
             if (start > p->idx)// start given is after current index or we're in a crossfade
             {
                 p->targetstart = start;
-                float tempLen = fabs(p->end - start) * 0.25f;
+                float tempLen = abs(p->end - start) * 0.25f;
                 if (cfxlen > tempLen)
                 {
                     p->cfxlen = tempLen;
@@ -622,7 +622,7 @@
             if (start < p->idx)// start given is before current index or we're in a crossfade
             {
                 p->targetstart = start;
-                float tempLen = fabs(p->end - start) * 0.25f;
+                float tempLen = abs(p->end - start) * 0.25f;
                 if (cfxlen > tempLen)
                 {
                     p->cfxlen = tempLen;
@@ -680,7 +680,7 @@
             if (end < p->idx) // end given is before current index or we're in a crossfade
             {
                 p->targetend = end;
-                float tempLen = fabs(end - p->start) * 0.25f;
+                float tempLen = abs(end - p->start) * 0.25f;
                 if (cfxlen > tempLen)
                 {
                     p->cfxlen = tempLen;
@@ -693,7 +693,7 @@
             if (end > p->idx) // end given is after current index or we're in a crossfade
             {
                 p->targetend = end;
-                float tempLen = fabs(end - p->start) * 0.25f;
+                float tempLen = abs(end - p->start) * 0.25f;
                 if (cfxlen > tempLen)
                 {
                     p->cfxlen = tempLen;
--- a/LEAF_JUCEPlugin/Source/MyTest.cpp
+++ b/LEAF_JUCEPlugin/Source/MyTest.cpp
@@ -25,12 +25,17 @@
 
 tAutotune at;
 
-tTriangle tri;
 
 tMinBLEP minblep;
 
 tPhasor phasor;
 
+tHighpass hipass;
+
+tMBSaw saw;
+tMBPulse pulse;
+tMBTriangle tri;
+
 float gain;
 float freq;
 float dtime;
@@ -47,28 +52,15 @@
 {
     LEAF_init(sampleRate, blockSize, memory, MSIZE, &getRandomFloat);
     
-    tTriangle_init(&tri);
+    tMBSaw_init(&saw);
     
-    tMinBLEP_init(&minblep);
+    tMBPulse_init(&pulse);
     
+    tMBTriangle_init(&tri);
+    
     tPhasor_init(&phasor);
-    //    tNoise_init(&noise, WhiteNoise);
-    //
-    //    tAutotune_init(&at, 1, 1024, 512);
     
-    //    tSVF_init(&bp1, SVFTypeBandpass, 100, 4.0f);
-    //    tSVF_init(&bp2, SVFTypeBandpass, 1000, 4.0f);
-    //
-    //    tFormantShifter_init(&fs, 20);
-    //
-    //    // Init and set record
-    //    tBuffer_init (&buff, leaf.sampleRate); // init, 1 second buffer
-    //    tBuffer_setRecordMode (&buff, RecordOneShot); // RecordOneShot records once through
-    //
-    //    // Init and set play
-    //    tSampler_init (&samp, &buff); // init, give address of record buffer
-    //    tSampler_setMode (&samp, PlayLoop); //set in Loop Mode
-    //    tSampler_setRate(&samp, 1.763f); // Rate of 1.0
+    tPhasor_setFreq(&phasor, 2000);
 }
 
 inline double getSawFall(double angle) {
@@ -82,33 +74,18 @@
 
 float   LEAFTest_tick            (float input)
 {
-    //    float sample = tNoise_tick(&noise);
-    //    sample *= 0.5f;
-    //    float b = tSVF_tick(&bp1, sample);
-    //    b += tSVF_tick(&bp2, sample);
-    //
-    //    return (tFormantShifter_tick(&fs, input));
-    //
-    //    tBuffer_tick(&buff, input);
     
-    //    return tSampler_tick(&samp);
+    tMBSaw_setFreq(&saw, y);
+    tMBPulse_setWidth(&pulse, x);
+    tMBPulse_setFreq(&pulse, y);
+    tMBTriangle_setSkew(&tri, x*2.0f - 1.0f);
+    tMBTriangle_setFreq(&tri, y);
     
-    //    tAutotune_setFreq(&at, 440.0f, 0);
+    tPhasor_tick(&phasor);
     
-    //    return tAutotune_tick(&at, input)[0];
+//    if (phasor->phaseDidReset) tMBSaw_sync(&saw, 0.0f);
     
-    tPhasor_setFreq(&phasor, y);
-    
-    
-    float sample = tPhasor_tick(&phasor) * 2.0f - 1.0f;
-    
-    if (phasor->phaseDidReset)
-    {
-        float offset = 1.0f - ((phasor->inc - phasor->phase) / phasor->inc);
-        tMinBLEP_addBLEP(&minblep, offset, 2, 0.0f);
-    }
-    
-    return tMinBLEP_tick(&minblep, sample) - phasor->inc * 2.0f;
+    return tMBSaw_tick(&saw);// - phasor->inc * 2.0f;
 }
 
 int firstFrame = 1;