shithub: leaf

Download patch

ref: 479c76dacf9488757e5a9734376f0b8068bdca93
parent: daea60c5d0a1be815d11368a236c9bdbe9e6bace
parent: 3ae7064aeb7485aed70048f8dc622282a5012a0c
author: spiricom <jeff@snyderphonics.com>
date: Tue Jun 29 13:28:54 EDT 2021

fixed merge conflicts

--- a/Examples/basic-oscillators.c
+++ b/Examples/basic-oscillators.c
@@ -14,7 +14,7 @@
 {
     LEAF leaf;
     
-    LEAF_init(&leaf, 44100, 128, mempool, 1000, &exampleRandom);
+    LEAF_init(&leaf, 44100, mempool, 1000, &exampleRandom);
     
     tCycle_init(&cycle, &leaf);
     tCycle_setFreq(&cycle, 220);
--- a/TestPlugin/Source/MyTest.cpp
+++ b/TestPlugin/Source/MyTest.cpp
@@ -40,6 +40,7 @@
 
 const int numWavetables = 1;
 tWaveTable wavetables[numWavetables];
+tSimpleRetune retune;
 
 float gain;
 float dtime;
@@ -61,8 +62,11 @@
 
 void    LEAFTest_init            (float sampleRate, int blockSize)
 {
-    LEAF_init(&leaf, sampleRate, blockSize, memory, MSIZE, &getRandomFloat);
+    LEAF_init(&leaf, sampleRate, memory, MSIZE, &getRandomFloat);
     
+    tSimpleRetune_init(&retune, 1, 100, 1200, 2048, &leaf);
+    tSimpleRetune_setMode(&retune, 1);
+    
 //    tWaveTable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
 //    tWaveTableS_init(&cwt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
     
@@ -81,10 +85,8 @@
     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;
     
-    tWaveSynth_init(&ws, 1, set, sizes, 4, 10000.f, &leaf);
+//    tWaveSynth_init(&ws, set, 2048, 4, 10000.f, &leaf);
     
     lastLoadedAudioSize = 0;
     loadedAudio.clear();
@@ -101,6 +103,10 @@
 
 float   LEAFTest_tick            (float input)
 {
+    tSimpleRetune_tuneVoice(&retune, 0, mtof(roundf(ftom(tSimpleRetune_getInputFrequency(&retune)))));
+    return tSimpleRetune_tick(&retune, input);
+    
+    
     float out = 0.0f;
     for (int i = 0; i < fmin(loadedAudio.size(), numWavetables); ++i)
     {
@@ -119,7 +125,7 @@
     tMBSaw_setFreq(&bsaw, val * 10000.f);
 //    tWaveTable_setFreq(&wt, val * 160000.f - 80000.0f);
 //    tWaveTableS_setFreq(&cwt, val * 10000.);
-    tWaveSynth_setFreq(&ws, 0, val * 10000.f);
+    tWaveSynth_setFreq(&ws, val * 10000.f);
 //    tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
 //    tSimpleRetune_tuneVoice(&sretune, 0, 300);
 
--- a/leaf/Inc/leaf-effects.h
+++ b/leaf/Inc/leaf-effects.h
@@ -610,6 +610,7 @@
         
         tPitchShift* ps;
         
+        float* pdBuffer;
         float* inBuffer;
         float* outBuffer;
         int bufSize;
--- a/leaf/Inc/leaf-filters.h
+++ b/leaf/Inc/leaf-filters.h
@@ -722,6 +722,7 @@
     float   tEfficientSVF_tick          (tEfficientSVF* const, float v0);
     void    tEfficientSVF_setFreq       (tEfficientSVF* const, uint16_t controlFreq);
     void    tEfficientSVF_setQ          (tEfficientSVF* const, float Q);
+    void    tEfficientSVF_setFreqAndQ   (tEfficientSVF* const, uint16_t controlFreq, float Q);
     
     //==============================================================================
     
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -65,9 +65,11 @@
     {
         tMempool mempool;
         // Underlying phasor
-        float phase;
-        float inc,freq;
-        float invSampleRate;
+        uint32_t phase;
+        uint32_t inc;
+		float freq;
+        float invSampleRateTimesTwoTo32;
+        uint32_t mask;
     } _tCycle;
     
     typedef _tCycle* tCycle;
@@ -78,6 +80,7 @@
     
     float   tCycle_tick         (tCycle* const osc);
     void    tCycle_setFreq      (tCycle* const osc, float freq);
+    void    tCycle_setPhase     (tCycle* const osc, float phase);
     void    tCycle_setSampleRate(tCycle* const osc, float sr);
     
     //==============================================================================
@@ -116,14 +119,16 @@
 
     typedef struct _tTriangle
     {
-        
         tMempool mempool;
         // Underlying phasor
-        float phase;
-        float inc,freq;
+        uint32_t phase;
+        uint32_t inc;
+        float freq;
         int oct;
         float w;
         float invSampleRate;
+        float invSampleRateTimesTwoTo32;
+        uint32_t mask;
     } _tTriangle;
     
     typedef _tTriangle* tTriangle;
@@ -134,6 +139,7 @@
     
     float   tTriangle_tick          (tTriangle* const osc);
     void    tTriangle_setFreq       (tTriangle* const osc, float freq);
+    void    tTriangle_setPhase      (tTriangle* const osc, float phase);
     void    tTriangle_setSampleRate (tTriangle* const osc, float sr);
     
     //==============================================================================
@@ -172,14 +178,16 @@
     
     typedef struct _tSquare
     {
-        
         tMempool mempool;
         // Underlying phasor
-        float phase;
-        float inc,freq;
+        uint32_t phase;
+        uint32_t inc;
+        float freq;
         int oct;
         float w;
         float invSampleRate;
+        float invSampleRateTimesTwoTo32;
+        uint32_t mask;
     } _tSquare;
     
     typedef _tSquare* tSquare;
@@ -190,6 +198,7 @@
 
     float   tSquare_tick        (tSquare* const osc);
     void    tSquare_setFreq     (tSquare* const osc, float freq);
+    void    tSquare_setPhase     (tSquare* const osc, float phase);
     void    tSquare_setSampleRate (tSquare* const osc, float sr);
     
     /*!
@@ -231,14 +240,16 @@
     
     typedef struct _tSawtooth
     {
-        
         tMempool mempool;
         // Underlying phasor
-        float phase;
-        float inc,freq;
+        uint32_t phase;
+        uint32_t inc;
+        float freq;
         int oct;
         float w;
         float invSampleRate;
+        float invSampleRateTimesTwoTo32;
+        uint32_t mask;
     } _tSawtooth;
     
     typedef _tSawtooth* tSawtooth;
@@ -249,6 +260,7 @@
 
     float   tSawtooth_tick          (tSawtooth* const osc);
     void    tSawtooth_setFreq       (tSawtooth* const osc, float freq);
+    void    tSawtooth_setPhase      (tSawtooth* const osc, float phase);
     void    tSawtooth_setSampleRate (tSawtooth* const osc, float sr);
     
     //==============================================================================
@@ -977,6 +989,7 @@
         float* baseTable;
         float** tables;
         int size;
+        int sizeMask;
         int numTables;
         float maxFreq;
         float baseFreq, invBaseFreq;
@@ -1086,34 +1099,47 @@
      @} */
     
     typedef struct _tWaveSynth
-    {
-        tMempool mempool;
-        
-        tWaveTable* tables;
-        tWaveOsc** oscs;
-        int numTables;
-        int numVoices;
-        float* g;
-        float index;
-        float maxFreq;
-    } _tWaveSynth;
+       {
+           tMempool mempool;
+           tWaveTable* tables;
+           int numTables;
+           float index;
+           float maxFreq;
+           int o1;
+           int o2;
+           float mix;
+           uint32_t phase;
+           int32_t inc;
+           float freq;
+           float invSampleRateTimesTwoTo32;
+           int oct;
+           int size;
+
+           // Determine base frequency
+           float baseFreq;
+           float invBaseFreq;
+           float sampleRate;
+           float w;
+           float aa;
+           int numSubTables;
+
+       } _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_init(tWaveSynth* const cy, tWaveTable* tables, int size,
+                                int numTables, float maxFreq, LEAF* const leaf);
+
+    void tWaveSynth_initToPool(tWaveSynth* const cy, tWaveTable* tables, int size,
+                                      int numTables, float maxFreq, tMempool* const mp);
     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_setFreq(tWaveSynth* const cy, 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);
+    void 	tWaveSynth_setTables(tWaveSynth* const cy, tWaveTable* tables, int numTables, int size);
     void    tWaveSynth_setSampleRate (tWaveSynth* const osc, float sr);
 
     //==============================================================================
@@ -1154,6 +1180,7 @@
         float** tables;
         int numTables;
         int* sizes;
+        int* sizeMasks;
         float maxFreq;
         float baseFreq, invBaseFreq;
         tButterworth bl;
@@ -1233,7 +1260,59 @@
     void    tWaveOscS_setSampleRate (tWaveOscS* const osc, float sr);
     
     //==============================================================================
+    /*!
+     @defgroup twaveoscs tWaveOscS
+     @ingroup oscillators
+     @brief A more space-efficient anti-aliased wavetable oscillator than tWaveOsc but with slightly worse fidelity.
+     @{
+
+     @fn void   tWaveOscS_init  (tWaveOscS* const osc, float* table, int size, float maxFreq, LEAF* const leaf)
+     @brief Initialize a tWaveOscS to the default mempool of a LEAF instance.
+     @param osc A pointer to the tWaveOscS 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   tWaveOscS_initToPool   (tWaveOscS* const osc, float* table, int size, float maxFreq, tMempool* const mempool)
+     @brief Initialize a tWaveOscS to a specified mempool.
+     @param osc A pointer to the tWaveOscS 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   tWaveOscS_free         (tWaveOscS* const osc)
+     @brief Free a tWaveOscS from its mempool.
+     @param osc A pointer to the tWaveOscS to free.
+
+     @fn float  tWaveOscS_tick         (tWaveOscS* const osc)
+     @brief Tick a tWaveOscS oscillator.
+     @param osc A pointer to the relevant tWaveOscS.
+     @return The ticked sample as a float from -1 to 1.
+
+     @fn void   tWaveOscS_setFreq      (tWaveOscS* const osc, float freq)
+     @brief Set the frequency of a tWaveOscS oscillator.
+     @param osc A pointer to the relevant tWaveOscS.
+     @param freq The frequency to set the oscillator to.
+
+     @} */
     
+    typedef struct _tWaveSubOscS
+    {
+        tMempool mempool;
+        tWaveTableS table;
+
+    } _tWaveSubOscS;
+
+    typedef _tWaveSubOscS* tWaveSubOscS;
+
+    void    tWaveSubOscS_init(tWaveSubOscS* const osc, tWaveTableS* const table, LEAF* const leaf);
+    void    tWaveSubOscS_initToPool(tWaveSubOscS* const osc, tWaveTableS* const table, tMempool* const mempool);
+    void    tWaveSubOscS_free(tWaveSubOscS* const osc);
+    float 	tWaveSubOscS_tick(tWaveSubOscS* const cy, float phase, int oct, float w);
+
+    //==============================================================================
     /*!
      @defgroup twavesynths tWaveSynthS
      @ingroup oscillators
@@ -1282,30 +1361,46 @@
     {
         tMempool mempool;
         
+        //tWaveTableS* tables;
+
         tWaveTableS* tables;
-        tWaveOscS** oscs;
+
+        tWaveSubOscS* oscs;
         int numTables;
-        int numVoices;
-        float* g;
         float index;
         float maxFreq;
+        int o1;
+        int o2;
+        float mix;
+        uint32_t phase;
+        int32_t inc;
+        float freq;
+        float invSampleRateTimesTwoTo32;
+        int oct;
+        int size;
+
+        // Determine base frequency
+        float baseFreq;
+        float invBaseFreq;
+        float sampleRate;
+        float w;
+        float aa;
+        int numSubTables;
+
     } _tWaveSynthS;
     
     typedef _tWaveSynthS* tWaveSynthS;
     
-    void    tWaveSynthS_init(tWaveSynthS* const osc, int numVoices, float** tables, int* sizes,
-                                   int numTables, float maxFreq, LEAF* const leaf);
-    void    tWaveSynthS_initToPool(tWaveSynthS* const osc, int numVoices, float** tables, int* sizes,
+    void 	tWaveSynthS_init(tWaveSynthS* const cy, tWaveTableS* tables, int size,
+                                int numTables, float maxFreq, LEAF* const leaf);
+    void    tWaveSynthS_initToPool(tWaveSynthS* const osc, tWaveTableS* tables, int size,
                                          int numTables, float maxFreq, tMempool* const mempool);
     void    tWaveSynthS_free(tWaveSynthS* const osc);
     
     float   tWaveSynthS_tick(tWaveSynthS* const osc);
-    float   tWaveSynthS_tickVoice(tWaveSynthS* const cy, int voice);
-    void    tWaveSynthS_setFreq(tWaveSynthS* const osc, int voice, float freq);
+    void    tWaveSynthS_setFreq(tWaveSynthS* const osc, float freq);
     void    tWaveSynthS_setAntiAliasing(tWaveSynthS* const osc, float aa);
     void    tWaveSynthS_setIndex(tWaveSynthS* const osc, float index);
-    void    tWaveSynthS_setIndexGain(tWaveSynthS* const osc, int i, float gain);
-    void    tWaveSynthS_setIndexPhase(tWaveSynthS* const osc, int i, float phase);
 //    void    tWaveSynthS_setIndexTable(tWaveSynthS* const osc, int i, float* table, int size);
     void    tWaveSynthS_setSampleRate (tWaveSynthS* const osc, float sr);
     
--- a/leaf/Inc/leaf-physical.h
+++ b/leaf/Inc/leaf-physical.h
@@ -337,6 +337,49 @@
     
     // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
     
+
+
+    typedef struct _tSimpleLivingString2
+    {
+
+        tMempool mempool;
+        float freq, waveLengthInSamples;        // the frequency of the string, determining delay length
+        float brightness;    // frequency for the bridge LP filter, in Hz
+        float decay; // amplitude damping factor for the string (only active in mode 0)
+        int levMode;
+        float curr;
+        tHermiteDelay delayLine;
+        tTwoZero bridgeFilter;
+        tHighpass DCblocker;
+        tFeedbackLeveler fbLev;
+        tExpSmooth wlSmooth;
+        float sampleRate;
+    } _tSimpleLivingString2;
+
+    typedef _tSimpleLivingString2* tSimpleLivingString2;
+
+    void    tSimpleLivingString2_init                (tSimpleLivingString2* const, float freq, float brightness,
+                                                     float decay, float targetLev, float levSmoothFactor,
+                                                     float levStrength, int levMode, LEAF* const leaf);
+    void    tSimpleLivingString2_initToPool          (tSimpleLivingString2* const, float freq, float brightness,
+                                                     float decay, float targetLev, float levSmoothFactor,
+                                                     float levStrength, int levMode, tMempool* const);
+    void    tSimpleLivingString2_free                (tSimpleLivingString2* const);
+
+    float   tSimpleLivingString2_tick                (tSimpleLivingString2* const, float input);
+    float   tSimpleLivingString2_sample              (tSimpleLivingString2* const);
+    void    tSimpleLivingString2_setFreq             (tSimpleLivingString2* const, float freq);
+    void    tSimpleLivingString2_setWaveLength       (tSimpleLivingString2* const, float waveLength); // in samples
+    void    tSimpleLivingString2_setBrightness         (tSimpleLivingString2* const, float brightness);
+    void    tSimpleLivingString2_setDecay            (tSimpleLivingString2* const, float decay); // should be near 1.0
+    void    tSimpleLivingString2_setTargetLev        (tSimpleLivingString2* const, float targetLev);
+    void    tSimpleLivingString2_setLevSmoothFactor  (tSimpleLivingString2* const, float levSmoothFactor);
+    void    tSimpleLivingString2_setLevStrength      (tSimpleLivingString2* const, float levStrength);
+    void    tSimpleLivingString2_setLevMode          (tSimpleLivingString2* const, int levMode);
+    void    tSimpleLivingString2_setSampleRate       (tSimpleLivingString2* const, float sr);
+
+    // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
     /*!
      @defgroup tlivingstring tLivingString
      @ingroup physical
@@ -452,7 +495,7 @@
     // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
     
     
-    /*!
+       /*!
      @defgroup tlivingstring2 tLivingString2
      @ingroup physical
      @brief String model with preparation and pick position separated.
@@ -560,6 +603,7 @@
     
     float   tLivingString2_tick                  (tLivingString2* const, float input);
     float   tLivingString2_tickEfficient                 (tLivingString2* const, float input);
+
     float   tLivingString2_udpateDelays(tLivingString2* const pl); //necessary if using tickEfficient (so that parameter setting can be put in a slower process). included in standard tick.
     float   tLivingString2_sample                (tLivingString2* const);
     void    tLivingString2_setFreq               (tLivingString2* const, float freq);
@@ -575,8 +619,6 @@
     void    tLivingString2_setLevStrength        (tLivingString2* const, float levStrength);
     void    tLivingString2_setLevMode            (tLivingString2* const, int levMode);
     void    tLivingString2_setSampleRate         (tLivingString2* const, float sr);
-    
-    
     
     // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
     // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
--- a/leaf/Src/leaf-effects.c
+++ b/leaf/Src/leaf-effects.c
@@ -1061,7 +1061,7 @@
     
     w->loopSize = loopSize;
     w->pitchfactor = 1.;
-    w->delaybuf = (float*) mpool_calloc(sizeof(float) * w->loopSize, m);
+    w->delaybuf = (float*) mpool_calloc(sizeof(float) * (w->loopSize+1), m);
 
     w->timeindex = 0;
     w->xfadevalue = -1;
@@ -1095,7 +1095,7 @@
     {
         float sample = tHighpass_tick(&w->hp, in[0]);
         w->delaybuf[0] = sample;
-        w->delaybuf[w->loopSize-1] = sample;   // copy one sample for interpolation
+        w->delaybuf[w->loopSize] = sample;   // copy one sample for interpolation
         n--;
         i++;
         in++;
@@ -1500,6 +1500,7 @@
     r->bufSize = bufSize;
     r->numVoices = numVoices;
     
+    r->pdBuffer = (float*) mpool_alloc(sizeof(float) * 2048, m);
     r->inBuffer = (float*) mpool_calloc(sizeof(float) * r->bufSize, m);
     r->outBuffer = (float*) mpool_calloc(sizeof(float) * r->bufSize, m);
     
@@ -1510,7 +1511,7 @@
     
     r->minInputFreq = minInputFreq;
     r->maxInputFreq = maxInputFreq;
-    tDualPitchDetector_initToPool(&r->dp, r->minInputFreq, r->maxInputFreq, r->inBuffer, r->bufSize, mp);
+    tDualPitchDetector_initToPool(&r->dp, r->minInputFreq, r->maxInputFreq, r->pdBuffer, 2048, mp);
     
     for (int i = 0; i < r->numVoices; ++i)
     {
@@ -1546,7 +1547,8 @@
     float out = r->outBuffer[r->index];
     r->outBuffer[r->index] = 0.0f;
     
-    if (++r->index >= r->bufSize)
+    r->index++;
+    if (r->index >= r->bufSize)
     {
         for (int i = 0; i < r->numVoices; ++i)
         {
@@ -1696,7 +1698,8 @@
         r->outBuffers[i][r->index] = 0.0f;
     }
 
-    if (++r->index >= r->bufSize)
+    r->index++;
+    if (r->index >= r->bufSize)
     {
         for (int i = 0; i < r->numVoices; ++i)
         {
--- a/leaf/Src/leaf-filters.c
+++ b/leaf/Src/leaf-filters.c
@@ -995,6 +995,17 @@
     svf->a2 = svf->g * svf->a1;
     svf->a3 = svf->g * svf->a2;
 }
+
+void    tEfficientSVF_setFreqAndQ   (tEfficientSVF* const svff, uint16_t input, float Q)
+{
+    _tEfficientSVF* svf = *svff;
+    
+    svf->g = __leaf_table_filtertan[input];
+    svf->k = 1.0f/Q;
+    svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+    svf->a2 = svf->g * svf->a1;
+    svf->a3 = svf->g * svf->a2;
+}
 #endif // LEAF_INCLUDE_FILTERTAN_TABLE
 
 /* Highpass */
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -30,9 +30,10 @@
     c->mempool = m;
     LEAF* leaf = c->mempool->leaf;
     
-    c->inc      =  0.0f;
-    c->phase    =  0.0f;
-    c->invSampleRate = leaf->invSampleRate;
+    c->inc      =  0;
+    c->phase    =  0;
+    c->invSampleRateTimesTwoTo32 = (leaf->invSampleRate * TWO_TO_32);
+    c->mask = SINE_TABLE_SIZE - 1;
 }
 
 void    tCycle_free (tCycle* const cy)
@@ -42,18 +43,6 @@
     mpool_free((char*)c, c->mempool);
 }
 
-void     tCycle_setFreq(tCycle* const cy, float freq)
-{
-    _tCycle* c = *cy;
-    
-    if (!isfinite(freq)) return;
-    
-    c->freq  = freq;
-
-    c->inc = freq * c->invSampleRate;
-    c->inc -= (int)c->inc;
-}
-
 //need to check bounds and wrap table properly to allow through-zero FM
 float   tCycle_tick(tCycle* const cy)
 {
@@ -66,26 +55,43 @@
     
     // 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 = SINE_TABLE_SIZE * c->phase;
-    idx = (int)temp;
+    temp = ((float)c->phase * 0.000000476837158f);
+    idx = ((int)temp) & c->mask;
     frac = temp - (float)idx;
     samp0 = __leaf_table_sinewave[idx];
-    if (++idx >= SINE_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_sinewave[idx];
 
     return (samp0 + (samp1 - samp0) * frac);
 }
 
+void     tCycle_setFreq(tCycle* const cy, float freq)
+{
+    _tCycle* c = *cy;
+    
+    //if (!isfinite(freq)) return;
+    
+    c->freq  = freq;
+    c->inc = freq * c->invSampleRateTimesTwoTo32;
+}
+
+void    tCycle_setPhase(tCycle* const cy, float phase)
+{
+    _tCycle* c = *cy;
+    
+    int i = phase;
+    phase -= i;
+    c->phase = phase * TWO_TO_32;
+}
+
 void     tCycle_setSampleRate (tCycle* const cy, float sr)
 {
     _tCycle* c = *cy;
     
-    c->invSampleRate = 1.0f/sr;
+    c->invSampleRateTimesTwoTo32 = (1.0f/sr) * TWO_TO_32;
     tCycle_setFreq(cy, c->freq);
 }
 #endif // LEAF_INCLUDE_SINE_TABLE
@@ -105,9 +111,11 @@
     c->mempool = m;
     LEAF* leaf = c->mempool->leaf;
     
-    c->inc      =  0.0f;
-    c->phase    =  0.0f;
+    c->inc      =  0;
+    c->phase    =  0;
     c->invSampleRate = leaf->invSampleRate;
+    c->invSampleRateTimesTwoTo32 = (c->invSampleRate * TWO_TO_32);
+    c->mask = TRI_TABLE_SIZE - 1;
     tTriangle_setFreq(cy, 220);
 }
 
@@ -118,26 +126,6 @@
     mpool_free((char*)c, c->mempool);
 }
 
-void tTriangle_setFreq(tTriangle* const cy, float freq)
-{
-    _tTriangle* c = *cy;
-    
-    c->freq = freq;
-    
-    c->inc = c->freq * c->invSampleRate;
-    c->inc -= (int)c->inc;
-    
-    // abs for negative frequencies
-    c->w = fabsf(c->freq * (TRI_TABLE_SIZE * c->invSampleRate));
-    
-    c->w = log2f_approx(c->w);//+ 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;
-    c->oct = (int)c->w;
-    c->w -= c->oct;
-    if (c->oct >= 10) c->oct = 9;
-}
-
-
 float   tTriangle_tick(tTriangle* const cy)
 {
     _tTriangle* c = *cy;
@@ -150,23 +138,22 @@
     
     // 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 = TRI_TABLE_SIZE * c->phase;
+    temp = ((float)c->phase * 0.000000476837158f);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
     frac = temp - (float)idx;
     samp0 = __leaf_table_triangle[c->oct][idx];
-    if (++idx >= TRI_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_triangle[c->oct][idx];
     
     float oct0 = (samp0 + (samp1 - samp0) * frac);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
+    frac = temp - (float)idx;
     samp0 = __leaf_table_triangle[c->oct+1][idx];
-    if (++idx >= TRI_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_triangle[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
@@ -174,11 +161,38 @@
     return oct0 + (oct1 - oct0) * c->w;
 }
 
+void tTriangle_setFreq(tTriangle* const cy, float freq)
+{
+    _tTriangle* c = *cy;
+    
+    c->freq = freq;
+    c->inc = freq * c->invSampleRateTimesTwoTo32;
+    
+    // abs for negative frequencies
+    c->w = fabsf(c->freq * (TRI_TABLE_SIZE * c->invSampleRate));
+    
+    c->w = log2f_approx(c->w);//+ 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;
+    c->oct = (int)c->w;
+    c->w -= c->oct;
+    if (c->oct >= 10) c->oct = 9;
+}
+
+void tTriangle_setPhase(tTriangle* const cy, float phase)
+{
+    _tTriangle* c = *cy;
+    
+    int i = phase;
+    phase -= i;
+    c->phase = phase * TWO_TO_32;
+}
+
 void     tTriangle_setSampleRate (tTriangle* const cy, float sr)
 {
     _tTriangle* c = *cy;
     
     c->invSampleRate = 1.0f/sr;
+    c->invSampleRateTimesTwoTo32 = c->invSampleRate * TWO_TO_32;
     tTriangle_setFreq(cy, c->freq);
 }
 #endif // LEAF_INCLUDE_TRIANGLE_TABLE
@@ -198,9 +212,11 @@
     c->mempool = m;
     LEAF* leaf = c->mempool->leaf;
     
-    c->inc      =  0.0f;
-    c->phase    =  0.0f;
+    c->inc      =  0;
+    c->phase    =  0;
     c->invSampleRate = leaf->invSampleRate;
+    c->invSampleRateTimesTwoTo32 = (c->invSampleRate * TWO_TO_32);
+    c->mask = SQR_TABLE_SIZE - 1;
     tSquare_setFreq(cy, 220);
 }
 
@@ -211,25 +227,6 @@
     mpool_free((char*)c, c->mempool);
 }
 
-void    tSquare_setFreq(tSquare* const cy, float freq)
-{
-    _tSquare* c = *cy;
-
-    c->freq  = freq;
-    
-    c->inc = c->freq * c->invSampleRate;
-    c->inc -= (int)c->inc;
-    
-    // abs for negative frequencies
-    c->w = fabsf(c->freq * (SQR_TABLE_SIZE * c->invSampleRate));
-    
-    c->w = log2f_approx(c->w);//+ 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;
-    c->oct = (int)c->w;
-    c->w -= c->oct;
-    if (c->oct >= 10) c->oct = 9;
-}
-
 float   tSquare_tick(tSquare* const cy)
 {
     _tSquare* c = *cy;
@@ -242,23 +239,22 @@
     
     // 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 = SQR_TABLE_SIZE * c->phase;
+    temp = ((float)c->phase * 0.000000476837158f);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
     frac = temp - (float)idx;
     samp0 = __leaf_table_squarewave[c->oct][idx];
-    if (++idx >= SQR_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_squarewave[c->oct][idx];
     
     float oct0 = (samp0 + (samp1 - samp0) * frac);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
+    frac = temp - (float)idx;
     samp0 = __leaf_table_squarewave[c->oct+1][idx];
-    if (++idx >= SQR_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_squarewave[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
@@ -266,11 +262,38 @@
     return oct0 + (oct1 - oct0) * c->w;
 }
 
+void    tSquare_setFreq(tSquare* const cy, float freq)
+{
+    _tSquare* c = *cy;
+    
+    c->freq  = freq;
+    c->inc = freq * c->invSampleRateTimesTwoTo32;
+    
+    // abs for negative frequencies
+    c->w = fabsf(c->freq * (SQR_TABLE_SIZE * c->invSampleRate));
+    
+    c->w = log2f_approx(c->w);//+ 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;
+    c->oct = (int)c->w;
+    c->w -= c->oct;
+    if (c->oct >= 10) c->oct = 9;
+}
+
+void    tSquare_setPhase(tSquare* const cy, float phase)
+{
+    _tSquare* c = *cy;
+    
+    int i = phase;
+    phase -= i;
+    c->phase = phase * TWO_TO_32;
+}
+
 void     tSquare_setSampleRate (tSquare* const cy, float sr)
 {
     _tSquare* c = *cy;
     
     c->invSampleRate = 1.0f/sr;
+    c->invSampleRateTimesTwoTo32 = c->invSampleRate * TWO_TO_32;
     tSquare_setFreq(cy, c->freq);
 }
 #endif // LEAF_INCLUDE_SQUARE_TABLE
@@ -290,9 +313,11 @@
     c->mempool = m;
     LEAF* leaf = c->mempool->leaf;
     
-    c->inc      = 0.0f;
-    c->phase    = 0.0f;
+    c->inc      = 0;
+    c->phase    = 0;
     c->invSampleRate = leaf->invSampleRate;
+    c->invSampleRateTimesTwoTo32 = (c->invSampleRate * TWO_TO_32);
+    c->mask = SAW_TABLE_SIZE - 1;
     tSawtooth_setFreq(cy, 220);
 }
 
@@ -303,25 +328,6 @@
     mpool_free((char*)c, c->mempool);
 }
 
-void    tSawtooth_setFreq(tSawtooth* const cy, float freq)
-{
-    _tSawtooth* c = *cy;
-    
-    c->freq  = freq;
-    
-    c->inc = c->freq * c->invSampleRate;
-    c->inc -= (int)c->inc;
-    
-    // abs for negative frequencies
-    c->w = fabsf(c->freq * (SAW_TABLE_SIZE * c->invSampleRate));
-    
-    c->w = log2f_approx(c->w);//+ 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 >= 10) c->oct = 9;
-}
-
 float   tSawtooth_tick(tSawtooth* const cy)
 {
     _tSawtooth* c = *cy;
@@ -334,23 +340,22 @@
     
     // Phasor increment
     c->phase += c->inc;
-    while (c->phase >= 1.0f) c->phase -= 1.0f;
-    while (c->phase < 0.0f) c->phase += 1.0f;
     
     // Wavetable synthesis
-    temp = SAW_TABLE_SIZE * c->phase;
+    temp = ((float)c->phase * 0.000000476837158f);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
     frac = temp - (float)idx;
     samp0 = __leaf_table_sawtooth[c->oct][idx];
-    if (++idx >= SAW_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_sawtooth[c->oct][idx];
     
     float oct0 = (samp0 + (samp1 - samp0) * frac);
     
-    idx = (int)temp;
+    idx = ((int)temp) & c->mask;
+    frac = temp - (float)idx;
     samp0 = __leaf_table_sawtooth[c->oct+1][idx];
-    if (++idx >= SAW_TABLE_SIZE) idx = 0;
+    idx = (idx + 1) & c->mask;
     samp1 = __leaf_table_sawtooth[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
@@ -358,11 +363,38 @@
     return oct0 + (oct1 - oct0) * c->w;
 }
 
+void    tSawtooth_setFreq(tSawtooth* const cy, float freq)
+{
+    _tSawtooth* c = *cy;
+    
+    c->freq  = freq;
+    c->inc = freq * c->invSampleRateTimesTwoTo32;
+    
+    // abs for negative frequencies
+    c->w = fabsf(c->freq * (SAW_TABLE_SIZE * c->invSampleRate));
+    
+    c->w = log2f_approx(c->w);//+ 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 >= 10) c->oct = 9;
+}
+
+void tSawtooth_setPhase(tSawtooth* const cy, float phase)
+{
+    _tSawtooth* c = *cy;
+    
+    int i = phase;
+    phase -= i;
+    c->phase = phase * TWO_TO_32;
+}
+
 void     tSawtooth_setSampleRate (tSawtooth* const cy, float sr)
 {
     _tSawtooth* c = *cy;
     
     c->invSampleRate = 1.0f/sr;
+    c->invSampleRateTimesTwoTo32 = c->invSampleRate * TWO_TO_32;
     tSawtooth_setFreq(cy, c->freq);
 }
 #endif // LEAF_INCLUDE_SAWTOOTH_TABLE
@@ -1785,7 +1817,7 @@
     }
     
     c->size = size;
-    
+    c->sizeMask = size-1;
     // Allocate memory for the tables
     c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
     c->baseTable = (float*) mpool_alloc(sizeof(float) * c->size, c->mempool);
@@ -1937,6 +1969,7 @@
     float samp1;
     
     int size = c->table->size;
+    int sizeMask = c->table->sizeMask;
     float** tables = c->table->tables;
     
     // Phasor increment
@@ -1950,6 +1983,7 @@
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[c->oct][idx];
+    idx = (idx + 1) & sizeMask;
     if (++idx >= size) idx = 0;
     samp1 = tables[c->oct][idx];
     
@@ -1957,7 +1991,7 @@
     
     idx = (int)temp;
     samp0 = tables[c->oct+1][idx];
-    if (++idx >= size) idx = 0;
+    idx = (idx + 1) & sizeMask;
     samp1 = tables[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
@@ -2011,132 +2045,144 @@
 //================================================================================================
 //================================================================================================
 
-void    tWaveSynth_init(tWaveSynth* const cy, int numVoices, float** tables, int* sizes,
-                        int numTables, float maxFreq, LEAF* const leaf)
+void tWaveSynth_init(tWaveSynth* const cy, tWaveTable* tables, int size,
+                            int numTables, float maxFreq, LEAF* const leaf)
 {
-    tWaveSynth_initToPool(cy, numVoices, tables, sizes, numTables, maxFreq, &leaf->mempool);
+    tWaveSynth_initToPool(cy, tables, size, numTables, maxFreq, &leaf->mempool);
 }
 
-void    tWaveSynth_initToPool(tWaveSynth* const cy, int numVoices, float** tables, int* sizes,
-                              int numTables, float maxFreq, tMempool* const mp)
+void tWaveSynth_initToPool(tWaveSynth* const cy, tWaveTable* tables, int size,
+                                  int numTables, float maxFreq, tMempool* const mp)
 {
     _tMempool* m = *mp;
     _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;
-    
+    LEAF* leaf = c->mempool->leaf;
+    c->tables =  tables;
+    c->numTables = numTables;
+
     c->index = 0.0f;
+    c->o1 = 0;
+    c->o2 = 1;
+    c->mix = 0.0f;
+    c->phase = 0;
+    c->inc = 0;
+    c->oct = 0;
+    c->size = size;
+    c->w = 0.0f;
+    c->aa = 0.5f;
+    c->sampleRate = leaf->sampleRate;
+    // Determine base frequency
+    c->baseFreq = c->sampleRate / (float) size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    c->numSubTables = c->tables[0]->numTables;
+
+    c->invSampleRateTimesTwoTo32 = leaf->invSampleRate * TWO_TO_32;
     c->maxFreq = maxFreq;
 }
 
-void    tWaveSynth_free(tWaveSynth* const cy)
+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)
+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;
-    
+    // Phasor increment (unsigned 32bit int wraps automatically with overflow so no need for if branch checks, as you need with float)
+    c->phase += c->inc;
+    float floatPhase = (double)c->phase * 2.32830643654e-10;
     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];
-    }
-    
+
+    float temp;
+    int idx;
+    float frac;
+    float samp0;
+    float samp1;
+
+    int oct = c->oct;
+
+    int sizeMask = c->tables[c->o1]->sizeMask;
+    float** tables = c->tables[c->o1]->tables;
+
+    // Wavetable synthesis
+    temp = sizeMask * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct][idx];
+    idx = (idx + 1) & sizeMask;
+    samp1 = tables[oct][idx];
+
+    float oct0 = (samp0 + (samp1 - samp0) * frac);
+
+    temp = sizeMask * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct+1][idx];
+    idx = (idx + 1) & sizeMask;
+    samp1 = tables[oct+1][idx];
+
+    float oct1 = (samp0 + (samp1 - samp0) * frac);
+
+    s1 = oct0 + (oct1 - oct0) * c->w;
+
+    sizeMask = c->tables[c->o2]->sizeMask;
+    tables = c->tables[c->o2]->tables;
+
+    // Wavetable synthesis
+    temp = sizeMask * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct][idx];
+    idx = (idx + 1) & sizeMask;
+    samp1 = tables[oct][idx];
+
+    oct0 = (samp0 + (samp1 - samp0) * frac);
+
+    temp = sizeMask * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct+1][idx];
+    idx = (idx + 1) & sizeMask;
+    samp1 = tables[oct+1][idx];
+
+    oct1 = (samp0 + (samp1 - samp0) * frac);
+
+    s2 = oct0 + (oct1 - oct0) * c->w;
+
     // Ideally should determine correlation to get a good equal power fade between tables
