shithub: leaf

Download patch

ref: 6e322e9033baed4027c8b3184c41fbc8df18b186
parent: 61205ba2be7fbb6b695eb0bdfa8ffc0ed365ac0b
author: spiricom <jeff@snyderphonics.com>
date: Thu Dec 26 14:56:16 EST 2019

jeff updates from working on vocodec over dec 22-26

binary files a/.DS_Store b/.DS_Store differ
binary files a/LEAF/.DS_Store b/LEAF/.DS_Store differ
binary files a/LEAF/Inc/.DS_Store b/LEAF/Inc/.DS_Store differ
--- a/LEAF/Inc/leaf-distortion.h
+++ b/LEAF/Inc/leaf-distortion.h
@@ -25,10 +25,24 @@
     
     typedef struct _tLockhartWavefolder
     {
-        double Ln1;
-        double Fn1;
+        float Ln1;
+        float Fn1;
         float xn1;
         
+        float RL;
+        float R;
+        float VT;
+        float Is;
+
+        float a;
+        float b;
+        float d;
+
+        // Antialiasing error threshold
+        float thresh;
+        float half_a;
+        float longthing;
+
     } _tLockhartWavefolder;
     
     typedef _tLockhartWavefolder* tLockhartWavefolder;
--- a/LEAF/Inc/leaf-filters.h
+++ b/LEAF/Inc/leaf-filters.h
@@ -50,12 +50,8 @@
         float gain;
         float a0,a1;
         float b0,b1;
-        
-        float coef;
-        
-        float freq;
-        
         float lastIn, lastOut;
+
         
     } _tOnePole;
     
@@ -83,7 +79,7 @@
         
         float radius, frequency;
         oBool normalize;
-        
+
         float lastOut[2];
         
     } _tTwoPole;
@@ -288,7 +284,7 @@
     {
         float gain;
         
-        float N;
+        int N;
         
         tSVF low[NUM_SVF_BW];
         tSVF high[NUM_SVF_BW];
--- a/LEAF/Inc/leaf-global.h
+++ b/LEAF/Inc/leaf-global.h
@@ -20,7 +20,7 @@
     float   sampleRate;
     float   invSampleRate;
     int     blockSize;
-    
+    float	twoPiTimesInvSampleRate;
     float   (*random)(void);
 } LEAF;
 
--- a/LEAF/Inc/leaf-math.h
+++ b/LEAF/Inc/leaf-math.h
@@ -64,13 +64,16 @@
 #define INV_LOG2                     3.321928095f
     
 #define SOS_M                         343.0f
-    
+#define TWO_TO_5                     32.0f
+#define INV_TWO_TO_5             0.03125f
 #define TWO_TO_7                     128.f
 #define INV_TWO_TO_7             0.0078125f
 #define TWO_TO_8                     256.f
 #define INV_TWO_TO_8             0.00390625f
-#define TWO_TO_5                     32.0f
-#define INV_TWO_TO_5             0.03125f
+#define TWO_TO_10                 1024.f
+#define INV_TWO_TO_10         0.0009765625f
+#define TWO_TO_11                 2048.f
+#define INV_TWO_TO_11         0.00048828125f
 #define TWO_TO_12                 4096.f
 #define INV_TWO_TO_12         0.00024414062f
 #define TWO_TO_15                 32768.f
@@ -133,8 +136,18 @@
     
 #define LOGTEN 2.302585092994
     
+    float fast_mtof(float f);
+
+    float fastexpf(float x);
+
+    float fasterexpf(float x);
+
     float mtof(float f);
     
+    float fast_mtof(float f);
+
+    float faster_mtof(float f);
+
     float ftom(float f);
     
     float powtodb(float f);
--- a/LEAF/Inc/leaf-reverb.h
+++ b/LEAF/Inc/leaf-reverb.h
@@ -136,8 +136,9 @@
     void    tDattorroReverb_free              (tDattorroReverb* const);
     
     float   tDattorroReverb_tick              (tDattorroReverb* const, float input);
-    
+    void    tDattorroReverb_tickStereo        (tDattorroReverb* const rev, float input, float* output);
     void    tDattorroReverb_setMix            (tDattorroReverb* const, float mix);
