shithub: leaf

Download patch

ref: dd56c541b544e4ac9a6e81c1cd367d08b127b2cd
parent: 7803edf0b50bd7e394b618d8eaa4fb97de600bd6
author: Matthew Wang <Matthew@nat-oitwireless-inside-vapornet100-10-9-82-139.princeton.edu>
date: Fri Oct 25 11:39:20 EDT 2019

replace pitchshifter with retune and autotune

binary files a/LEAF/Inc/.DS_Store b/LEAF/Inc/.DS_Store differ
--- a/LEAF/Inc/leaf-effects.h
+++ b/LEAF/Inc/leaf-effects.h
@@ -86,7 +86,7 @@
 
 // ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
-/* tSOLAD : pitch shifting algorithm that underlies tPitchShifter etc */
+/* tSOLAD : pitch shifting algorithm that underlies tRetune etc */
 #define LOOPSIZE (2048*2)      // (4096*2) // loop size must be power of two
 #define LOOPMASK (LOOPSIZE - 1)
 #define PITCHFACTORDEFAULT 1.0f
@@ -111,99 +111,122 @@
 
 void    tSOLAD_init             (tSOLAD* const);
 void    tSOLAD_free             (tSOLAD* const);
-
 // send one block of input samples, receive one block of output samples
 void    tSOLAD_ioSamples        (tSOLAD *w, float* in, float* out, int blocksize);
-
 // set periodicity analysis data
 void    tSOLAD_setPeriod        (tSOLAD *w, float period);
-
 // set pitch factor between 0.25 and 4
 void    tSOLAD_setPitchFactor   (tSOLAD *w, float pitchfactor);
-
 // force readpointer lag
 void    tSOLAD_setReadLag       (tSOLAD *w, float readlag);
-
 // reset state variables
 void    tSOLAD_resetState       (tSOLAD *w);
     
-// Pitch shifter
-typedef struct _tPitchShifter
+// Pitch shift
+typedef struct _tPitchShift
 {
-    tEnvPD env;
-    tSNAC snac;
     tSOLAD sola;
     tHighpass hp;
+    tPeriodDetection* p;
     
-    float* inBuffer;
     float* outBuffer;
     int frameSize;
     int bufSize;
+    
     int framesPerBuffer;
     int curBlock;
     int lastBlock;
     int index;
     
+    float pitchFactor;
+    float timeConstant;
+    float radius;
+} tPitchShift;
+
+void        tPitchShift_init                (tPitchShift* const, tPeriodDetection* const, float* out, int bufSize);
+void        tPitchShift_free                (tPitchShift* const);
+float       tPitchShift_shift               (tPitchShift* const);
+float       tPitchShift_shiftToFunc         (tPitchShift* const, float (*fun)(float));
+float       tPitchShift_shiftToFreq         (tPitchShift* const, float freq);
+void        tPitchShift_setPitchFactor      (tPitchShift* const, float pf);
+    
+// Retune
+typedef struct _tRetune
+{
+    tPeriodDetection pd;
+    tPitchShift* ps;
+    
+    float* inBuffer;
+    float** outBuffers;
+    float* tickOutput;
+    int frameSize;
+    int bufSize;
+    
     uint16_t hopSize;
     uint16_t windowSize;
     uint8_t fba;
     
-    float pitchFactor;
+    float* pitchFactor;
     float timeConstant;
     float radius;
-    float max;
-    float lastmax;
-    float deltamax;
     
-} tPitchShifter;
+    float inputPeriod;
+    
+    int numVoices;
+} tRetune;
 
-void        tPitchShifter_init              (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize);
-void        tPitchShifter_free              (tPitchShifter* const);
+void        tRetune_init                (tRetune* const, int numVoices, int bufSize, int frameSize);
+void        tRetune_free                (tRetune* const);
 