-    return s1 + (s2 - s1) * mix;
+    return s1 + (s2 - s1) * c->mix;
 }
 
-void tWaveSynth_setFreq(tWaveSynth* const cy, int voice, float freq)
+void tWaveSynth_setFreq(tWaveSynth* const cy, float freq)
 {
     _tWaveSynth* c = *cy;
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        tWaveOsc_setFreq(&c->oscs[t][voice], freq);
-    }
+
+    c->freq  = freq;
+
+    c->inc = c->freq * c->invSampleRateTimesTwoTo32;
+
+    // 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
+    // I bet we could turn this into a lookup and save a lot of processing
+    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->numSubTables - 1) c->oct = c->numSubTables - 2;
 }
 
 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);
-        }
-    }
+    c->aa = aa;
 }
 
 void tWaveSynth_setIndex(tWaveSynth* const cy, float index)
@@ -2143,33 +2189,54 @@
 {
     _tWaveSynth* c = *cy;
     c->index = index;
+    float f = c->index * (c->numTables - 1);
+
+    c->o1 = (int)f;
+    c->o2 = c->o1 + 1;
+    if (c->index >= 1.0f) c->o2 = c->o1;
+    c->mix = f - c->o1;
 }
 
-void tWaveSynth_setIndexGain(tWaveSynth* const cy, int i, float gain)
+void tWaveSynth_setTables(tWaveSynth* const cy, tWaveTable* tables, int numTables, int size)
 {
     _tWaveSynth* c = *cy;
-    if (i >= c->numTables) return;
-    c->g[i] = gain;
+    LEAF* leaf = c->mempool->leaf;
+    c->tables =  tables;
+    c->numTables = numTables;
+    c->size = size;
+
+    c->sampleRate = leaf->sampleRate;
+    // Determine base frequency
+    c->baseFreq = c->sampleRate / (float) size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    c->numSubTables = c->tables[0]->numTables;
+
 }
 