+    void    tDattorroReverb_setHP             (tDattorroReverb* const, float freq);
     void    tDattorroReverb_setSize           (tDattorroReverb* const, float size);
     void    tDattorroReverb_setInputDelay     (tDattorroReverb* const, float preDelay);
     void    tDattorroReverb_setInputFilter    (tDattorroReverb* const, float freq);
binary files a/LEAF/Src/.DS_Store b/LEAF/Src/.DS_Store differ
--- a/LEAF/Src/leaf-distortion.c
+++ b/LEAF/Src/leaf-distortion.c
@@ -28,6 +28,20 @@
     w->Ln1 = 0.0;
     w->Fn1 = 0.0;
     w->xn1 = 0.0f;
+
+    w->RL = 7.5e3;
+    w->R = 15e3;
+    w->VT = 26e-3;
+    w->Is = 10e-16;
+
+    w->a = 2.0*w->RL/w->R;
+    w->b = (w->R+2.0*w->RL)/(w->VT*w->R);
+    w->d = (w->RL*w->Is)/w->VT;
+    w->half_a = 0.5f * w->a;
+    w->longthing = (0.5*w->VT/w->b);
+
+    // Antialiasing error threshold
+    w->thresh = 10e-10;
 }
 
 void tLockhartWavefolder_free(tLockhartWavefolder* const wf)
@@ -73,37 +87,27 @@
     
     float out = 0.0f;
     // Constants
-    double RL = 7.5e3;
-    double R = 15e3;
-    double VT = 26e-3;
-    double Is = 10e-16;
+
     
-    double a = 2.0*RL/R;
-    double b = (R+2.0*RL)/(VT*R);
-    double d = (RL*Is)/VT;
-    
-    // Antialiasing error threshold
-    double thresh = 10e-10;
-    
     // Compute Antiderivative
     int l = (samp > 0) - (samp < 0);
-    double u = d*exp(l*b*samp);
+    double u = w->d*exp(l*w->b*samp);
     double Ln = tLockhartWavefolderLambert(u,w->Ln1);
-    double Fn = (0.5*VT/b)*(Ln*(Ln + 2.0)) - 0.5*a*samp*samp;
+    double Fn = w->longthing*(Ln*(Ln + 2.0)) - w->half_a*samp*samp;
     
     // Check for ill-conditioning