-float       tPitchShifter_tick              (tPitchShifter* const, float sample);
-float       tPitchShifterToFreq_tick        (tPitchShifter* const, float sample, float freq);
-float       tPitchShifterToFunc_tick        (tPitchShifter* const, float sample, float (*fun)(float));
-void        tPitchShifter_ioSamples_toFreq  (tPitchShifter* const, float* in, float* out, int size, float toFreq);
-void        tPitchShifter_ioSamples_toPeriod(tPitchShifter* const, float* in, float* out, int size, float toPeriod);
-void        tPitchShifter_ioSamples_toFunc  (tPitchShifter* const, float* in, float* out, int size, float (*fun)(float));
-void        tPitchShifter_setPitchFactor    (tPitchShifter* const, float pf);
-void        tPitchShifter_setTimeConstant   (tPitchShifter* const, float tc);
-void        tPitchShifter_setHopSize        (tPitchShifter* const, int hs);
-void        tPitchShifter_setWindowSize     (tPitchShifter* const, int ws);
-float       tPitchShifter_getPeriod         (tPitchShifter* const);
-
-//==============================================================================
-
-// Pitch shift
-typedef struct _tPitchShift
+float*      tRetune_tick                (tRetune* const, float sample);
+void        tRetune_setNumVoices        (tRetune* const, int numVoices);
+void        tRetune_setPitchFactors     (tRetune* const, float pf);
+void        tRetune_setPitchFactor      (tRetune* const, float pf, int voice);
+void        tRetune_setTimeConstant     (tRetune* const, float tc);
+void        tRetune_setHopSize          (tRetune* const, int hs);
+void        tRetune_setWindowSize       (tRetune* const, int ws);
+float       tRetune_getInputPeriod      (tRetune* const);
+float       tRetune_getInputFreq        (tRetune* const);
+    
+// Autotune
+typedef struct _tAutotune
 {
-    tSOLAD sola;
-    tHighpass hp;
-   tPeriodDetection* p;
+    tPeriodDetection pd;
+    tPitchShift* ps;
     
-    float* outBuffer;
+    float* inBuffer;
+    float** outBuffers;
+    float* tickOutput;
     int frameSize;
     int bufSize;
     
-    int framesPerBuffer;
-    int curBlock;
-    int lastBlock;
-    int index;
+    uint16_t hopSize;
+    uint16_t windowSize;
+    uint8_t fba;
     
-    float pitchFactor;
+    float* freq;
     float timeConstant;
     float radius;
-} tPitchShift;
+    
+    float inputPeriod;
+    
+    int numVoices;
+} tAutotune;
 
-void        tPitchShift_init                (tPitchShift* const,tPeriodDetection* const, float* out, int bufSize);
-void        tPitchShift_free                (tPitchShift* const);
+void        tAutotune_init                (tAutotune* const, int numVoices, int bufSize, int frameSize);
+void        tAutotune_free                (tAutotune* const);
 
-float       tPitchShift_shift               (tPitchShift* const);
-float       tPitchShift_shiftToFunc         (tPitchShift* const, float (*fun)(float));
-float       tPitchShift_shiftToFreq         (tPitchShift* const, float freq);
-void        tPitchShift_setPitchFactor      (tPitchShift* const, float pf);
+float*      tAutotune_tick                (tAutotune* const, float sample);
+void        tAutotune_setNumVoices        (tAutotune* const, int numVoices);
+void        tAutotune_setFreq             (tAutotune* const, float f, int voice);
+void        tAutotune_setTimeConstant     (tAutotune* const, float tc);
+void        tAutotune_setHopSize          (tAutotune* const, int hs);
+void        tAutotune_setWindowSize       (tAutotune* const, int ws);
+float       tAutotune_getInputPeriod      (tAutotune* const);
+float       tAutotune_getInputFreq        (tAutotune* const);
 
 //==============================================================================
+    
 
 #define FORD 7
 #define FORMANT_BUFFER_SIZE 2048
--- a/LEAF/Src/leaf-effects.c
+++ b/LEAF/Src/leaf-effects.c
@@ -402,331 +402,240 @@
 }
 
 //============================================================================================================
-// PITCHSHIFTER
+// RETUNE
 //============================================================================================================
-static int pitchshifter_attackdetect(tPitchShifter* ps);
 