-void tWaveSynth_setIndexPhase(tWaveSynth* const cy, int i, float phase)
+/*//// eventually gotta finish this so you can X/Y control the indices and fade between non-adjacent tables
+void tWaveSynthS_setIndexXY(tWaveSynthS* const cy, float indexX, float indexY)
 {
-    _tWaveSynth* c = *cy;
-    if (i >= c->numTables) return;
-    for (int v = 0; v < c->numVoices; ++v)
-    {
-        tWaveOsc_setPhaseOffset(&c->oscs[i][v], phase);
-    }
+    _tWaveSynthS* c = *cy;
+    c->index = index;
+    float f1 = c->index * (c->numTables - 1);
+
+    c->o1 = (int)f1;
+    c->o2 = c->o1 + 1;
+    if (c->index >= 1.0f) c->o2 = c->o1;
+    c->mix = f1 - c->o1;
+
+    float f2 = c->index * (c->numTables - 1);
 }
+*/
 
 void tWaveSynth_setSampleRate(tWaveSynth* const cy, float sr)
 {
     _tWaveSynth* c = *cy;
-    
+    //TODO: need to fix this -JS
     for (int i = 0; i < c->numTables; ++i)
     {
         tWaveTable_setSampleRate(&c->tables[i], sr);
-        for (int v = 0; v < c->numVoices; ++v) tWaveOsc_setSampleRate(&c->oscs[i][v], sr);
+        //tWaveSubOscS_setSampleRate(&c->oscs[i], sr);
     }
 }
 
