shithub: leaf

Download patch

ref: 6d13ff665679ae51cbad437a46d17236441afaa9
parent: 9179bd92e043cbd585ce50acb0caa7cb96d6fd16
author: Matthew Wang <Matthew@nat-oitwireless-inside-vapornet100-10-9-61-0.princeton.edu>
date: Thu Feb 28 14:59:03 EST 2019

Working oversampler 2x and 4x with modified SVF filter. May want to implement steeper filter later.

--- /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
+
+//==============================================================================
--- /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.5f, 0.1f, 2.f);
+    tOversamplerFilter_init(&os->filters[1], leaf.sampleRate*0.5f, 0.1f, 4.f);
+    tOversamplerFilter_init(&os->filters[2], leaf.sampleRate*0.5f, 0.1f, 4.f);
+    tOversamplerFilter_init(&os->filters[3] , leaf.sampleRate*0.5f, 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-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"
@@ -45,6 +46,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"
@@ -51,24 +53,24 @@
 #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"
 
-#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/LEAFLink.cpp
+++ b/LEAF_JUCEPlugin/Source/LEAFLink.cpp
@@ -20,11 +20,9 @@
 
 std::vector<juce::String> cSliderNames =  std::vector<juce::String>
 {
-    "sr",
-    "rnd",
-    "qual",
-    "op",
-    "mix"
+    "gain",
+    "frequency",
+    "distortion"
 };
 
 std::vector<juce::String> cComboBoxNames =  std::vector<juce::String>
--- a/LEAF_JUCEPlugin/Source/MyTest.cpp
+++ b/LEAF_JUCEPlugin/Source/MyTest.cpp
@@ -16,74 +16,46 @@
 static void leaf_pool_dump(void);
 static void run_pool_test(void);
 
-float mix = 0.f;
-float fx = 1.f;
-
-tCrusher crusher;
+float gain, freqVal;
+float clipThreshold = 1.f;
 
+tCycle test;
+tOversampler2x os2;
+tOversampler4x os4;
+
 void    LEAFTest_init            (float sampleRate, int blockSize)
 {
     LEAF_init(sampleRate, blockSize, &randomNumberGenerator);
 
-    tCrusher_init(&crusher);
+    tCycle_init(&test);
+    tOversampler2x_init(&os2);
+    tOversampler4x_init(&os4);
     
     leaf_pool_report();
 }
 
-int timer = 0;
 
+float softClip(float sample)
+{
+    return LEAF_softClip(sample, clipThreshold);
+}
+
 float   LEAFTest_tick            (float input)
-{
-    float sample = 0.f;
-    
-    sample = (mix * tCrusher_tick(&crusher, input)) + ((1.f - mix) * input);
+{
+    tCycle_setFreq(&test, freqVal);
+    float sample = tCycle_tick(&test);
     
-    return sample;
+    sample = tOversampler4x_tick(&os4, sample, &softClip);
+    
+    return sample * gain;
 }
 
 bool lastState = false, lastPlayState = false;
 void    LEAFTest_block           (void)
 {
-    float val = getSliderValue("mix");
-    
-    mix = val;
-    
-    val = getSliderValue("sr");
-    
-    tCrusher_setSamplingRatio(&crusher, val * 3.99f + 0.01f);
-    
-    val = getSliderValue("rnd");
-    
-    tCrusher_setRound(&crusher, val);
-    
-    val = getSliderValue("qual");
-    
-    tCrusher_setQuality(&crusher, val);
-    
-    val = getSliderValue("op");
-    
-    tCrusher_setOperation(&crusher, val);
-    
-    /*
-    float samp = -1.f + 2.f * val;
-    
-    union unholy_t bw;
-    bw.f = samp;
-    bw.i = (bw.i | (op << 23));
-    
-    DBG(String(samp) + " " + String(bw.f));
-     */
-    
-    // rounding test
-    /*
-    val = getSliderValue("rnd");
-    
-    float to_rnd = -1.f + 2.f * val;
-    
-    float rnd = LEAF_round(to_rnd, 0.3f);
-    
-    DBG("to_rnd: " + String(to_rnd) + " rnd: " + String(rnd));
-     */
+    clipThreshold = (1.f - getSliderValue("distortion")) * 0.3f;
+    gain = getSliderValue("gain") * 0.5f;
+    freqVal = getSliderValue("frequency") * 18000.f;
 }
 
 void    LEAFTest_controllerInput (int cnum, float cval)