-void tPitchShifter_init(tPitchShifter* const ps, float* in, float* out, int bufSize, int frameSize)
+void tRetune_init(tRetune* const r, int numVoices, int bufSize, int frameSize)
 {
-    ps->inBuffer = in;
-    ps->outBuffer = out;
-    ps->bufSize = bufSize;
-    ps->frameSize = frameSize;
-    ps->framesPerBuffer = ps->bufSize / ps->frameSize;
-    ps->curBlock = 1;
-    ps->lastBlock = 0;
-    ps->index = 0;
+    r->bufSize = bufSize;
+    r->frameSize = frameSize;
+    r->numVoices = numVoices;
     
-    ps->hopSize = DEFHOPSIZE;
-    ps->windowSize = DEFWINDOWSIZE;
-    ps->fba = FBA;
+    r->inBuffer = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+    r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
     
-    tEnvPD_init(&ps->env, ps->windowSize, ps->hopSize, ps->frameSize);
+    r->hopSize = DEFHOPSIZE;
+    r->windowSize = DEFWINDOWSIZE;
+    r->fba = FBA;
+    tRetune_setTimeConstant(r, DEFTIMECONSTANT);
     
-    tSNAC_init(&ps->snac, DEFOVERLAP);
+    tPeriodDetection_init(&r->pd, r->inBuffer, r->outBuffers[0], r->bufSize, r->frameSize);
     
-    tSOLAD_init(&ps->sola);
+    r->inputPeriod = 0.0f;
     
-    tHighpass_init(&ps->hp, HPFREQ);
-    
-    tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
-    
-    tPitchShifter_setTimeConstant(ps, DEFTIMECONSTANT);
+    r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
+    for (int i = 0; i < r->numVoices; ++i)
+    {
+        r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+        tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
+    }
 }
 
-void tPitchShifter_free(tPitchShifter* const ps)
+void tRetune_free(tRetune* const r)
 {
-    tEnvPD_free(&ps->env);
-    tSNAC_free(&ps->snac);
-    tSOLAD_free(&ps->sola);
-    tHighpass_free(&ps->hp);
+    tPeriodDetection_free(&r->pd);
+    for (int i = 0; i < r->numVoices; ++i)
+    {
+        tPitchShift_free(&r->ps[i]);
+        leaf_free(r->outBuffers[i]);
+    }
+    leaf_free(r->ps);
+    leaf_free(r->inBuffer);
+    leaf_free(r->outBuffers);
 }
 
-float tPitchShifter_tick(tPitchShifter* ps, float sample)
+float* tRetune_tick(tRetune* const r, float sample)
 {
-    float period, out;
-    int i, iLast;
+    r->inputPeriod = tPeriodDetection_findPeriod(&r->pd, sample);
     
-    i = (ps->curBlock*ps->frameSize);
-    iLast = (ps->lastBlock*ps->frameSize)+ps->index;
-    
-    out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-    ps->inBuffer[i+ps->index] = sample;
-    
-    ps->index++;
-    if (ps->index >= ps->frameSize)
+    for (int v = 0; v < r->numVoices; ++v)
     {
-        ps->index = 0;
-        
-        tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i]));
-        
-        if(pitchshifter_attackdetect(ps) == 1)
-        {
-            ps->fba = 5;
-            tSOLAD_setReadLag(&ps->sola, ps->windowSize);
-        }
-        
-        tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        period = tSNAC_getPeriod(&ps->snac);
-        
-        ps->curBlock++;
-        if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0;
-        ps->lastBlock++;
-        if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
-        
-        //separate here
-        
-        tSOLAD_setPeriod(&ps->sola, period);
-        
-        tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-        tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        
+        r->tickOutput[v] = tPitchShift_shift(&r->ps[v]);
     }
-    
-    return out;
+
+    return r->tickOutput;
 }
 