-    if (fabs(samp-w->xn1)<thresh) {
+    if (fabs(samp-w->xn1)<w->thresh) {
         
         // Compute Averaged Wavefolder Output
         double xn = 0.5*(samp+w->xn1);
-        u = d*exp(l*b*xn);
+        u = w->d*exp(l*w->b*xn);
         Ln = tLockhartWavefolderLambert(u,w->Ln1);
-        out = (float) (l*VT*Ln - a*xn);
+        out = (float) (l*w->VT*Ln - w->a*xn);
         if (isnan(out))
         {
             ;
         }
-        
+
     }
     else {
         
--- a/LEAF/Src/leaf-effects.c
+++ b/LEAF/Src/leaf-effects.c
@@ -644,13 +644,17 @@
 {
     _tAutotune* r = *rt;
     
-    r->inputPeriod = tPeriodDetection_findPeriod(&r->pd, sample);
-    
-    for (int v = 0; v < r->numVoices; ++v)
-    {
-        r->tickOutput[v] = tPitchShift_shiftToFreq(&r->ps[v], r->freq[v]);
-    }
-    
+    float tempPeriod = tPeriodDetection_findPeriod(&r->pd, sample);
+    if (tempPeriod < 1000.0f) //to avoid trying to follow consonants
+	{
+		r->inputPeriod = tempPeriod;
+	}
+
+	for (int v = 0; v < r->numVoices; ++v)
+	{
+		r->tickOutput[v] = tPitchShift_shiftToFreq(&r->ps[v], r->freq[v]);
+	}
+
     return r->tickOutput;
 }
 
@@ -1273,7 +1277,7 @@
     
     
     fs->falph = powf(0.001f, 80.0f / (leaf.sampleRate));
-    fs->flamb = -(0.8517f*sqrt(atanf(0.06583f*leaf.sampleRate))-0.1916f);
+    fs->flamb = -(0.8517f*sqrtf(atanf(0.06583f*leaf.sampleRate))-0.1916f);
     fs->fhp = 0.0f;
     fs->flp = 0.0f;
     fs->flpa = powf(0.001f, 10.0f / (leaf.sampleRate));
@@ -1280,6 +1284,8 @@
     fs->fmute = 1.0f;
     fs->fmutealph = powf(0.001f, 1.0f / (leaf.sampleRate));
     fs->cbi = 0;
+    fs->intensity = 1.0f;
+	fs->invIntensity = 1.0f;
 }
 
 void tFormantShifter_free(tFormantShifter* const fsr)
@@ -1314,12 +1320,11 @@
     
     in *= fs->intensity;
     
-    float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, fk;
+    float fa, fb, fc, foma, falph, ford, flamb, tf, fk;
     int ti4;
     ford = fs->ford;
     falph = fs->falph;
     foma = (1.0f - falph);
-    flpa = fs->flpa;
     flamb = fs->flamb;
     
     tf = in;
@@ -1356,11 +1361,11 @@
 {
     _tFormantShifter* fs = *fsr;
     
-    float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, tf2, f0resp, f1resp, frlamb;
+    float fa, fb, fc, falph, ford, flpa, flamb, tf, tf2, f0resp, f1resp, frlamb;
     int ti4;
     ford = fs->ford;
     falph = fs->falph;
-    foma = (1.0f - falph);
+
     flpa = fs->flpa;
     flamb = fs->flamb;
     tf = fs->shiftFactor * (1+flamb)/(1-flamb);
@@ -1368,7 +1373,7 @@
     ti4 = fs->cbi;
     
     tf2 = in;
-    fa = 0;
+    fa = 0.0f;
     fb = fa;
     for (int i=0; i<ford; i++)
     {
@@ -1407,13 +1412,13 @@
     tf = 2.0f*tf2;
     tf2 = tf;
     tf = (1.0f - f1resp + f0resp);
-    if (tf!=0)
+    if (tf!=0.0f)
     {
         tf2 = (tf2 + f0resp) / tf;
     }
     else
     {
-        tf2 = 0;
+        tf2 = 0.0f;
     }
     
     //  third time: update delay registers
@@ -1434,16 +1439,16 @@
     
     // Bring up the gain slowly when formant correction goes from disabled
     // to enabled, while things stabilize.
-    if (fs->fmute>0.5)
+    if (fs->fmute>0.5f)
     {
-        tf = tf*(fs->fmute - 0.5)*2;
+        tf = tf*(fs->fmute - 0.5f)*2.0f;
     }
     else
     {
-        tf = 0;
+        tf = 0.0f;
     }
     tf2 = fs->fmutealph;
-    fs->fmute = (1-tf2) + tf2*fs->fmute;
+    fs->fmute = (1.0f-tf2) + tf2*fs->fmute;
     // now tf is signal output
     // ...and we're done messing with formants
     
@@ -1461,5 +1466,14 @@
 {
     _tFormantShifter* fs = *fsr;
     fs->intensity = intensity;
-    fs->invIntensity = 1.0f/fs->intensity;
+    //make sure you don't divide by zero, doofies
+    if (fs->intensity != 0.0f)
+    {
+    	fs->invIntensity = 1.0f/fs->intensity;
+    }
+    else
+    {
+    	fs->invIntensity = 1.0f;
+    }
+
 }
--- a/LEAF/Src/leaf-envelopes.c
+++ b/LEAF/Src/leaf-envelopes.c
@@ -514,7 +514,12 @@
     
     r->curr += r->inc;
     
-    if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f))) r->inc = 0.0f;
+    if (((r->curr >= r->dest) && (r->inc > 0.0f)) || ((r->curr <= r->dest) && (r->inc < 0.0f)))
+	{
+		r->inc = 0.0f;
+		r->curr=r->dest;
+	}
+
     // Palle: There is a slight risk that you overshoot here and stay on dest+inc, which with a large inc value could be a real problem
     // I suggest you add: r->curr=r->dest in the true if case
     
