shithub: leaf

Download patch

ref: 23656d71aa2efc07bc509af95d3ecc18542a7ec5
parent: 6da3c6430ec4b9e8998dc385c484e9bca9523120
author: Matthew Wang <mjw7@princeton.edu>
date: Thu Jan 28 09:48:42 EST 2021

split Wavetable into WaveTable and WaveOsc; rework Waveset into WaveSynth

--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -31,15 +31,15 @@
 tNoise noise;
 tButterworth bw;
 
-tWavetable wt;
-tCompactWavetable cwt;
-tWaveset ws;
+tWaveTable wt;
+tCompactWaveTable cwt;
+tWaveSynth ws;
 
 tBuffer samp;
 tMBSampler sampler;
 
 const int numWavetables = 1;
-tWavetable wavetables[numWavetables];
+tWaveTable wavetables[numWavetables];
 
 float gain;
 float dtime;
@@ -63,8 +63,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);
@@ -77,15 +77,14 @@
     tPhasor_setFreq(&phasor, 220.f);
     
     float* 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];
+    set[0] = (float*)__leaf_table_sinewave;
+    set[1] = (float*)__leaf_table_triangle[0];
+    set[2] = (float*)__leaf_table_squarewave[0];
+    set[3] = (float*)__leaf_table_sawtooth[0];
     int sizes[4];
     for (int i = 0; i < 4; i++) sizes[i] = 2048;
     
-    tWaveset_init(&ws, set, 4, sizes, 10000.f, &leaf);
-    tWaveset_setIndexGain(&ws, 0, -1.0f);
+    tWaveSynth_init(&ws, 1, set, sizes, 4, 10000.f, &leaf);
     
     lastLoadedAudioSize = 0;
     loadedAudio.clear();
@@ -105,7 +104,7 @@
     float out = 0.0f;
     for (int i = 0; i < fmin(loadedAudio.size(), numWavetables); ++i)
     {
-        out += tWavetable_tick(&wavetables[i]);
+//        out += tWaveTable_tick(&wavetables[i]);
     }
     return out;
 }
@@ -118,14 +117,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.);
-    tWaveset_setFreq(&ws, val * 10000.f);
+//    tWaveTable_setFreq(&wt, val * 160000.f - 80000.0f);
+//    tCompactWaveTable_setFreq(&cwt, val * 10000.);
+    tWaveSynth_setFreq(&ws, 0, val * 10000.f);
 //    tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
 //    tSimpleRetune_tuneVoice(&sretune, 0, 300);
 
     val = getSliderValue("slider2");
-    tWaveset_setIndex(&ws, val);
+    tWaveSynth_setIndex(&ws, val);
 //    tRetune_setPitchFactor(&retune, val * 3.0f + 0.5f, 1);
     
     val = getSliderValue("slider3");
@@ -134,12 +133,12 @@
     if (lastLoadedAudioSize < loadedAudio.size())
     {
         int i = (loadedAudio.size() - 1) % numWavetables;
-        if (loadedAudio.size() - 1 >= numWavetables) tWavetable_free(&wavetables[i]);
-        tWavetable_init(&wavetables[i], loadedAudio[loadedAudio.size() - 1].getReadPointer(0), loadedAudio[loadedAudio.size() - 1].getNumSamples(), 20000, &leaf);
+        if (loadedAudio.size() - 1 >= numWavetables) tWaveTable_free(&wavetables[i]);
+        tWaveTable_init(&wavetables[i], (float*)loadedAudio[loadedAudio.size() - 1].getReadPointer(0), loadedAudio[loadedAudio.size() - 1].getNumSamples(), 20000, &leaf);
         
         lastLoadedAudioSize = loadedAudio.size();
     }