-float tPitchShifterToFreq_tick(tPitchShifter* ps, float sample, float freq)
+void tRetune_setNumVoices(tRetune* const r, int numVoices)
 {
-    float period, out;
-    int i, iLast;
+    for (int i = 0; i < r->numVoices; ++i)
+    {
+        tPitchShift_free(&r->ps[i]);
+        leaf_free(r->outBuffers[i]);
+    }
+    leaf_free(r->ps);
+    leaf_free(r->outBuffers);
     
-    i = (ps->curBlock*ps->frameSize);
-    iLast = (ps->lastBlock*ps->frameSize)+ps->index;
+    r->numVoices = numVoices;
     
-    out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-    ps->inBuffer[i+ps->index] = sample;
-    
-    ps->index++;
-    if (ps->index >= ps->frameSize)
+    r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
+    r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        ps->index = 0;
-        
-        tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i]));
-        
-        if(pitchshifter_attackdetect(ps) == 1)
-        {
-            ps->fba = 5;
-            tSOLAD_setReadLag(&ps->sola, ps->windowSize);
-        }
-        
-        tSNAC_ioSamples(&ps->snac, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        period = tSNAC_getPeriod(&ps->snac);
-        
-        tSOLAD_setPeriod(&ps->sola, period);
-        
-        ps->pitchFactor = period*freq*leaf.invSampleRate;
-        tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-        tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        
-        ps->curBlock++;
-        if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0;
-        ps->lastBlock++;
-        if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
+        r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+        tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
     }
     
-    return out;
+    
 }
 
