shithub: leaf

Download patch

ref: 0659ec34571cfa3b83fc8c4a9719f75ff4126ec2
parent: cb6284e95107db310a8b4193f15fa6e45941a5d7
parent: 8733f5cc1504c08044c19f7d6c4f0dce6d39c349
author: mulshine <mulshine@princeton.edu>
date: Tue May 14 10:04:32 EDT 2019

Merge fixed.

--- a/LEAF/Inc/leaf-delay.h
+++ b/LEAF/Inc/leaf-delay.h
@@ -75,6 +75,8 @@
 float       tDelayL_tapOut      (tDelayL*  const, float tapDelay);
 float       tDelayL_addTo       (tDelayL*  const, float value, uint32_t tapDelay);
 float       tDelayL_tick        (tDelayL*  const, float sample);
+void   		tDelayL_tickIn 		(tDelayL* const d, float input);
+float   	tDelayL_tickOut 	(tDelayL* const d);
 float       tDelayL_getLastOut  (tDelayL*  const);
 float       tDelayL_getLastIn   (tDelayL*  const);
 
--- a/LEAF/Inc/leaf-globals.h
+++ b/LEAF/Inc/leaf-globals.h
@@ -49,15 +49,14 @@
 #define MPOLY_NUM_MAX_VOICES 8
 #define NUM_OSC 4
 #define INV_NUM_OSC (1.0f / NUM_OSC)
-#define PS_FRAME_SIZE 1024 // SNAC_FRAME_SIZE in LEAFCore.h should match (or be smaller than?) this
+#define PS_FRAME_SIZE 1024 // SNAC_FRAME_SIZE in leaf-pitch.h should match (or be smaller than?) this
 #define ENV_WINDOW_SIZE 1024
 #define ENV_HOP_SIZE 256
-#define NUM_KNOBS 4
 
 #define     DELAY_LENGTH        16000   // The maximum delay length of all Delay/DelayL/DelayA components.
                                             // Feel free to change to suit memory constraints or desired delay max length / functionality.
 