@@ -2209,11 +2276,13 @@
     c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
     c->sizes = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
     c->sizes[0] = size;
+    c->sizeMasks[0] = (size - 1);
     c->baseTable = (float*) mpool_alloc(sizeof(float) * c->sizes[0], c->mempool);
     c->tables[0] = c->baseTable;
     for (int t = 1; t < c->numTables; ++t)
     {
-        c->sizes[t] = c->sizes[t-1] / 2;
+        c->sizes[t] = c->sizes[t-1] / 2 > 128 ? c->sizes[t-1] / 2 : 128;
+        c->sizeMasks[t] = (c->sizes[t] - 1);
         c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->sizes[t], c->mempool);
     }
     
@@ -2224,21 +2293,38 @@
     }
     
     // Make bandlimited copies
+    f = c->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, c->sampleRate * 0.25f, mp);
+    tButterworth_initToPool(&c->bl, 8, -1.0f, f, 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)
+        // Size is going down; we need to downsample
+        if (c->sizes[t] < c->sizes[t-1])
         {
-            for (int i = 0; i < c->sizes[t]; ++i)
+            // Similar to tWaveTable, doing multiple passes here helps, but not sure what number is optimal
+            for (int p = 0; p < 12; ++p)
             {
-                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);
+                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);
+                }
             }
         }