--- a/LEAF/Src/leaf-filters.c
+++ b/LEAF/Src/leaf-filters.c
@@ -279,7 +279,7 @@
     f->radius = radius;
     
     f->b2 = radius * radius;
-    f->b1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
+    f->b1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
     
     // Normalize the filter gain. From STK.
     if ( f->b1 > 0.0f ) // Maximum at z = 0.
@@ -331,7 +331,7 @@
     
     f->gain = 1.0f;
     f->a0 = 1.0;
-    
+
     tOnePole_setFreq(ft, freq);
     
     f->lastIn = 0.0f;
@@ -374,7 +374,7 @@
 void        tOnePole_setFreq        (tOnePole* const ft, float freq)
 {
     _tOnePole* f = *ft;
-    f->b0 = freq * TWO_PI * leaf.invSampleRate;
+    f->b0 = freq * leaf.twoPiTimesInvSampleRate;
     f->b0 = LEAF_clip(0.0f, f->b0, 1.0f);
     f->a1 = 1.0f - f->b0;
 }
@@ -462,7 +462,8 @@
 {
     _tTwoPole* f = *ft;
     
-    if (frequency < 0.0f)   frequency = 0.0f; // need to also handle when frequency > nyquist
+    if (frequency < 0.0f)   frequency = 0.0f;
+    if (frequency > (leaf.sampleRate * 0.49f))   frequency = leaf.sampleRate * 0.49f;
     if (radius < 0.0f)      radius = 0.0f;
     if (radius >= 1.0f)     radius = 0.999999f;
     
@@ -471,14 +472,14 @@
     f->normalize = normalize;
     
     f->a2 = radius * radius;
-    f->a1 =  -2.0f * radius * cos(TWO_PI * frequency * leaf.invSampleRate);
+    f->a1 =  -2.0f * radius * cosf(frequency * leaf.twoPiTimesInvSampleRate);
     
     if ( normalize )
     {
         // Normalize the filter gain ... not terribly efficient.
-        float real = 1 - radius + (f->a2 - radius) * cos(TWO_PI * 2 * frequency * leaf.invSampleRate);
-        float imag = (f->a2 - radius) * sin(TWO_PI * 2 * frequency * leaf.invSampleRate);
-        f->b0 = sqrt( pow(real, 2) + pow(imag, 2) );
+        float real = 1 - radius + (f->a2 - radius) * cosf(2 * frequency * leaf.twoPiTimesInvSampleRate);
+        float imag = (f->a2 - radius) * sinf(2 * frequency * leaf.twoPiTimesInvSampleRate);
+        f->b0 = sqrtf( powf(real, 2) + powf(imag, 2) );
     }
 }
 
@@ -501,14 +502,14 @@
     _tTwoPole* f = *ft;
     
     f->a2 = f->radius * f->radius;
-    f->a1 =  -2.0f * f->radius * cos(TWO_PI * f->frequency * leaf.invSampleRate);
+    f->a1 =  -2.0f * f->radius * cosf(f->frequency * leaf.twoPiTimesInvSampleRate);
     
     if ( f->normalize )
     {
         // Normalize the filter gain ... not terribly efficient.
-        float real = 1 - f->radius + (f->a2 - f->radius) * cos(TWO_PI * 2 * f->frequency * leaf.invSampleRate);
-        float imag = (f->a2 - f->radius) * sin(TWO_PI * 2 * f->frequency * leaf.invSampleRate);
-        f->b0 = sqrt( pow(real, 2) + pow(imag, 2) );
+        float real = 1 - f->radius + (f->a2 - f->radius) * cosf(2 * f->frequency * leaf.twoPiTimesInvSampleRate);
+        float imag = (f->a2 - f->radius) * sinf(2 * f->frequency * leaf.twoPiTimesInvSampleRate);
+        f->b0 = sqrtf( powf(real, 2) + powf(imag, 2) );
     }
 }
 
