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)