+        else
+        {
+            tButterworth_setF2(&c->bl, f);
+            for (int p = 0; p < 12; ++p)
+            {
+                for (int i = 0; i < c->sizes[t]; ++i)
+                {
+                    c->tables[t][i] = tButterworth_tick(&c->bl, c->tables[t-1][i]);
+                }
+            }
+            f *= 0.5f; //halve the cutoff for next pass
+        }
     }
     tOversampler_free(&c->ds);
     tButterworth_free(&c->bl);
@@ -2333,6 +2419,8 @@
     c->mempool = m;
     LEAF* leaf = c->mempool->leaf;
     
+    c->table = *table;
+
     c->invSampleRate = leaf->invSampleRate;
     c->inc = 0.0f;
     c->phase = 0.0f;
@@ -2364,6 +2452,7 @@
     if (c->phase < 0.0f) c->phase += 1.0f;
     
     int* sizes = c->table->sizes;
+    int* sizeMasks = c->table->sizeMasks;
     float** tables = c->table->tables;
     
     // Wavetable synthesis
@@ -2371,16 +2460,16 @@
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[c->oct][idx];
-    if (++idx >= sizes[c->oct]) idx = 0;
+    idx = (idx + 1) & sizeMasks[c->oct];
     samp1 = tables[c->oct][idx];
     
     float oct0 = (samp0 + (samp1 - samp0) * frac);
     
-    temp = sizes[c->oct+1] * c->phase;
+    temp = sizes[c->oct+1] * (c->phase + c->phaseOffset);
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[c->oct+1][idx];
-    if (++idx >= sizes[c->oct+1]) idx = 0;
+    idx = (idx + 1) & sizeMasks[c->oct + 1];
     samp1 = tables[c->oct+1][idx];
     
     float oct1 = (samp0 + (samp1 - samp0) * frac);