-float tPitchShifterToFunc_tick(tPitchShifter* ps, float sample, float (*fun)(float))
+void tRetune_setPitchFactors(tRetune* const r, float pf)
 {
-    float period, out;
-    int i, iLast;
-    
-    i = (ps->curBlock*ps->frameSize);
-    iLast = (ps->lastBlock*ps->frameSize)+ps->index;
-    
-    out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-    ps->inBuffer[i+ps->index] = sample;
-    
-    ps->index++;
-    if (ps->index >= ps->frameSize)
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        ps->index = 0;
-        
-        tEnvPD_processBlock(&ps->env, &(ps->inBuffer[i]));
-        
-        if(pitchshifter_attackdetect(ps) == 1)
-        {
-            ps->fba = 5;
-            tSOLAD_setReadLag(&ps->sola, ps->windowSize);
-        }
-        
-        tSNAC_ioSamples(&ps->snac, (&ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        period = tSNAC_getPeriod(&ps->snac);
-        
-        tSOLAD_setPeriod(&ps->sola, period);
-        
-        ps->pitchFactor = period/fun(period);
-        tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-        tSOLAD_ioSamples(&ps->sola, &(ps->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-        
-        ps->curBlock++;
-        if (ps->curBlock >= ps->framesPerBuffer) ps->curBlock = 0;
-        ps->lastBlock++;
-        if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
+        r->pitchFactor[i] = pf;
+        tPitchShift_setPitchFactor(&r->ps[i], r->pitchFactor[i]);
     }
-    
-    return out;
 }
 
-void tPitchShifter_ioSamples(tPitchShifter* ps, float* in, float* out, int size)
+void tRetune_setPitchFactor(tRetune* const r, float pf, int voice)
 {
-    float period;
+    r->pitchFactor[voice] = pf;
+    tPitchShift_setPitchFactor(&r->ps[voice], r->pitchFactor[voice]);
+}
+
+void tRetune_setTimeConstant(tRetune* const r, float tc)
+{
+    r->timeConstant = tc;
+    r->radius = expf(-1000.0f * r->hopSize * leaf.invSampleRate / r->timeConstant);
+}
+
+void tRetune_setHopSize(tRetune* const r, int hs)
+{
+    r->hopSize = hs;
+    tPeriodDetection_setHopSize(&r->pd, r->hopSize);
+}
+
+void tRetune_setWindowSize(tRetune* const r, int ws)
+{
+    r->windowSize = ws;
+    tPeriodDetection_setWindowSize(&r->pd, r->windowSize);
+}
+
+float tRetune_getInputPeriod(tRetune* const r)
+{
+    return r->inputPeriod;
+}
+
+float tRetune_getInputFreq(tRetune* const r)
+{
+    return 1.0f/r->inputPeriod;
+}
+
+//============================================================================================================
+// AUTOTUNE
+//============================================================================================================
+
+void tAutotune_init(tAutotune* const r, int numVoices, int bufSize, int frameSize)
+{
+    r->bufSize = bufSize;
+    r->frameSize = frameSize;
+    r->numVoices = numVoices;
     
-    tEnvPD_processBlock(&ps->env, in);
+    r->inBuffer = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+    r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
     
-    if(pitchshifter_attackdetect(ps) == 1)
-    {
-        ps->fba = 5;
-        tSOLAD_setReadLag(&ps->sola, ps->windowSize);
-    }
+    r->hopSize = DEFHOPSIZE;
+    r->windowSize = DEFWINDOWSIZE;
+    r->fba = FBA;
+    tAutotune_setTimeConstant(r, DEFTIMECONSTANT);
     
-    tSNAC_ioSamples(&ps->snac, in, out, size);
-    period = tSNAC_getPeriod(&ps->snac);
+    tPeriodDetection_init(&r->pd, r->inBuffer, r->outBuffers[0], r->bufSize, r->frameSize);
     
-    tSOLAD_setPeriod(&ps->sola, period);
-    
-    tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-    tSOLAD_ioSamples(&ps->sola, in, out, size);
-    
-    for (int cc = 0; cc < size; ++cc)
+    r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        out[cc] = tHighpass_tick(&ps->hp, out[cc]);
+        r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+        tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
     }
+    
+    r->inputPeriod = 0.0f;
 }
 
-void tPitchShifter_ioSamples_toFreq(tPitchShifter* ps, float* in, float* out, int size, float toFreq)
+void tAutotune_free(tAutotune* const r)
 {
-    float period;
-    
-    tEnvPD_processBlock(&ps->env, in);
-    
-    if(pitchshifter_attackdetect(ps) == 1)
+    tPeriodDetection_free(&r->pd);
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        ps->fba = 5;
-        tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+        tPitchShift_free(&r->ps[i]);
+        leaf_free(r->outBuffers[i]);
     }
-    
-    tSNAC_ioSamples(&ps->snac, in, out, size);
-    period = tSNAC_getPeriod(&ps->snac);
-    
-    tSOLAD_setPeriod(&ps->sola, period);
-    ps->pitchFactor = period*toFreq;
-    tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-    tSOLAD_ioSamples(&ps->sola, in, out, size);
-    
-    for (int cc = 0; cc < size; ++cc)
-    {
-        out[cc] = tHighpass_tick(&ps->hp, out[cc]);
-    }
+    leaf_free(r->ps);
+    leaf_free(r->inBuffer);
+    leaf_free(r->outBuffers);
 }
 
-void tPitchShifter_ioSamples_toPeriod(tPitchShifter* ps, float* in, float* out, int size, float toPeriod)
+float* tAutotune_tick(tAutotune* const r, float sample)
 {
-    float period;
+    r->inputPeriod = tPeriodDetection_findPeriod(&r->pd, sample);
     
-    tEnvPD_processBlock(&ps->env, in);
-    
-    if(pitchshifter_attackdetect(ps) == 1)
+    for (int v = 0; v < r->numVoices; ++v)
     {
-        ps->fba = 5;
-        tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+        r->tickOutput[v] = tPitchShift_shiftToFreq(&r->ps[v], r->freq[v]);
     }
     
-    tSNAC_ioSamples(&ps->snac, in, out, size);
-    period = tSNAC_getPeriod(&ps->snac);
-    
-    tSOLAD_setPeriod(&ps->sola, period);
-    ps->pitchFactor = period/toPeriod;
-    tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-    tSOLAD_ioSamples(&ps->sola, in, out, size);
-    
-    for (int cc = 0; cc < size; ++cc)
-    {
-        out[cc] = tHighpass_tick(&ps->hp, out[cc]);
-    }
+    return r->tickOutput;
 }
 
-void tPitchShifter_ioSamples_toFunc(tPitchShifter* ps, float* in, float* out, int size, float (*fun)(float))
+void tAutotune_setNumVoices(tAutotune* const r, int numVoices)
 {
-    float period;
-    
-    tEnvPD_processBlock(&ps->env, in);
-    
-    if(pitchshifter_attackdetect(ps) == 1)
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        ps->fba = 5;
-        tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+        tPitchShift_free(&r->ps[i]);
+        leaf_free(r->outBuffers[i]);
     }
+    leaf_free(r->ps);
+    leaf_free(r->outBuffers);
     
-    tSNAC_ioSamples(&ps->snac, in, out, size);
-    period = tSNAC_getPeriod(&ps->snac);
+    r->numVoices = numVoices;
     
-    tSOLAD_setPeriod(&ps->sola, period);
-    ps->pitchFactor = period/fun(period);
-    tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-    tSOLAD_ioSamples(&ps->sola, in, out, size);
-    
-    for (int cc = 0; cc < size; ++cc)
+    r->outBuffers = (float**) leaf_alloc(sizeof(float*) * r->numVoices);
+    r->ps = (tPitchShift*) leaf_alloc(sizeof(tPitchShift) * r->numVoices);
+    for (int i = 0; i < r->numVoices; ++i)
     {
-        out[cc] = tHighpass_tick(&ps->hp, out[cc]);
+        r->outBuffers[i] = (float*) leaf_alloc(sizeof(float) * r->bufSize);
+        tPitchShift_init(&r->ps[i], &r->pd, r->outBuffers[i], r->bufSize);
     }
+    
+    
 }
 