-#define TALKBOX_BUFFER_LENGTH   1600    // Every talkbox instance introduces 5 buffers of this size
+
 
     
 union unholy_t { /* a union between a float and an integer */
--- a/LEAF/Inc/leaf-mempool.h
+++ b/LEAF/Inc/leaf-mempool.h
@@ -50,7 +50,9 @@
     
 //==============================================================================
 
+
 #define MPOOL_POOL_SIZE   500000
+
 #define MPOOL_ALIGN_SIZE (8)
 
 //#define size_t unsigned long
--- /dev/null
+++ b/LEAF/Inc/leaf-oversampler.h
@@ -1,0 +1,55 @@
+//
+//  leaf-oversampler.h
+//  LEAF
+//
+//  Created by Matthew Wang and Joshua Becker on 2/28/19.
+//  Copyright © 2019 Princeton University. All rights reserved.
+//
+//==============================================================================
+
+#ifndef LEAF_OVERSAMPLER_H_INCLUDED
+#define LEAF_OVERSAMPLER_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+    
+//==============================================================================
+    
+#include "leaf-globals.h"
+#include "leaf-math.h"
+#include "leaf-filter.h"
+    
+//==============================================================================
+typedef struct _tOversamplerFilter
+{
+    float cutoff, Q;
+    float ic1eq,ic2eq;
+    float g,k,a1,a2,a3;
+} tOversamplerFilter;
+
+typedef struct _tOversampler2x
+{
+    tOversamplerFilter filters[2];
+} tOversampler2x;
+
+void        tOversampler2x_init(tOversampler2x* const);
+float       tOversampler2x_tick(tOversampler2x* const, float input, float (*nonLinearTick)(float));
+
+typedef struct _tOversampler4x
+{
+    tOversamplerFilter filters[4];
+} tOversampler4x;
+
+void        tOversampler4x_init(tOversampler4x* const);
+float       tOversampler4x_tick(tOversampler4x* const, float input, float (*nonLinearTick)(float));
+    
+//==============================================================================
+    
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // LEAF_OVERSAMPLER_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-utilities.h
+++ b/LEAF/Inc/leaf-utilities.h
@@ -1,24 +1,28 @@
-/*==============================================================================
+/*
+  ==============================================================================
 
-    leaf-utilities.h
+    LEAFUtilities.h
     Created: 20 Jan 2017 12:02:17pm
     Author:  Michael R Mulshine
 
-==============================================================================*/
+  ==============================================================================
+*/
 
-#ifndef LEAF_UTILITIES_H_INCLUDED
-#define LEAF_UTILITIES_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
+#ifndef LEAFUTILITIES_H_INCLUDED
+#define LEAFUTILITIES_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
 #endif
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 #include "leaf-globals.h"
 #include "leaf-math.h"
+#include "leaf-filter.h"
+#include "leaf-delay.h"
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 // STACK implementation (fixed size)
 #define STACK_SIZE 128
@@ -46,7 +50,7 @@
 int     tStack_next                 (tStack* const);
 int     tStack_get                  (tStack* const, int which);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 /* Ramp */
 typedef struct _tRamp {
@@ -68,8 +72,149 @@
 int     tRamp_setDest   (tRamp* const, float dest);
 int     tRamp_setVal    (tRamp* const, float val);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
+/* Exponential Smoother */
+typedef struct _tExpSmooth {
+    float factor, oneminusfactor;
+    float curr,dest;
+
+} tExpSmooth;
+
+void    tExpSmooth_init      (tExpSmooth* const, float val, float factor);
+void    tExpSmooth_free      (tExpSmooth* const);
+
+float   tExpSmooth_tick      (tExpSmooth* const);
+float   tExpSmooth_sample    (tExpSmooth* const);
+int     tExpSmooth_setFactor   (tExpSmooth* const, float factor);
+int     tExpSmooth_setDest   (tExpSmooth* const, float dest);
+int     tExpSmooth_setVal    (tExpSmooth* const, float val);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* PowerEnvelopeFollower */
+typedef struct _tPwrFollow {
+    float factor, oneminusfactor;
+    float curr;
+
+} tPwrFollow;
+
+void    tPwrFollow_init      (tPwrFollow* const, float factor);
+void    tPwrFollow_free      (tPwrFollow* const);
+float   tPwrFollow_tick      (tPwrFollow* const, float input);
+float   tPwrFollow_sample    (tPwrFollow* const);
+int     tPwrFollow_setFactor   (tPwrFollow* const, float factor);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+//Reed Table - borrowed from STK
+typedef struct _tReedTable {
+    float offset, slope;
+} tReedTable;
+
+void    tReedTable_init      (tReedTable* const, float offset, float slope);
+void    tReedTable_free      (tReedTable* const);
+float   tReedTable_tick      (tReedTable* const, float input);
+float   tReedTable_tanh_tick     (tReedTable* const p, float input); //tanh softclip version of reed table - replacing the hard clip in original stk code
+void     tReedTable_setOffset   (tReedTable* const, float offset);
+void     tReedTable_setSlope (tReedTable* const, float slope);
+
+
+
+///
+/* Feedback leveller */
+// An auto VCA that you put into a feedback circuit to make it stay at the same level.
+// It can enforce level bidirectionally (amplifying and attenuating as needed) or
+// just attenutating. The former option allows for infinite sustain strings, for example, while
+// The latter option allows for decaying strings, which can never exceed
+// a specific level.
+
+typedef struct _tFBleveller {
+    float targetLevel;	// target power level
+    float strength;		// how strongly level difference affects the VCA
+    int	  mode;			// 0 for upwards limiting only, 1 for biderctional limiting
+    float curr;
+    tPwrFollow pwrFlw;	// internal power follower needed for level tracking
+
+} tFBleveller;
+
+void    tFBleveller_init      (tFBleveller* const, float targetLevel, float factor, float strength, int mode);
+void    tFBleveller_free      (tFBleveller* const);
+
+float   tFBleveller_tick      (tFBleveller* const, float input);
+float   tFBleveller_sample    (tFBleveller* const);
+int     tFBleveller_setTargetLevel   (tFBleveller* const, float TargetLevel);
+int     tFBleveller_setFactor   (tFBleveller* const, float factor);
+int     tFBleveller_setMode   (tFBleveller* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting
+int     tFBleveller_setStrength   (tFBleveller* const, float strength);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* Simple Living String */
+typedef struct _tSimpleLivingString {
+	float freq, waveLengthInSamples;		// the frequency of the string, determining delay length
+	float dampFreq;	// frequency for the bridge LP filter, in Hz
+	float decay; // amplitude damping factor for the string (only active in mode 0)
+	float levMode;
+	float curr;
+	tDelayL delayLine;
+	tOnePole bridgeFilter;
+	tHighpass DCblocker;
+	tFBleveller fbLev;
+	tExpSmooth wlSmooth;
+} tSimpleLivingString;
+
+void    tSimpleLivingString_init      (tSimpleLivingString* const, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode);
+void    tSimpleLivingString_free      (tSimpleLivingString* const);
+float   tSimpleLivingString_tick      (tSimpleLivingString* const, float input);
+float   tSimpleLivingString_sample    (tSimpleLivingString* const);
+int     tSimpleLivingString_setFreq   			(tSimpleLivingString* const, float freq);
+int     tSimpleLivingString_setWaveLength		(tSimpleLivingString* const, float waveLength); // in samples
+int     tSimpleLivingString_setDampFreq   		(tSimpleLivingString* const, float dampFreq);
+int     tSimpleLivingString_setDecay     		(tSimpleLivingString* const, float decay); // should be near 1.0
+int     tSimpleLivingString_setTargetLev		(tSimpleLivingString* const, float targetLev);
+int     tSimpleLivingString_setLevSmoothFactor  (tSimpleLivingString* const, float levSmoothFactor);
+int     tSimpleLivingString_setLevStrength		(tSimpleLivingString* const, float levStrength);
+int     tSimpleLivingString_setLevMode		(tSimpleLivingString* const, int levMode);
+
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* Living String */
+typedef struct _tLivingString {
+	float freq, waveLengthInSamples;		// the frequency of the whole string, determining delay length
+	float pickPos;	// the pick position, dividing the string in two, in ratio
+	float prepIndex;	// the amount of pressure on the pickpoint of the string (near 0=soft obj, near 1=hard obj)
+	float dampFreq;	// frequency for the bridge LP filter, in Hz
+	float decay; // amplitude damping factor for the string (only active in mode 0)
+	float levMode;
+	float curr;
+	tDelayL delLF,delUF,delUB,delLB;	// delay for lower/upper/forward/backward part of the waveguide model
+	tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL;
+	tHighpass DCblockerL, DCblockerU;
+	tFBleveller fbLevU, fbLevL;
+	tExpSmooth wlSmooth, ppSmooth;
+} tLivingString;
+
+void    tLivingString_init      (tLivingString* const, float freq, float pickPos, float prepIndex, float dampFreq, float decay,
+												float targetLev, float levSmoothFactor, float levStrength, int levMode);
+void    tLivingString_free      (tLivingString* const);
+float   tLivingString_tick      (tLivingString* const, float input);
+float   tLivingString_sample    (tLivingString* const);
+int     tLivingString_setFreq   			(tLivingString* const, float freq);
+int     tLivingString_setWaveLength			(tLivingString* const, float waveLength); // in samples
+int     tLivingString_setPickPos   			(tLivingString* const, float pickPos);
+int     tLivingString_setPrepIndex 			(tLivingString* const, float prepIndex);
+int     tLivingString_setDampFreq   		(tLivingString* const, float dampFreq);
+int     tLivingString_setDecay     			(tLivingString* const, float decay); // should be near 1.0
+int     tLivingString_setTargetLev			(tLivingString* const, float targetLev);
+int     tLivingString_setLevSmoothFactor  	(tLivingString* const, float levSmoothFactor);
+int     tLivingString_setLevStrength		(tLivingString* const, float levStrength);
+int     tLivingString_setLevMode			(tLivingString* const, int levMode);
+
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
 /* Compressor */
 typedef struct _tCompressor
 {
@@ -86,7 +231,7 @@
 void    tCompressor_free    (tCompressor* const);
 float   tCompressor_tick    (tCompressor* const, float input);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 /* Attack-Decay envelope */
 typedef struct _tEnvelope {
@@ -118,7 +263,7 @@
 int     tEnvelope_loop      (tEnvelope*  const, oBool loop);
 int     tEnvelope_on        (tEnvelope*  const, float velocity);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 /* ADSR */
 typedef struct _tADSR
@@ -150,7 +295,7 @@
 int     tADSR_on        (tADSR*  const, float velocity);
 int     tADSR_off       (tADSR*  const);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 /* Envelope Follower */
 typedef struct _tEnvelopeFollower
@@ -168,7 +313,7 @@
 int     tEnvelopeFollower_decayCoeff     (tEnvelopeFollower*  const, float decayCoeff);
 int     tEnvelopeFollower_attackThresh   (tEnvelopeFollower*  const, float attackThresh);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 /* tAtkDtk */
 #define DEFBLOCKSIZE 1024
@@ -219,7 +364,7 @@
 // find largest transient in input block, return index of attack
 int     tAtkDtk_detect          (tAtkDtk* const, float *in);
 
-//==============================================================================
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
 
 // ENV~ from PD, modified for LEAF
 #define MAXOVERLAP 32
@@ -244,14 +389,12 @@
 float   tEnv_tick           (tEnv* const);
 void    tEnv_processBlock   (tEnv* const, float* in);
 
-//==============================================================================
-    
-#ifdef __cplusplus
-}
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+    
+#ifdef __cplusplus
+}
 #endif
 
-#endif  // LEAF_UTILITIES_H_INCLUDED
-
-//==============================================================================
+#endif  // LEAFUTILITIES_H_INCLUDED
 
 
--- a/LEAF/Inc/leaf-vocoder.h
+++ b/LEAF/Inc/leaf-vocoder.h
@@ -22,7 +22,7 @@
 
 /* tTalkbox */
 #define NUM_TALKBOX_PARAM 4
-#define TALKBOX_BUFFER_LENGTH 1024 //1600
+#define TALKBOX_BUFFER_LENGTH   1024    // Every talkbox instance introduces 5 buffers of this size - was originally 1600
 
 typedef struct _tTalkbox
 {
--- a/LEAF/Src/leaf-delay.c
+++ b/LEAF/Src/leaf-delay.c
@@ -178,6 +178,30 @@
     return d->lastOut;
 }
 
+void   tDelayL_tickIn (tDelayL* const d, float input)
+{
+    d->buff[d->inPoint] = input * d->gain;
+
+    // Increment input pointer modulo length.
+    if (++(d->inPoint) == d->maxDelay )    d->inPoint = 0;
+}
+
+float   tDelayL_tickOut (tDelayL* const d)
+{
+    uint32_t idx = (uint32_t) d->outPoint;
+
+    d->lastOut =    LEAF_interpolate_hermite (d->buff[((idx - 1) + d->maxDelay) % d->maxDelay],
+                                              d->buff[idx],
+                                              d->buff[(idx + 1) % d->maxDelay],
+                                              d->buff[(idx + 2) % d->maxDelay],
+                                              d->alpha);
+
+    // Increment output pointer modulo length
+    if ( (++d->outPoint) >= d->maxDelay )   d->outPoint = 0;
+
+    return d->lastOut;
+}
+
 int     tDelayL_setDelay (tDelayL* const d, float delay)
 {
     d->delay = LEAF_clip(0.0f, delay,  d->maxDelay);
--- /dev/null
+++ b/LEAF/Src/leaf-oversampler.c
@@ -1,0 +1,124 @@
+//
+//  leaf-oversampler.c
+//  LEAF
+//
+//  Created by Matthew Wang and Joshua Becker on 2/28/19.
+//  Copyright © 2019 Princeton University. All rights reserved.
+//
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-oversampler.h"
+#else
+
+#include "../Inc/leaf-oversampler.h"
+
+#endif
+
+// Currently just using a double sample rate version of SVF from leaf-filter.c, may want to implement better filter for oversampling.
+// Quick testing seems to indicate that this filter sufficiently handles most aliasing.
+void tOversamplerFilter_init(tOversamplerFilter* const lpf, float freq, float Q, float sampleRateMultiplier)
+{
+    lpf->ic1eq = 0;
+    lpf->ic2eq = 0;
+    
+    float a1,a2,a3,g,k;
+    float scaledInverseSampleRate = leaf.invSampleRate * (1 / sampleRateMultiplier);
+    
+    g = tanf(PI * freq * scaledInverseSampleRate);
+    k = 1.0f/Q;
+    a1 = 1.0f/(1.0f+g*(g+k));
+    a2 = g*a1;
+    a3 = g*a2;
+    
+    lpf->g = g;
+    lpf->k = k;
+    lpf->a1 = a1;
+    lpf->a2 = a2;
+    lpf->a3 = a3;
+}
+
+float tOversamplerFilter_tick(tOversamplerFilter* const lpf, float v0)
+{
+    float v1,v2,v3;
+    v3 = v0 - lpf->ic2eq;
+    v1 = (lpf->a1 * lpf->ic1eq) + (lpf->a2 * v3);
+    v2 = lpf->ic2eq + (lpf->a2 * lpf->ic1eq) + (lpf->a3 * v3);
+    lpf->ic1eq = (2.0f * v1) - lpf->ic1eq;
+    lpf->ic2eq = (2.0f * v2) - lpf->ic2eq;
+    
+    return v2;
+}
+
+// 2X Oversampler
+void tOversampler2x_init(tOversampler2x* const os)
+{
+    tOversamplerFilter_init(&os->filters[0], leaf.sampleRate*0.5f, 0.1f, 2.f);
+    tOversamplerFilter_init(&os->filters[1], leaf.sampleRate*0.5f, 0.1f, 2.f);
+}
+
+float tOversampler2x_tick(tOversampler2x* const os, float input, float (*nonLinearTick)(float))
+{
+    float sample = input;
+    float oversample = 0.f;
+    
+    sample = tOversamplerFilter_tick(&os->filters[0], sample);
+    oversample = tOversamplerFilter_tick(&os->filters[0], oversample);
+    
+    sample = nonLinearTick(sample);
+    oversample = nonLinearTick(oversample);
+    
+    sample = tOversamplerFilter_tick(&os->filters[1], sample);
+    oversample = tOversamplerFilter_tick(&os->filters[1], oversample);
+    
+    return sample;
+}
+
+// 4X Oversampler
+void tOversampler4x_init(tOversampler4x* const os)
+{
+    tOversamplerFilter_init(&os->filters[0], leaf.sampleRate*0.25f, 0.1f, 2.f); //sample rate was *0.5 but I assume that was copypaste mistake (copied from 2X filter) - JS
+    tOversamplerFilter_init(&os->filters[1], leaf.sampleRate*0.25f, 0.1f, 4.f);
+    tOversamplerFilter_init(&os->filters[2], leaf.sampleRate*0.25f, 0.1f, 4.f);
+    tOversamplerFilter_init(&os->filters[3] , leaf.sampleRate*0.25f, 0.1f, 2.f);
+}
+
+float tOversampler4x_tick(tOversampler4x* const os, float input, float (*nonLinearTick)(float))
+{
+    float sample = input;
+    float oversample1 = 0.f;
+    float oversample2 = 0.f;
+    float oversample3 = 0.f;
+    // Phase 1:
+    //  x = [sample, oversample2]
+    //  lpf(x)
+    // Phase 2:
+    //  x = [sample, oversample1, oversample2, oversample3]
+    //  lpf(dist(lpf(x)))
+    // Phase 3:
+    //  x = [sample, oversample2]
+    //  lpf(x)
+    
+    sample = tOversamplerFilter_tick(&os->filters[0], sample);
+    oversample2 = tOversamplerFilter_tick(&os->filters[0], oversample2);
+    
+    sample = tOversamplerFilter_tick(&os->filters[1], sample);
+    oversample1 = tOversamplerFilter_tick(&os->filters[1], oversample1);
+    oversample2 = tOversamplerFilter_tick(&os->filters[1], oversample2);
+    oversample3 = tOversamplerFilter_tick(&os->filters[1], oversample3);
+    
+    sample = nonLinearTick(sample);
+    oversample1 = nonLinearTick(oversample1);
+    oversample2 = nonLinearTick(oversample2);
+    oversample3 = nonLinearTick(oversample3);
+    
+    sample = tOversamplerFilter_tick(&os->filters[2], sample);
+    oversample1 = tOversamplerFilter_tick(&os->filters[2], oversample1);
+    oversample2 = tOversamplerFilter_tick(&os->filters[2], oversample2);
+    oversample3 = tOversamplerFilter_tick(&os->filters[2], oversample3);
+    
+    sample = tOversamplerFilter_tick(&os->filters[3], sample);
+    oversample2 = tOversamplerFilter_tick(&os->filters[3], oversample2);
+    
+    return sample;
+}
--- a/LEAF/Src/leaf-utilities.c
+++ b/LEAF/Src/leaf-utilities.c
@@ -1,10 +1,12 @@
-/*==============================================================================
+/*
+  ==============================================================================
 
-    leaf-utilities.c
+    LEAFUtilities.c
     Created: 20 Jan 2017 12:02:17pm
     Author:  Michael R Mulshine
 
-==============================================================================*/
+  ==============================================================================
+*/
 
 
 #if _WIN32 || _WIN64
@@ -29,12 +31,12 @@
 {
     if (f <= -1500.0f) return(0);
     else if (f > 1499.0f) return(mtof(1499.0f));
-    else return (8.17579891564f * exp(0.0577622650f * f));
+    else return (8.17579891564f * expf(0.0577622650f * f));
 }
 
 float ftom(float f)
 {
-    return (f > 0 ? 17.3123405046f * log(.12231220585f * f) : -1500.0f);
+    return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
 }
 
 float powtodb(float f)
@@ -42,7 +44,7 @@
     if (f <= 0) return (0);
     else
     {
-        float val = 100 + 10.f/LOGTEN * log(f);
+        float val = 100 + 10.f/LOGTEN * logf(f);
         return (val < 0 ? 0 : val);
     }
 }
@@ -65,7 +67,7 @@
     {
         if (f > 870.0f)
             f = 870.0f;
-        return (exp((LOGTEN * 0.1f) * (f-100.0f)));
+        return (expf((LOGTEN * 0.1f) * (f-100.0f)));
     }
 }
 
@@ -78,7 +80,7 @@
         if (f > 485.0f)
             f = 485.0f;
     }
-    return (exp((LOGTEN * 0.05f) * (f-100.0f)));
+    return (expf((LOGTEN * 0.05f) * (f-100.0f)));
 }
 
 /* ---------------- env~ - simple envelope follower. ----------------- */