@@ -663,8 +664,8 @@
 {
     _tBiQuad* f = *ft;
     
-    // Should also deal with frequency being > half sample rate / nyquist. See STK
     if (freq < 0.0f)    freq = 0.0f;
+    if (freq > (leaf.sampleRate * 0.49f))   freq = leaf.sampleRate * 0.49f;
     if (radius < 0.0f)  radius = 0.0f;
     if (radius >= 1.0f)  radius = 1.0f;
     
@@ -673,7 +674,7 @@
     f->normalize = normalize;
     
     f->a2 = radius * radius;
-    f->a1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate);
+    f->a1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate);
     
     if (normalize)
     {
@@ -687,12 +688,12 @@
 {
     _tBiQuad* f = *ft;
     
-    // Should also deal with frequency being > half sample rate / nyquist. See STK
     if (freq < 0.0f)    freq = 0.0f;
+    if (freq > (leaf.sampleRate * 0.49f))   freq = leaf.sampleRate * 0.49f;
     if (radius < 0.0f)  radius = 0.0f;
     
     f->b2 = radius * radius;
-    f->b1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
+    f->b1 = -2.0f * radius * cosf(freq * leaf.twoPiTimesInvSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
     
     // Does not attempt to normalize filter gain.
 }
@@ -755,7 +756,7 @@
 {
     _tBiQuad* f = *ft;
     f->a2 = f->radius * f->radius;
-    f->a1 = -2.0f * f->radius * cosf(TWO_PI * f->frequency * leaf.invSampleRate);
+    f->a1 = -2.0f * f->radius * cosf(f->frequency * leaf.twoPiTimesInvSampleRate);
     
     if (f->normalize)
     {
@@ -770,7 +771,7 @@
 {
     _tHighpass* f = *ft = (_tHighpass*) leaf_alloc(sizeof(_tHighpass));
     
-    f->R = (1.0f-((freq * 2.0f * 3.14f)* leaf.invSampleRate));
+    f->R = (1.0f - (freq * leaf.twoPiTimesInvSampleRate));
     f->ys = 0.0f;
     f->xs = 0.0f;
     
@@ -788,7 +789,7 @@
 {
     _tHighpass* f = *ft;
     f->frequency = freq;
-    f->R = (1.0f-((freq * 2.0f * 3.14f) * leaf.invSampleRate));
+    f->R = (1.0f - (freq * leaf.twoPiTimesInvSampleRate));
     
 }
 
@@ -813,7 +814,7 @@
     f->R = (1.0f-((f->frequency * 2.0f * 3.14f) * leaf.invSampleRate));
 }
 
-// Less efficient, more accurate version of SVF, in which cutoff frequency is taken as floating point Hz value and tanh
+// Less efficient, more accurate version of SVF, in which cutoff frequency is taken as floating point Hz value and tanf
 // is calculated when frequency changes.
 void tSVF_init(tSVF* const svff, SVFType type, float freq, float Q)
 {
@@ -825,17 +826,11 @@
     svf->ic2eq = 0;
     
     float a1,a2,a3,g,k;
-    g = tanf(PI * freq * leaf.invSampleRate);
-    k = 1.0f/Q;
-    a1 = 1.0f/(1.0f+g*(g+k));
-    a2 = g*a1;
-    a3 = g*a2;
-    
-    svf->g = g;
-    svf->k = k;
-    svf->a1 = a1;
-    svf->a2 = a2;
-    svf->a3 = a3;
+    svf->g = tanf(PI * freq * leaf.invSampleRate);
+    svf->k = 1.0f/Q;
+    svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+    svf->a2 = g*a1;
+    svf->a3 = g*a2;
 }
 
 void tSVF_free(tSVF* const svff)
@@ -896,17 +891,11 @@
     svf->ic2eq = 0;
     
     float a1,a2,a3,g,k;
-    g = filtertan[input];
-    k = 1.0f/Q;
-    a1 = 1.0f/(1.0f+g*(g+k));
-    a2 = g*a1;
-    a3 = g*a2;
-    
-    svf->g = g;
-    svf->k = k;
-    svf->a1 = a1;
-    svf->a2 = a2;
-    svf->a3 = a3;
+    svf->g = filtertan[input];
+    svf->k = 1.0f/Q;
+    svf->a1 = 1.0f/(1.0f+g*(g+k));
+    svf->a2 = g*a1;
+    svf->a3 = g*a2;
 }
 
 void tEfficientSVF_free(tEfficientSVF* const svff)
--- a/LEAF/Src/leaf-math.c
+++ b/LEAF/Src/leaf-math.c
@@ -73,6 +73,22 @@
     return alias.f;
 }
 
+
+float fastexpf(float x) {
+  x = 1.0f + (x * 0.0009765625f);
+  x *= x; x *= x; x *= x; x *= x;
+  x *= x; x *= x; x *= x; x *= x;
+  x *= x; x *= x;
+  return x;
+}
+
+float fasterexpf(float x) {
+  x = 1.0 + (x * 0.00390625f);
+  x *= x; x *= x; x *= x; x *= x;
+  x *= x; x *= x; x *= x; x *= x;
+  return x;
+}
+
 // fast floating-point exp2 function taken from Robert Bristow Johnson's
 // post in the music-dsp list on Date: Tue, 02 Sep 2014 16:50:11 -0400
 float fastexp2f(float x)
@@ -394,6 +410,16 @@
     if (f <= -1500.0f) return(0);
     else if (f > 1499.0f) return(mtof(1499.0f));
     else return (8.17579891564f * expf(0.0577622650f * f));
+}
+
+float fast_mtof(float f)
+{
+    return (8.17579891564f * fastexpf(0.0577622650f * f));
+}
+
+float faster_mtof(float f)
+{
+    return (8.17579891564f * fastexpf(0.0577622650f * f));
 }
 
 float ftom(float f)
--- a/LEAF/Src/leaf-reverb.c
+++ b/LEAF/Src/leaf-reverb.c
@@ -357,7 +357,7 @@
     
     tOnePole_free(&r->f1_filter);
     
-    tHighpass_free(&r->f2_hp);
+    tHighpass_free(&r->f1_hp);
     
     tCycle_free(&r->f1_lfo);
     
@@ -479,6 +479,112 @@
     return (input * (1.0f - r->mix) + sample * r->mix);
 }
 