-void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf)
+void tAutotune_setFreq(tAutotune* const r, float f, int voice)
 {
-    ps->pitchFactor = pf;
+    for (int i = 0; i < r->numVoices; ++i)
+    {
+        r->freq[i] = f;
+    }
 }
 
-void tPitchShifter_setTimeConstant(tPitchShifter* ps, float tc)
+void tAutotune_setTimeConstant(tAutotune* const r, float tc)
 {
-    ps->timeConstant = tc;
-    ps->radius = expf(-1000.0f * ps->hopSize * leaf.invSampleRate / ps->timeConstant);
+    r->timeConstant = tc;
+    r->radius = expf(-1000.0f * r->hopSize * leaf.invSampleRate / r->timeConstant);
 }
 
-void tPitchShifter_setHopSize(tPitchShifter* ps, int hs)
+void tAutotune_setHopSize(tAutotune* const r, int hs)
 {
-    ps->hopSize = hs;
+    r->hopSize = hs;
+    tPeriodDetection_setHopSize(&r->pd, r->hopSize);
 }
 
-void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws)
+void tAutotune_setWindowSize(tAutotune* const r, int ws)
 {
-    ps->windowSize = ws;
+    r->windowSize = ws;
+    tPeriodDetection_setWindowSize(&r->pd, r->windowSize);
 }
 
-float tPitchShifter_getPeriod(tPitchShifter* ps)
+float tAutotune_getInputPeriod(tAutotune* const r)
 {
-    return tSNAC_getPeriod(&ps->snac);
+    return r->inputPeriod;
 }
 
-static int pitchshifter_attackdetect(tPitchShifter* ps)
+float tAutotune_getInputFreq(tAutotune* const r)
 {
-    float envout;
-    
-    envout = tEnvPD_tick(&ps->env);
-    
-    if (envout >= 1.0f)
-    {
-        ps->lastmax = ps->max;
-        if (envout > ps->max)
-        {
-            ps->max = envout;
-        }
-        else
-        {
-            ps->deltamax = envout - ps->max;
-            ps->max = ps->max * ps->radius;
-        }
-        ps->deltamax = ps->max - ps->lastmax;
-    }
-    
-    ps->fba = ps->fba ? (ps->fba - 1) : 0;
-    
-    return (ps->fba == 0 && (ps->max > 60 && ps->deltamax > 6)) ? 1 : 0;
+    return 1.0f/r->inputPeriod;
 }
 
-
 //============================================================================================================
 // PITCHSHIFT
 //============================================================================================================
@@ -735,7 +644,7 @@
 {
     float envout;
     
-    envout = tEnvPD_tick(&ps->p->env);
+    envout = tEnv_tick(&ps->p->env);
     
     if (envout >= 1.0f)
     {
@@ -757,7 +666,7 @@
     return (ps->p->fba == 0 && (ps->p->max > 60 && ps->p->deltamax > 6)) ? 1 : 0;
 }
 
-void tPitchShift_init (tPitchShift* const ps,tPeriodDetection* p, float* out, int bufSize)
+void tPitchShift_init (tPitchShift* const ps, tPeriodDetection* p, float* out, int bufSize)
 {
     ps->p = p;