@@ -103,7 +105,7 @@
     
     for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
     for (i = 0; i < npoints; i++)
-        x->buf[i] = (1.0f - cos((2 * PI * i) / npoints))/npoints;
+        x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints;
     for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0;
     
     x->x_f = 0;
@@ -761,6 +763,8 @@
     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;
+    // 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
     
     return r->curr;
 }
@@ -775,6 +779,417 @@
     r->inv_sr_ms = 1.0f / (leaf.sampleRate * 0.001f);
     r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms)*((float)r->samples_per_tick);
 }
+
+
+/* Exponential Smoother */
+void    tExpSmooth_init(tExpSmooth* const smooth, float val, float factor)
+{	// factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms
+	smooth->curr=val;
+	smooth->dest=val;
+	if (factor<0) factor=0;
+	if (factor>1) factor=1;
+	smooth->factor=factor;
+	smooth->oneminusfactor=1.0f-factor;
+}
+
+int     tExpSmooth_setFactor(tExpSmooth* const smooth, float factor)
+{	// factor is usually a value between 0 and 0.1. Lower value is slower. 0.01 for example gives you a smoothing time of about 10ms
+	if (factor<0)
+		factor=0;
+	else
+		if (factor>1) factor=1;
+	smooth->factor=factor;
+	smooth->oneminusfactor=1.0f-factor;
+    return 0;
+}
+
+int     tExpSmooth_setDest(tExpSmooth* const smooth, float dest)
+{
+	smooth->dest=dest;
+    return 0;
+}
+
+int     tExpSmooth_setVal(tExpSmooth* const smooth, float val)
+{
+	smooth->curr=val;
+    return 0;
+}
+
+float   tExpSmooth_tick(tExpSmooth* const smooth)
+{
+    smooth->curr = smooth->factor*smooth->dest+smooth->oneminusfactor*smooth->curr;
+    return smooth->curr;
+}
+
+float   tExpSmooth_sample(tExpSmooth* const smooth)
+{
+    return smooth->curr;
+}
+
+
+/* Power Follower */
+
+void    tPwrFollow_init(tPwrFollow* const p, float factor)
+{
+	p->curr=0.0f;
+	p->factor=factor;
+	p->oneminusfactor=1.0f-factor;
+}
+
+int     tPwrFollow_setFactor(tPwrFollow* const p, float factor)
+{
+	if (factor<0) factor=0;
+	if (factor>1) factor=1;
+	p->factor=factor;
+	p->oneminusfactor=1.0f-factor;
+    return 0;
+}
+
+float   tPwrFollow_tick(tPwrFollow* const p, float input)
+{
+    p->curr = p->factor*input*input+p->oneminusfactor*p->curr;
+    return p->curr;
+}
+
+float   tPwrFollow_sample(tPwrFollow* const p)
+{
+    return p->curr;
+}
+
+/* Feedback Leveler */
+
+void    tFBleveller_init(tFBleveller* const p, float targetLevel, float factor, float strength, int mode)
+{
+	p->curr=0.0f;
+	p->targetLevel=targetLevel;
+	tPwrFollow_init(&p->pwrFlw,factor);
+	p->mode=mode;
+	p->strength=strength;
+}
+
+int     tFBleveller_setStrength(tFBleveller* const p, float strength)
+{	// strength is how strongly level diff is affecting the amp ratio
+	// try 0.125 for a start
+	p->strength=strength;
+    return 0;
+}
+
+int     tFBleveller_setFactor(tFBleveller* const p, float factor)
+{
+	tPwrFollow_setFactor(&p->pwrFlw,factor);
+    return 0;
+}
+
+int     tFBleveller_setMode(tFBleveller* const p, int mode)
+{	// 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting)
+	p->mode=mode;
+    return 0;
+}
+
+float   tFBleveller_tick(tFBleveller* const p, float input)
+{
+	float levdiff=(tPwrFollow_tick(&p->pwrFlw, input)-p->targetLevel);
+	if (p->mode==0 && levdiff<0) levdiff=0;
+	p->curr=input*(1-p->strength*levdiff);
+	return p->curr;
+}
+
+float   tFBleveller_sample(tFBleveller* const p)
+{
+    return p->curr;
+}
+
+
+int     tFBleveller_setTargetLevel   (tFBleveller* const p, float TargetLevel)
+{
+	p->targetLevel=TargetLevel;
+}
+
+///Reed Table model
+//default values from STK are 0.6 offset and -0.8 slope
+
+void    tReedTable_init      (tReedTable* const p, float offset, float slope)
+{
+	p->offset = offset;
+	p->slope = slope;
+}
+
+void    tReedTable_free      (tReedTable* const p)
+{
+	;
+}
+
+float   tReedTable_tick      (tReedTable* const p, float input)
+{
+	// The input is differential pressure across the reed.
+	float output = p->offset + (p->slope * input);
+
+	// If output is > 1, the reed has slammed shut and the
+	// reflection function value saturates at 1.0.
+	if ( output > 1.0f) output = 1.0f;
+
+	// This is nearly impossible in a physical system, but
+	// a reflection function value of -1.0 corresponds to
+	// an open end (and no discontinuity in bore profile).
+	if ( output < -1.0f) output = -1.0f;
+
+	return output;
+}
+
+float   tReedTable_tanh_tick     (tReedTable* const p, float input)
+{
+	// The input is differential pressure across the reed.
+	float output = p->offset + (p->slope * input);
+
+	// If output is > 1, the reed has slammed shut and the
+	// reflection function value saturates at 1.0.
+	return tanhf(output);
+}
+
+void     tReedTable_setOffset   (tReedTable* const p, float offset)
+{
+	p->offset = offset;
+}
+
+void     tReedTable_setSlope   (tReedTable* const p, float slope)
+{
+	p->slope = slope;
+}
+
+
+
+/* Simple Living String*/
+
+void    tSimpleLivingString_init(tSimpleLivingString* const p, float freq, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode)
+{
+	p->curr=0.0f;
+	tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions)
+	tSimpleLivingString_setFreq(p, freq);
+	tDelayL_init(&p->delayLine,p->waveLengthInSamples, 2400);
+	tOnePole_init(&p->bridgeFilter, dampFreq);
+	tHighpass_init(&p->DCblocker,13);
+	p->decay=decay;
+	tFBleveller_init(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode);
+	p->levMode=levMode;
+}
+
+int     tSimpleLivingString_setFreq(tSimpleLivingString* const p, float freq)
+{
+	if (freq<20) freq=20;
+	else if (freq>10000) freq=10000;
+	p->waveLengthInSamples = leaf.sampleRate/freq;
+	tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+    return 0;
+}
+
+int     tSimpleLivingString_setWaveLength(tSimpleLivingString* const p, float waveLength)
+{
+	if (waveLength<4.8) waveLength=4.8;
+	else if (waveLength>2400) waveLength=2400;
+	p->waveLengthInSamples = waveLength;
+	tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+    return 0;
+}
+
+int     tSimpleLivingString_setDampFreq(tSimpleLivingString* const p, float dampFreq)
+{
+	tOnePole_setFreq(&p->bridgeFilter, dampFreq);
+    return 0;
+}
+
+int     tSimpleLivingString_setDecay(tSimpleLivingString* const p, float decay)
+{
+	p->decay=decay;
+    return 0;
+}
+
+int     tSimpleLivingString_setTargetLev(tSimpleLivingString* const p, float targetLev)
+{
+	tFBleveller_setTargetLevel(&p->fbLev, targetLev);
+    return 0;
+}
+
+int     tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor)
+{
+	tFBleveller_setFactor(&p->fbLev, levSmoothFactor);
+    return 0;
+}
+
+int     tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength)
+{
+	tFBleveller_setStrength(&p->fbLev, levStrength);
+    return 0;
+}
+
+int     tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode)
+{
+	tFBleveller_setMode(&p->fbLev, levMode);
+	p->levMode=levMode;
+    return 0;
+}
+
+float   tSimpleLivingString_tick(tSimpleLivingString* const p, float input)
+{
+	float stringOut=tOnePole_tick(&p->bridgeFilter,tDelayL_tickOut(&p->delayLine));
+	float stringInput=tHighpass_tick(&p->DCblocker, tFBleveller_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input));
+	tDelayL_tickIn(&p->delayLine, stringInput);
+	tDelayL_setDelay(&p->delayLine, tExpSmooth_tick(&p->wlSmooth));
+    p->curr = stringOut;
+    return p->curr;
+}
+
+float   tSimpleLivingString_sample(tSimpleLivingString* const p)
+{
+    return p->curr;
+}
+
+/* Living String*/
+
+void    tLivingString_init(tLivingString* const p, float freq, float pickPos, float prepIndex, float dampFreq, float decay, float targetLev, float levSmoothFactor, float levStrength, int levMode)
+{
+	p->curr=0.0f;
+	tExpSmooth_init(&p->wlSmooth, leaf.sampleRate/freq, 0.01); // smoother for string wavelength (not freq, to avoid expensive divisions)
+	tLivingString_setFreq(p, freq);
+	tExpSmooth_init(&p->ppSmooth, pickPos, 0.01); // smoother for pick position
+	tLivingString_setPickPos(p, pickPos);
+	p->prepIndex=prepIndex;
+	tDelayL_init(&p->delLF,p->waveLengthInSamples, 2400);
+	tDelayL_init(&p->delUF,p->waveLengthInSamples, 2400);
+	tDelayL_init(&p->delUB,p->waveLengthInSamples, 2400);
+	tDelayL_init(&p->delLB,p->waveLengthInSamples, 2400);
+	tOnePole_init(&p->bridgeFilter, dampFreq);
+	tOnePole_init(&p->nutFilter, dampFreq);
+	tOnePole_init(&p->prepFilterU, dampFreq);
+	tOnePole_init(&p->prepFilterL, dampFreq);
+	tHighpass_init(&p->DCblockerU,13);
+	tHighpass_init(&p->DCblockerL,13);
+	p->decay=decay;
+	tFBleveller_init(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode);
+	tFBleveller_init(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode);
+	p->levMode=levMode;
+}
+
+int     tLivingString_setFreq(tLivingString* const p, float freq)
+{	// NOTE: It is faster to set wavelength in samples directly
+	if (freq<20) freq=20;
+	else if (freq>10000) freq=10000;
+	p->waveLengthInSamples = leaf.sampleRate/freq;
+	tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+    return 0;
+}
+
+int     tLivingString_setWaveLength(tLivingString* const p, float waveLength)
+{
+	if (waveLength<4.8) waveLength=4.8;
+	else if (waveLength>2400) waveLength=2400;
+	p->waveLengthInSamples = waveLength;
+	tExpSmooth_setDest(&p->wlSmooth, p->waveLengthInSamples);
+    return 0;
+}
+
+int     tLivingString_setPickPos(tLivingString* const p, float pickPos)
+{	// between 0 and 1
+	if (pickPos<0.f) pickPos=0.f;
+	else if (pickPos>1.f) pickPos=1.f;
+	p->pickPos = pickPos;
+	tExpSmooth_setDest(&p->ppSmooth, p->pickPos);
+    return 0;
+}
+
+int     tLivingString_setPrepIndex(tLivingString* const p, float prepIndex)
+{	// between 0 and 1
+	if (prepIndex<0.f) prepIndex=0.f;
+	else if (prepIndex>1.f) prepIndex=1.f;
+	p->prepIndex = prepIndex;
+    return 0;
+}
+
+int     tLivingString_setDampFreq(tLivingString* const p, float dampFreq)
+{
+	tOnePole_setFreq(&p->bridgeFilter, dampFreq);
+	tOnePole_setFreq(&p->nutFilter, dampFreq);
+	tOnePole_setFreq(&p->prepFilterU, dampFreq);
+	tOnePole_setFreq(&p->prepFilterL, dampFreq);
+    return 0;
+}
+
+int     tLivingString_setDecay(tLivingString* const p, float decay)
+{
+	p->decay=decay;
+    return 0;
+}
+
+int     tLivingString_setTargetLev(tLivingString* const p, float targetLev)
+{
+	tFBleveller_setTargetLevel(&p->fbLevU, targetLev);
+	tFBleveller_setTargetLevel(&p->fbLevL, targetLev);
+    return 0;
+}
+
+int     tLivingString_setLevSmoothFactor(tLivingString* const p, float levSmoothFactor)
+{
+	tFBleveller_setFactor(&p->fbLevU, levSmoothFactor);
+	tFBleveller_setFactor(&p->fbLevL, levSmoothFactor);
+    return 0;
+}
+
+int     tLivingString_setLevStrength(tLivingString* const p, float levStrength)
+{
+	tFBleveller_setStrength(&p->fbLevU, levStrength);
+	tFBleveller_setStrength(&p->fbLevL, levStrength);
+    return 0;
+}
+
+int     tLivingString_setLevMode(tLivingString* const p, int levMode)
+{
+	tFBleveller_setMode(&p->fbLevU, levMode);
+	tFBleveller_setMode(&p->fbLevL, levMode);
+	p->levMode=levMode;
+    return 0;
+}
+
+float   tLivingString_tick(tLivingString* const p, float input)
+{
+	// from pickPos upwards=forwards
+	float fromLF=tDelayL_tickOut(&p->delLF);
+	float fromUF=tDelayL_tickOut(&p->delUF);
+	float fromUB=tDelayL_tickOut(&p->delUB);
+	float fromLB=tDelayL_tickOut(&p->delLB);
+	// into upper half of string, from nut, going backwards
+	float fromNut=-tFBleveller_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF)));
+	tDelayL_tickIn(&p->delUB, fromNut);
+	// into lower half of string, from pickpoint, going backwards
+	float fromLowerPrep=-tOnePole_tick(&p->prepFilterL, fromLF);
+	float intoLower=p->prepIndex*fromLowerPrep+(1-p->prepIndex)*fromUB+input;
+	tDelayL_tickIn(&p->delLB, intoLower);
+	// into lower half of string, from bridge
+	float fromBridge=-tFBleveller_tick(&p->fbLevL, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB)));
+	tDelayL_tickIn(&p->delLF, fromBridge);
+	// into upper half of string, from pickpoint, going forwards/upwards
+	float fromUpperPrep=-tOnePole_tick(&p->prepFilterU, fromUB);
+	float intoUpper=p->prepIndex*fromUpperPrep+(1-p->prepIndex)*fromLF+input;
+	tDelayL_tickIn(&p->delUF, intoUpper);
+	// update all delay lengths
+	float pickP=tExpSmooth_tick(&p->ppSmooth);
+	float wLen=tExpSmooth_tick(&p->wlSmooth);
+	float lowLen=pickP*wLen;
+	float upLen=(1-pickP)*wLen;
+	tDelayL_setDelay(&p->delLF, lowLen);
+	tDelayL_setDelay(&p->delLB, lowLen);
+	tDelayL_setDelay(&p->delUF, upLen);
+	tDelayL_setDelay(&p->delUB, upLen);
+    p->curr = fromBridge;
+    return p->curr;
+}
+
+float   tLivingString_sample(tLivingString* const p)
+{
+    return p->curr;
+}
+
+
+/* Stack */
+
 // If stack contains note, returns index. Else returns -1;
 int tStack_contains(tStack* const ns, uint16_t noteVal)
 {
--- a/LEAF/Src/leaf-wavefolder.c
+++ b/LEAF/Src/leaf-wavefolder.c
@@ -16,7 +16,7 @@
 
 #endif
 
-void tLockhartWavefolderInit(tLockhartWavefolder* const w)
+void tLockhartWavefolder_init(tLockhartWavefolder* const w)
 {
     w->Ln1 = 0.0;
     w->Fn1 = 0.0;
@@ -54,7 +54,7 @@
     return w;
 }
 
-float tLockhartWavefolderTick(tLockhartWavefolder* const w, float samp)
+float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp)
 {
     int l;
     double u, Ln, Fn, xn;
--- a/LEAF/leaf.h
+++ b/LEAF/leaf.h
@@ -9,14 +9,14 @@
 */
 
 #ifndef LEAF_H_INCLUDED
-#define LEAF_H_INCLUDED
-
-#define LEAF_DEBUG 0
-
-#if LEAF_DEBUG
-#include "../LEAF_JUCEPlugin/JuceLibraryCode/JuceHeader.h"
-#endif
+#define LEAF_H_INCLUDED
 
+#define LEAF_DEBUG 0
+
+#if LEAF_DEBUG
+#include "../LEAF_JUCEPlugin/JuceLibraryCode/JuceHeader.h"
+#endif
+
 #if _WIN32 || _WIN64
 
 #include ".\Inc\leaf-globals.h"
@@ -25,6 +25,7 @@
 #include ".\Inc\leaf-delay.h"
 #include ".\Inc\leaf-filter.h"
 #include ".\Inc\leaf-oscillator.h"
+#include ".\Inc\leaf-oversampler.h"
 #include ".\Inc\leaf-reverb.h"
 #include ".\Inc\leaf-vocoder.h"
 #include ".\Inc\leaf-808.h"
@@ -31,8 +32,8 @@
 #include ".\Inc\leaf-string.h"
 #include ".\Inc\leaf-pitch.h"
 #include ".\Inc\leaf-formant.h"
-#include ".\Inc\leaf-midi.h"
-#include ".\Inc\leaf-sample.h"
+#include ".\Inc\leaf-midi.h"
+#include ".\Inc\leaf-sample.h"
 #include ".\Inc\leaf-crusher.h"
 #include ".\Inc\leaf-wavefolder.h"
 #include ".\Inc\leaf-wavetables.h"
@@ -46,6 +47,7 @@
 #include "./Inc/leaf-delay.h"
 #include "./Inc/leaf-filter.h"
 #include "./Inc/leaf-oscillator.h"
+#include "./Inc/leaf-oversampler.h"
 #include "./Inc/leaf-reverb.h"
 #include "./Inc/leaf-vocoder.h"
 #include "./Inc/leaf-808.h"
@@ -52,25 +54,25 @@
 #include "./Inc/leaf-string.h"
 #include "./Inc/leaf-pitch.h"
 #include "./Inc/leaf-formant.h"
-#include "./Inc/leaf-midi.h"
-#include "./Inc/leaf-sample.h"
+#include "./Inc/leaf-midi.h"
+#include "./Inc/leaf-sample.h"
 #include "./Inc/leaf-crusher.h"
 #include "./Inc/leaf-wavefolder.h"
 #include "./Inc/leaf-wavetables.h"
 #include "./Inc/leaf-crusher.h"
 
-#endif
+#endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#ifdef __cplusplus
+extern "C" {
+#endif
     
 void        LEAF_init            (float sampleRate, int blocksize, float(*randomNumberFunction)(void));
 void        LEAF_setSampleRate   (float sampleRate);
-float       LEAF_getSampleRate   (void);
-
-#ifdef __cplusplus
-}
-#endif
+float       LEAF_getSampleRate   (void);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif  // LEAF_H_INCLUDED
--- a/LEAF_JUCEPlugin/Source/MyTest.cpp
+++ b/LEAF_JUCEPlugin/Source/MyTest.cpp
@@ -191,3 +191,4 @@
     
     leaf_pool_dump();
 }
+