-    if (loadedAudio.size() > 0) tWavetable_setFreq(&wavetables[0], 220);//val * 10000.f);
+//    if (loadedAudio.size() > 0) tWaveTable_setFreq(&wavetables[0], 220);//val * 10000.f);
 }
 
 void    LEAFTest_controllerInput (int cnum, float cval)
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -922,44 +922,34 @@
     //==============================================================================
     
     /*!
-     @defgroup twavetable tWavetable
+     @defgroup twavetable tWaveTable
      @ingroup oscillators
-     @brief Anti-aliased wavetable oscillator.
+     @brief Anti-aliased wavetable generator.
      @{
      
-     @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.
+     @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.
+     @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 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
+    typedef struct _tWaveTable
     {
         tMempool mempool;
         
@@ -967,6 +957,41 @@
         int size;
         int numTables;
         float baseFreq, invBaseFreq;
+        tButterworth bl;
+    } _tWaveTable;
+    
+    typedef _tWaveTable* tWaveTable;
+    
+    void    tWaveTable_init(tWaveTable* const osc, float* table, int size,
+                            float maxFreq, LEAF* const leaf);
+    void    tWaveTable_initToPool(tWaveTable* const osc, float* table, int size,
+                                  float maxFreq, tMempool* const mempool);
+    void    tWaveTable_free(tWaveTable* const osc);
+   
+    //==============================================================================
+    
+    /*!
+     @defgroup twavetableosc tWaveOsc
+     @ingroup oscillators
+     @brief Anti-aliased wavetable oscillator.
+     @{
+     
+     @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 _tWaveOsc
+    {
+        tMempool mempool;
+        tWaveTable table;
         float inc, freq;
         float phase;
         float phaseOffset;
@@ -974,103 +999,216 @@
         int oct;
         float w;
         float aa;
-        
-        tButterworth bl;
-    } _tWavetable;
+    } _tWaveOsc;
     
-    typedef _tWavetable* tWavetable;
+    typedef _tWaveOsc* tWaveOsc;
     
-    void    tWavetable_init(tWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf);
-    void    tWavetable_initToPool(tWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool);
-    void    tWavetable_free(tWavetable* const osc);
+    void    tWaveOsc_init(tWaveOsc* const osc, tWaveTable* const table, LEAF* const leaf);
+    void    tWaveOsc_initToPool(tWaveOsc* const osc, tWaveTable* const table, tMempool* const mempool);
+    void    tWaveOsc_free(tWaveOsc* const osc);
     
-    float   tWavetable_tick(tWavetable* const osc);
-    void    tWavetable_setFreq(tWavetable* const osc, float freq);
-    void    tWavetable_setAntiAliasing(tWavetable* const osc, float aa);
-    void    tWavetable_setPhaseOffset(tWavetable* const osc, float phase);
+    float   tWaveOsc_tick(tWaveOsc* const osc);
+    void    tWaveOsc_setFreq(tWaveOsc* const osc, float freq);
+    void    tWaveOsc_setAntiAliasing(tWaveOsc* const osc, float aa);
+    void    tWaveOsc_setPhaseOffset(tWaveOsc* const osc, float phase);
     
     //==============================================================================
     
     /*!
-     @defgroup tcompactwavetable tCompactWavetable
+     @defgroup twaveset tWaveSynth
      @ingroup oscillators
-     @brief A more space-efficient anti-aliased wavetable oscillator than tWavetable but with slightly worse fidelity.
+     @brief Set of anti-aliased wavetable oscillators that can be faded between.
      @{
      
-     @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.
+     @fn void    tWaveSynth_init(tWaveSynth* const osc, const float** tables, int n, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tWaveSynth to the default mempool of a LEAF instance.
+     @param osc A pointer to the tWaveSynth 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    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.
+     @fn void  tWaveSynth_initToPool(tWaveSynth* const osc, const float** tables, int n, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tWaveSynth 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    tCompactWavetable_free         (tCompactWavetable* const osc)
-     @brief Free a tCompactWavetable from its mempool.
-     @param osc A pointer to the tCompactWavetable to free.
+     @fn void    tWaveSynth_free         (tWaveSynth* const osc)
+     @brief Free a tWaveSynth from its mempool.
+     @param osc A pointer to the tWaveSynth to free.
      
-     @fn float   tCompactWavetable_tick         (tCompactWavetable* const osc)
-     @brief Tick a tCompactWavetable oscillator.
-     @param osc A pointer to the relevant tCompactWavetable.
+     @fn float   tWaveSynth_tick         (tWaveSynth* const osc)
+     @brief Tick a tWaveSynth oscillator.
+     @param osc A pointer to the relevant tWaveSynth.
      @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.
+     @fn void    tWaveSynth_setFreq      (tWaveSynth* const osc, float freq)
+     @brief Set the frequency of a tWaveSynth oscillator.
+     @param osc A pointer to the relevant tWaveSynth.
      @param freq The frequency to set the oscillator to.
      
+     @fn void    tWaveSynth_setIndex(tWaveSynth* 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 _tCompactWavetable
+    typedef struct _tWaveSynth
     {
         tMempool mempool;
         
+        tWaveTable* tables;
+        tWaveOsc** oscs;
+        int numTables;
+        int numVoices;
+        float* g;
+        float index;
+        float maxFreq;
+    } _tWaveSynth;
+    
+    typedef _tWaveSynth* tWaveSynth;
+    
+    void    tWaveSynth_init(tWaveSynth* const osc, int numVoices, float** tables, int* sizes,
+                            int numTables, float maxFreq, LEAF* const leaf);
+    void    tWaveSynth_initToPool(tWaveSynth* const osc, int numVoices, float** tables, int* sizes,
+                                  int numTables, float maxFreq, tMempool* const mempool);
+    void    tWaveSynth_free(tWaveSynth* const osc);
+    
+    float   tWaveSynth_tick(tWaveSynth* const osc);
+    float   tWaveSynth_tickVoice(tWaveSynth* const cy, int voice);
+    void    tWaveSynth_setFreq(tWaveSynth* const osc, int voice, float freq);
+    void    tWaveSynth_setAntiAliasing(tWaveSynth* const osc, float aa);
+    void    tWaveSynth_setIndex(tWaveSynth* const osc, float index);
+    void    tWaveSynth_setIndexGain(tWaveSynth* const osc, int i, float gain);
+    void    tWaveSynth_setIndexPhase(tWaveSynth* const osc, int i, float phase);
+//    void    tWaveSynth_setIndexTable(tWaveSynth* const osc, int i, float* table, int size);
+
+    //==============================================================================
+    
+    /*!
+     @defgroup tcompactwavetable tCompactWaveTable
+     @ingroup oscillators
+     @brief A more space-efficient anti-aliased wavetable generator 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.
+     
+     @} */
+    
+    typedef struct _tCompactWaveTable
+    {
+        tMempool mempool;
+        
         float** tables;
         int numTables;
         int* sizes;
         float baseFreq, invBaseFreq;
+        tButterworth bl;
+        float dsBuffer[2];
+        tOversampler ds;
+    } _tCompactWaveTable;
+    
+    typedef _tCompactWaveTable* tCompactWaveTable;
+    
+    void    tCompactWaveTable_init(tCompactWaveTable* const osc, float* table, int size, float maxFreq, LEAF* const leaf);
+    void    tCompactWaveTable_initToPool(tCompactWaveTable* const osc, float* table, int size, float maxFreq, tMempool* const mempool);
+    void    tCompactWaveTable_free(tCompactWaveTable* const osc);
+    
+    /*!
+     @defgroup tcompactwaveosc tCompactWaveOsc
+     @ingroup oscillators
+     @brief A more space-efficient anti-aliased wavetable oscillator than tWaveOsc but with slightly worse fidelity.
+     @{
+     
+     @fn void   tCompactWaveOsc_init  (tCompactWaveOsc* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tCompactWaveOsc to the default mempool of a LEAF instance.
+     @param osc A pointer to the tCompactWaveOsc 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   tCompactWaveOsc_initToPool   (tCompactWaveOsc* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tCompactWaveOsc to a specified mempool.
+     @param osc A pointer to the tCompactWaveOsc 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   tCompactWaveOsc_free         (tCompactWaveOsc* const osc)
+     @brief Free a tCompactWaveOsc from its mempool.
+     @param osc A pointer to the tCompactWaveOsc to free.
+     
+     @fn float  tCompactWaveOsc_tick         (tCompactWaveOsc* const osc)
+     @brief Tick a tCompactWaveOsc oscillator.
+     @param osc A pointer to the relevant tCompactWaveOsc.
+     @return The ticked sample as a float from -1 to 1.
+     
+     @fn void   tCompactWaveOsc_setFreq      (tCompactWaveOsc* const osc, float freq)
+     @brief Set the frequency of a tCompactWaveOsc oscillator.
+     @param osc A pointer to the relevant tCompactWaveOsc.
+     @param freq The frequency to set the oscillator to.
+     
+     @} */
+    
+    typedef struct _tCompactWaveOsc
+    {
+        tMempool mempool;
+        tCompactWaveTable table;
         float inc, freq;
         float phase;
-        
+        float phaseOffset;
         int oct;
         float w;
         float aa;
-        
-        tButterworth bl;
-        
-        float dsBuffer[2];
-        tOversampler ds;
-    } _tCompactWavetable;
+    } _tCompactWaveOsc;
     