@@ -2401,6 +2490,7 @@
     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
+    // I bet we could turn this into a lookup and save a lot of processing
     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;
@@ -2431,46 +2521,118 @@
 //================================================================================================
 //================================================================================================
 
-void tWaveSynthS_init(tWaveSynthS* const cy, int numVoices, float** tables, int* sizes,
+
+
+
+
+void tWaveSubOscS_init(tWaveSubOscS* const cy, tWaveTableS* const table, LEAF* const leaf)
+{
+    tWaveSubOscS_initToPool(cy, table, &leaf->mempool);
+}
+
+void tWaveSubOscS_initToPool(tWaveSubOscS* const cy, tWaveTableS* const table, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tWaveSubOscS* c = *cy = (_tWaveSubOscS*) mpool_alloc(sizeof(_tWaveSubOscS), m);
+    c->mempool = m;
+
+    c->table = *table;
+}
+
+void tWaveSubOscS_free(tWaveSubOscS* const cy)
+{
+    _tWaveSubOscS* c = *cy;
+    mpool_free((char*)c, c->mempool);
+}
+
+float tWaveSubOscS_tick(tWaveSubOscS* const cy, float phase, int oct, float w)
+{
+    _tWaveSubOscS* c = *cy;
+
+    float temp;
+    int idx;
+    float frac;
+    float samp0;
+    float samp1;
+
+    int* sizes = c->table->sizes;
+    int* sizeMasks = c->table->sizeMasks;
+    float** tables = c->table->tables;
+
+    // Wavetable synthesis
+    temp = sizes[oct] * phase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct][idx];
+    idx = (idx + 1) & sizeMasks[oct];
+    samp1 = tables[oct][idx];
+
+    float oct0 = (samp0 + (samp1 - samp0) * frac);
+
+    temp = sizes[oct+1] * phase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct+1][idx];
+    idx = (idx + 1) & sizeMasks[oct+1];
+    samp1 = tables[oct+1][idx];
+
+    float oct1 = (samp0 + (samp1 - samp0) * frac);
+
+    return oct0 + (oct1 - oct0) * w;
+}
+
+
+
+
+
+//================================================================================================
+//================================================================================================
+
+void tWaveSynthS_init(tWaveSynthS* const cy, tWaveTableS* tables, int size,
                             int numTables, float maxFreq, LEAF* const leaf)
 {
-    tWaveSynthS_initToPool(cy, numVoices, tables, sizes, numTables, maxFreq, &leaf->mempool);
+    tWaveSynthS_initToPool(cy, tables, size, numTables, maxFreq, &leaf->mempool);
 }
 
-void tWaveSynthS_initToPool(tWaveSynthS* const cy, int numVoices, float** tables, int* sizes,
+void tWaveSynthS_initToPool(tWaveSynthS* const cy, tWaveTableS* tables, int size,
                                   int numTables, float maxFreq, tMempool* const mp)
 {
     _tMempool* m = *mp;
     _tWaveSynthS* c = *cy = (_tWaveSynthS*) mpool_alloc(sizeof(_tWaveSynthS), m);
+
     c->mempool = m;
+
+    LEAF* leaf = c->mempool->leaf;
+    c->tables =  tables;
+    c->numTables = numTables;
     
-    c->numTables = 0;
-    for (int t = 0; t < numTables; ++t)
-    {
-        if (sizes[t] > 0) c->numTables++;
-    }
+    //c->oscs = (tWaveSubOscS*) mpool_alloc(sizeof(tWaveSubOscS*) * c->numTables, m);
+
+//    int i = 0;
+    //for (int t = 0; t < numTables; ++t)
+    //{
+		//tWaveTableS_initToPool(&c->tables[i], table + (size*t), size, maxFreq, mp); //is the sizeoffloat necessary? is the pointer location in bytes or 32-bit words?
+		//tWaveSubOscS_initToPool(&c->oscs[i], tables[i], mp);
+		//i++;
+    //}
     
-    c->tables = (tWaveTableS*) mpool_alloc(sizeof(tWaveTableS) * c->numTables, m);
-    c->oscs = (tWaveOscS**) mpool_alloc(sizeof(tWaveOscS*) * c->numTables, m);
-    
-    c->numVoices = numVoices;
-    
-    int i = 0;
-    for (int t = 0; t < numTables; ++t)
-    {
-        if (sizes[t] > 0)
-        {
-            tWaveTableS_initToPool(&c->tables[i], tables[t], sizes[t], maxFreq, mp);
-            c->oscs[i] = (tWaveOscS*) mpool_alloc(sizeof(tWaveOscS) * c->numVoices, m);
-            for (int v = 0; v < c->numVoices; ++v) tWaveOscS_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->o1 = 0;
+    c->o2 = 1;
+    c->mix = 0.0f;
+    c->phase = 0;
+    c->inc = 0;
+    c->oct = 0;
+    c->size = size;
+    c->w = 0.0f;
+    c->aa = 0.5f;
+    c->sampleRate = leaf->sampleRate;
+    // Determine base frequency
+    c->baseFreq = c->sampleRate / (float) size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    c->numSubTables = c->tables[0]->numTables;
+
+    c->invSampleRateTimesTwoTo32 = leaf->invSampleRate * TWO_TO_32;
     c->maxFreq = maxFreq;
 }
 
@@ -2480,83 +2642,115 @@
     
     for (int i = 0; i < c->numTables; ++i)
     {
-        tWaveTableS_free(&c->tables[i]);
-        for (int v = 0; v < c->numVoices; ++v) tWaveOscS_free(&c->oscs[i][v]);
-        mpool_free((char*)c->oscs[i], c->mempool);
+        //tWaveSubOscS_free(&c->oscs[i]);
+        //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->oscs, c->mempool);
     mpool_free((char*)c, c->mempool);
 }
 
+volatile int errorCounter = 0;
 float tWaveSynthS_tick(tWaveSynthS* const cy)
 {
     _tWaveSynthS* 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;
-    
+    // Phasor increment (unsigned 32bit int wraps automatically with overflow so no need for if branch checks, as you need with float)
+    c->phase += c->inc;
+    float floatPhase = (double)c->phase * 2.32830643654e-10;
     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 += tWaveOscS_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 tWaveSynthS_tickVoice(tWaveSynthS* const cy, int voice)
-{
-    _tWaveSynthS* 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 = tWaveOscS_tick(&c->oscs[t][voice]);
-        if (t == o1) s1 = s0 * c->g[t];
-        if (t == o2) s2 = s0 * c->g[t];
-    }
-    
+    //s1 = tWaveSubOscS_tick(&c->oscs[c->o1], floatPhase, c->oct, c->w);
+    //s2 = tWaveSubOscS_tick(&c->oscs[c->o2], floatPhase, c->oct, c->w);
+
+
+    float temp;
+    int idx;
+    float frac;
+    float samp0;
+    float samp1;
+
+    int oct = c->oct;
+
+
+    int* sizeMasks = c->tables[c->o1]->sizeMasks;
+    float** tables = c->tables[c->o1]->tables;
+
+    // Wavetable synthesis
+    temp = sizeMasks[oct] * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct][idx];
+    idx = (idx + 1) & sizeMasks[oct];
+    samp1 = tables[oct][idx];
+
+    float oct0 = (samp0 + (samp1 - samp0) * frac);
+
+
+
+    temp = sizeMasks[oct+1] * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct+1][idx];
+    idx = (idx + 1) & sizeMasks[oct+1];
+    samp1 = tables[oct+1][idx];
+
+    float oct1 = (samp0 + (samp1 - samp0) * frac);
+
+    s1 = oct0 + (oct1 - oct0) * c->w;
+
+
+    sizeMasks = c->tables[c->o2]->sizeMasks;
+    tables = c->tables[c->o2]->tables;
+
+    // Wavetable synthesis
+    temp = sizeMasks[oct] * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct][idx];
+    idx = (idx + 1) & sizeMasks[oct];
+    samp1 = tables[oct][idx];
+
+    oct0 = (samp0 + (samp1 - samp0) * frac);
+
+    temp = sizeMasks[oct+1] * floatPhase;
+    idx = (int)temp;
+    frac = temp - (float)idx;
+    samp0 = tables[oct+1][idx];
+    idx = (idx + 1) & sizeMasks[oct+1];
+    samp1 = tables[oct+1][idx];
+
+    oct1 = (samp0 + (samp1 - samp0) * frac);
+
+    s2 = oct0 + (oct1 - oct0) * c->w;
+
     // Ideally should determine correlation to get a good equal power fade between tables
-    return s1 + (s2 - s1) * mix;
+    return s1 + (s2 - s1) * c->mix;
 }
 
