shithub: leaf

Download patch

ref: be773ed33f71a0faa6d518c50b44eed4524c3522
parent: 65ab3d024da463b1da721f4737f7614121680ef5
author: Matthew Wang <mjw7@princeton.edu>
date: Fri Jan 8 10:39:23 EST 2021

tWaveset object, fade between multiple wavetables

--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -33,6 +33,7 @@
 
 tWavetable wt;
 tCompactWavetable cwt;
+tWaveset ws;
 
 tBuffer samp;
 tMBSampler sampler;
@@ -57,8 +58,8 @@
 {
     LEAF_init(&leaf, sampleRate, blockSize, memory, MSIZE, &getRandomFloat);
     
-    tWavetable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
-    tCompactWavetable_init(&cwt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
+//    tWavetable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
+//    tCompactWavetable_init(&cwt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
     
     tMBTriangle_init(&btri, &leaf);
     tMBPulse_init(&bpulse, &leaf);
@@ -69,6 +70,15 @@
     
     tPhasor_init(&phasor, &leaf);
     tPhasor_setFreq(&phasor, 220.f);
+    
+    float const* set[4];
+    set[0] = __leaf_table_sinewave;
+    set[1] = __leaf_table_triangle[0];
+    set[2] = __leaf_table_squarewave[0];
+    set[3] = __leaf_table_sawtooth[0];
+    
+    tWaveset_init(&ws, set, 4, 2048, 10000.f, &leaf);
+    tWaveset_setIndexGain(&ws, 0, -1.0f);
 }
 
 inline double getSawFall(double angle) {
@@ -86,7 +96,8 @@
 //    return tSimpleRetune_tick(&sretune, input);
 //    tMBPulse_sync(&bpulse, tPhasor_tick(&phasor) * 2.f - 1.f);
 //    return tMBPulse_tick(&bpulse);
-    return tWavetable_tick(&wt);
+//    return tWavetable_tick(&wt);
+    return tWaveset_tick(&ws);
 }
 
 int firstFrame = 1;
@@ -97,12 +108,14 @@
     tMBTriangle_setFreq(&btri, val * 440.f);
     tMBPulse_setFreq(&bpulse, val * 160000.f - 80000.0f);
     tMBSaw_setFreq(&bsaw, val * 10000.f);
-    tWavetable_setFreq(&wt, val * 160000.f - 80000.0f);
-    tCompactWavetable_setFreq(&cwt, val * 10000.);
+//    tWavetable_setFreq(&wt, val * 160000.f - 80000.0f);
+//    tCompactWavetable_setFreq(&cwt, val * 10000.);
+    tWaveset_setFreq(&ws, val * 10000.f);
 //    tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
 //    tSimpleRetune_tuneVoice(&sretune, 0, 300);
 
     val = getSliderValue("slider2");
+    tWaveset_setIndex(&ws, val);
 //    tRetune_setPitchFactor(&retune, val * 3.0f + 0.5f, 1);
     
     val = getSliderValue("slider3");
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -29,202 +29,6 @@
     //==============================================================================
     
     /*!
-     @defgroup ttable tTable
-     @ingroup oscillators
-     @brief Simple aliasing wavetable oscillator.
-     @{
-
-     @fn void    tTable_init  (tTable* const osc, float* table, int size, LEAF* const leaf)
-     @brief Initialize a tTable to the default mempool of a LEAF instance.
-     @param osc A pointer to the tTable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wavetable.
-     @param leaf A pointer to the leaf instance.
-
-     @fn void    tTable_initToPool   (tTable* const osc, float* table, int size, tMempool* const mempool)
-     @brief Initialize a tTable to a specified mempool.
-     @param osc A pointer to the tTable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wave table.
-     @param mempool A pointer to the tMempool to use.
-
-     @fn void    tTable_free         (tTable* const osc)
-     @brief Free a tTable from its mempool.
-     @param osc A pointer to the tTable to free.
- 
-     @fn float   tTable_tick         (tTable* const osc)
-     @brief Tick a tTable oscillator.
-     @param osc A pointer to the relevant tTable.
-     @return The ticked sample as a float from -1 to 1.
-
-     @fn void    tTable_setFreq      (tTable* const osc, float freq)
-     @brief Set the frequency of a tTable oscillator.
-     @param osc A pointer to the relevant tTable.
-     @param freq The frequency to set the oscillator to.
-     
-     @} */
-    
-    typedef struct _tTable
-    {
-        tMempool mempool;
-        
-        float* waveTable;
-        int size;
-        float inc, freq;
-        float phase;
-    } _tTable;
-    
-    typedef _tTable* tTable;
-
-     void    tTable_init(tTable* const osc, float* table, int size, LEAF* const leaf);
-     void    tTable_initToPool(tTable* const osc, float* table, int size, tMempool* const mempool);
-     void    tTable_free(tTable* const osc);
-    
-     float   tTable_tick(tTable* const osc);
-     void    tTable_setFreq(tTable* const osc, float freq);
-    
-    //==============================================================================
-    
-    /*!
-     @defgroup twavetable tWavetable
-     @ingroup oscillators
-     @brief Anti-aliased wavetable oscillator.
-     @{
-     
-     @fn void    tWavetable_init  (tWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
-     @brief Initialize a tWavetable to the default mempool of a LEAF instance.
-     @param osc A pointer to the tWavetable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wavetable.
-     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
-     @param leaf A pointer to the leaf instance.
-     
-     @fn void    tWavetable_initToPool   (tWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
-     @brief Initialize a tWavetable to a specified mempool.
-     @param osc A pointer to the tWavetable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wave table.
-     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
-     @param mempool A pointer to the tMempool to use.
-     
-     @fn void    tWavetable_free         (tWavetable* const osc)
-     @brief Free a tWavetable from its mempool.
-     @param osc A pointer to the tWavetable to free.
-     
-     @fn float   tWavetable_tick         (tWavetable* const osc)
-     @brief Tick a tWavetable oscillator.
-     @param osc A pointer to the relevant tWavetable.
-     @return The ticked sample as a float from -1 to 1.
-     
-     @fn void    tWavetable_setFreq      (tWavetable* const osc, float freq)
-     @brief Set the frequency of a tWavetable oscillator.
-     @param osc A pointer to the relevant tWavetable.
-     @param freq The frequency to set the oscillator to.
-     
-     @} */
-    
-    typedef struct _tWavetable
-    {
-        tMempool mempool;
-        
-        float** tables;
-        int size;
-        int numTables;
-        float baseFreq, invBaseFreq;
-        float inc, freq;
-        float phase;
-        
-        int oct;
-        float w;
-        float aa;
-        
-        tButterworth bl;
-    } _tWavetable;
-    
-    typedef _tWavetable* tWavetable;
-    
-    void    tWavetable_init(tWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
-    void    tWavetable_initToPool(tWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
-    void    tWavetable_free(tWavetable* const osc);
-    
-    float   tWavetable_tick(tWavetable* const osc);
-    void    tWavetable_setFreq(tWavetable* const osc, float freq);
-    void    tWavetable_setAntiAliasing(tWavetable* const osc, float aa);
-    
-    //==============================================================================
-    
-    /*!
-     @defgroup tcompactwavetable tCompactWavetable
-     @ingroup oscillators
-     @brief A more space-efficient anti-aliased wavetable oscillator than tWavetable but with slightly worse fidelity.
-     @{
-     
-     @fn void    tCompactWavetable_init  (tCompactWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
-     @brief Initialize a tCompactWavetable to the default mempool of a LEAF instance.
-     @param osc A pointer to the tCompactWavetable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wavetable.
-     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
-     @param leaf A pointer to the leaf instance.
-     
-     @fn void    tCompactWavetable_initToPool   (tCompactWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
-     @brief Initialize a tCompactWavetable to a specified mempool.
-     @param osc A pointer to the tCompactWavetable to initialize.
-     @param table A pointer to the wavetable data.
-     @param size The number of samples in the wave table.
-     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
-     @param mempool A pointer to the tMempool to use.
-     
-     @fn void    tCompactWavetable_free         (tCompactWavetable* const osc)
-     @brief Free a tCompactWavetable from its mempool.
-     @param osc A pointer to the tCompactWavetable to free.
-     
-     @fn float   tCompactWavetable_tick         (tCompactWavetable* const osc)
-     @brief Tick a tCompactWavetable oscillator.
-     @param osc A pointer to the relevant tCompactWavetable.
-     @return The ticked sample as a float from -1 to 1.
-     
-     @fn void    tCompactWavetable_setFreq      (tCompactWavetable* const osc, float freq)
-     @brief Set the frequency of a tCompactWavetable oscillator.
-     @param osc A pointer to the relevant tCompactWavetable.
-     @param freq The frequency to set the oscillator to.
-     
-     @} */
-    
-    typedef struct _tCompactWavetable
-    {
-        tMempool mempool;
-        
-        float** tables;
-        int numTables;
-        int* sizes;
-        float baseFreq, invBaseFreq;
-        float inc, freq;
-        float phase;
-        
-        int oct;
-        float w;
-        float aa;
-        
-        tButterworth bl;
-        
-        float dsBuffer[2];
-        tOversampler ds;
-    } _tCompactWavetable;
-    
-    typedef _tCompactWavetable* tCompactWavetable;
-    
-    void    tCompactWavetable_init(tCompactWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
-    void    tCompactWavetable_initToPool(tCompactWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
-    void    tCompactWavetable_free(tCompactWavetable* const osc);
-    
-    float   tCompactWavetable_tick(tCompactWavetable* const osc);
-    void    tCompactWavetable_setFreq(tCompactWavetable* const osc, float freq);
-    void    tCompactWavetable_setAntiAliasing(tCompactWavetable* const osc, float aa);
-    
-    //==============================================================================
-    
-    /*!
      @defgroup tcycle tCycle
      @ingroup oscillators
      @brief Wavetable cycle/sine wave oscillator
@@ -1057,6 +861,270 @@
     void tMBSaw_setFreq(tMBSaw* const osc, float f);
     float tMBSaw_sync(tMBSaw* const osc, float sync);
     void tMBSaw_setSyncMode(tMBSaw* const osc, int hardOrSoft);
+    
+    //==============================================================================
+    
+    /*!
+     @defgroup ttable tTable
+     @ingroup oscillators
+     @brief Simple aliasing wavetable oscillator.
+     @{
+     
+     @fn void    tTable_init  (tTable* const osc, float* table, int size, LEAF* const leaf)
+     @brief Initialize a tTable to the default mempool of a LEAF instance.
+     @param osc A pointer to the tTable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wavetable.
+     @param leaf A pointer to the leaf instance.
+     
+     @fn void    tTable_initToPool   (tTable* const osc, float* table, int size, tMempool* const mempool)
+     @brief Initialize a tTable to a specified mempool.
+     @param osc A pointer to the tTable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wave table.
+     @param mempool A pointer to the tMempool to use.
+     
+     @fn void    tTable_free         (tTable* const osc)
+     @brief Free a tTable from its mempool.
+     @param osc A pointer to the tTable to free.
+     
+     @fn float   tTable_tick         (tTable* const osc)
+     @brief Tick a tTable oscillator.
+     @param osc A pointer to the relevant tTable.
+     @return The ticked sample as a float from -1 to 1.
+     
+     @fn void    tTable_setFreq      (tTable* const osc, float freq)
+     @brief Set the frequency of a tTable oscillator.
+     @param osc A pointer to the relevant tTable.
+     @param freq The frequency to set the oscillator to.
+     
+     @} */
+    
+    typedef struct _tTable
+    {
+        tMempool mempool;
+        
+        float* waveTable;
+        int size;
+        float inc, freq;
+        float phase;
+    } _tTable;
+    
+    typedef _tTable* tTable;
+    
+    void    tTable_init(tTable* const osc, float* table, int size, LEAF* const leaf);
+    void    tTable_initToPool(tTable* const osc, float* table, int size, tMempool* const mempool);
+    void    tTable_free(tTable* const osc);
+    
+    float   tTable_tick(tTable* const osc);
+    void    tTable_setFreq(tTable* const osc, float freq);
+    
+    //==============================================================================
+    
+    /*!
+     @defgroup twavetable tWavetable
+     @ingroup oscillators
+     @brief Anti-aliased wavetable oscillator.
+     @{
+     
+     @fn void    tWavetable_init  (tWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tWavetable to the default mempool of a LEAF instance.
+     @param osc A pointer to the tWavetable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wavetable.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param leaf A pointer to the leaf instance.
+     
+     @fn void    tWavetable_initToPool   (tWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tWavetable to a specified mempool.
+     @param osc A pointer to the tWavetable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wave table.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param mempool A pointer to the tMempool to use.
+     
+     @fn void    tWavetable_free         (tWavetable* const osc)
+     @brief Free a tWavetable from its mempool.
+     @param osc A pointer to the tWavetable to free.
+     
+     @fn float   tWavetable_tick         (tWavetable* const osc)
+     @brief Tick a tWavetable oscillator.
+     @param osc A pointer to the relevant tWavetable.
+     @return The ticked sample as a float from -1 to 1.
+     
+     @fn void    tWavetable_setFreq      (tWavetable* const osc, float freq)
+     @brief Set the frequency of a tWavetable oscillator.
+     @param osc A pointer to the relevant tWavetable.
+     @param freq The frequency to set the oscillator to.
+     
+     @} */
+    
+    typedef struct _tWavetable
+    {
+        tMempool mempool;
+        
+        float** tables;
+        int size;
+        int numTables;
+        float baseFreq, invBaseFreq;
+        float inc, freq;
+        float phase;
+        
+        int oct;
+        float w;
+        float aa;
+        
+        tButterworth bl;
+    } _tWavetable;
+    
+    typedef _tWavetable* tWavetable;
+    
+    void    tWavetable_init(tWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
+    void    tWavetable_initToPool(tWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
+    void    tWavetable_free(tWavetable* const osc);
+    
+    float   tWavetable_tick(tWavetable* const osc);
+    void    tWavetable_setFreq(tWavetable* const osc, float freq);
+    void    tWavetable_setAntiAliasing(tWavetable* const osc, float aa);
+    
+    //==============================================================================
+    
+    /*!
+     @defgroup tcompactwavetable tCompactWavetable
+     @ingroup oscillators
+     @brief A more space-efficient anti-aliased wavetable oscillator than tWavetable but with slightly worse fidelity.
+     @{
+     
+     @fn void    tCompactWavetable_init  (tCompactWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tCompactWavetable to the default mempool of a LEAF instance.
+     @param osc A pointer to the tCompactWavetable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wavetable.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param leaf A pointer to the leaf instance.
+     
+     @fn void    tCompactWavetable_initToPool   (tCompactWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tCompactWavetable to a specified mempool.
+     @param osc A pointer to the tCompactWavetable to initialize.
+     @param table A pointer to the wavetable data.
+     @param size The number of samples in the wave table.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param mempool A pointer to the tMempool to use.
+     
+     @fn void    tCompactWavetable_free         (tCompactWavetable* const osc)
+     @brief Free a tCompactWavetable from its mempool.
+     @param osc A pointer to the tCompactWavetable to free.
+     
+     @fn float   tCompactWavetable_tick         (tCompactWavetable* const osc)
+     @brief Tick a tCompactWavetable oscillator.
+     @param osc A pointer to the relevant tCompactWavetable.
+     @return The ticked sample as a float from -1 to 1.
+     
+     @fn void    tCompactWavetable_setFreq      (tCompactWavetable* const osc, float freq)
+     @brief Set the frequency of a tCompactWavetable oscillator.
+     @param osc A pointer to the relevant tCompactWavetable.
+     @param freq The frequency to set the oscillator to.
+     
+     @} */
+    
+    typedef struct _tCompactWavetable
+    {
+        tMempool mempool;
+        
+        float** tables;
+        int numTables;
+        int* sizes;
+        float baseFreq, invBaseFreq;
+        float inc, freq;
+        float phase;
+        
+        int oct;
+        float w;
+        float aa;
+        
+        tButterworth bl;
+        
+        float dsBuffer[2];
+        tOversampler ds;
+    } _tCompactWavetable;
+    
+    typedef _tCompactWavetable* tCompactWavetable;
+    
+    void    tCompactWavetable_init(tCompactWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
+    void    tCompactWavetable_initToPool(tCompactWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
+    void    tCompactWavetable_free(tCompactWavetable* const osc);
+    
+    float   tCompactWavetable_tick(tCompactWavetable* const osc);
+    void    tCompactWavetable_setFreq(tCompactWavetable* const osc, float freq);
+    void    tCompactWavetable_setAntiAliasing(tCompactWavetable* const osc, float aa);
+    
+    //==============================================================================
+    
+    /*!
+     @defgroup twaveset tWaveset
+     @ingroup oscillators
+     @brief Set of anti-aliased wavetable oscillators that can be faded between.
+     @{
+     
+     @fn void    tWaveset_init(tWaveset* const osc, const float** tables, int n, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tWaveset to the default mempool of a LEAF instance.
+     @param osc A pointer to the tWaveset to initialize.
+     @param tables An array of pointers to wavetable data.
+     @param n The number of wavetables.
+     @param size The number of samples in each of the wavetables.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param leaf A pointer to the leaf instance.
+     
+     @fn void  tWaveset_initToPool(tWaveset* const osc, const float** tables, int n, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tWaveset to a specified mempool.
+     @param osc A pointer to the tWavetable to initialize.
+     @param tables An array of pointers to wavetable data.
+     @param n The number of wavetables.
+     @param size The number of samples in each of the wavetables.
+     @param maxFreq The maximum expected frequency of the oscillator. The higher this is, the more memory will be needed.
+     @param mempool A pointer to the tMempool to use.
+     
+     @fn void    tWaveset_free         (tWaveset* const osc)
+     @brief Free a tWaveset from its mempool.
+     @param osc A pointer to the tWaveset to free.
+     
+     @fn float   tWaveset_tick         (tWaveset* const osc)
+     @brief Tick a tWaveset oscillator.
+     @param osc A pointer to the relevant tWaveset.
+     @return The ticked sample as a float from -1 to 1.
+     
+     @fn void    tWaveset_setFreq      (tWaveset* const osc, float freq)
+     @brief Set the frequency of a tWaveset oscillator.
+     @param osc A pointer to the relevant tWaveset.
+     @param freq The frequency to set the oscillator to.
+     
+     @fn void    tWaveset_setIndex(tWaveset* const osc, float index)
+     @brief Set the output index of the wavetable set.
+     @param index The new index from 0.0 to 1.0 as a smooth fade from the first wavetable in the set to the last.
+     
+     @} */
+    
+    typedef struct _tWaveset
+    {
+        tMempool mempool;
+        
+        tWavetable* wt;
+        int n;
+        float* g;
+        float index;
+    } _tWaveset;
+    
+    typedef _tWaveset* tWaveset;
+    
+    void    tWaveset_init(tWaveset* const osc, const float** tables, int n, int size, float maxFreq, LEAF* const leaf);
+    void    tWaveset_initToPool(tWaveset* const osc, const float** tables, int n, int size, float maxFreq, tMempool* const mempool);
+    void    tWaveset_free(tWaveset* const osc);
+    
+    float   tWaveset_tick(tWaveset* const osc);
+    void    tWaveset_setFreq(tWaveset* const osc, float freq);
+    void    tWaveset_setAntiAliasing(tWaveset* const osc, float aa);
+    void    tWaveset_setIndex(tWaveset* const osc, float index);
+    void    tWaveset_setIndexGain(tWaveset* const osc, int i, float gain);
 
     
 #ifdef __cplusplus
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -16,376 +16,6 @@
 
 #endif
 
-// WaveTable
-void    tTable_init(tTable* const cy, float* waveTable, int size, LEAF* const leaf)
-{
-    tTable_initToPool(cy, waveTable, size, &leaf->mempool);
-}
-
-void    tTable_initToPool(tTable* const cy, float* waveTable, int size, tMempool* const mp)
-{
-    _tMempool* m = *mp;
-    _tTable* c = *cy = (_tTable*)mpool_alloc(sizeof(_tTable), m);
-    c->mempool = m;
-    
-    c->waveTable = waveTable;
-    c->size = size;
-    c->inc = 0.0f;
-    c->phase = 0.0f;
-}
-
-void    tTable_free(tTable* const cy)
-{
-    _tTable* c = *cy;
-    
-    mpool_free((char*)c, c->mempool);
-}
-
-void     tTable_setFreq(tTable* const cy, float freq)
-{
-    _tTable* c = *cy;
-    LEAF* leaf = c->mempool->leaf;
-    
-    if (!isfinite(freq)) return;
-    
-    c->freq = freq;
-    c->inc = freq * leaf->invSampleRate;
-    c->inc -= (int)c->inc;
-}
-
-float   tTable_tick(tTable* const cy)
-{
-    _tTable* c = *cy;
-    float temp;
-    int intPart;
-    float fracPart;
-    float samp0;
-    float samp1;
-    
-    // Phasor increment
-    c->phase += c->inc;
-    if (c->phase >= 1.0f) c->phase -= 1.0f;
-    if (c->phase < 0.0f) c->phase += 1.0f;
-    
-    // Wavetable synthesis
-    
-    temp = c->size * c->phase;
-    intPart = (int)temp;
-    fracPart = temp - (float)intPart;
-    samp0 = c->waveTable[intPart];
-    if (++intPart >= c->size) intPart = 0;
-    samp1 = c->waveTable[intPart];
-    
-    return (samp0 + (samp1 - samp0) * fracPart);
-}
-
-void     tTableSampleRateChanged(tTable* const cy)
-{
-    _tTable* c = *cy;
-    LEAF* leaf = c->mempool->leaf;
-    
-    c->inc = c->freq * leaf->invSampleRate;
-    c->inc -= (int)c->inc;
-}
-
-void tWavetable_init(tWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
-{
-    tWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
-}
-
-void tWavetable_initToPool(tWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
-{
-    _tMempool* m = *mp;
-    _tWavetable* c = *cy = (_tWavetable*) mpool_alloc(sizeof(_tWavetable), m);
-    c->mempool = m;
-    
-    // Determine base frequency
-    c->baseFreq = m->leaf->sampleRate / (float) size;
-    c->invBaseFreq = 1.0f / c->baseFreq;
-    
-    // Determine how many tables we need
-    // Assume we need at least 2, the fundamental + one to account for setting extra anti aliasing
-    c->numTables = 2;
-    float f = c->baseFreq;
-    while (f < maxFreq)
-    {
-        c->numTables++;
-        f *= 2.0f; // pass this multiplier in to set spacing of tables? would need to change setFreq too
-    }
-    
-    c->size = size;
-
-    // Allocate memory for the tables
-    c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, m);
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->size, m);
-    }
-    
-    // Copy table
-    for (int i = 0; i < c->size; ++i)
-    {
-        c->tables[0][i] = table[i];
-    }
-    
-    // Make bandlimited copies
-    f = m->leaf->sampleRate * 0.25; //start at half nyquist
-    // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
-    tButterworth_initToPool(&c->bl, 8, -1.0f, f, mp);
-    for (int t = 1; t < c->numTables; ++t)
-    {
-        tButterworth_setF2(&c->bl, f);
-        // Do several passes here to prevent errors at the beginning of the waveform
-        // Not sure how many passes to do, seem to need more as the filter cutoff goes down
-        // 12 might be excessive but seems to work for now.
-        for (int p = 0; p < 12; ++p)
-        {
-            for (int i = 0; i < c->size; ++i)
-            {
-                c->tables[t][i] = tButterworth_tick(&c->bl, c->tables[t-1][i]);
-            }
-        }
-        f *= 0.5f; //halve the cutoff for next pass
-    }
-    tButterworth_free(&c->bl);
-
-
-    c->inc = 0.0f;
-    c->phase = 0.0f;
-    c->aa = 0.5f;
-    
-    tWavetable_setFreq(cy, 220);
-}
-
-void tWavetable_free(tWavetable* const cy)
-{
-    _tWavetable* c = *cy;
-    
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        mpool_free((char*)c->tables[t], c->mempool);
-    }
-    mpool_free((char*)c->tables, c->mempool);
-    mpool_free((char*)c, c->mempool);
-}
-
-float tWavetable_tick(tWavetable* const cy)
-{
-    _tWavetable* c = *cy;
-    
-    float temp;
-    int idx;
-    float frac;
-    float samp0;
-    float samp1;
-    
-    // Phasor increment
-    c->phase += c->inc;
-    if (c->phase >= 1.0f) c->phase -= 1.0f;
-    if (c->phase < 0.0f) c->phase += 1.0f;
-    
-    // Wavetable synthesis
-    temp = c->size * c->phase;
-    
-    idx = (int)temp;
-    frac = temp - (float)idx;
-    samp0 = c->tables[c->oct][idx];
-    if (++idx >= c->size) idx = 0;
-    samp1 = c->tables[c->oct][idx];
-    
-    float oct0 = (samp0 + (samp1 - samp0) * frac);
-    
-    idx = (int)temp;
-    samp0 = c->tables[c->oct+1][idx];
-    if (++idx >= c->size) idx = 0;
-    samp1 = c->tables[c->oct+1][idx];
-    
-    float oct1 = (samp0 + (samp1 - samp0) * frac);
-    
-    return oct0 + (oct1 - oct0) * c->w;
-}
-
-void tWavetable_setFreq(tWavetable* const cy, float freq)
-{
-    _tWavetable* c = *cy;
-    
-    LEAF* leaf = c->mempool->leaf;
-    
-    c->freq  = freq;
-    
-    c->inc = c->freq * leaf->invSampleRate;
-    c->inc -= (int)c->inc;
-    
-    // abs for negative frequencies
-    c->w = fabsf(c->freq * c->invBaseFreq);
-    
-    // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
-    c->w = log2f_approx(c->w) + c->aa; // adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
-    if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
-    c->oct = (int)c->w;
-    c->w -= c->oct;
-    
-    // When out of range of our tables, this will prevent a crash.
-    // Also causes a blip but fine since we're above maxFreq at this point.
-    if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
-}
-
-void tWavetable_setAntiAliasing(tWavetable* const cy, float aa)
-{
-    _tWavetable* c = *cy;
-    
-    c->aa = aa;
-    tWavetable_setFreq(cy, c->freq);
-}
-
-void tCompactWavetable_init(tCompactWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
-{
-    tCompactWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
-}
-
-void tCompactWavetable_initToPool(tCompactWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
-{
-    _tMempool* m = *mp;
-    _tCompactWavetable* c = *cy = (_tCompactWavetable*) mpool_alloc(sizeof(_tCompactWavetable), m);
-    c->mempool = m;
-    
-    // Determine base frequency
-    c->baseFreq = m->leaf->sampleRate / (float) size;
-    c->invBaseFreq = 1.0f / c->baseFreq;
-    
-    // Determine how many tables we need
-    c->numTables = 2;
-    float f = c->baseFreq;
-    while (f < maxFreq)
-    {
-        c->numTables++;
-        f *= 2.0f; // pass this multiplier in to set spacing of tables?
-    }
-        
-    // Allocate memory for the tables
-    c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
-    c->sizes = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
-    int n = size;
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        c->sizes[t] = n;
-        c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->sizes[t], m);
-        n = c->sizes[t] / 2;
-    }
-    
-    // Copy table
-    for (int i = 0; i < c->sizes[0]; ++i)
-    {
-        c->tables[0][i] = table[i];
-    }
-    
-    // Make bandlimited copies
-    // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
-    tButterworth_initToPool(&c->bl, 8, -1.0f, m->leaf->sampleRate * 0.25f, mp);
-    tOversampler_initToPool(&c->ds, 2, 1, mp);
-    for (int t = 1; t < c->numTables; ++t)
-    {
-        // Similar to tWavetable, doing multiple passes here helps, but not sure what number is optimal
-        for (int p = 0; p < 12; ++p)
-        {
-            for (int i = 0; i < c->sizes[t]; ++i)
-            {
-                c->dsBuffer[0] = tButterworth_tick(&c->bl, c->tables[t-1][i*2]);
-                c->dsBuffer[1] = tButterworth_tick(&c->bl, c->tables[t-1][(i*2)+1]);
-                c->tables[t][i] = tOversampler_downsample(&c->ds, c->dsBuffer);
-            }
-        }
-    }
-    tOversampler_free(&c->ds);
-    tButterworth_free(&c->bl);
-
-    c->inc = 0.0f;
-    c->phase = 0.0f;
-    c->aa = 0.5f;
-    
-    tCompactWavetable_setFreq(cy, 220);
-}
-
-void    tCompactWavetable_free(tCompactWavetable* const cy)
-{
-    _tCompactWavetable* c = *cy;
-    
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        mpool_free((char*)c->tables[t], c->mempool);
-    }
-    mpool_free((char*)c->tables, c->mempool);
-    mpool_free((char*)c->sizes, c->mempool);
-    mpool_free((char*)c, c->mempool);
-}
-
-float   tCompactWavetable_tick(tCompactWavetable* const cy)
-{
-    _tCompactWavetable* c = *cy;
-    
-    float temp;
-    int idx;
-    float frac;
-    float samp0;
-    float samp1;
-    
-    // Phasor increment
-    c->phase += c->inc;
-    if (c->phase >= 1.0f) c->phase -= 1.0f;
-    if (c->phase < 0.0f) c->phase += 1.0f;
-    
-    // Wavetable synthesis
-    temp = c->sizes[c->oct] * c->phase;
-    idx = (int)temp;
-    frac = temp - (float)idx;
-    samp0 = c->tables[c->oct][idx];
-    if (++idx >= c->sizes[c->oct]) idx = 0;
-    samp1 = c->tables[c->oct][idx];
-    
-    float oct0 = (samp0 + (samp1 - samp0) * frac);
-    
-    temp = c->sizes[c->oct+1] * c->phase;
-    idx = (int)temp;
-    frac = temp - (float)idx;
-    samp0 = c->tables[c->oct+1][idx];
-    if (++idx >= c->sizes[c->oct+1]) idx = 0;
-    samp1 = c->tables[c->oct+1][idx];
-    
-    float oct1 = (samp0 + (samp1 - samp0) * frac);
-    
-    return oct0 + (oct1 - oct0) * c->w;
-}
-
-void    tCompactWavetable_setFreq(tCompactWavetable* const cy, float freq)
-{
-    _tCompactWavetable* c = *cy;
-    
-    LEAF* leaf = c->mempool->leaf;
-    
-    c->freq  = freq;
-    
-    c->inc = c->freq * leaf->invSampleRate;
-    c->inc -= (int)c->inc;
-    
-    // abs for negative frequencies
-    c->w = fabsf(c->freq * c->invBaseFreq);
-    
-    // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
-    c->w = log2f_approx(c->w) + c->aa;//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
-    if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
-    c->oct = (int)c->w;
-    c->w -= c->oct;
-    if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
-}
-
-void tCompactWavetable_setAntiAliasing(tCompactWavetable* const cy, float aa)
-{
-    _tCompactWavetable* c = *cy;
-    
-    c->aa = aa;
-    tCompactWavetable_setFreq(cy, c->freq);
-}
-
 #if LEAF_INCLUDE_SINE_TABLE
 // Cycle
 void    tCycle_init(tCycle* const cy, LEAF* const leaf)
@@ -1999,4 +1629,469 @@
 {
     _tMBSaw* c = *osc;
     c->softsync = hardOrSoft > 0 ? 1 : 0;
+}
+
+
+// WaveTable
+void    tTable_init(tTable* const cy, float* waveTable, int size, LEAF* const leaf)
+{
+    tTable_initToPool(cy, waveTable, size, &leaf->mempool);
+}
+
+void    tTable_initToPool(tTable* const cy, float* waveTable, int size, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tTable* c = *cy = (_tTable*)mpool_alloc(sizeof(_tTable), m);
+    c->mempool = m;
+    
+    c->waveTable = waveTable;
+    c->size = size;
+    c->inc = 0.0f;
+    c->phase = 0.0f;
+}
+
+void    tTable_free(tTable* const cy)
+{
+    _tTable* c = *cy;
+    
+    mpool_free((char*)c, c->mempool);
+}
+
+void     tTable_setFreq(tTable* const cy, float freq)
+{
+    _tTable* c = *cy;
+    LEAF* leaf = c->mempool->leaf;
+    
+    if (!isfinite(freq)) return;
+    
+    c->freq = freq;
+    c->inc = freq * leaf->invSampleRate;
+    c->inc -= (int)c->inc;
+}
+
+float   tTable_tick(tTable* const cy)
+{
+    _tTable* c = *cy;
+    float temp;
+    int intPart;
+    float fracPart;
+    float samp0;
+    float samp1;
+    
+    // Phasor increment
+    c->phase += c->inc;
+    if (c->phase >= 1.0f) c->phase -= 1.0f;
+    if (c->phase < 0.0f) c->phase += 1.0f;
+    
+    // Wavetable synthesis
+    
+    temp = c->size * c->phase;
+    intPart = (int)temp;
+    fracPart = temp - (float)intPart;
+    samp0 = c->waveTable[intPart];
+    if (++intPart >= c->size) intPart = 0;
+    samp1 = c->waveTable[intPart];
+    
+    return (samp0 + (samp1 - samp0) * fracPart);
+}
+
+void     tTableSampleRateChanged(tTable* const cy)
+{
+    _tTable* c = *cy;
+    LEAF* leaf = c->mempool->leaf;
+    
+    c->inc = c->freq * leaf->invSampleRate;
+    c->inc -= (int)c->inc;
+}
+
+void tWavetable_init(tWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
+{
+    tWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
+}
+
+void tWavetable_initToPool(tWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tWavetable* c = *cy = (_tWavetable*) mpool_alloc(sizeof(_tWavetable), m);
+    c->mempool = m;
+    
+    // Determine base frequency
+    c->baseFreq = m->leaf->sampleRate / (float) size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    
+    // Determine how many tables we need
+    // Assume we need at least 2, the fundamental + one to account for setting extra anti aliasing
+    c->numTables = 2;
+    float f = c->baseFreq;
+    while (f < maxFreq)
+    {
+        c->numTables++;
+        f *= 2.0f; // pass this multiplier in to set spacing of tables? would need to change setFreq too
+    }
+    
+    c->size = size;
+    
+    // Allocate memory for the tables
+    c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, m);
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->size, m);
+    }
+    
+    // Copy table
+    for (int i = 0; i < c->size; ++i)
+    {
+        c->tables[0][i] = table[i];
+    }
+    
+    // Make bandlimited copies
+    f = m->leaf->sampleRate * 0.25; //start at half nyquist
+    // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
+    tButterworth_initToPool(&c->bl, 8, -1.0f, f, mp);
+    for (int t = 1; t < c->numTables; ++t)
+    {
+        tButterworth_setF2(&c->bl, f);
+        // Do several passes here to prevent errors at the beginning of the waveform
+        // Not sure how many passes to do, seem to need more as the filter cutoff goes down
+        // 12 might be excessive but seems to work for now.
+        for (int p = 0; p < 12; ++p)
+        {
+            for (int i = 0; i < c->size; ++i)
+            {
+                c->tables[t][i] = tButterworth_tick(&c->bl, c->tables[t-1][i]);
+            }
+        }
+        f *= 0.5f; //halve the cutoff for next pass
+    }
+    tButterworth_free(&c->bl);
+    
+    
+    c->inc = 0.0f;
+    c->phase = 0.0f;
+    c->aa = 0.5f;
+    
+    tWavetable_setFreq(cy, 220);
+}
+
+void tWavetable_free(tWavetable* const cy)
+{
+    _tWavetable* c = *cy;
+    
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        mpool_free((char*)c->tables[t], c->mempool);
+    }
+    mpool_free((char*)c->tables, c->mempool);
+    mpool_free((char*)c, c->mempool);
+}
+
+float tWavetable_tick(tWavetable* const cy)
+{
+    _tWavetable* c = *cy;
+    
+    float temp;
+    int idx;
+    float frac;
+    float samp0;
+    float samp1;
+    
+    // Phasor increment
+    c->phase += c->inc;
+    if (c->phase >= 1.0f) c->phase -= 1.0f;
+    if (c->phase < 0.0f) c->phase += 1.0f;
+    
+    // Wavetable synthesis
+    temp = c->size * c->phase;
+    
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = c->tables[c->oct][idx];
+    if (++idx >= c->size) idx = 0;
+    samp1 = c->tables[c->oct][idx];
+    
+    float oct0 = (samp0 + (samp1 - samp0) * frac);
+    
+    idx = (int)temp;
+    samp0 = c->tables[c->oct+1][idx];
+    if (++idx >= c->size) idx = 0;
+    samp1 = c->tables[c->oct+1][idx];
+    
+    float oct1 = (samp0 + (samp1 - samp0) * frac);
+    
+    return oct0 + (oct1 - oct0) * c->w;
+}
+
+void tWavetable_setFreq(tWavetable* const cy, float freq)
+{
+    _tWavetable* c = *cy;
+    
+    LEAF* leaf = c->mempool->leaf;
+    
+    c->freq  = freq;
+    
+    c->inc = c->freq * leaf->invSampleRate;
+    c->inc -= (int)c->inc;
+    
+    // abs for negative frequencies
+    c->w = fabsf(c->freq * c->invBaseFreq);
+    
+    // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
+    c->w = log2f_approx(c->w) + c->aa; // adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
+    if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
+    c->oct = (int)c->w;
+    c->w -= c->oct;
+    
+    // When out of range of our tables, this will prevent a crash.
+    // Also causes a blip but fine since we're above maxFreq at this point.
+    if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
+}
+
+void tWavetable_setAntiAliasing(tWavetable* const cy, float aa)
+{
+    _tWavetable* c = *cy;
+    
+    c->aa = aa;
+    tWavetable_setFreq(cy, c->freq);
+}
+
+
+
+void tCompactWavetable_init(tCompactWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
+{
+    tCompactWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
+}
+
+void tCompactWavetable_initToPool(tCompactWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tCompactWavetable* c = *cy = (_tCompactWavetable*) mpool_alloc(sizeof(_tCompactWavetable), m);
+    c->mempool = m;
+    
+    // Determine base frequency
+    c->baseFreq = m->leaf->sampleRate / (float) size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    
+    // Determine how many tables we need
+    c->numTables = 2;
+    float f = c->baseFreq;
+    while (f < maxFreq)
+    {
+        c->numTables++;
+        f *= 2.0f; // pass this multiplier in to set spacing of tables?
+    }
+    
+    // Allocate memory for the tables
+    c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
+    c->sizes = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
+    int n = size;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        c->sizes[t] = n;
+        c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->sizes[t], m);
+        n = c->sizes[t] / 2;
+    }
+    
+    // Copy table
+    for (int i = 0; i < c->sizes[0]; ++i)
+    {
+        c->tables[0][i] = table[i];
+    }
+    
+    // Make bandlimited copies
+    // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
+    tButterworth_initToPool(&c->bl, 8, -1.0f, m->leaf->sampleRate * 0.25f, mp);
+    tOversampler_initToPool(&c->ds, 2, 1, mp);
+    for (int t = 1; t < c->numTables; ++t)
+    {
+        // Similar to tWavetable, doing multiple passes here helps, but not sure what number is optimal
+        for (int p = 0; p < 12; ++p)
+        {
+            for (int i = 0; i < c->sizes[t]; ++i)
+            {
+                c->dsBuffer[0] = tButterworth_tick(&c->bl, c->tables[t-1][i*2]);
+                c->dsBuffer[1] = tButterworth_tick(&c->bl, c->tables[t-1][(i*2)+1]);
+                c->tables[t][i] = tOversampler_downsample(&c->ds, c->dsBuffer);
+            }
+        }
+    }
+    tOversampler_free(&c->ds);
+    tButterworth_free(&c->bl);
+    
+    c->inc = 0.0f;
+    c->phase = 0.0f;
+    c->aa = 0.5f;
+    
+    tCompactWavetable_setFreq(cy, 220);
+}
+
+void    tCompactWavetable_free(tCompactWavetable* const cy)
+{
+    _tCompactWavetable* c = *cy;
+    
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        mpool_free((char*)c->tables[t], c->mempool);
+    }
+    mpool_free((char*)c->tables, c->mempool);
+    mpool_free((char*)c->sizes, c->mempool);
+    mpool_free((char*)c, c->mempool);
+}
+
+float   tCompactWavetable_tick(tCompactWavetable* const cy)
+{
+    _tCompactWavetable* c = *cy;
+    
+    float temp;
+    int idx;
+    float frac;
+    float samp0;
+    float samp1;
+    
+    // Phasor increment
+    c->phase += c->inc;
+    if (c->phase >= 1.0f) c->phase -= 1.0f;
+    if (c->phase < 0.0f) c->phase += 1.0f;
+    
+    // Wavetable synthesis
+    temp = c->sizes[c->oct] * c->phase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = c->tables[c->oct][idx];
+    if (++idx >= c->sizes[c->oct]) idx = 0;
+    samp1 = c->tables[c->oct][idx];
+    
+    float oct0 = (samp0 + (samp1 - samp0) * frac);
+    
+    temp = c->sizes[c->oct+1] * c->phase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = c->tables[c->oct+1][idx];
+    if (++idx >= c->sizes[c->oct+1]) idx = 0;
+    samp1 = c->tables[c->oct+1][idx];
+    
+    float oct1 = (samp0 + (samp1 - samp0) * frac);
+    
+    return oct0 + (oct1 - oct0) * c->w;
+}
+
+void    tCompactWavetable_setFreq(tCompactWavetable* const cy, float freq)
+{
+    _tCompactWavetable* c = *cy;
+    
+    LEAF* leaf = c->mempool->leaf;
+    
+    c->freq  = freq;
+    
+    c->inc = c->freq * leaf->invSampleRate;
+    c->inc -= (int)c->inc;
+    
+    // abs for negative frequencies
+    c->w = fabsf(c->freq * c->invBaseFreq);
+    
+    // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
+    c->w = log2f_approx(c->w) + c->aa;//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
+    if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
+    c->oct = (int)c->w;
+    c->w -= c->oct;
+    if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
+}
+
+void tCompactWavetable_setAntiAliasing(tCompactWavetable* const cy, float aa)
+{
+    _tCompactWavetable* c = *cy;
+    
+    c->aa = aa;
+    tCompactWavetable_setFreq(cy, c->freq);
+}
+
+//================================================================================================
+//================================================================================================
+
+void    tWaveset_init(tWaveset* const cy, const float** tables, int n, int size, float maxFreq, LEAF* const leaf)
+{
+    tWaveset_initToPool(cy, tables, n, size, maxFreq, &leaf->mempool);
+}
+
+void    tWaveset_initToPool(tWaveset* const cy, const float** tables, int n, int size, float maxFreq, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tWaveset* c = *cy = (_tWaveset*) mpool_alloc(sizeof(_tWaveset), m);
+    c->mempool = m;
+    
+    c->n = n;
+    
+    c->g = (float*) mpool_alloc(sizeof(tWavetable) * c->n, m);
+    c->wt = (tWavetable*) mpool_alloc(sizeof(tWavetable) * c->n, m);
+    for (int i = 0; i < c->n; ++i)
+    {
+        c->g[i] = 1.0f;
+        tWavetable_initToPool(&c->wt[i], tables[i], size, maxFreq, mp);
+    }
+    
+    c->index = 0.0f;
+}
+
+void    tWaveset_free(tWaveset* const cy)
+{
+    _tWaveset* c = *cy;
+    
+    for (int i = 0; i < c->n; ++i)
+    {
+        tWavetable_free(&c->wt[i]);
+    }
+    mpool_free((char*)c->wt, c->mempool);
+    mpool_free((char*)c, c->mempool);
+}
+
+float   tWaveset_tick(tWaveset* const cy)
+{
+    _tWaveset* c = *cy;
+    
+    float p = c->index * (c->n - 1);
+    
+    int o1 = (int)p;
+    int o2 = o1 + 1;
+    if (c->index >= 1.0f) o2 = o1;
+    float mix = p - o1;
+    
+    float s0, s1, s2;
+    for (int i = 0; i < c->n; ++i)
+    {
+        s0 = tWavetable_tick(&c->wt[i]) * c->g[i];
+        if (i == o1) s1 = s0;
+        if (i == o2) s2 = s0;
+    }
+    
+    // Ideally should determine correlation to get a good equal power fade between tables
+    return s1 + (s2 - s1) * mix;
+}
+
+void    tWaveset_setFreq(tWaveset* const cy, float freq)
+{
+    _tWaveset* c = *cy;
+    for (int i = 0; i < c->n; ++i)
+    {
+        tWavetable_setFreq(&c->wt[i], freq);
+    }
+}
+
+void    tWaveset_setAntiAliasing(tWaveset* const cy, float aa)
+{
+    _tWaveset* c = *cy;
+    for (int i = 0; i < c->n; ++i)
+    {
+        tWavetable_setAntiAliasing(&c->wt[i], aa);
+    }
+}
+
+void    tWaveset_setIndex(tWaveset* const cy, float index)
+{
+    _tWaveset* c = *cy;
+    c->index = index;
+}
+
+void    tWaveset_setIndexGain(tWaveset* const cy, int i, float gain)
+{
+    _tWaveset* c = *cy;
+    c->g[i] = gain;
 }