-    typedef _tCompactWavetable* tCompactWavetable;
+    typedef _tCompactWaveOsc* tCompactWaveOsc;
     
-    void    tCompactWavetable_init(tCompactWavetable* const osc, float* table, int size, float maxFreq, LEAF* const leaf);
-    void    tCompactWavetable_initToPool(tCompactWavetable* const osc, float* table, int size, float maxFreq, tMempool* const mempool);
-    void    tCompactWavetable_free(tCompactWavetable* const osc);
+    void    tCompactWaveOsc_init(tCompactWaveOsc* const osc, tCompactWaveTable* const table, LEAF* const leaf);
+    void    tCompactWaveOsc_initToPool(tCompactWaveOsc* const osc, tCompactWaveTable* const table, tMempool* const mempool);
+    void    tCompactWaveOsc_free(tCompactWaveOsc* const osc);
     
-    float   tCompactWavetable_tick(tCompactWavetable* const osc);
-    void    tCompactWavetable_setFreq(tCompactWavetable* const osc, float freq);
-    void    tCompactWavetable_setAntiAliasing(tCompactWavetable* const osc, float aa);
+    float   tCompactWaveOsc_tick(tCompactWaveOsc* const osc);
+    void    tCompactWaveOsc_setFreq(tCompactWaveOsc* const osc, float freq);
+    void    tCompactWaveOsc_setAntiAliasing(tCompactWaveOsc* const osc, float aa);
+    void    tCompactWaveOsc_setPhaseOffset(tCompactWaveOsc* const osc, float phase);
     
     //==============================================================================
     
     /*!
-     @defgroup twaveset tWaveset
+     @defgroup tCompactWaveset tCompactWaveSynth
      @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.
+     @fn void    tCompactWaveSynth_init(tWaveSynth* const osc, const float** tables, int n, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tCompactWaveSynth to the default mempool of a LEAF instance.
+     @param osc A pointer to the tCompactWaveSynth 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.
@@ -1077,9 +1215,9 @@
      @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.
+     @fn void  tCompactWaveSynth_initToPool(tWaveSynth* const osc, const float** tables, int n, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tCompactWaveSynth to a specified mempool.
+     @param osc A pointer to the tCompactWaveTable 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.
@@ -1086,50 +1224,55 @@
      @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 void    tCompactWaveSynth_free         (tWaveSynth* const osc)
+     @brief Free a tCompactWaveSynth from its mempool.
+     @param osc A pointer to the tCompactWaveSynth to free.
      
-     @fn float   tWaveset_tick         (tWaveset* const osc)
-     @brief Tick a tWaveset oscillator.
-     @param osc A pointer to the relevant tWaveset.
+     @fn float   tCompactWaveSynth_tick         (tWaveSynth* const osc)
+     @brief Tick a tCompactWaveSynth oscillator.
+     @param osc A pointer to the relevant tCompactWaveSynth.
      @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.
+     @fn void    tCompactWaveSynth_setFreq      (tWaveSynth* const osc, float freq)
+     @brief Set the frequency of a tCompactWaveSynth oscillator.
+     @param osc A pointer to the relevant tCompactWaveSynth.
      @param freq The frequency to set the oscillator to.
      
-     @fn void    tWaveset_setIndex(tWaveset* const osc, float index)
+     @fn void    tCompactWaveSynth_setIndex(tWaveSynth* 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
+    typedef struct _tCompactWaveSynth
     {
         tMempool mempool;
         
-        tWavetable* wt;
-        int n;
+        tCompactWaveTable* tables;
+        tCompactWaveOsc** oscs;
+        int numTables;
+        int numVoices;
         float* g;
-        float* p;
         float index;
-    } _tWaveset;
+        float maxFreq;
+    } _tCompactWaveSynth;
     
-    typedef _tWaveset* tWaveset;
+    typedef _tCompactWaveSynth* tCompactWaveSynth;
     
-    void    tWaveset_init(tWaveset* const osc, float** tables, int n, int* sizes, float maxFreq, LEAF* const leaf);
-    void    tWaveset_initToPool(tWaveset* const osc, float** tables, int n, int* sizes, float maxFreq, tMempool* const mempool);
-    void    tWaveset_free(tWaveset* const osc);
+    void    tCompactWaveSynth_init(tCompactWaveSynth* const osc, int numVoices, float** tables, int* sizes,
+                                   int numTables, float maxFreq, LEAF* const leaf);
+    void    tCompactWaveSynth_initToPool(tCompactWaveSynth* const osc, int numVoices, float** tables, int* sizes,
+                                         int numTables, float maxFreq, tMempool* const mempool);
+    void    tCompactWaveSynth_free(tCompactWaveSynth* 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);
-    void    tWaveset_setIndexPhase(tWaveset* const osc, int i, float phase);
-
+    float   tCompactWaveSynth_tick(tCompactWaveSynth* const osc);
+    float   tCompactWaveSynth_tickVoice(tCompactWaveSynth* const cy, int voice);
+    void    tCompactWaveSynth_setFreq(tCompactWaveSynth* const osc, int voice, float freq);
+    void    tCompactWaveSynth_setAntiAliasing(tCompactWaveSynth* const osc, float aa);
+    void    tCompactWaveSynth_setIndex(tCompactWaveSynth* const osc, float index);
+    void    tCompactWaveSynth_setIndexGain(tCompactWaveSynth* const osc, int i, float gain);
+    void    tCompactWaveSynth_setIndexPhase(tCompactWaveSynth* const osc, int i, float phase);
+//    void    tCompactWaveSynth_setIndexTable(tCompactWaveSynth* const osc, int i, float* table, int size);
     
 #ifdef __cplusplus
 }
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -1704,15 +1704,15 @@
     c->inc -= (int)c->inc;
 }
 
-void tWavetable_init(tWavetable* const cy, float* table, int size, float maxFreq, LEAF* const leaf)
+void tWaveTable_init(tWaveTable* const cy, float* table, int size, float maxFreq, LEAF* const leaf)
 {
-    tWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
+    tWaveTable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
 }
 
-void tWavetable_initToPool(tWavetable* const cy, float* table, int size, float maxFreq, tMempool* const mp)
+void tWaveTable_initToPool(tWaveTable* const cy, float* table, int size, float maxFreq, tMempool* const mp)
 {
     _tMempool* m = *mp;
-    _tWavetable* c = *cy = (_tWavetable*) mpool_alloc(sizeof(_tWavetable), m);
+    _tWaveTable* c = *cy = (_tWaveTable*) mpool_alloc(sizeof(_tWaveTable), m);
     c->mempool = m;
     
     // Determine base frequency
@@ -1764,18 +1764,11 @@
         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)
+void tWaveTable_free(tWaveTable* const cy)
 {
-    _tWavetable* c = *cy;
+    _tWaveTable* c = *cy;
     
     for (int t = 0; t < c->numTables; ++t)
     {
@@ -1785,10 +1778,40 @@
     mpool_free((char*)c, c->mempool);
 }
 
-float tWavetable_tick(tWavetable* const cy)
+//=======================================================================================
+//=======================================================================================
+
+void tWaveOsc_init(tWaveOsc* const cy, tWaveTable* const table, LEAF* const leaf)
 {
-    _tWavetable* c = *cy;
+    tWaveOsc_initToPool(cy, table, &leaf->mempool);
+}
+
+void tWaveOsc_initToPool(tWaveOsc* const cy, tWaveTable* const table, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tWaveOsc* c = *cy = (_tWaveOsc*) mpool_alloc(sizeof(_tWaveOsc), m);
+    c->mempool = m;
     
+    c->table = *table;
+
+    c->inc = 0.0f;
+    c->phase = 0.0f;
+    c->phaseOffset = 0.0f;
+    c->aa = 0.5f;
+    
+    tWaveOsc_setFreq(cy, 220);
+}
+
+void tWaveOsc_free(tWaveOsc* const cy)
+{
+    _tWaveOsc* c = *cy;
+    mpool_free((char*)c, c->mempool);
+}
+
+float tWaveOsc_tick(tWaveOsc* const cy)
+{
+    _tWaveOsc* c = *cy;
+    
     float temp;
     int idx;
     float frac;
@@ -1795,6 +1818,9 @@
     float samp0;
     float samp1;
     
+    int size = c->table->size;
+    float** tables = c->table->tables;
+    
     // Phasor increment
     c->phase += c->inc;
     if (c->phase + c->phaseOffset >= 1.0f) c->phase -= 1.0f;
@@ -1801,20 +1827,20 @@
     if (c->phase + c->phaseOffset < 0.0f) c->phase += 1.0f;
     
     // Wavetable synthesis
-    temp = c->size * (c->phase + c->phaseOffset);
+    temp = size * (c->phase + c->phaseOffset);
     
     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];
+    samp0 = tables[c->oct][idx];
+    if (++idx >= size) idx = 0;
+    samp1 = 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];
+    samp0 = tables[c->oct+1][idx];
+    if (++idx >= size) idx = 0;
+    samp1 = tables[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
     
@@ -1821,9 +1847,9 @@
     return oct0 + (oct1 - oct0) * c->w;
 }
 
-void tWavetable_setFreq(tWavetable* const cy, float freq)
+void tWaveOsc_setFreq(tWaveOsc* const cy, float freq)
 {
-    _tWavetable* c = *cy;
+    _tWaveOsc* c = *cy;
     
     LEAF* leaf = c->mempool->leaf;
     
@@ -1833,7 +1859,7 @@
     c->inc -= (int)c->inc;
     
     // abs for negative frequencies
-    c->w = fabsf(c->freq * c->invBaseFreq);
+    c->w = fabsf(c->freq * c->table->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
@@ -1843,34 +1869,203 @@
     
     // 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;
+    if (c->oct >= c->table->numTables - 1) c->oct = c->table->numTables - 2;
 }
 
-void tWavetable_setAntiAliasing(tWavetable* const cy, float aa)
+void tWaveOsc_setAntiAliasing(tWaveOsc* const cy, float aa)
 {
-    _tWavetable* c = *cy;
+    _tWaveOsc* c = *cy;
     c->aa = aa;
-    tWavetable_setFreq(cy, c->freq);
+    tWaveOsc_setFreq(cy, c->freq);
 }
 
-void tWavetable_setPhaseOffset(tWavetable* const cy, float phase)
+void tWaveOsc_setPhaseOffset(tWaveOsc* const cy, float phase)
 {
-    _tWavetable* c = *cy;
+    _tWaveOsc* c = *cy;
     c->phaseOffset = phase - (int)phase;
 }
 
+//================================================================================================
+//================================================================================================
 
-void tCompactWavetable_init(tCompactWavetable* const cy, float* table, int size, float maxFreq, LEAF* const leaf)
+void    tWaveSynth_init(tWaveSynth* const cy, int numVoices, float** tables, int* sizes,
+                        int numTables, float maxFreq, LEAF* const leaf)
 {
-    tCompactWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
+    tWaveSynth_initToPool(cy, numVoices, tables, sizes, numTables, maxFreq, &leaf->mempool);
 }
 
-void tCompactWavetable_initToPool(tCompactWavetable* const cy, float* table, int size, float maxFreq, tMempool* const mp)
+void    tWaveSynth_initToPool(tWaveSynth* const cy, int numVoices, float** tables, int* sizes,
+                              int numTables, float maxFreq, tMempool* const mp)
 {
     _tMempool* m = *mp;
-    _tCompactWavetable* c = *cy = (_tCompactWavetable*) mpool_alloc(sizeof(_tCompactWavetable), m);
+    _tWaveSynth* c = *cy = (_tWaveSynth*) mpool_alloc(sizeof(_tWaveSynth), m);
     c->mempool = m;
     
+    c->numTables = 0;
+    for (int t = 0; t < numTables; ++t)
+    {
+        if (sizes[t] > 0) c->numTables++;
+    }
+    
+    c->tables = (tWaveTable*) mpool_alloc(sizeof(tWaveTable) * c->numTables, m);
+    c->oscs = (tWaveOsc**) mpool_alloc(sizeof(tWaveOsc*) * c->numTables, m);
+
+    c->numVoices = numVoices;
+    
+    int i = 0;
+    for (int t = 0; t < numTables; ++t)
+    {
+        if (sizes[t] > 0)
+        {
+            tWaveTable_initToPool(&c->tables[i], tables[t], sizes[t], maxFreq, mp);
+            c->oscs[i] = (tWaveOsc*) mpool_alloc(sizeof(tWaveOsc) * c->numVoices, m);
+            for (int v = 0; v < c->numVoices; ++v) tWaveOsc_initToPool(&c->oscs[i][v], &c->tables[i], mp);
+            i++;
+        }
+    }
+    
+    c->g = (float*) mpool_alloc(sizeof(float) * c->numTables, m);
+    for (int i = 0; i < c->numTables; ++i)  c->g[i] = 1.0f;
+    
+    c->index = 0.0f;
+    c->maxFreq = maxFreq;
+}
+
+void    tWaveSynth_free(tWaveSynth* const cy)
+{
+    _tWaveSynth* c = *cy;
+    
+    for (int i = 0; i < c->numTables; ++i)
+    {
+        tWaveTable_free(&c->tables[i]);
+        for (int v = 0; v < c->numVoices; ++v) tWaveOsc_free(&c->oscs[i][v]);
+        mpool_free((char*)c->oscs[i], c->mempool);
+    }
+    mpool_free((char*)c->g, c->mempool);
+    mpool_free((char*)c->oscs, c->mempool);
+    mpool_free((char*)c->tables, c->mempool);
+    mpool_free((char*)c, c->mempool);
+}
+
+float   tWaveSynth_tick(tWaveSynth* const cy)
+{
+    _tWaveSynth* c = *cy;
+    
+    float f = c->index * (c->numTables - 1);
+    
+    int o1 = (int)f;
+    int o2 = o1 + 1;
+    if (c->index >= 1.0f) o2 = o1;
+    float mix = f - o1;
+    
+    float s1 = 0.f, s2 = 0.f;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        float s0 = 0.f;
+        for (int v = 0; v < c->numVoices; ++v) s0 += tWaveOsc_tick(&c->oscs[t][v]);
+        if (t == o1) s1 = s0 * c->g[t];
+        if (t == o2) s2 = s0 * c->g[t];
+    }
+    
+    // Ideally should determine correlation to get a good equal power fade between tables
+    return s1 + (s2 - s1) * mix;
+}
+
+float tWaveSynth_tickVoice(tWaveSynth* const cy, int voice)
+{
+    _tWaveSynth* c = *cy;
+    
+    float f = c->index * (c->numTables - 1);
+    
+    int o1 = (int)f;
+    int o2 = o1 + 1;
+    if (c->index >= 1.0f) o2 = o1;
+    float mix = f - o1;
+    
+    float s1 = 0.f, s2 = 0.f;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        // Should we tick every voice anyway to preserve relative phases?
+        float s0 = tWaveOsc_tick(&c->oscs[t][voice]);
+        if (t == o1) s1 = s0 * c->g[t];
+        if (t == o2) s2 = s0 * c->g[t];
+    }
+    
+    // Ideally should determine correlation to get a good equal power fade between tables
+    return s1 + (s2 - s1) * mix;
+}
+
+void tWaveSynth_setFreq(tWaveSynth* const cy, int voice, float freq)
+{
+    _tWaveSynth* c = *cy;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        tWaveOsc_setFreq(&c->oscs[t][voice], freq);
+    }
+}
+
+void tWaveSynth_setAntiAliasing(tWaveSynth* const cy, float aa)
+{
+    _tWaveSynth* c = *cy;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        for (int v = 0; v < c->numVoices; ++v)
+        {
+            tWaveOsc_setAntiAliasing(&c->oscs[t][v], aa);
+        }
+    }
+}
+
+void tWaveSynth_setIndex(tWaveSynth* const cy, float index)
+{
+    _tWaveSynth* c = *cy;
+    c->index = index;
+}
+
+void tWaveSynth_setIndexGain(tWaveSynth* const cy, int i, float gain)
+{
+    _tWaveSynth* c = *cy;
+    if (i >= c->numTables) return;
+    c->g[i] = gain;
+}
+
+void tWaveSynth_setIndexPhase(tWaveSynth* const cy, int i, float phase)
+{
+    _tWaveSynth* c = *cy;
+    if (i >= c->numTables) return;
+    for (int v = 0; v < c->numVoices; ++v)
+    {
+        tWaveOsc_setPhaseOffset(&c->oscs[i][v], phase);
+    }
+}
+
+//void tWaveSynth_setIndexTable(tWaveSynth* const cy, int i, float* table, int size)
+//{
+//    _tWaveSynth* c = *cy;
+//    if (i >= c->numTables) return;
+//    if (
+//    tWaveTable_free(&c->tables[i]);
+//    tWaveTable_initToPool(&c->tables[i], table, size, c->maxFreq, &c->mempool);
+//    for (int v = 0; v < c->numVoices; ++v)
+//    {
+//        tWaveOsc_setFreq(&c->oscs[i][v], c->oscs[i][v]->freq);
+//    }
+//}
+
+//=======================================================================================
+//=======================================================================================
+
+void tCompactWaveTable_init(tCompactWaveTable* const cy, float* table, int size, float maxFreq, LEAF* const leaf)
+{
+    tCompactWaveTable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
+}
+
+void tCompactWaveTable_initToPool(tCompactWaveTable* const cy, 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;
@@ -1907,7 +2102,7 @@
     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
+        // 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)
@@ -1920,17 +2115,11 @@
     }
     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)
+void    tCompactWaveTable_free(tCompactWaveTable* const cy)
 {
-    _tCompactWavetable* c = *cy;
+    _tCompactWaveTable* c = *cy;
     
     for (int t = 0; t < c->numTables; ++t)
     {
@@ -1941,10 +2130,38 @@
     mpool_free((char*)c, c->mempool);
 }
 
-float   tCompactWavetable_tick(tCompactWavetable* const cy)
+//================================================================================================
+//================================================================================================
+
+void tCompactWaveOsc_init(tCompactWaveOsc* const cy, tCompactWaveTable* const table, LEAF* const leaf)
 {
-    _tCompactWavetable* c = *cy;
+    tCompactWaveOsc_initToPool(cy, table, &leaf->mempool);
+}
+
+void tCompactWaveOsc_initToPool(tCompactWaveOsc* const cy, tCompactWaveTable* const table, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tCompactWaveOsc* c = *cy = (_tCompactWaveOsc*) mpool_alloc(sizeof(_tCompactWaveOsc), m);
+    c->mempool = m;
     
+    c->inc = 0.0f;
+    c->phase = 0.0f;
+    c->phaseOffset = 0.0f;
+    c->aa = 0.5f;
+    
+    tCompactWaveOsc_setFreq(cy, 220);
+}
+
+void tCompactWaveOsc_free(tCompactWaveOsc* const cy)
+{
+    _tCompactWaveOsc* c = *cy;
+    mpool_free((char*)c, c->mempool);
+}
+
+float tCompactWaveOsc_tick(tCompactWaveOsc* const cy)
+{
+    _tCompactWaveOsc* c = *cy;
+    
     float temp;
     int idx;
     float frac;
@@ -1956,22 +2173,25 @@
     if (c->phase >= 1.0f) c->phase -= 1.0f;
     if (c->phase < 0.0f) c->phase += 1.0f;
     
+    int* sizes = c->table->sizes;
+    float** tables = c->table->tables;
+    
     // Wavetable synthesis
-    temp = c->sizes[c->oct] * c->phase;
+    temp = sizes[c->oct] * (c->phase + c->phaseOffset);
     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];
+    samp0 = tables[c->oct][idx];
+    if (++idx >= sizes[c->oct]) idx = 0;
+    samp1 = tables[c->oct][idx];
     
     float oct0 = (samp0 + (samp1 - samp0) * frac);
     
-    temp = c->sizes[c->oct+1] * c->phase;
+    temp = 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];
+    samp0 = tables[c->oct+1][idx];
+    if (++idx >= sizes[c->oct+1]) idx = 0;
+    samp1 = tables[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
     
@@ -1978,9 +2198,9 @@
     return oct0 + (oct1 - oct0) * c->w;
 }
 
-void    tCompactWavetable_setFreq(tCompactWavetable* const cy, float freq)
+void tCompactWaveOsc_setFreq(tCompactWaveOsc* const cy, float freq)
 {
-    _tCompactWavetable* c = *cy;
+    _tCompactWaveOsc* c = *cy;
     
     LEAF* leaf = c->mempool->leaf;
     
@@ -1990,7 +2210,7 @@
     c->inc -= (int)c->inc;
     
     // abs for negative frequencies
-    c->w = fabsf(c->freq * c->invBaseFreq);
+    c->w = fabsf(c->freq * c->table->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
@@ -1997,73 +2217,89 @@
     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;
+    if (c->oct >= c->table->numTables - 1) c->oct = c->table->numTables - 2;
 }
 
-void tCompactWavetable_setAntiAliasing(tCompactWavetable* const cy, float aa)
+void tCompactWaveOsc_setAntiAliasing(tCompactWaveOsc* const cy, float aa)
 {
-    _tCompactWavetable* c = *cy;
-    
+    _tCompactWaveOsc* c = *cy;
     c->aa = aa;
-    tCompactWavetable_setFreq(cy, c->freq);
+    tCompactWaveOsc_setFreq(cy, c->freq);
 }
 
+void tCompactWaveOsc_setPhaseOffset(tCompactWaveOsc* const cy, float phase)
+{
+    _tCompactWaveOsc* c = *cy;
+    c->phaseOffset = phase - (int)phase;
+}
+
 //================================================================================================
 //================================================================================================
 
-void    tWaveset_init(tWaveset* const cy, float** tables, int n, int* sizes, float maxFreq, LEAF* const leaf)
+void tCompactWaveSynth_init(tCompactWaveSynth* const cy, int numVoices, float** tables, int* sizes,
+                            int numTables, float maxFreq, LEAF* const leaf)
 {
-    tWaveset_initToPool(cy, tables, n, sizes, maxFreq, &leaf->mempool);
+    tCompactWaveSynth_initToPool(cy, numVoices, tables, sizes, numTables, maxFreq, &leaf->mempool);
 }
 
-void    tWaveset_initToPool(tWaveset* const cy, float** tables, int n, int* sizes, float maxFreq, tMempool* const mp)
+void tCompactWaveSynth_initToPool(tCompactWaveSynth* const cy, int numVoices, float** tables, int* sizes,
+                                  int numTables, float maxFreq, tMempool* const mp)
 {
     _tMempool* m = *mp;
-    _tWaveset* c = *cy = (_tWaveset*) mpool_alloc(sizeof(_tWaveset), m);
+    _tCompactWaveSynth* c = *cy = (_tCompactWaveSynth*) mpool_alloc(sizeof(_tCompactWaveSynth), m);
     c->mempool = m;
     
-    c->n = 0;
-    for (int t = 0; t < n; ++t)
+    c->numTables = 0;
+    for (int t = 0; t < numTables; ++t)
     {
-        if (sizes[t] > 0) c->n++;
+        if (sizes[t] > 0) c->numTables++;
     }
     
-    c->wt = (tWavetable*) mpool_alloc(sizeof(tWavetable) * c->n, m);
+    c->tables = (tCompactWaveTable*) mpool_alloc(sizeof(tCompactWaveTable) * c->numTables, m);
+    c->oscs = (tCompactWaveOsc**) mpool_alloc(sizeof(tCompactWaveOsc*) * c->numTables, m);
     
+    c->numVoices = numVoices;
+    
     int i = 0;
-    for (int t = 0; t < n; ++t)
+    for (int t = 0; t < numTables; ++t)
     {
         if (sizes[t] > 0)
         {
-            tWavetable_initToPool(&c->wt[i], tables[t], sizes[t], maxFreq, mp);
+            tCompactWaveTable_initToPool(&c->tables[i], tables[t], sizes[t], maxFreq, mp);
+            c->oscs[i] = (tCompactWaveOsc*) mpool_alloc(sizeof(tCompactWaveOsc) * c->numVoices, m);
+            for (int v = 0; v < c->numVoices; ++v) tCompactWaveOsc_initToPool(&c->oscs[i][v], &c->tables[i], mp);
             i++;
         }
     }
     
-    c->g = (float*) mpool_alloc(sizeof(tWavetable) * c->n, m);
-    for (int i = 0; i < c->n; ++i)  c->g[i] = 1.0f;
+    c->g = (float*) mpool_alloc(sizeof(float) * c->numTables, m);
+    for (int i = 0; i < c->numTables; ++i)  c->g[i] = 1.0f;
     
     c->index = 0.0f;
+    c->maxFreq = maxFreq;
 }
 
-void    tWaveset_free(tWaveset* const cy)
+void tCompactWaveSynth_free(tCompactWaveSynth* const cy)
 {
-    _tWaveset* c = *cy;
+    _tCompactWaveSynth* c = *cy;
     
-    for (int i = 0; i < c->n; ++i)
+    for (int i = 0; i < c->numTables; ++i)
     {
-        tWavetable_free(&c->wt[i]);
+        tCompactWaveTable_free(&c->tables[i]);
+        for (int v = 0; v < c->numVoices; ++v) tCompactWaveOsc_free(&c->oscs[i][v]);
+        mpool_free((char*)c->oscs[i], c->mempool);
     }
     mpool_free((char*)c->g, c->mempool);
-    mpool_free((char*)c->wt, c->mempool);
+    mpool_free((char*)c->oscs, c->mempool);
+    mpool_free((char*)c->tables, c->mempool);
     mpool_free((char*)c, c->mempool);
 }
 
-float   tWaveset_tick(tWaveset* const cy)
+float tCompactWaveSynth_tick(tCompactWaveSynth* const cy)
 {
-    _tWaveset* c = *cy;
+    _tCompactWaveSynth* c = *cy;
     
-    float f = c->index * (c->n - 1);
+    float f = c->index * (c->numTables - 1);
     
     int o1 = (int)f;
     int o2 = o1 + 1;
@@ -2070,12 +2306,13 @@
     if (c->index >= 1.0f) o2 = o1;
     float mix = f - o1;
     
-    float s0 = 0.f, s1 = 0.f, s2 = 0.f;
-    for (int i = 0; i < c->n; ++i)
+    float s1 = 0.f, s2 = 0.f;
+    for (int t = 0; t < c->numTables; ++t)
     {
-        s0 = tWavetable_tick(&c->wt[i]) * c->g[i];
-        if (i == o1) s1 = s0;
-        if (i == o2) s2 = s0;
+        float s0 = 0.f;
+        for (int v = 0; v < c->numVoices; ++v) s0 += tCompactWaveOsc_tick(&c->oscs[t][v]);
+        if (t == o1) s1 = s0 * c->g[t];
+        if (t == o2) s2 = s0 * c->g[t];
     }
     
     // Ideally should determine correlation to get a good equal power fade between tables
@@ -2082,40 +2319,82 @@
     return s1 + (s2 - s1) * mix;
 }
 
-void    tWaveset_setFreq(tWaveset* const cy, float freq)
+float tCompactWaveSynth_tickVoice(tCompactWaveSynth* const cy, int voice)
 {
-    _tWaveset* c = *cy;
-    for (int i = 0; i < c->n; ++i)
+    _tCompactWaveSynth* c = *cy;
+    
+    float f = c->index * (c->numTables - 1);
+    
+    int o1 = (int)f;
+    int o2 = o1 + 1;
+    if (c->index >= 1.0f) o2 = o1;
+    float mix = f - o1;
+    
+    float s1 = 0.f, s2 = 0.f;
+    for (int t = 0; t < c->numTables; ++t)
     {
-        tWavetable_setFreq(&c->wt[i], freq);
+        // Should we tick every voice anyway to preserve relative phases?
+        float s0 = tCompactWaveOsc_tick(&c->oscs[t][voice]);
+        if (t == o1) s1 = s0 * c->g[t];
+        if (t == o2) s2 = s0 * c->g[t];
     }
+    
+    // Ideally should determine correlation to get a good equal power fade between tables
+    return s1 + (s2 - s1) * mix;
 }
 
-void    tWaveset_setAntiAliasing(tWaveset* const cy, float aa)
+void tCompactWaveSynth_setFreq(tCompactWaveSynth* const cy, int voice, float freq)
 {
-    _tWaveset* c = *cy;
-    for (int i = 0; i < c->n; ++i)
+    _tCompactWaveSynth* c = *cy;
+    for (int t = 0; t < c->numTables; ++t)
     {
-        tWavetable_setAntiAliasing(&c->wt[i], aa);
+        tCompactWaveOsc_setFreq(&c->oscs[t][voice], freq);
     }
 }
 
-void    tWaveset_setIndex(tWaveset* const cy, float index)
+void tCompactWaveSynth_setAntiAliasing(tCompactWaveSynth* const cy, float aa)
 {
-    _tWaveset* c = *cy;
+    _tCompactWaveSynth* c = *cy;
+    for (int t = 0; t < c->numTables; ++t)
+    {
+        for (int v = 0; v < c->numVoices; ++v)
+        {
+            tCompactWaveOsc_setAntiAliasing(&c->oscs[t][v], aa);
+        }
+    }
+}
+
+void tCompactWaveSynth_setIndex(tCompactWaveSynth* const cy, float index)
+{
+    _tCompactWaveSynth* c = *cy;
     c->index = index;
 }
 
-void    tWaveset_setIndexGain(tWaveset* const cy, int i, float gain)
+void tCompactWaveSynth_setIndexGain(tCompactWaveSynth* const cy, int i, float gain)
 {
-    _tWaveset* c = *cy;
-    if (i >= c->n) return;
+    _tCompactWaveSynth* c = *cy;
+    if (i >= c->numTables) return;
     c->g[i] = gain;
 }
 
-void    tWaveset_setIndexPhase(tWaveset* const cy, int i, float phase)
+void tCompactWaveSynth_setIndexPhase(tCompactWaveSynth* const cy, int i, float phase)
 {
-    _tWaveset* c = *cy;
-    if (i >= c->n) return;
-    tWavetable_setPhaseOffset(&c->wt[i], phase);
+    _tCompactWaveSynth* c = *cy;
+    if (i >= c->numTables) return;
+    for (int v = 0; v < c->numVoices; ++v)
+    {
+        tCompactWaveOsc_setPhaseOffset(&c->oscs[i][v], phase);
+    }
 }
+//
+//void tCompactWaveSynth_setIndexTable(tCompactWaveSynth* const cy, int i, float* table, int size)
+//{
+//    _tCompactWaveSynth* c = *cy;
+//    if (i >= c->numTables) return;
+//    tCompactWaveTable_free(&c->tables[i]);
+//    tCompactWaveTable_initToPool(&c->tables[i], table, size, c->maxFreq, &c->mempool);
+//    for (int v = 0; v < c->numVoices; ++v)
+//    {
+//        tCompactWaveOsc_setFreq(&c->oscs[i][v], c->oscs[i][v]->freq);
+//    }
+//}
--- a/leaf/leaf-config.h
+++ b/leaf/leaf-config.h
@@ -18,7 +18,7 @@
 
 //==============================================================================
 
-//! Include FIR tables required to use tOversampler and tCompactWavetable which uses tOversampler. 
+//! Include FIR tables required to use tOversampler and tCompactWaveTable which uses tOversampler. 
 #define LEAF_INCLUDE_OVERSAMPLER_TABLES 1
 
 // Unused