-void tWaveSynthS_setFreq(tWaveSynthS* const cy, int voice, float freq)
+void tWaveSynthS_setFreq(tWaveSynthS* const cy, float freq)
 {
     _tWaveSynthS* c = *cy;
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        tWaveOscS_setFreq(&c->oscs[t][voice], freq);
-    }
+
+    c->freq  = freq;
+
+    c->inc = c->freq * c->invSampleRateTimesTwoTo32;
+
+    // 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
+    // I bet we could turn this into a lookup and save a lot of processing
+    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->numSubTables - 1) c->oct = c->numSubTables - 2;
 }
 
 void tWaveSynthS_setAntiAliasing(tWaveSynthS* const cy, float aa)
 {
     _tWaveSynthS* c = *cy;
-    for (int t = 0; t < c->numTables; ++t)
-    {
-        for (int v = 0; v < c->numVoices; ++v)
-        {
-            tWaveOscS_setAntiAliasing(&c->oscs[t][v], aa);
-        }
-    }
+    c->aa = aa;
 }
 
 void tWaveSynthS_setIndex(tWaveSynthS* const cy, float index)
@@ -2563,32 +2757,38 @@
 {
     _tWaveSynthS* c = *cy;
     c->index = index;
-}
+    float f = c->index * (c->numTables - 1);
 
-void tWaveSynthS_setIndexGain(tWaveSynthS* const cy, int i, float gain)
-{
-    _tWaveSynthS* c = *cy;
-    if (i >= c->numTables) return;
-    c->g[i] = gain;
+    c->o1 = (int)f;
+    c->o2 = c->o1 + 1;
+    if (c->index >= 1.0f) c->o2 = c->o1;
+    c->mix = f - c->o1;
 }
 
-void tWaveSynthS_setIndexPhase(tWaveSynthS* const cy, int i, float phase)
+/*//// eventually gotta finish this so you can X/Y control the indices and fade between non-adjacent tables
+void tWaveSynthS_setIndexXY(tWaveSynthS* const cy, float indexX, float indexY)
 {
     _tWaveSynthS* c = *cy;
-    if (i >= c->numTables) return;
-    for (int v = 0; v < c->numVoices; ++v)
-    {
-        tWaveOscS_setPhaseOffset(&c->oscs[i][v], phase);
-    }
+    c->index = index;
+    float f1 = c->index * (c->numTables - 1);
+
+    c->o1 = (int)f1;
+    c->o2 = c->o1 + 1;
+    if (c->index >= 1.0f) c->o2 = c->o1;
+    c->mix = f1 - c->o1;
+
+    float f2 = c->index * (c->numTables - 1);
 }
+*/
 
 void tWaveSynthS_setSampleRate(tWaveSynthS* const cy, float sr)
 {
     _tWaveSynthS* c = *cy;
+    //TODO: need to fix this -JS
     for (int i = 0; i < c->numTables; ++i)
     {
         tWaveTableS_setSampleRate(&c->tables[i], sr);
-        for (int v = 0; v < c->numVoices; ++v) tWaveOscS_setSampleRate(&c->oscs[i][v], sr);
+        //tWaveSubOscS_setSampleRate(&c->oscs[i], sr);
     }
 }
 //
--- a/leaf/Src/leaf-physical.c
+++ b/leaf/Src/leaf-physical.c
@@ -498,6 +498,141 @@
     tHighpass_setSampleRate(&p->DCblocker, p->sampleRate);
 }
 
+
+
+/* Simple Living String*/
+
+void    tSimpleLivingString2_init(tSimpleLivingString2* const pl, float freq, float brightness,
+                                 float decay, float targetLev, float levSmoothFactor,
+                                 float levStrength, int levMode, LEAF* const leaf)
+{
+    tSimpleLivingString2_initToPool(pl, freq, brightness, decay, targetLev, levSmoothFactor, levStrength, levMode, &leaf->mempool);
+}
+
+void    tSimpleLivingString2_initToPool  (tSimpleLivingString2* const pl, float freq, float brightness,
+                                         float decay, float targetLev, float levSmoothFactor,
+                                         float levStrength, int levMode, tMempool* const mp)
+{
+    _tMempool* m = *mp;
+    _tSimpleLivingString2* p = *pl = (_tSimpleLivingString2*) mpool_alloc(sizeof(_tSimpleLivingString2), m);
+    p->mempool = m;
+    LEAF* leaf = p->mempool->leaf;
+
+    p->sampleRate = leaf->sampleRate;
+    p->curr=0.0f;
+    tExpSmooth_initToPool(&p->wlSmooth, p->sampleRate/freq, 0.01f, mp); // smoother for string wavelength (not freq, to avoid expensive divisions)
+    tSimpleLivingString2_setFreq(pl, freq);
+    tHermiteDelay_initToPool(&p->delayLine,p->waveLengthInSamples, 2400, mp);
+    tHermiteDelay_clear(&p->delayLine);
+    tTwoZero_initToPool(&p->bridgeFilter, mp);
+    tSimpleLivingString2_setBrightness(pl, brightness);
+    tHighpass_initToPool(&p->DCblocker,13, mp);
+    p->decay=decay;
+    tFeedbackLeveler_initToPool(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode, mp);
+    p->levMode=levMode;
+}
+
+void    tSimpleLivingString2_free (tSimpleLivingString2* const pl)
+{
+    _tSimpleLivingString2* p = *pl;
+
+    tExpSmooth_free(&p->wlSmooth);
+    tHermiteDelay_free(&p->delayLine);
+    tTwoZero_free(&p->bridgeFilter);
+    tHighpass_free(&p->DCblocker);
+    tFeedbackLeveler_free(&p->fbLev);
+
+    mpool_free((char*)p, p->mempool);
+}
+
+void     tSimpleLivingString2_setFreq(tSimpleLivingString2* const pl, float freq)
+{
+    _tSimpleLivingString2* p = *pl;
+
+    if (freq<20) freq=20;
+    else if (freq>10000) freq=10000;
+    p->waveLengthInSamples = p->sampleRate/freq -1;
+    tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+}
+
+void     tSimpleLivingString2_setWaveLength(tSimpleLivingString2* const pl, float waveLength)
+{
+    _tSimpleLivingString2* p = *pl;
+
+    if (waveLength<4.8) waveLength=4.8f;
+    else if (waveLength>2400) waveLength=2400;
+    p->waveLengthInSamples = waveLength-1;
+    tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+}
+
+void     tSimpleLivingString2_setBrightness(tSimpleLivingString2* const pl, float brightness)
+{
+    _tSimpleLivingString2* p = *pl;
+    float h0=(1.0 + brightness) * 0.5f;
+    float h1=(1.0 - brightness) * 0.25f;
+    tTwoZero_setCoefficients(&p->bridgeFilter, h1, h0, h1);
+}
+
+void     tSimpleLivingString2_setDecay(tSimpleLivingString2* const pl, float decay)
+{
+    _tSimpleLivingString2* p = *pl;
+    p->decay=decay;
+}
+
+void     tSimpleLivingString2_setTargetLev(tSimpleLivingString2* const pl, float targetLev)
+{
+    _tSimpleLivingString2* p = *pl;
+    tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev);
+}
+
+void     tSimpleLivingString2_setLevSmoothFactor(tSimpleLivingString2* const pl, float levSmoothFactor)
+{
+    _tSimpleLivingString2* p = *pl;
+    tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor);
+}
+
+void     tSimpleLivingString2_setLevStrength(tSimpleLivingString2* const pl, float levStrength)
+{
+    _tSimpleLivingString2* p = *pl;
+    tFeedbackLeveler_setStrength(&p->fbLev, levStrength);
+}
+
+void     tSimpleLivingString2_setLevMode(tSimpleLivingString2* const pl, int levMode)
+{
+    _tSimpleLivingString2* p = *pl;
+    tFeedbackLeveler_setMode(&p->fbLev, levMode);
+    p->levMode=levMode;
+}
+
+float   tSimpleLivingString2_tick(tSimpleLivingString2* const pl, float input)
+{
+    _tSimpleLivingString2* p = *pl;
+
+    float stringOut=tTwoZero_tick(&p->bridgeFilter,tHermiteDelay_tickOut(&p->delayLine));
+    float stringInput=tHighpass_tick(&p->DCblocker,(tFeedbackLeveler_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input)));
+    tHermiteDelay_tickIn(&p->delayLine, stringInput);
+    tHermiteDelay_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth));
+    p->curr = stringOut;
+    return p->curr;
+}
+
+
+float   tSimpleLivingString2_sample(tSimpleLivingString2* const pl)
+{
+    _tSimpleLivingString2* p = *pl;
+    return p->curr;
+}
+
+void   tSimpleLivingString2_setSampleRate(tSimpleLivingString2* const pl, float sr)
+{
+    _tSimpleLivingString2* p = *pl;
+    float freq = p->sampleRate/p->waveLengthInSamples;
+    p->sampleRate = sr;
+    p->waveLengthInSamples = p->sampleRate/freq;
+    tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+    tTwoZero_setSampleRate(&p->bridgeFilter, p->sampleRate);
+    tHighpass_setSampleRate(&p->DCblocker, p->sampleRate);
+}
 /* Living String*/
 
 void    tLivingString_init(tLivingString* const pl, float freq, float pickPos, float prepIndex,
@@ -754,8 +889,9 @@
     tTwoZero_initToPool(&p->nutFilter, mp);
     tTwoZero_initToPool(&p->prepFilterU, mp);
     tTwoZero_initToPool(&p->prepFilterL, mp);
-    tHighpass_initToPool(&p->DCblockerU,13, mp);
-    tHighpass_initToPool(&p->DCblockerL,13, mp);
+    tLivingString2_setBrightness(pl, brightness);
+    tHighpass_initToPool(&p->DCblockerU,8, mp);
+    tHighpass_initToPool(&p->DCblockerL,8, mp);
     p->decay=decay;
     p->prepIndex = prepIndex;
     tFeedbackLeveler_initToPool(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode, mp);
@@ -910,30 +1046,30 @@
     float lowLen=prepP*wLen;
     float upLen=(1.0f-prepP)*wLen;
     uint32_t pickPInt;
-/*
+
     if (pickP > prepP)
     {
         float fullPickPoint =  ((pickP*wLen) - lowLen);
-        pickPInt = (uint) fullPickPoint; // where does the input go? that's the pick point
+        pickPInt = (uint32_t) fullPickPoint; // where does the input go? that's the pick point
         float pickPFloat = fullPickPoint - pickPInt;
 
         tHermiteDelay_addTo(&p->delUF, input * (1.0f - pickPFloat), pickPInt);
         tHermiteDelay_addTo(&p->delUF, input * pickPFloat, pickPInt + 1);
-        tHermiteDelay_addTo(&p->delUB, input * (1.0f - pickPFloat), (uint) (upLen - pickPInt));
-        tHermiteDelay_addTo(&p->delUB, input * pickPFloat, (uint) (upLen - pickPInt - 1));
+        tHermiteDelay_addTo(&p->delUB, input * (1.0f - pickPFloat), (uint32_t) (upLen - pickPInt));
+        tHermiteDelay_addTo(&p->delUB, input * pickPFloat, (uint32_t) (upLen - pickPInt - 1));
     }
     else
     {
          float fullPickPoint =  pickP * wLen;
-        pickPInt = (uint) fullPickPoint; // where does the input go? that's the pick point
+        pickPInt = (uint32_t) fullPickPoint; // where does the input go? that's the pick point
         float pickPFloat = fullPickPoint - pickPInt;
 
         tHermiteDelay_addTo(&p->delLF, input * (1.0f - pickPFloat), pickPInt);
         tHermiteDelay_addTo(&p->delLF, input * pickPFloat, pickPInt + 1);
-        tHermiteDelay_addTo(&p->delLB, input * (1.0f - pickPFloat), (uint) (lowLen - pickPInt));
-        tHermiteDelay_addTo(&p->delLB, input * pickPFloat, (uint) (lowLen - pickPInt - 1));
+        tHermiteDelay_addTo(&p->delLB, input * (1.0f - pickPFloat), (uint32_t) (lowLen - pickPInt));
+        tHermiteDelay_addTo(&p->delLB, input * pickPFloat, (uint32_t) (lowLen - pickPInt - 1));
     }
-*/
+/*
     if (pickP > prepP)
     {
         float fullPickPoint =  ((pickP*wLen) - lowLen);
@@ -950,13 +1086,13 @@
         tHermiteDelay_addTo(&p->delLF, input, pickPInt);
         tHermiteDelay_addTo(&p->delLB, input, (uint32_t) (lowLen - pickPInt));
     }
-
+*/
     float fromLF=tHermiteDelay_tickOut(&p->delLF);
     float fromUF=tHermiteDelay_tickOut(&p->delUF);
     float fromUB=tHermiteDelay_tickOut(&p->delUB);
     float fromLB=tHermiteDelay_tickOut(&p->delLB);
     // into upper half of string, from bridge, going backwards
-    float fromBridge=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tTwoZero_tick(&p->bridgeFilter, fromUF)));
+    float fromBridge=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1.0f)*tHighpass_tick(&p->DCblockerU, tTwoZero_tick(&p->bridgeFilter, fromUF)));
     tHermiteDelay_tickIn(&p->delUB, fromBridge);
     // into lower half of string, from prepPoint, going backwards
     float fromLowerPrep=-tTwoZero_tick(&p->prepFilterL, fromLF);