+void   tDattorroReverb_tickStereo              (tDattorroReverb* const rev, float input, float* output)
+{
+    _tDattorroReverb* r = *rev;
+
+    // INPUT
+    float in_sample = tTapeDelay_tick(&r->in_delay, input);
+
+    in_sample = tOnePole_tick(&r->in_filter, in_sample);
+
+    for (int i = 0; i < 4; i++)
+    {
+        in_sample = tAllpass_tick(&r->in_allpass[i], in_sample);
+    }
+
+    // FEEDBACK 1
+    float f1_sample = in_sample + r->f2_last; // + f2_last_out;
+
+    tAllpass_setDelay(&r->f1_allpass, SAMP(30.51f) + tCycle_tick(&r->f1_lfo) * SAMP(4.0f));
+
+    f1_sample = tAllpass_tick(&r->f1_allpass, f1_sample);
+
+    f1_sample = tTapeDelay_tick(&r->f1_delay_1, f1_sample);
+
+    f1_sample = tOnePole_tick(&r->f1_filter, f1_sample);
+
+    f1_sample = f1_sample + r->f1_delay_2_last * 0.5f;
+
+    float f1_delay_2_sample = tTapeDelay_tick(&r->f1_delay_2, f1_sample * 0.5f);
+
+    r->f1_delay_2_last = f1_delay_2_sample;
+
+    f1_sample = r->f1_delay_2_last + f1_sample;
+
+    f1_sample = tHighpass_tick(&r->f1_hp, f1_sample);
+
+    f1_sample *= r->feedback_gain;
+
+    f1_sample = tanhf(f1_sample);
+
+    r->f1_last = tTapeDelay_tick(&r->f1_delay_3, f1_sample);
+
+    // FEEDBACK 2
+    float f2_sample = in_sample + r->f1_last;
+
+    tAllpass_setDelay(&r->f2_allpass, SAMP(22.58f) + tCycle_tick(&r->f2_lfo) * SAMP(4.0f));
+
+    f2_sample = tAllpass_tick(&r->f2_allpass, f2_sample);
+
+    f2_sample = tTapeDelay_tick(&r->f2_delay_1, f2_sample);
+
+    f2_sample = tOnePole_tick(&r->f2_filter, f2_sample);
+
+    f2_sample = f2_sample + r->f2_delay_2_last * 0.5f;
+
+    float f2_delay_2_sample = tTapeDelay_tick(&r->f2_delay_2, f2_sample * 0.5f);
+
+    r->f2_delay_2_last = f2_delay_2_sample;
+
+    f2_sample = r->f2_delay_2_last + f2_sample;
+
+    f2_sample = tHighpass_tick(&r->f2_hp, f2_sample);
+
+    f2_sample *= r->feedback_gain;
+
+    f2_sample = tanhf(f2_sample);
+
+    r->f2_last = tTapeDelay_tick(&r->f2_delay_3, f2_sample);
+
+
+    // TAP OUT 1
+    f1_sample =     tTapeDelay_tapOut(&r->f1_delay_1, SAMP(8.9f)) +
+    tTapeDelay_tapOut(&r->f1_delay_1, SAMP(99.8f));
+
+    f1_sample -=    tTapeDelay_tapOut(&r->f1_delay_2, SAMP(64.2f));
+
+    f1_sample +=    tTapeDelay_tapOut(&r->f1_delay_3, SAMP(67.f));
+
+    f1_sample -=    tTapeDelay_tapOut(&r->f2_delay_1, SAMP(66.8f));
+
+    f1_sample -=    tTapeDelay_tapOut(&r->f2_delay_2, SAMP(6.3f));
+
+    f1_sample -=    tTapeDelay_tapOut(&r->f2_delay_3, SAMP(35.8f));
+
+    f1_sample *=    0.14f;
+
+    // TAP OUT 2
+    f2_sample =     tTapeDelay_tapOut(&r->f2_delay_1, SAMP(11.8f)) +
+    tTapeDelay_tapOut(&r->f2_delay_1, SAMP(121.7f));
+
+    f2_sample -=    tTapeDelay_tapOut(&r->f2_delay_2, SAMP(6.3f));
+
+    f2_sample +=    tTapeDelay_tapOut(&r->f2_delay_3, SAMP(89.7f));
+
+    f2_sample -=    tTapeDelay_tapOut(&r->f1_delay_1, SAMP(70.8f));
+
+    f2_sample -=    tTapeDelay_tapOut(&r->f1_delay_2, SAMP(11.2f));
+
+    f2_sample -=    tTapeDelay_tapOut(&r->f1_delay_3, SAMP(4.1f));
+
+    f2_sample *=    0.14f;
+
+    output[0] = input * (1.0f - r->mix) + f1_sample  * r->mix;
+    output[1] = input * (1.0f - r->mix) + f2_sample * r->mix;
+
+}
+
 void    tDattorroReverb_setMix            (tDattorroReverb* const rev, float mix)
 {
     _tDattorroReverb* r = *rev;
@@ -485,6 +591,16 @@
     r->mix = LEAF_clip(0.0f, mix, 1.0f);
 }
 
+
+void    tDattorroReverb_setHP           (tDattorroReverb* const rev, float freq)
+{
+    _tDattorroReverb* r = *rev;
+    float newFreq = LEAF_clip(20.0f, freq, 20000.0f);
+    tHighpass_setFreq(&r->f1_hp, newFreq);
+    tHighpass_setFreq(&r->f2_hp, newFreq);
+}
+
+
 void    tDattorroReverb_setSize           (tDattorroReverb* const rev, float size)
 {
     _tDattorroReverb* r = *rev;
@@ -507,6 +623,7 @@
     tTapeDelay_setDelay(&r->f1_delay_3, SAMP(125.f));
     
     // maybe change rate of SINE LFO's when size changes?
+    //tCycle_setFreq(&r->f2_lfo, 0.07f * size * r->size_max);
     
     // FEEDBACK 2
     //tAllpass_setDelay(&r->f2_allpass, SAMP(22.58f));
--- a/LEAF/Src/leaf.c
+++ b/LEAF/Src/leaf.c
@@ -30,6 +30,8 @@
     
     leaf.invSampleRate = 1.0f/sr;
     
+    leaf.twoPiTimesInvSampleRate = leaf.invSampleRate * TWO_PI;
+
     leaf.random = random;
 }