@@ -976,11 +1112,41 @@
     tHermiteDelay_setDelay(&p->delUF, upLen);
     tHermiteDelay_setDelay(&p->delUB, upLen);
     
-    uint32_t pickupPosInt;
+    uint32_t PUPInt;
     float pickupOut = 0.0f;
-    if (p->pickupPos < 0.98f)
+    float pupos = tExpSmooth_tick(&p->puSmooth);
+    if (pupos < 0.9999f)
     {
-        float fullPickupPos = (p->pickupPos*upLen);
+        if (pupos > prepP)
+        {
+            float fullPUPoint =  ((pupos*wLen) - lowLen);
+            PUPInt = (uint32_t) fullPUPoint; // where does the input go? that's the pick point
+            float PUPFloat = fullPUPoint - PUPInt;
+
+            pickupOut = tHermiteDelay_tapOut(&p->delUF, PUPInt) * (1.0f - PUPFloat);
+            pickupOut += tHermiteDelay_tapOut(&p->delUF, PUPInt + 1) * PUPFloat;
+            pickupOut += tHermiteDelay_tapOut(&p->delUB, (uint32_t) (upLen - PUPInt)) * (1.0f - PUPFloat);
+            pickupOut += tHermiteDelay_tapOut(&p->delUB, (uint32_t) (upLen - PUPInt - 1))  * PUPFloat;
+        }
+        else
+        {
+             float fullPUPoint =  pupos * wLen;
+            PUPInt = (uint32_t) fullPUPoint; // where does the input go? that's the pick point
+            float PUPFloat = fullPUPoint - PUPInt;
+
+            pickupOut = tHermiteDelay_tapOut(&p->delLF, PUPInt) * (1.0f - PUPFloat);
+            pickupOut += tHermiteDelay_tapOut(&p->delLF,  PUPInt + 1) * PUPFloat;
+            pickupOut += tHermiteDelay_tapOut(&p->delLB, (uint32_t) (lowLen - PUPInt)) * (1.0f - PUPFloat);
+            pickupOut += tHermiteDelay_tapOut(&p->delLB, (uint32_t) (lowLen - PUPInt - 1)) * PUPFloat;
+        }
+
+        p->curr = pickupOut;
+
+
+
+
+/*
+    	float fullPickupPos = (pupos*upLen);
         pickupPosInt = (uint32_t) fullPickupPos;
         float pickupPosFloat = fullPickupPos - pickupPosInt;
         if (pickupPosInt == 0)
@@ -990,6 +1156,7 @@
         pickupOut = tHermiteDelay_tapOutInterpolated(&p->delUF, pickupPosInt, pickupPosFloat);
         pickupOut += tHermiteDelay_tapOutInterpolated(&p->delUB, (uint32_t) (upLen - pickupPosInt), pickupPosFloat);
         p->curr = pickupOut;
+        */
     }
     else
     
@@ -1065,19 +1232,16 @@
     return p->curr;
 }
 
+
 float   tLivingString2_udpateDelays(tLivingString2* const pl)
 {
     _tLivingString2* p = *pl;
 
-
-
     //need to determine which delay line to put it into (should be half amplitude into forward and backward lines for the correct portion of string)
 
     float lowLen=p->prpSmooth->dest*p->wlSmooth->dest;
     float upLen=(1.0f-p->prpSmooth->dest)*p->wlSmooth->dest;
 
-
-
 	tHermiteDelay_setDelay(&p->delLF, lowLen);
     tHermiteDelay_setDelay(&p->delLB, lowLen);
     tHermiteDelay_setDelay(&p->delUF, upLen);
@@ -1103,6 +1267,7 @@
     tHighpass_setSampleRate(&p->DCblockerU, p->sampleRate);
     tHighpass_setSampleRate(&p->DCblockerL, p->sampleRate);
 }
+
 
 //////////---------------------------
 
--- a/leaf/leaf-config.h
+++ b/leaf/leaf-config.h
@@ -58,8 +58,13 @@
 
 #define LEAF_USE_CMSIS 0
 
+#ifdef __cplusplus
 //! Use stdlib malloc() and free() internally instead of LEAF's normal mempool behavior for when you want to avoid being limited to and managing mempool a fixed mempool size. Usage of all object remains essentially the same.
+
+#define LEAF_USE_DYNAMIC_ALLOCATION 1
+#else
 #define LEAF_USE_DYNAMIC_ALLOCATION 0
+#endif
 
 //==============================================================================