ref: 7803edf0b50bd7e394b618d8eaa4fb97de600bd6
parent: 3b564d49db43601e7e6bbe0b013febbbd90217a4
author: Matthew Wang <Matthew@nat-oitwireless-inside-vapornet100-10-9-82-139.princeton.edu>
date: Fri Oct 25 08:17:42 EDT 2019
recategorization of objects, some objects renamed
binary files a/LEAF/Inc/.DS_Store b/LEAF/Inc/.DS_Store differ
--- a/LEAF/Inc/leaf-808.h
+++ /dev/null
@@ -1,184 +1,0 @@
-/*==============================================================================
-
- leaf-808.h
- Created: 30 Nov 2018 10:24:44am
- Author: airship
-
-==============================================================================*/
-
-#ifndef LEAF_808_H_INCLUDED
-#define LEAF_808_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-math.h"
-#include "leaf-oscillator.h"
-#include "leaf-utilities.h"
-#include "leaf-filter.h"
-
-//==============================================================================
-
-// 808 Cowbell
-typedef struct _t808Cowbell {
-
- tSquare p[2];
- tNoise stick;
- tSVF bandpassOsc;
- tSVF bandpassStick;
- tEnvelope envGain;
- tEnvelope envStick;
- tEnvelope envFilter;
- tHighpass highpass;
- float oscMix;
- float filterCutoff;
- oBool useStick;
-
-} t808Cowbell;
-
-void t808Cowbell_init (t808Cowbell* const, int useStick);
-void t808Cowbell_free (t808Cowbell* const);
-float t808Cowbell_tick (t808Cowbell* const);
-void t808Cowbell_on (t808Cowbell* const, float vel);
-void t808Cowbell_setDecay (t808Cowbell* const, float decay);
-void t808Cowbell_setHighpassFreq (t808Cowbell* const, float freq);
-void t808Cowbell_setBandpassFreq (t808Cowbell* const, float freq);
-void t808Cowbell_setFreq (t808Cowbell* const, float freq);
-void t808Cowbell_setOscMix (t808Cowbell* const, float oscMix);
-void t808Cowbell_setStick (t808Cowbell* const, int useStick);
-
-//==============================================================================
-
-// 808 Hihat
-typedef struct _t808Hihat {
-
- // 6 Square waves
- tSquare p[6];
- tNoise n;
- tSVF bandpassOsc;
- tSVF bandpassStick;
- tEnvelope envGain;
- tEnvelope envStick;
- tEnvelope noiseFMGain;
- tHighpass highpass;
- tNoise stick;
-
- float freq;
- float stretch;
- float FM_amount;
- float oscNoiseMix;
-
-} t808Hihat;
-
-void t808Hihat_init (t808Hihat* const);
-void t808Hihat_free (t808Hihat* const);
-
-float t808Hihat_tick (t808Hihat* const);
-void t808Hihat_on (t808Hihat* const, float vel);
-void t808Hihat_setOscNoiseMix (t808Hihat* const, float oscNoiseMix);
-void t808Hihat_setDecay (t808Hihat* const, float decay);
-void t808Hihat_setHighpassFreq (t808Hihat* const, float freq);
-void t808Hihat_setOscBandpassFreq (t808Hihat* const, float freq);
-void t808Hihat_setOscBandpassQ (t808Hihat* const hihat, float Q);
-void t808Hihat_setStickBandPassFreq (t808Hihat* const, float freq);
-void t808Hihat_setStickBandPassQ (t808Hihat* const hihat, float Q);
-void t808Hihat_setOscFreq (t808Hihat* const, float freq);
-void t808Hihat_setStretch (t808Hihat* const hihat, float stretch);
-void t808Hihat_setFM (t808Hihat* const hihat, float FM_amount);
-
-//==============================================================================
-
-// 808 Snare
-typedef struct _t808Snare {
-
- // Tone 1, Tone 2, Noise
- tTriangle tone[2]; // Tri (not yet antialiased or wavetabled)
- tNoise noiseOsc;
- tSVF toneLowpass[2];
- tSVF noiseLowpass; // Lowpass from SVF filter
- tEnvelope toneEnvOsc[2];
- tEnvelope toneEnvGain[2];
- tEnvelope noiseEnvGain;
- tEnvelope toneEnvFilter[2];
- tEnvelope noiseEnvFilter;
-
- float toneGain[2];
- float noiseGain;
-
- float toneNoiseMix;
-
- float tone1Freq, tone2Freq;
-
- float noiseFilterFreq;
-
-
-} t808Snare;
-
-void t808Snare_init (t808Snare* const);
-void t808Snare_free (t808Snare* const);
-
-float t808Snare_tick (t808Snare* const);
-void t808Snare_on (t808Snare* const, float vel);
-void t808Snare_setTone1Freq (t808Snare* const, float freq);
-void t808Snare_setTone2Freq (t808Snare* const, float freq);
-void t808Snare_setTone1Decay (t808Snare* const, float decay);
-void t808Snare_setTone2Decay (t808Snare* const, float decay);
-void t808Snare_setNoiseDecay (t808Snare* const, float decay);
-void t808Snare_setToneNoiseMix (t808Snare* const, float toneNoiseMix);
-void t808Snare_setNoiseFilterFreq (t808Snare* const, float noiseFilterFreq);
-void t808Snare_setNoiseFilterQ (t808Snare* const, float noiseFilterQ);
-
-//==============================================================================
-
-// 808 Kick
-typedef struct _t808Kick {
-
-
- tCycle tone; // Tri
- tNoise noiseOsc;
- tSVF toneLowpass;
- tEnvelope toneEnvOscChirp;
- tEnvelope toneEnvOscSigh;
- tEnvelope toneEnvGain;
- tEnvelope noiseEnvGain;
- tEnvelope toneEnvFilter;
-
- float toneGain;
- float noiseGain;
-
- float toneInitialFreq;
- float sighAmountInHz;
- float chirpRatioMinusOne;
- float noiseFilterFreq;
-
-
-} t808Kick;
-
-void t808Kick_init (t808Kick* const);
-void t808Kick_free (t808Kick* const);
-
-float t808Kick_tick (t808Kick* const);
-void t808Kick_on (t808Kick* const, float vel);
-void t808Kick_setToneFreq (t808Kick* const, float freq);
-void t808Kick_setToneDecay (t808Kick* const, float decay);
-void t808Kick_setNoiseDecay (t808Kick* const, float decay);
-void t808Kick_setSighAmount (t808Kick* const, float sigh);
-void t808Kick_setChirpAmount (t808Kick* const, float chirp);
-void t808Kick_setToneNoiseMix (t808Kick* const, float toneNoiseMix);
-void t808Kick_setNoiseFilterFreq (t808Kick* const, float noiseFilterFreq);
-void t808Kick_setNoiseFilterQ (t808Kick* const, float noiseFilterQ);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_808_H_INCLUDED
-
-//==============================================================================
-
-
--- a/LEAF/Inc/leaf-WDF.h
+++ /dev/null
@@ -1,89 +1,0 @@
-/*
- * leaf-WDF.h
- *
- * Created on: Sep 25, 2019
- * Author: jeffsnyder
- */
-
-#ifndef LEAF_INC_LEAF_WDF_H_
-#define LEAF_INC_LEAF_WDF_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-//==============================================================================
-
-typedef enum WDFComponentType
-{
- SeriesAdaptor = 0,
- ParallelAdaptor,
- Resistor,
- Capacitor,
- Inductor,
- Inverter,
- ResistiveSource,
- IdealSource,
- Diode,
- DiodePair,
- RootNil,
- WDFComponentNil
-} WDFComponentType;
-
-typedef struct _tWDF tWDF; // needed to allow tWDF pointers in struct
-struct _tWDF
-{
- WDFComponentType type;
- float port_resistance_up;
- float port_resistance_left;
- float port_resistance_right;
- float port_conductance_up;
- float port_conductance_left;
- float port_conductance_right;
- float incident_wave_up;
- float incident_wave_left;
- float incident_wave_right;
- float reflected_wave_up;
- float reflected_wave_left;
- float reflected_wave_right;
- float gamma_zero;
- float sample_rate;
- float value;
- tWDF* child_left;
- tWDF* child_right;
- float (*get_port_resistance)(tWDF* const);
- float (*get_reflected_wave_up)(tWDF* const, float);
- float (*get_reflected_wave_down)(tWDF* const, float, float);
- void (*set_incident_wave)(tWDF* const, float, float);
-};
-
-//WDF Linear Components
-void tWDF_init(tWDF* const r, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR);
-void tWDF_free(tWDF* const r);
-float tWDF_tick(tWDF* const r, float sample, tWDF* const outputPoint, uint8_t paramsChanged);
-
-void tWDF_setValue(tWDF* const r, float value);
-void tWDF_setSampleRate(tWDF* const r, float sample_rate);
-uint8_t tWDF_isLeaf(tWDF* const r);
-
-float tWDF_getPortResistance(tWDF* const r);
-float tWDF_getReflectedWaveUp(tWDF* const r, float input); //for tree, only uses input for resistive source
-float tWDF_getReflectedWaveDown(tWDF* const r, float input, float incident_wave); //for roots
-void tWDF_setIncidentWave(tWDF* const r, float incident_wave, float input);
-
-float tWDF_getVoltage(tWDF* const r);
-float tWDF_getCurrent(tWDF* const r);
-
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LEAF_INC_LEAF_WDF_H_ */
--- /dev/null
+++ b/LEAF/Inc/leaf-analysis.h
@@ -1,0 +1,226 @@
+/*==============================================================================
+
+ leaf-analysis.h
+ Created: 25 Oct 2019 10:30:52am
+ Author: Matthew Wang
+
+ ==============================================================================*/
+
+#ifndef LEAF_ANALYSIS_H_INCLUDED
+#define LEAF_ANALYSIS_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-mempool.h"
+#include "leaf-math.h"
+#include "leaf-filters.h"
+
+//==============================================================================
+
+/* Envelope Follower */
+typedef struct _tEnvelopeFollower
+{
+ float y;
+ float a_thresh;
+ float d_coeff;
+
+} tEnvelopeFollower;
+
+void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff);
+void tEnvelopeFollower_free (tEnvelopeFollower* const);
+
+float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x);
+int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
+int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* PowerEnvelopeFollower */
+typedef struct _tPowerFollower {
+ float factor, oneminusfactor;
+ float curr;
+
+} tPowerFollower;
+
+void tPowerFollower_init (tPowerFollower* const, float factor);
+void tPowerFollower_free (tPowerFollower* const);
+float tPowerFollower_tick (tPowerFollower* const, float input);
+float tPowerFollower_sample (tPowerFollower* const);
+int tPowerFollower_setFactor (tPowerFollower* const, float factor);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+// ENV~ from PD, modified for LEAF
+#define MAXOVERLAP 32
+#define INITVSTAKEN 64
+#define ENV_WINDOW_SIZE 1024
+#define ENV_HOP_SIZE 256
+
+typedef struct _tEnvPD
+{
+ float buf[ENV_WINDOW_SIZE + INITVSTAKEN];
+ uint16_t x_phase; /* number of points since last output */
+ uint16_t x_period; /* requested period of output */
+ uint16_t x_realperiod; /* period rounded up to vecsize multiple */
+ uint16_t x_npoints; /* analysis window size in samples */
+ float x_result; /* result to output */
+ float x_sumbuf[MAXOVERLAP]; /* summing buffer */
+ float x_f;
+ uint16_t windowSize, hopSize, blockSize;
+ uint16_t x_allocforvs; /* extra buffer for DSP vector size */
+} tEnvPD;
+
+void tEnvPD_init (tEnvPD* const, int windowSize, int hopSize, int blockSize);
+void tEnvPD_free (tEnvPD* const);
+float tEnvPD_tick (tEnvPD* const);
+void tEnvPD_processBlock (tEnvPD* const, float* in);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* tAttackDetection */
+#define DEFBLOCKSIZE 1024
+#define DEFTHRESHOLD 6
+#define DEFATTACK 10
+#define DEFRELEASE 10
+
+typedef struct _tAttackDetection
+{
+ float env;
+
+ //Attack & Release times in msec
+ int atk;
+ int rel;
+
+ //Attack & Release coefficients based on times
+ float atk_coeff;
+ float rel_coeff;
+
+ int blocksize;
+ int samplerate;
+
+ //RMS amplitude of previous block - used to decide if attack is present
+ float prevAmp;
+
+ float threshold;
+} tAttackDetection;
+
+void tAttackDetection_init (tAttackDetection* const, int blocksize);
+void tAttackDetection_init_expanded (tAttackDetection* const, int blocksize, int atk, int rel);
+void tAttackDetection_free (tAttackDetection* const);
+
+// set expected input blocksize
+void tAttackDetection_setBlocksize (tAttackDetection* const, int size);
+
+// change atkDetector sample rate
+void tAttackDetection_setSamplerate (tAttackDetection* const, int inRate);
+
+// set attack time and coeff
+void tAttackDetection_setAtk (tAttackDetection* const, int inAtk);
+
+// set release time and coeff
+void tAttackDetection_setRel (tAttackDetection* const, int inRel);
+
+// set level above which values are identified as attacks
+void tAttackDetection_setThreshold (tAttackDetection* const, float thres);
+
+// find largest transient in input block, return index of attack
+int tAttackDetection_detect (tAttackDetection* const, float *in);
+
+//==============================================================================
+
+// tSNAC: period detector
+#define SNAC_FRAME_SIZE 1024 // default analysis framesize // should be the same as (or smaller than?) PS_FRAME_SIZE
+#define DEFOVERLAP 1 // default overlap
+#define DEFBIAS 0.2f // default bias
+#define DEFMINRMS 0.003f // default minimum RMS
+#define SEEK 0.85f // seek-length as ratio of framesize
+
+typedef struct _tSNAC
+{
+ float* inputbuf;
+ float* processbuf;
+ float* spectrumbuf;
+ float* biasbuf;
+ uint16_t timeindex;
+ uint16_t framesize;
+ uint16_t overlap;
+ uint16_t periodindex;
+
+ float periodlength;
+ float fidelity;
+ float biasfactor;
+ float minrms;
+
+} tSNAC;
+
+void tSNAC_init (tSNAC* const, int overlaparg); // constructor
+void tSNAC_free (tSNAC* const); // destructor
+
+void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size);
+void tSNAC_setOverlap (tSNAC *s, int lap);
+void tSNAC_setBias (tSNAC *s, float bias);
+void tSNAC_setMinRMS (tSNAC *s, float rms);
+
+/*To get freq, perform SAMPLE_RATE/snac_getperiod() */
+float tSNAC_getPeriod (tSNAC *s);
+float tSNAC_getfidelity (tSNAC *s);
+
+#define DEFPITCHRATIO 2.0f
+#define DEFTIMECONSTANT 100.0f
+#define DEFHOPSIZE 64
+#define DEFWINDOWSIZE 64
+#define FBA 20
+#define HPFREQ 40.0f
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+// Period detection
+typedef struct _tPeriodDetection
+{
+ tEnvPD env;
+ tSNAC snac;
+ float* inBuffer;
+ float* outBuffer;
+ int frameSize;
+ int bufSize;
+ int framesPerBuffer;
+ int curBlock;
+ int lastBlock;
+ int i;
+ int indexstore;
+ int iLast;
+ int index;
+ float period;
+
+ uint16_t hopSize;
+ uint16_t windowSize;
+ uint8_t fba;
+
+ float timeConstant;
+ float radius;
+ float max;
+ float lastmax;
+ float deltamax;
+
+}tPeriodDetection;
+
+void tPeriodDetection_init (tPeriodDetection* const, float* in, float* out, int bufSize, int frameSize);
+void tPeriodDetection_free (tPeriodDetection* const);
+
+float tPeriodDetection_findPeriod (tPeriodDetection* const, float sample);
+void tPeriodDetection_setHopSize (tPeriodDetection* p, int hs);
+void tPeriodDetection_setWindowSize (tPeriodDetection* p, int ws);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_ANALYSIS_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-crusher.h
+++ /dev/null
@@ -1,64 +1,0 @@
-/*
- ==============================================================================
-
- leaf-crusher.h
- Created: 7 Feb 2019 10:58:22am
- Author: airship
-
- ==============================================================================
-*/
-
-#ifndef LEAF_CRUSHER_H_INCLUDED
-#define LEAF_CRUSHER_H_INCLUDED
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-//==============================================================================
-
-typedef struct _tCrusher
-{
- float srr;
- float mult, div;
- float rnd;
-
- uint32_t op; //which bitwise operation (0-7)
-
- float gain;
-
-} tCrusher;
-
-
-void tCrusher_init (tCrusher* const);
-void tCrusher_free (tCrusher* const);
-
-float tCrusher_tick (tCrusher* const, float input);
-
-// 0.0 - 1.0
-void tCrusher_setOperation (tCrusher* const, float op);
-
-// 0.0 - 1.0
-void tCrusher_setQuality (tCrusher* const, float val);
-
-// what division to round to
-void tCrusher_setRound (tCrusher* const, float rnd);
-
-// sampling ratio
-void tCrusher_setSamplingRatio (tCrusher* const, float ratio);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_WAVEFOLDER_H_INCLUDED
-
-//==============================================================================
--- a/LEAF/Inc/leaf-delay.h
+++ b/LEAF/Inc/leaf-delay.h
@@ -48,7 +48,7 @@
//==============================================================================
/* Linearly-interpolating delay, reimplemented from STK (Cook and Scavone). */
-typedef struct _tDelayL
+typedef struct _tLinearDelay
{
float gain;
float* buff;
@@ -63,26 +63,26 @@
float alpha, omAlpha;
-} tDelayL;
+} tLinearDelay;
-void tDelayL_init (tDelayL* const, float delay, uint32_t maxDelay);
-void tDelayL_free (tDelayL* const);
+void tLinearDelay_init (tLinearDelay* const, float delay, uint32_t maxDelay);
+void tLinearDelay_free (tLinearDelay* const);
-int tDelayL_setDelay (tDelayL* const, float delay);
-float tDelayL_getDelay (tDelayL* const);
-void tDelayL_tapIn (tDelayL* const, float in, uint32_t tapDelay);
-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);
+int tLinearDelay_setDelay (tLinearDelay* const, float delay);
+float tLinearDelay_getDelay (tLinearDelay* const);
+void tLinearDelay_tapIn (tLinearDelay* const, float in, uint32_t tapDelay);
+float tLinearDelay_tapOut (tLinearDelay* const, float tapDelay);
+float tLinearDelay_addTo (tLinearDelay* const, float value, uint32_t tapDelay);
+float tLinearDelay_tick (tLinearDelay* const, float sample);
+void tLinearDelay_tickIn (tLinearDelay* const d, float input);
+float tLinearDelay_tickOut (tLinearDelay* const d);
+float tLinearDelay_getLastOut (tLinearDelay* const);
+float tLinearDelay_getLastIn (tLinearDelay* const);
//==============================================================================
/* Allpass-interpolating delay, reimplemented from STK (Cook and Scavone). */
-typedef struct _tDelayA
+typedef struct _tAllpassDelay
{
float gain;
float* buff;
@@ -99,19 +99,19 @@
float apInput;
-} tDelayA;
+} tAllpassDelay;
-void tDelayA_init (tDelayA* const, float delay, uint32_t maxDelay);
-void tDelayA_free (tDelayA* const);
+void tAllpassDelay_init (tAllpassDelay* const, float delay, uint32_t maxDelay);
+void tAllpassDelay_free (tAllpassDelay* const);
-int tDelayA_setDelay (tDelayA* const, float delay);
-float tDelayA_getDelay (tDelayA* const);
-void tDelayA_tapIn (tDelayA* const, float in, uint32_t tapDelay);
-float tDelayA_tapOut (tDelayA* const, uint32_t tapDelay);
-float tDelayA_addTo (tDelayA* const, float value, uint32_t tapDelay);
-float tDelayA_tick (tDelayA* const, float sample);
-float tDelayA_getLastOut (tDelayA* const);
-float tDelayA_getLastIn (tDelayA* const);
+int tAllpassDelay_setDelay (tAllpassDelay* const, float delay);
+float tAllpassDelay_getDelay (tAllpassDelay* const);
+void tAllpassDelay_tapIn (tAllpassDelay* const, float in, uint32_t tapDelay);
+float tAllpassDelay_tapOut (tAllpassDelay* const, uint32_t tapDelay);
+float tAllpassDelay_addTo (tAllpassDelay* const, float value, uint32_t tapDelay);
+float tAllpassDelay_tick (tAllpassDelay* const, float sample);
+float tAllpassDelay_getLastOut (tAllpassDelay* const);
+float tAllpassDelay_getLastIn (tAllpassDelay* const);
//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-distortion.h
@@ -1,0 +1,99 @@
+/*==============================================================================
+
+ leaf-distortion.h
+ Created: 25 Oct 2019 10:23:28am
+ Author: Matthew Wang
+
+==============================================================================*/
+
+#ifndef LEAF_DISTORTION_H_INCLUDED
+#define LEAF_DISTORTION_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-mempool.h"
+#include "leaf-math.h"
+
+//==============================================================================
+
+/* tLockhartWavefolder */
+
+typedef struct _tLockhartWavefolder
+{
+ double Ln1;
+ double Fn1;
+ float xn1;
+
+} tLockhartWavefolder;
+
+void tLockhartWavefolder_init (tLockhartWavefolder* const);
+void tLockhartWavefolder_free (tLockhartWavefolder* const);
+
+float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp);
+
+//==============================================================================
+
+typedef struct _tCrusher
+{
+ float srr;
+ float mult, div;
+ float rnd;
+
+ uint32_t op; //which bitwise operation (0-7)
+
+ float gain;
+
+} tCrusher;
+
+
+void tCrusher_init (tCrusher* const);
+void tCrusher_free (tCrusher* const);
+
+float tCrusher_tick (tCrusher* const, float input);
+
+// 0.0 - 1.0
+void tCrusher_setOperation (tCrusher* const, float op);
+
+// 0.0 - 1.0
+void tCrusher_setQuality (tCrusher* const, float val);
+
+// what division to round to
+void tCrusher_setRound (tCrusher* const, float rnd);
+
+// sampling ratio
+void tCrusher_setSamplingRatio (tCrusher* const, float ratio);
+
+//==============================================================================
+
+typedef struct _tOversampler
+{
+ int ratio;
+ float* pCoeffs;
+ float* upState;
+ float* downState;
+ int numTaps;
+ int phaseLength;
+} tOversampler;
+
+void tOversampler_init(tOversampler* const, int order, oBool extraQuality);
+void tOversampler_free(tOversampler* const);
+void tOversampler_upsample(tOversampler* const, float input, float* output);
+float tOversampler_downsample(tOversampler *const os, float* input);
+float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float));
+int tOversampler_getLatency(tOversampler* const os);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_DISTORTION_H_INCLUDED
+
+//==============================================================================
+
--- /dev/null
+++ b/LEAF/Inc/leaf-dynamics.h
@@ -1,0 +1,79 @@
+/*==============================================================================
+
+ leaf-dynamics.h
+ Created: 30 Nov 2018 11:57:05am
+ Author: airship
+
+==============================================================================*/
+
+#ifndef LEAF_DYNAMICS_H_INCLUDED
+#define LEAF_DYNAMICS_H_INCLUDED
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-math.h"
+#include "leaf-analysis.h"
+
+//==============================================================================
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* Compressor */
+typedef struct _tCompressor
+{
+ float tauAttack, tauRelease;
+ float T, R, W, M; // Threshold, compression Ratio, decibel Width of knee transition, decibel Make-up gain
+
+ float x_G[2], y_G[2], x_T[2], y_T[2];
+
+ oBool isActive;
+
+}tCompressor;
+
+void tCompressor_init (tCompressor* const);
+void tCompressor_free (tCompressor* const);
+float tCompressor_tick (tCompressor* const, float input);
+
+///
+/* 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 _tFeedbackLeveler {
+ 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;
+ tPowerFollower pwrFlw; // internal power follower needed for level tracking
+
+} tFeedbackLeveler;
+
+void tFeedbackLeveler_init (tFeedbackLeveler* const, float targetLevel, float factor, float strength, int mode);
+void tFeedbackLeveler_free (tFeedbackLeveler* const);
+
+float tFeedbackLeveler_tick (tFeedbackLeveler* const, float input);
+float tFeedbackLeveler_sample (tFeedbackLeveler* const);
+void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const, float TargetLevel);
+void tFeedbackLeveler_setFactor (tFeedbackLeveler* const, float factor);
+void tFeedbackLeveler_setMode (tFeedbackLeveler* const, int mode); // 0 for upwards limiting only, 1 for biderctional limiting
+void tFeedbackLeveler_setStrength (tFeedbackLeveler* const, float strength);
+
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_DYNAMICS_H_INCLUDED
+
+//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-effects.h
@@ -1,0 +1,251 @@
+/*==============================================================================
+
+ leaf-effects.h
+ Created: 20 Jan 2017 12:01:54pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#ifndef LEAF_EFFECTS_H_INCLUDED
+#define LEAF_EFFECTS_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-math.h"
+#include "leaf-analysis.h"
+
+//==============================================================================
+
+/* tTalkbox */
+#define NUM_TALKBOX_PARAM 4
+
+typedef struct _tTalkbox
+{
+ float param[NUM_TALKBOX_PARAM];
+
+ int bufsize;
+ float* car0;
+ float* car1;
+ float* window;
+ float* buf0;
+ float* buf1;
+
+ float emphasis;
+ int32_t K, N, O, pos;
+ float wet, dry, FX;
+ float d0, d1, d2, d3, d4;
+ float u0, u1, u2, u3, u4;
+
+} tTalkbox;
+
+void tTalkbox_init (tTalkbox* const, int bufsize);
+void tTalkbox_free (tTalkbox* const);
+float tTalkbox_tick (tTalkbox* const, float synth, float voice);
+void tTalkbox_update (tTalkbox* const);
+void tTalkbox_suspend (tTalkbox* const);
+void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
+void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o);
+void tTalkbox_setQuality (tTalkbox* const, float quality);
+
+//==============================================================================
+
+/* tVocoder */
+#define NUM_VOCODER_PARAM 8
+#define NBANDS 16
+
+typedef struct _tVocoder
+{
+ float param[NUM_VOCODER_PARAM];
+
+ float gain; //output level
+ float thru, high; //hf thru
+ float kout; //downsampled output
+ int32_t kval; //downsample counter
+ int32_t nbnd; //number of bands
+
+ //filter coeffs and buffers - seems it's faster to leave this global than make local copy
+ float f[NBANDS][13]; //[0-8][0 1 2 | 0 1 2 3 | 0 1 2 3 | val rate]
+
+} tVocoder;
+
+void tVocoder_init (tVocoder* const);
+void tVocoder_free (tVocoder* const);
+float tVocoder_tick (tVocoder* const, float synth, float voice);
+void tVocoder_update (tVocoder* const);
+void tVocoder_suspend (tVocoder* const);
+
+//==============================================================================
+
+
+//==============================================================================
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* tSOLAD : pitch shifting algorithm that underlies tPitchShifter etc */
+#define LOOPSIZE (2048*2) // (4096*2) // loop size must be power of two
+#define LOOPMASK (LOOPSIZE - 1)
+#define PITCHFACTORDEFAULT 1.0f
+#define INITPERIOD 64.0f
+#define MAXPERIOD (float)((LOOPSIZE - w->blocksize) * 0.8f)
+#define MINPERIOD 8.0f
+
+typedef struct _tSOLAD
+{
+ uint16_t timeindex; // current reference time, write index
+ uint16_t blocksize; // signal input / output block size
+ float pitchfactor; // pitch factor between 0.25 and 4
+ float readlag; // read pointer's lag behind write pointer
+ float period; // period length in input signal
+ float jump; // read pointer jump length and direction
+ float xfadelength; // crossfade length expressed at input sample rate
+ float xfadevalue; // crossfade phase and value
+
+ float* delaybuf;
+
+} tSOLAD;
+
+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
+{
+ tEnvPD env;
+ tSNAC snac;
+ tSOLAD sola;
+ tHighpass hp;
+
+ float* inBuffer;
+ float* outBuffer;
+ int frameSize;
+ int bufSize;
+ int framesPerBuffer;
+ int curBlock;
+ int lastBlock;
+ int index;
+
+ uint16_t hopSize;
+ uint16_t windowSize;
+ uint8_t fba;
+
+ float pitchFactor;
+ float timeConstant;
+ float radius;
+ float max;
+ float lastmax;
+ float deltamax;
+
+} tPitchShifter;
+
+void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize);
+void tPitchShifter_free (tPitchShifter* 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
+{
+ tSOLAD sola;
+ tHighpass hp;
+ tPeriodDetection* p;
+
+ 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);
+
+//==============================================================================
+
+#define FORD 7
+#define FORMANT_BUFFER_SIZE 2048
+
+typedef struct _tFormantShifter
+{
+ int ford;
+ int bufsize;
+ float falph;
+ float flamb;
+ float* fk;
+ float* fb;
+ float* fc;
+ float* frb;
+ float* frc;
+ float* fsig;
+ float* fsmooth;
+ float fhp;
+ float flp;
+ float flpa;
+ float** fbuff;
+ float* ftvec;
+ float fmute;
+ float fmutealph;
+ unsigned int cbi;
+
+} tFormantShifter;
+
+void tFormantShifter_init (tFormantShifter* const, int bufsize, int order);
+void tFormantShifter_free (tFormantShifter* const);
+
+float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp);
+float tFormantShifter_remove (tFormantShifter* const, float input);
+float tFormantShifter_add (tFormantShifter* const, float input, float fwarp);
+void tFormantShifter_ioSamples (tFormantShifter* const, float* in, float* out, int size, float fwarp);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_EFFECTS_H_INCLUDED
+
+//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-electrical.h
@@ -1,0 +1,89 @@
+/*
+ * leaf-electrical.h
+ *
+ * Created on: Sep 25, 2019
+ * Author: jeffsnyder
+ */
+
+#ifndef LEAF_INC_LEAF_ELECTRICAL_H_
+#define LEAF_INC_LEAF_ELECTRICAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-math.h"
+
+//==============================================================================
+
+typedef enum WDFComponentType
+{
+ SeriesAdaptor = 0,
+ ParallelAdaptor,
+ Resistor,
+ Capacitor,
+ Inductor,
+ Inverter,
+ ResistiveSource,
+ IdealSource,
+ Diode,
+ DiodePair,
+ RootNil,
+ WDFComponentNil
+} WDFComponentType;
+
+typedef struct _tWDF tWDF; // needed to allow tWDF pointers in struct
+struct _tWDF
+{
+ WDFComponentType type;
+ float port_resistance_up;
+ float port_resistance_left;
+ float port_resistance_right;
+ float port_conductance_up;
+ float port_conductance_left;
+ float port_conductance_right;
+ float incident_wave_up;
+ float incident_wave_left;
+ float incident_wave_right;
+ float reflected_wave_up;
+ float reflected_wave_left;
+ float reflected_wave_right;
+ float gamma_zero;
+ float sample_rate;
+ float value;
+ tWDF* child_left;
+ tWDF* child_right;
+ float (*get_port_resistance)(tWDF* const);
+ float (*get_reflected_wave_up)(tWDF* const, float);
+ float (*get_reflected_wave_down)(tWDF* const, float, float);
+ void (*set_incident_wave)(tWDF* const, float, float);
+};
+
+//WDF Linear Components
+void tWDF_init(tWDF* const r, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR);
+void tWDF_free(tWDF* const r);
+float tWDF_tick(tWDF* const r, float sample, tWDF* const outputPoint, uint8_t paramsChanged);
+
+void tWDF_setValue(tWDF* const r, float value);
+void tWDF_setSampleRate(tWDF* const r, float sample_rate);
+uint8_t tWDF_isLeaf(tWDF* const r);
+
+float tWDF_getPortResistance(tWDF* const r);
+float tWDF_getReflectedWaveUp(tWDF* const r, float input); //for tree, only uses input for resistive source
+float tWDF_getReflectedWaveDown(tWDF* const r, float input, float incident_wave); //for roots
+void tWDF_setIncidentWave(tWDF* const r, float incident_wave, float input);
+
+float tWDF_getVoltage(tWDF* const r);
+float tWDF_getCurrent(tWDF* const r);
+
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LEAF_INC_LEAF_ELECTRICAL_H_ */
--- /dev/null
+++ b/LEAF/Inc/leaf-envelopes.h
@@ -1,0 +1,136 @@
+/*
+ ==============================================================================
+
+ leaf-envelopes.h
+ Created: 20 Jan 2017 12:02:17pm
+ Author: Michael R Mulshine
+
+ ==============================================================================
+*/
+
+#ifndef LEAF_ENVELOPES_H_INCLUDED
+#define LEAF_ENVELOPES_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+#include "leaf-math.h"
+#include "leaf-filters.h"
+#include "leaf-delay.h"
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* Attack-Decay envelope */
+typedef struct _tEnvelope {
+
+ const float *exp_buff;
+ const float *inc_buff;
+ uint32_t buff_size;
+
+ float next;
+
+ float attackInc, decayInc, rampInc;
+
+ oBool inAttack, inDecay, inRamp;
+
+ oBool loop;
+
+ float gain, rampPeak;
+
+ float attackPhase, decayPhase, rampPhase;
+
+} tEnvelope;
+
+void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop);
+void tEnvelope_free (tEnvelope* const);
+
+float tEnvelope_tick (tEnvelope* const);
+int tEnvelope_setAttack (tEnvelope* const, float attack);
+int tEnvelope_setDecay (tEnvelope* const, float decay);
+int tEnvelope_loop (tEnvelope* const, oBool loop);
+int tEnvelope_on (tEnvelope* const, float velocity);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* ADSR */
+typedef struct _tADSR
+{
+ const float *exp_buff;
+ const float *inc_buff;
+ uint32_t buff_size;
+
+ float next;
+
+ float attackInc, decayInc, releaseInc, rampInc;
+
+ oBool inAttack, inDecay, inSustain, inRelease, inRamp;
+
+ float sustain, gain, rampPeak, releasePeak;
+
+ float attackPhase, decayPhase, releasePhase, rampPhase;
+
+} tADSR;
+
+void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
+void tADSR_free (tADSR* const);
+
+float tADSR_tick (tADSR* const);
+int tADSR_setAttack (tADSR* const, float attack);
+int tADSR_setDecay (tADSR* const, float decay);
+int tADSR_setSustain(tADSR* const, float sustain);
+int tADSR_setRelease(tADSR* const, float release);
+int tADSR_on (tADSR* const, float velocity);
+int tADSR_off (tADSR* const);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* Ramp */
+typedef struct _tRamp {
+ float inc;
+ float inv_sr_ms;
+ float minimum_time;
+ float curr,dest;
+ float time;
+ int samples_per_tick;
+
+} tRamp;
+
+void tRamp_init (tRamp* const, float time, int samplesPerTick);
+void tRamp_free (tRamp* const);
+
+float tRamp_tick (tRamp* const);
+float tRamp_sample (tRamp* const);
+int tRamp_setTime (tRamp* const, float time);
+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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_ENVELOPES_H_INCLUDED
+
+
--- a/LEAF/Inc/leaf-filter.h
+++ /dev/null
@@ -1,312 +1,0 @@
-/*==============================================================================
-
- leaf-filter.h
- Created: 20 Jan 2017 12:01:10pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#ifndef LEAF_FILTER_H_INCLUDED
-#define LEAF_FILTER_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-math.h"
-#include "leaf-delay.h"
-#include "leaf-tables.h"
-
-//==============================================================================
-
-/* tAllpass: Schroeder allpass. Comb-filter with feedforward and feedback. */
-typedef struct _tAllpass
-{
- float gain;
-
- tDelayL delay;
-
- float lastOut;
-
-} tAllpass;
-
-void tAllpass_init (tAllpass* const, float initDelay, uint32_t maxDelay);
-void tAllpass_free (tAllpass* const);
-
-float tAllpass_tick (tAllpass* const, float input);
-void tAllpass_setGain (tAllpass* const, float gain);
-void tAllpass_setDelay (tAllpass* const f, float delay);
-
-
-//==============================================================================
-
-/* tOnePole: OnePole filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tOnePole
-{
- float gain;
- float a0,a1;
- float b0,b1;
-
- float coef;
-
- float freq;
-
- float lastIn, lastOut;
-
-} tOnePole;
-
-void tOnePole_init (tOnePole* const, float thePole);
-void tOnePole_free (tOnePole* const);
-
-float tOnePole_tick (tOnePole* const, float input);
-void tOnePole_setB0 (tOnePole* const, float b0);
-void tOnePole_setA1 (tOnePole* const, float a1);
-void tOnePole_setPole (tOnePole* const, float thePole);
-void tOnePole_setFreq (tOnePole* const, float freq);
-void tOnePole_setCoefficients(tOnePole* const, float b0, float a1);
-void tOnePole_setGain (tOnePole* const, float gain);
-
-//==============================================================================
-
-/* TwoPole filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tTwoPole
-{
- float gain;
- float a0, a1, a2;
- float b0;
-
- float radius, frequency;
- oBool normalize;
-
- float lastOut[2];
-
-} tTwoPole;
-
-void tTwoPole_init (tTwoPole* const);
-void tTwoPole_free (tTwoPole* const);
-
-float tTwoPole_tick (tTwoPole* const, float input);
-void tTwoPole_setB0 (tTwoPole* const, float b0);
-void tTwoPole_setA1 (tTwoPole* const, float a1);
-void tTwoPole_setA2 (tTwoPole* const, float a2);
-void tTwoPole_setResonance (tTwoPole* const, float freq, float radius, oBool normalize);
-void tTwoPole_setCoefficients(tTwoPole* const, float b0, float a1, float a2);
-void tTwoPole_setGain (tTwoPole* const, float gain);
-
-//==============================================================================
-
-/* OneZero filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tOneZero
-{
- float gain;
- float b0,b1;
- float lastIn, lastOut, frequency;
-
-} tOneZero;
-
-void tOneZero_init (tOneZero* const, float theZero);
-void tOneZero_free (tOneZero* const);
-float tOneZero_tick (tOneZero* const, float input);
-void tOneZero_setB0 (tOneZero* const, float b0);
-void tOneZero_setB1 (tOneZero* const, float b1);
-void tOneZero_setZero (tOneZero* const, float theZero);
-void tOneZero_setCoefficients(tOneZero* const, float b0, float b1);
-void tOneZero_setGain (tOneZero* const, float gain);
-float tOneZero_getPhaseDelay(tOneZero *f, float frequency );
-
-//==============================================================================
-
-/* TwoZero filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tTwoZero
-{
- float gain;
- float b0, b1, b2;
-
- float frequency, radius;
-
- float lastIn[2];
-
-} tTwoZero;
-
-void tTwoZero_init (tTwoZero* const);
-void tTwoZero_free (tTwoZero* const);
-
-float tTwoZero_tick (tTwoZero* const, float input);
-void tTwoZero_setB0 (tTwoZero* const, float b0);
-void tTwoZero_setB1 (tTwoZero* const, float b1);
-void tTwoZero_setB2 (tTwoZero* const, float b2);
-void tTwoZero_setNotch (tTwoZero* const, float frequency, float radius);
-void tTwoZero_setCoefficients(tTwoZero* const, float b0, float b1, float b2);
-void tTwoZero_setGain (tTwoZero* const, float gain);
-
-//==============================================================================
-
-/* PoleZero filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tPoleZero
-{
- float gain;
- float a0,a1;
- float b0,b1;
-
- float lastIn, lastOut;
-
-} tPoleZero;
-
-void tPoleZero_init (tPoleZero* const);
-void tPoleZero_free (tPoleZero* const);
-
-float tPoleZero_tick (tPoleZero* const, float input);
-void tPoleZero_setB0 (tPoleZero* const, float b0);
-void tPoleZero_setB1 (tPoleZero* const, float b1);
-void tPoleZero_setA1 (tPoleZero* const, float a1);
-void tPoleZero_setCoefficients (tPoleZero* const, float b0, float b1, float a1);
-void tPoleZero_setAllpass (tPoleZero* const, float coeff);
-void tPoleZero_setBlockZero (tPoleZero* const, float thePole);
-void tPoleZero_setGain (tPoleZero* const, float gain);
-
-//==============================================================================
-
-/* BiQuad filter, reimplemented from STK (Cook and Scavone). */
-typedef struct _tBiQuad
-{
- float gain;
- float a0, a1, a2;
- float b0, b1, b2;
-
- float lastIn[2];
- float lastOut[2];
-
- float frequency, radius;
- oBool normalize;
-} tBiQuad;
-
-void tBiQuad_init (tBiQuad* const);
-void tBiQuad_free (tBiQuad* const);
-
-float tBiQuad_tick (tBiQuad* const, float input);
-void tBiQuad_setB0 (tBiQuad* const, float b0);
-void tBiQuad_setB1 (tBiQuad* const, float b1);
-void tBiQuad_setB2 (tBiQuad* const, float b2);
-void tBiQuad_setA1 (tBiQuad* const, float a1);
-void tBiQuad_setA2 (tBiQuad* const, float a2);
-void tBiQuad_setNotch (tBiQuad* const, float freq, float radius);
-void tBiQuad_setResonance (tBiQuad* const, float freq, float radius, oBool normalize);
-void tBiQuad_setCoefficients(tBiQuad* const, float b0, float b1, float b2, float a1, float a2);
-void tBiQuad_setGain (tBiQuad* const, float gain);
-
-//==============================================================================
-
-/* State Variable Filter, algorithm from Andy Simper. */
-typedef enum SVFType
-{
- SVFTypeHighpass = 0,
- SVFTypeLowpass,
- SVFTypeBandpass,
- SVFTypeNotch,
- SVFTypePeak,
-} SVFType;
-
-typedef struct _tSVF
-{
- SVFType type;
- float cutoff, Q;
- float ic1eq,ic2eq;
- float g,k,a1,a2,a3;
-
-} tSVF;
-
-void tSVF_init (tSVF* const, SVFType type, float freq, float Q);
-void tSVF_free (tSVF* const);
-
-float tSVF_tick (tSVF* const, float v0);
-int tSVF_setFreq (tSVF* const, float freq);
-int tSVF_setQ (tSVF* const, float Q);
-
-//==============================================================================
-
-/* Efficient State Variable Filter for 14-bit control input, [0, 4096). */
-typedef struct _tSVFE
-{
- SVFType type;
- float cutoff, Q;
- float ic1eq,ic2eq;
- float g,k,a1,a2,a3;
-
-} tSVFE;
-
-void tSVFE_init (tSVFE* const, SVFType type, uint16_t controlFreq, float Q);
-void tSVFE_free (tSVFE* const);
-
-float tSVFE_tick (tSVFE* const, float v0);
-int tSVFE_setFreq (tSVFE* const, uint16_t controlFreq);
-int tSVFE_setQ (tSVFE* const, float Q);
-
-//==============================================================================
-
-/* Simple Highpass filter. */
-typedef struct _tHighpass
-{
- float xs, ys, R;
- float frequency;
-
-} tHighpass;
-
-void tHighpass_init (tHighpass* const, float freq);
-void tHighpass_free (tHighpass* const);
-
-float tHighpass_tick (tHighpass* const, float x);
-void tHighpass_setFreq (tHighpass* const, float freq);
-float tHighpass_getFreq (tHighpass* const);
-
-//==============================================================================
-
-// Butterworth Filter
-#define NUM_SVF_BW 16
-typedef struct _tButterworth
-{
- float gain;
-
- float N;
-
- tSVF low[NUM_SVF_BW];
- tSVF high[NUM_SVF_BW];
-
- float f1,f2;
-
-} tButterworth;
-
-void tButterworth_init (tButterworth* const, int N, float f1, float f2);
-void tButterworth_free (tButterworth* const);
-
-float tButterworth_tick (tButterworth* const, float input);
-void tButterworth_setF1 (tButterworth* const, float in);
-void tButterworth_setF2 (tButterworth* const, float in);
-void tButterworth_setFreqs (tButterworth* const, float f1, float f2);
-
-//==============================================================================
-
-typedef struct _tFIR
-{
- float* past;
- float* coeff;
- int numTaps;
-
-} tFIR;
-
-void tFIR_init (tFIR* const, float* coeffs, int numTaps);
-void tFIR_free (tFIR* const);
-
-float tFIR_tick (tFIR* const, float input);
-void tFIR_coeffs (tFIR* const, float in);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_FILTER_H_INCLUDED
-
-//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-filters.h
@@ -1,0 +1,312 @@
+/*==============================================================================
+
+ leaf-filters.h
+ Created: 20 Jan 2017 12:01:10pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#ifndef LEAF_FILTERS_H_INCLUDED
+#define LEAF_FILTERS_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-math.h"
+#include "leaf-delay.h"
+#include "leaf-tables.h"
+
+//==============================================================================
+
+/* tAllpass: Schroeder allpass. Comb-filter with feedforward and feedback. */
+typedef struct _tAllpass
+{
+ float gain;
+
+ tLinearDelay delay;
+
+ float lastOut;
+
+} tAllpass;
+
+void tAllpass_init (tAllpass* const, float initDelay, uint32_t maxDelay);
+void tAllpass_free (tAllpass* const);
+
+float tAllpass_tick (tAllpass* const, float input);
+void tAllpass_setGain (tAllpass* const, float gain);
+void tAllpass_setDelay (tAllpass* const f, float delay);
+
+
+//==============================================================================
+
+/* tOnePole: OnePole filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tOnePole
+{
+ float gain;
+ float a0,a1;
+ float b0,b1;
+
+ float coef;
+
+ float freq;
+
+ float lastIn, lastOut;
+
+} tOnePole;
+
+void tOnePole_init (tOnePole* const, float thePole);
+void tOnePole_free (tOnePole* const);
+
+float tOnePole_tick (tOnePole* const, float input);
+void tOnePole_setB0 (tOnePole* const, float b0);
+void tOnePole_setA1 (tOnePole* const, float a1);
+void tOnePole_setPole (tOnePole* const, float thePole);
+void tOnePole_setFreq (tOnePole* const, float freq);
+void tOnePole_setCoefficients(tOnePole* const, float b0, float a1);
+void tOnePole_setGain (tOnePole* const, float gain);
+
+//==============================================================================
+
+/* TwoPole filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tTwoPole
+{
+ float gain;
+ float a0, a1, a2;
+ float b0;
+
+ float radius, frequency;
+ oBool normalize;
+
+ float lastOut[2];
+
+} tTwoPole;
+
+void tTwoPole_init (tTwoPole* const);
+void tTwoPole_free (tTwoPole* const);
+
+float tTwoPole_tick (tTwoPole* const, float input);
+void tTwoPole_setB0 (tTwoPole* const, float b0);
+void tTwoPole_setA1 (tTwoPole* const, float a1);
+void tTwoPole_setA2 (tTwoPole* const, float a2);
+void tTwoPole_setResonance (tTwoPole* const, float freq, float radius, oBool normalize);
+void tTwoPole_setCoefficients(tTwoPole* const, float b0, float a1, float a2);
+void tTwoPole_setGain (tTwoPole* const, float gain);
+
+//==============================================================================
+
+/* OneZero filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tOneZero
+{
+ float gain;
+ float b0,b1;
+ float lastIn, lastOut, frequency;
+
+} tOneZero;
+
+void tOneZero_init (tOneZero* const, float theZero);
+void tOneZero_free (tOneZero* const);
+float tOneZero_tick (tOneZero* const, float input);
+void tOneZero_setB0 (tOneZero* const, float b0);
+void tOneZero_setB1 (tOneZero* const, float b1);
+void tOneZero_setZero (tOneZero* const, float theZero);
+void tOneZero_setCoefficients(tOneZero* const, float b0, float b1);
+void tOneZero_setGain (tOneZero* const, float gain);
+float tOneZero_getPhaseDelay(tOneZero *f, float frequency );
+
+//==============================================================================
+
+/* TwoZero filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tTwoZero
+{
+ float gain;
+ float b0, b1, b2;
+
+ float frequency, radius;
+
+ float lastIn[2];
+
+} tTwoZero;
+
+void tTwoZero_init (tTwoZero* const);
+void tTwoZero_free (tTwoZero* const);
+
+float tTwoZero_tick (tTwoZero* const, float input);
+void tTwoZero_setB0 (tTwoZero* const, float b0);
+void tTwoZero_setB1 (tTwoZero* const, float b1);
+void tTwoZero_setB2 (tTwoZero* const, float b2);
+void tTwoZero_setNotch (tTwoZero* const, float frequency, float radius);
+void tTwoZero_setCoefficients(tTwoZero* const, float b0, float b1, float b2);
+void tTwoZero_setGain (tTwoZero* const, float gain);
+
+//==============================================================================
+
+/* PoleZero filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tPoleZero
+{
+ float gain;
+ float a0,a1;
+ float b0,b1;
+
+ float lastIn, lastOut;
+
+} tPoleZero;
+
+void tPoleZero_init (tPoleZero* const);
+void tPoleZero_free (tPoleZero* const);
+
+float tPoleZero_tick (tPoleZero* const, float input);
+void tPoleZero_setB0 (tPoleZero* const, float b0);
+void tPoleZero_setB1 (tPoleZero* const, float b1);
+void tPoleZero_setA1 (tPoleZero* const, float a1);
+void tPoleZero_setCoefficients (tPoleZero* const, float b0, float b1, float a1);
+void tPoleZero_setAllpass (tPoleZero* const, float coeff);
+void tPoleZero_setBlockZero (tPoleZero* const, float thePole);
+void tPoleZero_setGain (tPoleZero* const, float gain);
+
+//==============================================================================
+
+/* BiQuad filter, reimplemented from STK (Cook and Scavone). */
+typedef struct _tBiQuad
+{
+ float gain;
+ float a0, a1, a2;
+ float b0, b1, b2;
+
+ float lastIn[2];
+ float lastOut[2];
+
+ float frequency, radius;
+ oBool normalize;
+} tBiQuad;
+
+void tBiQuad_init (tBiQuad* const);
+void tBiQuad_free (tBiQuad* const);
+
+float tBiQuad_tick (tBiQuad* const, float input);
+void tBiQuad_setB0 (tBiQuad* const, float b0);
+void tBiQuad_setB1 (tBiQuad* const, float b1);
+void tBiQuad_setB2 (tBiQuad* const, float b2);
+void tBiQuad_setA1 (tBiQuad* const, float a1);
+void tBiQuad_setA2 (tBiQuad* const, float a2);
+void tBiQuad_setNotch (tBiQuad* const, float freq, float radius);
+void tBiQuad_setResonance (tBiQuad* const, float freq, float radius, oBool normalize);
+void tBiQuad_setCoefficients(tBiQuad* const, float b0, float b1, float b2, float a1, float a2);
+void tBiQuad_setGain (tBiQuad* const, float gain);
+
+//==============================================================================
+
+/* State Variable Filter, algorithm from Andy Simper. */
+typedef enum SVFType
+{
+ SVFTypeHighpass = 0,
+ SVFTypeLowpass,
+ SVFTypeBandpass,
+ SVFTypeNotch,
+ SVFTypePeak,
+} SVFType;
+
+typedef struct _tSVF
+{
+ SVFType type;
+ float cutoff, Q;
+ float ic1eq,ic2eq;
+ float g,k,a1,a2,a3;
+
+} tSVF;
+
+void tSVF_init (tSVF* const, SVFType type, float freq, float Q);
+void tSVF_free (tSVF* const);
+
+float tSVF_tick (tSVF* const, float v0);
+int tSVF_setFreq (tSVF* const, float freq);
+int tSVF_setQ (tSVF* const, float Q);
+
+//==============================================================================
+
+/* Efficient State Variable Filter for 14-bit control input, [0, 4096). */
+typedef struct _tEfficientSVF
+{
+ SVFType type;
+ float cutoff, Q;
+ float ic1eq,ic2eq;
+ float g,k,a1,a2,a3;
+
+} tEfficientSVF;
+
+void tEfficientSVF_init (tEfficientSVF* const, SVFType type, uint16_t controlFreq, float Q);
+void tEfficientSVF_free (tEfficientSVF* const);
+
+float tEfficientSVF_tick (tEfficientSVF* const, float v0);
+int tEfficientSVF_setFreq (tEfficientSVF* const, uint16_t controlFreq);
+int tEfficientSVF_setQ (tEfficientSVF* const, float Q);
+
+//==============================================================================
+
+/* Simple Highpass filter. */
+typedef struct _tHighpass
+{
+ float xs, ys, R;
+ float frequency;
+
+} tHighpass;
+
+void tHighpass_init (tHighpass* const, float freq);
+void tHighpass_free (tHighpass* const);
+
+float tHighpass_tick (tHighpass* const, float x);
+void tHighpass_setFreq (tHighpass* const, float freq);
+float tHighpass_getFreq (tHighpass* const);
+
+//==============================================================================
+
+// Butterworth Filter
+#define NUM_SVF_BW 16
+typedef struct _tButterworth
+{
+ float gain;
+
+ float N;
+
+ tSVF low[NUM_SVF_BW];
+ tSVF high[NUM_SVF_BW];
+
+ float f1,f2;
+
+} tButterworth;
+
+void tButterworth_init (tButterworth* const, int N, float f1, float f2);
+void tButterworth_free (tButterworth* const);
+
+float tButterworth_tick (tButterworth* const, float input);
+void tButterworth_setF1 (tButterworth* const, float in);
+void tButterworth_setF2 (tButterworth* const, float in);
+void tButterworth_setFreqs (tButterworth* const, float f1, float f2);
+
+//==============================================================================
+
+typedef struct _tFIR
+{
+ float* past;
+ float* coeff;
+ int numTaps;
+
+} tFIR;
+
+void tFIR_init (tFIR* const, float* coeffs, int numTaps);
+void tFIR_free (tFIR* const);
+
+float tFIR_tick (tFIR* const, float input);
+void tFIR_coeffs (tFIR* const, float in);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_FILTERS_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-formant.h
+++ /dev/null
@@ -1,68 +1,0 @@
-/*==============================================================================
-
- leaf-formant.h
- Created: 30 Nov 2018 11:03:37am
- Author: airship
-
-==============================================================================*/
-
-#ifndef LEAF_FORMANT_H_INCLUDED
-#define LEAF_FORMANT_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-mempool.h"
-#include "leaf-math.h"
-
-//==============================================================================
-
-#define FORD 7
-#define FORMANT_BUFFER_SIZE 2048
-
-typedef struct _tFormantShifter
-{
- int ford;
- int bufsize;
- float falph;
- float flamb;
- float* fk;
- float* fb;
- float* fc;
- float* frb;
- float* frc;
- float* fsig;
- float* fsmooth;
- float fhp;
- float flp;
- float flpa;
- float** fbuff;
- float* ftvec;
- float fmute;
- float fmutealph;
- unsigned int cbi;
-
-} tFormantShifter;
-
-void tFormantShifter_init (tFormantShifter* const, int bufsize, int order);
-void tFormantShifter_free (tFormantShifter* const);
-
-float tFormantShifter_tick (tFormantShifter* const, float input, float fwarp);
-float tFormantShifter_remove (tFormantShifter* const, float input);
-float tFormantShifter_add (tFormantShifter* const, float input, float fwarp);
-void tFormantShifter_ioSamples (tFormantShifter* const, float* in, float* out, int size, float fwarp);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_FORMANT_H_INCLUDED
-
-//==============================================================================
-
--- /dev/null
+++ b/LEAF/Inc/leaf-instruments.h
@@ -1,0 +1,184 @@
+/*==============================================================================
+
+ leaf-instruments.h
+ Created: 30 Nov 2018 10:24:44am
+ Author: airship
+
+==============================================================================*/
+
+#ifndef LEAF_INSTRUMENTS_H_INCLUDED
+#define LEAF_INSTRUMENTS_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-math.h"
+#include "leaf-oscillators.h"
+#include "leaf-filters.h"
+#include "leaf-envelopes.h"
+
+//==============================================================================
+
+// 808 Cowbell
+typedef struct _t808Cowbell {
+
+ tSquare p[2];
+ tNoise stick;
+ tSVF bandpassOsc;
+ tSVF bandpassStick;
+ tEnvelope envGain;
+ tEnvelope envStick;
+ tEnvelope envFilter;
+ tHighpass highpass;
+ float oscMix;
+ float filterCutoff;
+ oBool useStick;
+
+} t808Cowbell;
+
+void t808Cowbell_init (t808Cowbell* const, int useStick);
+void t808Cowbell_free (t808Cowbell* const);
+float t808Cowbell_tick (t808Cowbell* const);
+void t808Cowbell_on (t808Cowbell* const, float vel);
+void t808Cowbell_setDecay (t808Cowbell* const, float decay);
+void t808Cowbell_setHighpassFreq (t808Cowbell* const, float freq);
+void t808Cowbell_setBandpassFreq (t808Cowbell* const, float freq);
+void t808Cowbell_setFreq (t808Cowbell* const, float freq);
+void t808Cowbell_setOscMix (t808Cowbell* const, float oscMix);
+void t808Cowbell_setStick (t808Cowbell* const, int useStick);
+
+//==============================================================================
+
+// 808 Hihat
+typedef struct _t808Hihat {
+
+ // 6 Square waves
+ tSquare p[6];
+ tNoise n;
+ tSVF bandpassOsc;
+ tSVF bandpassStick;
+ tEnvelope envGain;
+ tEnvelope envStick;
+ tEnvelope noiseFMGain;
+ tHighpass highpass;
+ tNoise stick;
+
+ float freq;
+ float stretch;
+ float FM_amount;
+ float oscNoiseMix;
+
+} t808Hihat;
+
+void t808Hihat_init (t808Hihat* const);
+void t808Hihat_free (t808Hihat* const);
+
+float t808Hihat_tick (t808Hihat* const);
+void t808Hihat_on (t808Hihat* const, float vel);
+void t808Hihat_setOscNoiseMix (t808Hihat* const, float oscNoiseMix);
+void t808Hihat_setDecay (t808Hihat* const, float decay);
+void t808Hihat_setHighpassFreq (t808Hihat* const, float freq);
+void t808Hihat_setOscBandpassFreq (t808Hihat* const, float freq);
+void t808Hihat_setOscBandpassQ (t808Hihat* const hihat, float Q);
+void t808Hihat_setStickBandPassFreq (t808Hihat* const, float freq);
+void t808Hihat_setStickBandPassQ (t808Hihat* const hihat, float Q);
+void t808Hihat_setOscFreq (t808Hihat* const, float freq);
+void t808Hihat_setStretch (t808Hihat* const hihat, float stretch);
+void t808Hihat_setFM (t808Hihat* const hihat, float FM_amount);
+
+//==============================================================================
+
+// 808 Snare
+typedef struct _t808Snare {
+
+ // Tone 1, Tone 2, Noise
+ tTriangle tone[2]; // Tri (not yet antialiased or wavetabled)
+ tNoise noiseOsc;
+ tSVF toneLowpass[2];
+ tSVF noiseLowpass; // Lowpass from SVF filter
+ tEnvelope toneEnvOsc[2];
+ tEnvelope toneEnvGain[2];
+ tEnvelope noiseEnvGain;
+ tEnvelope toneEnvFilter[2];
+ tEnvelope noiseEnvFilter;
+
+ float toneGain[2];
+ float noiseGain;
+
+ float toneNoiseMix;
+
+ float tone1Freq, tone2Freq;
+
+ float noiseFilterFreq;
+
+
+} t808Snare;
+
+void t808Snare_init (t808Snare* const);
+void t808Snare_free (t808Snare* const);
+
+float t808Snare_tick (t808Snare* const);
+void t808Snare_on (t808Snare* const, float vel);
+void t808Snare_setTone1Freq (t808Snare* const, float freq);
+void t808Snare_setTone2Freq (t808Snare* const, float freq);
+void t808Snare_setTone1Decay (t808Snare* const, float decay);
+void t808Snare_setTone2Decay (t808Snare* const, float decay);
+void t808Snare_setNoiseDecay (t808Snare* const, float decay);
+void t808Snare_setToneNoiseMix (t808Snare* const, float toneNoiseMix);
+void t808Snare_setNoiseFilterFreq (t808Snare* const, float noiseFilterFreq);
+void t808Snare_setNoiseFilterQ (t808Snare* const, float noiseFilterQ);
+
+//==============================================================================
+
+// 808 Kick
+typedef struct _t808Kick {
+
+
+ tCycle tone; // Tri
+ tNoise noiseOsc;
+ tSVF toneLowpass;
+ tEnvelope toneEnvOscChirp;
+ tEnvelope toneEnvOscSigh;
+ tEnvelope toneEnvGain;
+ tEnvelope noiseEnvGain;
+ tEnvelope toneEnvFilter;
+
+ float toneGain;
+ float noiseGain;
+
+ float toneInitialFreq;
+ float sighAmountInHz;
+ float chirpRatioMinusOne;
+ float noiseFilterFreq;
+
+
+} t808Kick;
+
+void t808Kick_init (t808Kick* const);
+void t808Kick_free (t808Kick* const);
+
+float t808Kick_tick (t808Kick* const);
+void t808Kick_on (t808Kick* const, float vel);
+void t808Kick_setToneFreq (t808Kick* const, float freq);
+void t808Kick_setToneDecay (t808Kick* const, float decay);
+void t808Kick_setNoiseDecay (t808Kick* const, float decay);
+void t808Kick_setSighAmount (t808Kick* const, float sigh);
+void t808Kick_setChirpAmount (t808Kick* const, float chirp);
+void t808Kick_setToneNoiseMix (t808Kick* const, float toneNoiseMix);
+void t808Kick_setNoiseFilterFreq (t808Kick* const, float noiseFilterFreq);
+void t808Kick_setNoiseFilterQ (t808Kick* const, float noiseFilterQ);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_INSTRUMENTS_H_INCLUDED
+
+//==============================================================================
+
+
--- a/LEAF/Inc/leaf-midi.h
+++ b/LEAF/Inc/leaf-midi.h
@@ -18,9 +18,37 @@
#include "leaf-global.h"
#include "leaf-mempool.h"
#include "leaf-math.h"
-#include "leaf-utilities.h"
+#include "leaf-envelopes.h"
//==============================================================================
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+// STACK implementation (fixed size)
+#define STACK_SIZE 128
+typedef struct _tStack
+{
+ int data[STACK_SIZE];
+ uint16_t pos;
+ uint16_t size;
+ uint16_t capacity;
+ oBool ordered;
+
+} tStack;
+
+void tStack_init (tStack* const);
+void tStack_free (tStack* const);
+
+void tStack_setCapacity (tStack* const, uint16_t cap);
+int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item);
+void tStack_add (tStack* const, uint16_t item);
+int tStack_remove (tStack* const, uint16_t item);
+void tStack_clear (tStack* const);
+int tStack_first (tStack* const);
+int tStack_getSize (tStack* const);
+int tStack_contains (tStack* const, uint16_t item);
+int tStack_next (tStack* const);
+int tStack_get (tStack* const, int which);
/* tPoly */
typedef struct _tPoly
--- a/LEAF/Inc/leaf-oscillator.h
+++ /dev/null
@@ -1,181 +1,0 @@
-/*==============================================================================
-
- leaf-oscillator.h
- Created: 20 Jan 2017 12:00:58pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#ifndef LEAF_OSCILLATOR_H_INCLUDED
-#define LEAF_OSCILLATOR_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-math.h"
-
-#include "leaf-filter.h"
-
-//==============================================================================
-
-/* tNeuron */
-typedef enum NeuronMode
-{
- NeuronNormal = 0,
- NeuronTanh,
- NeuronAaltoShaper,
- NeuronModeNil
-} NeuronMode;
-
-typedef struct _tNeuron
-{
- tPoleZero f;
-
- NeuronMode mode;
-
- float voltage, current;
- float timeStep;
-
- float alpha[3];
- float beta[3];
- float rate[3];
- float V[3];
- float P[3];
- float gK, gN, gL, C;
-} tNeuron;
-
-void tNeuron_init (tNeuron* const);
-void tNeuron_free (tNeuron* const);
-
-void tNeuron_reset (tNeuron* const);
-float tNeuron_Tick (tNeuron* const);
-void tNeuron_setMode (tNeuron* const, NeuronMode mode);
-void tNeuron_setCurrent (tNeuron* const, float current);
-void tNeuron_setK (tNeuron* const, float K);
-void tNeuron_setL (tNeuron* const, float L);
-void tNeuron_setN (tNeuron* const, float N);
-void tNeuron_setC (tNeuron* const, float C);
-void tNeuron_setV1 (tNeuron* const, float V1);
-void tNeuron_setV2 (tNeuron* const, float V2);
-void tNeuron_setV3 (tNeuron* const, float V3);
-void tNeuron_setTimeStep (tNeuron* const, float timestep);
-
-//==============================================================================
-
-/* tPhasor: Aliasing phasor [0.0, 1.0) */
-typedef struct _tPhasor
-{
- float phase;
- float inc,freq;
-
-} tPhasor;
-
-void tPhasor_init (tPhasor* const);
-void tPhasor_free (tPhasor* const);
-
-float tPhasor_tick (tPhasor* const);
-int tPhasor_setFreq (tPhasor* const, float freq);
-
-//==============================================================================
-
-/* tCycle: Cycle/Sine waveform. Wavetable synthesis.*/
-typedef struct _tCycle
-{
- // Underlying phasor
- float phase;
- float inc,freq;
-
-} tCycle;
-
-void tCycle_init (tCycle* const);
-void tCycle_free (tCycle* const);
-
-float tCycle_tick (tCycle* const);
-int tCycle_setFreq (tCycle* const, float freq);
-
-//==============================================================================
-
-/* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */
-typedef struct _tSawtooth
-{
- // Underlying phasor
- float phase;
- float inc,freq;
-
-} tSawtooth;
-
-void tSawtooth_init (tSawtooth* const);
-void tSawtooth_free (tSawtooth* const);
-
-float tSawtooth_tick (tSawtooth* const);
-int tSawtooth_setFreq (tSawtooth* const, float freq);
-
-//==============================================================================
-
-/* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */
-typedef struct _tTriangle
-{
- // Underlying phasor
- float phase;
- float inc,freq;
-
-} tTriangle;
-
-void tTriangle_init (tTriangle* const);
-void tTriangle_free (tTriangle* const);
-
-float tTriangle_tick (tTriangle* const);
-int tTriangle_setFreq (tTriangle* const, float freq);
-
-//==============================================================================
-
-/* tSquare: Anti-aliased Square waveform using wavetable interpolation. Wavetables constructed from sine components. */
-typedef struct _tSquare
-{
- // Underlying phasor
- float phase;
- float inc,freq;
-
-} tSquare;
-
-void tSquare_init (tSquare* const);
-void tSquare_free (tSquare* const);
-
-float tSquare_tick (tSquare* const);
-int tSquare_setFreq (tSquare* const, float freq);
-
-//==============================================================================
-
-/* tNoise. WhiteNoise, PinkNoise. */
-typedef enum NoiseType
-{
- WhiteNoise=0,
- PinkNoise,
- NoiseTypeNil,
-} NoiseType;
-
-typedef struct _tNoise
-{
- NoiseType type;
- float pinkb0, pinkb1, pinkb2;
- float(*rand)();
-
-} tNoise;
-
-void tNoise_init (tNoise* const, NoiseType type);
-void tNoise_free (tNoise* const);
-
-float tNoise_tick (tNoise* const);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_OSCILLATOR_H_INCLUDED
-
-//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-oscillators.h
@@ -1,0 +1,180 @@
+/*==============================================================================
+
+ leaf-oscillators.h
+ Created: 20 Jan 2017 12:00:58pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#ifndef LEAF_OSCILLATORS_H_INCLUDED
+#define LEAF_OSCILLATORS_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-math.h"
+#include "leaf-filters.h"
+
+//==============================================================================
+
+/* tCycle: Cycle/Sine waveform. Wavetable synthesis.*/
+typedef struct _tCycle
+{
+ // Underlying phasor
+ float phase;
+ float inc,freq;
+
+} tCycle;
+
+void tCycle_init (tCycle* const);
+void tCycle_free (tCycle* const);
+
+float tCycle_tick (tCycle* const);
+int tCycle_setFreq (tCycle* const, float freq);
+
+//==============================================================================
+
+/* tTriangle: Anti-aliased Triangle waveform using wavetable interpolation. Wavetables constructed from sine components. */
+typedef struct _tTriangle
+{
+ // Underlying phasor
+ float phase;
+ float inc,freq;
+
+} tTriangle;
+
+void tTriangle_init (tTriangle* const);
+void tTriangle_free (tTriangle* const);
+
+float tTriangle_tick (tTriangle* const);
+int tTriangle_setFreq (tTriangle* const, float freq);
+
+//==============================================================================
+
+/* tSquare: Anti-aliased Square waveform using wavetable interpolation. Wavetables constructed from sine components. */
+typedef struct _tSquare
+{
+ // Underlying phasor
+ float phase;
+ float inc,freq;
+
+} tSquare;
+
+void tSquare_init (tSquare* const);
+void tSquare_free (tSquare* const);
+
+float tSquare_tick (tSquare* const);
+int tSquare_setFreq (tSquare* const, float freq);
+
+//==============================================================================
+
+/* tSawtooth: Anti-aliased Sawtooth waveform using wavetable interpolation. Wavetables constructed from sine components. */
+typedef struct _tSawtooth
+{
+ // Underlying phasor
+ float phase;
+ float inc,freq;
+
+} tSawtooth;
+
+void tSawtooth_init (tSawtooth* const);
+void tSawtooth_free (tSawtooth* const);
+
+float tSawtooth_tick (tSawtooth* const);
+int tSawtooth_setFreq (tSawtooth* const, float freq);
+
+//==============================================================================
+
+/* tPhasor: Aliasing phasor [0.0, 1.0) */
+typedef struct _tPhasor
+{
+ float phase;
+ float inc,freq;
+
+} tPhasor;
+
+void tPhasor_init (tPhasor* const);
+void tPhasor_free (tPhasor* const);
+
+float tPhasor_tick (tPhasor* const);
+int tPhasor_setFreq (tPhasor* const, float freq);
+
+//==============================================================================
+
+/* tNoise. WhiteNoise, PinkNoise. */
+typedef enum NoiseType
+{
+ WhiteNoise=0,
+ PinkNoise,
+ NoiseTypeNil,
+} NoiseType;
+
+typedef struct _tNoise
+{
+ NoiseType type;
+ float pinkb0, pinkb1, pinkb2;
+ float(*rand)(void);
+
+} tNoise;
+
+void tNoise_init (tNoise* const, NoiseType type);
+void tNoise_free (tNoise* const);
+
+float tNoise_tick (tNoise* const);
+
+//==============================================================================
+
+/* tNeuron */
+typedef enum NeuronMode
+{
+ NeuronNormal = 0,
+ NeuronTanh,
+ NeuronAaltoShaper,
+ NeuronModeNil
+} NeuronMode;
+
+typedef struct _tNeuron
+{
+ tPoleZero f;
+
+ NeuronMode mode;
+
+ float voltage, current;
+ float timeStep;
+
+ float alpha[3];
+ float beta[3];
+ float rate[3];
+ float V[3];
+ float P[3];
+ float gK, gN, gL, C;
+} tNeuron;
+
+void tNeuron_init (tNeuron* const);
+void tNeuron_free (tNeuron* const);
+
+void tNeuron_reset (tNeuron* const);
+float tNeuron_Tick (tNeuron* const);
+void tNeuron_setMode (tNeuron* const, NeuronMode mode);
+void tNeuron_setCurrent (tNeuron* const, float current);
+void tNeuron_setK (tNeuron* const, float K);
+void tNeuron_setL (tNeuron* const, float L);
+void tNeuron_setN (tNeuron* const, float N);
+void tNeuron_setC (tNeuron* const, float C);
+void tNeuron_setV1 (tNeuron* const, float V1);
+void tNeuron_setV2 (tNeuron* const, float V2);
+void tNeuron_setV3 (tNeuron* const, float V3);
+void tNeuron_setTimeStep (tNeuron* const, float timestep);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_OSCILLATORS_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-oversampler.h
+++ /dev/null
@@ -1,51 +1,0 @@
-//
-// 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-global.h"
-#include "leaf-mempool.h"
-#include "leaf-math.h"
-#include "leaf-filter.h"
-
-//==============================================================================
-
-typedef struct _tOversampler
-{
- int ratio;
- float* pCoeffs;
- float* upState;
- float* downState;
- int numTaps;
- int phaseLength;
-} tOversampler;
-
-void tOversampler_init(tOversampler* const, int order, oBool extraQuality);
-void tOversampler_free(tOversampler* const);
-void tOversampler_upsample(tOversampler* const, float input, float* output);
-float tOversampler_downsample(tOversampler *const os, float* input);
-float tOversampler_tick(tOversampler* const, float input, float (*effectTick)(float));
-int tOversampler_getLatency(tOversampler* const os);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_OVERSAMPLER_H_INCLUDED
-
-//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-physical.h
@@ -1,0 +1,221 @@
+/*
+ ==============================================================================
+
+ leaf-physical.h
+ Created: 30 Nov 2018 10:41:55am
+ Author: airship
+
+ ==============================================================================
+*/
+
+#ifndef LEAF_PHYSICAL_H_INCLUDED
+#define LEAF_PHYSICAL_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-math.h"
+#include "leaf-delay.h"
+#include "leaf-filters.h"
+#include "leaf-oscillators.h"
+#include "leaf-envelopes.h"
+#include "leaf-dynamics.h"
+
+//==============================================================================
+
+/* Karplus Strong model */
+typedef struct _tPluck
+{
+ tAllpassDelay delayLine; // Allpass or Linear?? big difference...
+ tOneZero loopFilter;
+ tOnePole pickFilter;
+ tNoise noise;
+
+ float lastOut;
+ float loopGain;
+ float lastFreq;
+
+ float sr;
+
+} tPluck;
+
+void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]);
+void tPluck_free (tPluck* const);
+
+float tPluck_tick (tPluck* const);
+
+// Pluck the string.
+void tPluck_pluck (tPluck* const, float amplitude);
+
+// Start a note with the given frequency and amplitude.;
+void tPluck_noteOn (tPluck* const, float frequency, float amplitude );
+
+// Stop a note with the given amplitude (speed of decay).
+void tPluck_noteOff (tPluck* const, float amplitude );
+
+// Set instrument parameters for a particular frequency.
+void tPluck_setFrequency (tPluck* const, float frequency );
+
+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
+void tPluck_controlChange (tPluck* const, int number, float value);
+
+// tPluck Utilities.
+float tPluck_getLastOut (tPluck* const);
+
+//==============================================================================
+
+/* Stif Karplus Strong model */
+typedef struct _tKarplusStrong
+{
+ tAllpassDelay delayLine;
+ tLinearDelay combDelay;
+ tOneZero filter;
+ tNoise noise;
+ tBiQuad biquad[4];
+
+
+
+ uint32_t length;
+ float loopGain;
+ float baseLoopGain;
+ float lastFrequency;
+ float lastLength;
+ float stretching;
+ float pluckAmplitude;
+ float pickupPosition;
+
+ float lastOut;
+
+} tKarplusStrong;
+
+typedef enum SKControlType
+{
+ SKPickPosition = 0,
+ SKStringDamping,
+ SKDetune,
+ SKControlTypeNil
+} SKControlType;
+
+void tKarplusStrong_init (tKarplusStrong* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]);
+void tKarplusStrong_free (tKarplusStrong* const);
+
+float tKarplusStrong_tick (tKarplusStrong* const);
+
+// Pluck the string.
+void tKarplusStrong_pluck (tKarplusStrong* const, float amplitude);
+
+// Start a note with the given frequency and amplitude.;
+void tKarplusStrong_noteOn (tKarplusStrong* const, float frequency, float amplitude );
+
+// Stop a note with the given amplitude (speed of decay).
+void tKarplusStrong_noteOff (tKarplusStrong* const, float amplitude );
+
+// Set instrument parameters for a particular frequency.
+void tKarplusStrong_setFrequency (tKarplusStrong* const, float frequency );
+
+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
+// Use SKPickPosition, SKStringDamping, or SKDetune for type.
+void tKarplusStrong_controlChange (tKarplusStrong* const, SKControlType type, float value);
+
+// Set the stretch "factor" of the string (0.0 - 1.0).
+void tKarplusStrong_setStretch (tKarplusStrong* const, float stretch );
+
+// Set the pluck or "excitation" position along the string (0.0 - 1.0).
+void tKarplusStrong_setPickupPosition (tKarplusStrong* const, float position );
+
+// Set the base loop gain.
+void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const, float aGain );
+
+// tKarplusStrong utilities.
+float tKarplusStrong_getLastOut (tKarplusStrong* const);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+/* 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;
+ tLinearDelay delayLine;
+ tOnePole bridgeFilter;
+ tHighpass DCblocker;
+ tFeedbackLeveler 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;
+ tLinearDelay delLF,delUF,delUB,delLB; // delay for lower/upper/forward/backward part of the waveguide model
+ tOnePole bridgeFilter, nutFilter, prepFilterU, prepFilterL;
+ tHighpass DCblockerL, DCblockerU;
+ tFeedbackLeveler 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);
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
+
+//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);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_PHYSICAL_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-pitch.h
+++ /dev/null
@@ -1,161 +1,0 @@
-/*
- ==============================================================================
-
- leaf-pitch.h
- Created: 30 Nov 2018 11:03:13am
- Author: airship
-
- ==============================================================================
-*/
-
-#ifndef LEAF_PITCH_H_INCLUDED
-#define LEAF_PITCH_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-#include "leaf-filter.h"
-#include "leaf-utilities.h"
-
-//==============================================================================
-
-#define DEFPITCHRATIO 2.0f
-#define DEFTIMECONSTANT 100.0f
-#define DEFHOPSIZE 64
-#define DEFWINDOWSIZE 64
-#define FBA 20
-#define HPFREQ 40.0f
-
-
-//==============================================================================
-
-// Pitch shifter
-typedef struct _tPitchShifter
-{
- tEnv env;
- tSNAC snac;
- tSOLAD sola;
- tHighpass hp;
-
- float* inBuffer;
- float* outBuffer;
- int frameSize;
- int bufSize;
- int framesPerBuffer;
- int curBlock;
- int lastBlock;
- int index;
-
- uint16_t hopSize;
- uint16_t windowSize;
- uint8_t fba;
-
- float pitchFactor;
- float timeConstant;
- float radius;
- float max;
- float lastmax;
- float deltamax;
-
-} tPitchShifter;
-
-void tPitchShifter_init (tPitchShifter* const, float* in, float* out, int bufSize, int frameSize);
-void tPitchShifter_free (tPitchShifter* 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);
-
-//==============================================================================
-
-// Period detection
-typedef struct _tPeriod
-{
- tEnv env;
- tSNAC snac;
- float* inBuffer;
- float* outBuffer;
- int frameSize;
- int bufSize;
- int framesPerBuffer;
- int curBlock;
- int lastBlock;
- int i;
- int indexstore;
- int iLast;
- int index;
- float period;
-
- uint16_t hopSize;
- uint16_t windowSize;
- uint8_t fba;
-
- float timeConstant;
- float radius;
- float max;
- float lastmax;
- float deltamax;
-
-}tPeriod;
-
-void tPeriod_init (tPeriod* const, float* in, float* out, int bufSize, int frameSize);
-void tPeriod_free (tPeriod* const);
-
-float tPeriod_findPeriod (tPeriod* const, float sample);
-void tPeriod_setHopSize (tPeriod* p, int hs);
-void tPeriod_setWindowSize (tPeriod* p, int ws);
-
-//==============================================================================
-
-// Pitch shift
-typedef struct _tPitchShift
-{
- tSOLAD sola;
- tHighpass hp;
- tPeriod* p;
-
- 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, tPeriod* 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);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_PITCH_H_INCLUDED
-
-//==============================================================================
--- a/LEAF/Inc/leaf-reverb.h
+++ b/LEAF/Inc/leaf-reverb.h
@@ -17,15 +17,14 @@
#include "leaf-global.h"
#include "leaf-math.h"
-
#include "leaf-delay.h"
-#include "leaf-filter.h"
-#include "leaf-oscillator.h"
+#include "leaf-filters.h"
+#include "leaf-oscillators.h"
//==============================================================================
-/* PRCRev: Reverb, reimplemented from STK (Cook and Scavone). */
-typedef struct _tPRCRev
+/* PRCReverb: Reverb, reimplemented from STK (Cook and Scavone). */
+typedef struct _tPRCReverb
{
float mix, t60;
@@ -38,23 +37,23 @@
float lastIn, lastOut;
-} tPRCRev;
+} tPRCReverb;
-void tPRCRev_init (tPRCRev* const, float t60);
-void tPRCRev_free (tPRCRev* const);
+void tPRCReverb_init (tPRCReverb* const, float t60);
+void tPRCReverb_free (tPRCReverb* const);
-float tPRCRev_tick (tPRCRev* const, float input);
+float tPRCReverb_tick (tPRCReverb* const, float input);
// Set reverb time in seconds.
-void tPRCRev_setT60 (tPRCRev* const, float t60);
+void tPRCReverb_setT60 (tPRCReverb* const, float t60);
// Set mix between dry input and wet output signal.
-void tPRCRev_setMix (tPRCRev* const, float mix);
+void tPRCReverb_setMix (tPRCReverb* const, float mix);
//==============================================================================
-/* NRev: Reverb, reimplemented from STK (Cook and Scavone). */
-typedef struct _tNRev
+/* NReverb: Reverb, reimplemented from STK (Cook and Scavone). */
+typedef struct _tNReverb
{
float mix, t60;
@@ -68,22 +67,22 @@
float lastIn, lastOut;
-} tNRev;
+} tNReverb;
-void tNRev_init (tNRev* const, float t60);
-void tNRev_free (tNRev* const);
+void tNReverb_init (tNReverb* const, float t60);
+void tNReverb_free (tNReverb* const);
-float tNRev_tick (tNRev* const, float input);
+float tNReverb_tick (tNReverb* const, float input);
// Set reverb time in seconds.
-void tNRev_setT60 (tNRev* const, float t60);
+void tNReverb_setT60 (tNReverb* const, float t60);
// Set mix between dry input and wet output signal.
-void tNRev_setMix (tNRev* const, float mix);
+void tNReverb_setMix (tNReverb* const, float mix);
//==============================================================================
-typedef struct _tDattorro
+typedef struct _tDattorroReverb
{
float predelay;
float input_filter;
@@ -125,19 +124,19 @@
tCycle f2_lfo;
-} tDattorro;
+} tDattorroReverb;
-void tDattorro_init (tDattorro* const);
-void tDattorro_free (tDattorro* const);
+void tDattorroReverb_init (tDattorroReverb* const);
+void tDattorroReverb_free (tDattorroReverb* const);
-float tDattorro_tick (tDattorro* const, float input);
+float tDattorroReverb_tick (tDattorroReverb* const, float input);
-void tDattorro_setMix (tDattorro* const, float mix);
-void tDattorro_setSize (tDattorro* const, float size);
-void tDattorro_setInputDelay (tDattorro* const, float preDelay);
-void tDattorro_setInputFilter (tDattorro* const, float freq);
-void tDattorro_setFeedbackFilter (tDattorro* const, float freq);
-void tDattorro_setFeedbackGain (tDattorro* const, float gain);
+void tDattorroReverb_setMix (tDattorroReverb* const, float mix);
+void tDattorroReverb_setSize (tDattorroReverb* const, float size);
+void tDattorroReverb_setInputDelay (tDattorroReverb* const, float preDelay);
+void tDattorroReverb_setInputFilter (tDattorroReverb* const, float freq);
+void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const, float freq);
+void tDattorroReverb_setFeedbackGain (tDattorroReverb* const, float gain);
#ifdef __cplusplus
}
--- a/LEAF/Inc/leaf-sample.h
+++ /dev/null
@@ -1,125 +1,0 @@
-/*==============================================================================
-
- leaf-sample.h
- Created: 23 Jan 2019 11:22:09am
- Author: Mike Mulshine
-
-==============================================================================*/
-
-
-#ifndef LEAF_SAMPLE_H_INCLUDED
-#define LEAF_SAMPLE_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-#include "leaf-utilities.h"
-
-//==============================================================================
-
- typedef enum RecordMode
- {
- RecordOneShot = 0,
- RecordLoop,
- RecordModeNil
- } RecordMode;
-
- typedef struct _tBuffer
- {
- float* buff;
-
- uint32_t idx;
- uint32_t length;
-
- RecordMode mode;
-
- int active;
-
- } tBuffer;
-
- void tBuffer_init (tBuffer* const, uint32_t length);
- void tBuffer_free (tBuffer* const);
-
- void tBuffer_tick (tBuffer* const, float sample);
-
- void tBuffer_read(tBuffer* const, float* buff, uint32_t len);
-
- float tBuffer_get (tBuffer* const, int idx);
-
- void tBuffer_record (tBuffer* const);
- void tBuffer_stop (tBuffer* const);
-
- void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
-
- void tBuffer_clear (tBuffer* const);
-
-//==============================================================================
-
- typedef enum PlayMode
- {
- PlayNormal,
- PlayLoop,
- PlayBackAndForth,
- PlayModeNil
- } PlayMode;
-
- typedef struct _tSampler
- {
- tBuffer* samp;
-
- tRamp gain;
-
- float idx;
- float inc;
- float last;
- float iinc;
- int8_t dir;
- int8_t flip;
- int8_t bnf;
-
- int32_t start;
- int32_t end;
- uint32_t len;
- uint32_t cfxlen;
-
- PlayMode mode;
- int retrigger;
-
- int active;
-
- } tSampler;
-
- void tSampler_init (tSampler* const, tBuffer* const);
- void tSampler_free (tSampler* const);
-
- float tSampler_tick (tSampler* const);
-
- void tSampler_setSample (tSampler* const, tBuffer* s);
-
- void tSampler_setMode (tSampler* const, PlayMode mode);
-
- void tSampler_play (tSampler* const);
- void tSampler_stop (tSampler* const);
-
- void tSampler_setStart (tSampler* const, int32_t start);
- void tSampler_setEnd (tSampler* const, int32_t end);
-
- void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length);
-
- void tSampler_setRate (tSampler* const, float rate);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_SAMPLE_H_INCLUDED
-
-//==============================================================================
--- /dev/null
+++ b/LEAF/Inc/leaf-sampling.h
@@ -1,0 +1,124 @@
+/*==============================================================================
+
+leaf-sampling.h
+Created: 23 Jan 2019 11:22:09am
+Author: Mike Mulshine
+
+==============================================================================*/
+
+
+#ifndef LEAF_SAMPLING_H_INCLUDED
+#define LEAF_SAMPLING_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//==============================================================================
+
+#include "leaf-global.h"
+#include "leaf-math.h"
+#include "leaf-envelopes.h"
+
+//==============================================================================
+
+typedef enum RecordMode
+{
+ RecordOneShot = 0,
+ RecordLoop,
+ RecordModeNil
+} RecordMode;
+
+typedef struct _tBuffer
+{
+ float* buff;
+
+ uint32_t idx;
+ uint32_t length;
+
+ RecordMode mode;
+
+ int active;
+
+} tBuffer;
+
+void tBuffer_init (tBuffer* const, uint32_t length);
+void tBuffer_free (tBuffer* const);
+
+void tBuffer_tick (tBuffer* const, float sample);
+
+void tBuffer_read(tBuffer* const, float* buff, uint32_t len);
+
+float tBuffer_get (tBuffer* const, int idx);
+
+void tBuffer_record (tBuffer* const);
+void tBuffer_stop (tBuffer* const);
+
+void tBuffer_setRecordMode (tBuffer* const, RecordMode mode);
+
+void tBuffer_clear (tBuffer* const);
+
+//==============================================================================
+
+typedef enum PlayMode
+{
+ PlayNormal,
+ PlayLoop,
+ PlayBackAndForth,
+ PlayModeNil
+} PlayMode;
+
+typedef struct _tSampler
+{
+ tBuffer* samp;
+
+ tRamp gain;
+
+ float idx;
+ float inc;
+ float last;
+ float iinc;
+ int8_t dir;
+ int8_t flip;
+ int8_t bnf;
+
+ int32_t start;
+ int32_t end;
+ uint32_t len;
+ uint32_t cfxlen;
+
+ PlayMode mode;
+ int retrigger;
+
+ int active;
+
+} tSampler;
+
+void tSampler_init (tSampler* const, tBuffer* const);
+void tSampler_free (tSampler* const);
+
+float tSampler_tick (tSampler* const);
+
+void tSampler_setSample (tSampler* const, tBuffer* s);
+
+void tSampler_setMode (tSampler* const, PlayMode mode);
+
+void tSampler_play (tSampler* const);
+void tSampler_stop (tSampler* const);
+
+void tSampler_setStart (tSampler* const, int32_t start);
+void tSampler_setEnd (tSampler* const, int32_t end);
+
+void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length);
+
+void tSampler_setRate (tSampler* const, float rate);
+
+//==============================================================================
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // LEAF_SAMPLING_H_INCLUDED
+
+//==============================================================================
--- a/LEAF/Inc/leaf-string.h
+++ /dev/null
@@ -1,143 +1,0 @@
-/*
- ==============================================================================
-
- leaf-string.h
- Created: 30 Nov 2018 10:41:55am
- Author: airship
-
- ==============================================================================
-*/
-
-#ifndef LEAF_STRING_H_INCLUDED
-#define LEAF_STRING_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-#include "leaf-delay.h"
-#include "leaf-filter.h"
-#include "leaf-oscillator.h"
-
-//==============================================================================
-
-/* Karplus Strong model */
-typedef struct _tPluck
-{
- tDelayA delayLine; // Allpass or Linear?? big difference...
- tOneZero loopFilter;
- tOnePole pickFilter;
- tNoise noise;
-
- float lastOut;
- float loopGain;
- float lastFreq;
-
- float sr;
-
-} tPluck;
-
-void tPluck_init (tPluck* const, float lowestFrequency); //float delayBuff[DELAY_LENGTH]);
-void tPluck_free (tPluck* const);
-
-float tPluck_tick (tPluck* const);
-
-// Pluck the string.
-void tPluck_pluck (tPluck* const, float amplitude);
-
-// Start a note with the given frequency and amplitude.;
-void tPluck_noteOn (tPluck* const, float frequency, float amplitude );
-
-// Stop a note with the given amplitude (speed of decay).
-void tPluck_noteOff (tPluck* const, float amplitude );
-
-// Set instrument parameters for a particular frequency.
-void tPluck_setFrequency (tPluck* const, float frequency );
-
-// Perform the control change specified by \e number and \e value (0.0 - 128.0).
-void tPluck_controlChange (tPluck* const, int number, float value);
-
-// tPluck Utilities.
-float tPluck_getLastOut (tPluck* const);
-
-//==============================================================================
-
-/* Stif Karplus Strong model */
-typedef struct _tStifKarp
-{
- tDelayA delayLine;
- tDelayL combDelay;
- tOneZero filter;
- tNoise noise;
- tBiQuad biquad[4];
-
-
-
- uint32_t length;
- float loopGain;
- float baseLoopGain;
- float lastFrequency;
- float lastLength;
- float stretching;
- float pluckAmplitude;
- float pickupPosition;
-
- float lastOut;
-
-} tStifKarp;
-
-typedef enum SKControlType
-{
- SKPickPosition = 0,
- SKStringDamping,
- SKDetune,
- SKControlTypeNil
-} SKControlType;
-
-void tStifKarp_init (tStifKarp* const, float lowestFrequency); // float delayBuff[2][DELAY_LENGTH]);
-void tStifKarp_free (tStifKarp* const);
-
-float tStifKarp_tick (tStifKarp* const);
-
-// Pluck the string.
-void tStifKarp_pluck (tStifKarp* const, float amplitude);
-
-// Start a note with the given frequency and amplitude.;
-void tStifKarp_noteOn (tStifKarp* const, float frequency, float amplitude );
-
-// Stop a note with the given amplitude (speed of decay).
-void tStifKarp_noteOff (tStifKarp* const, float amplitude );
-
-// Set instrument parameters for a particular frequency.
-void tStifKarp_setFrequency (tStifKarp* const, float frequency );
-
-// Perform the control change specified by \e number and \e value (0.0 - 128.0).
-// Use SKPickPosition, SKStringDamping, or SKDetune for type.
-void tStifKarp_controlChange (tStifKarp* const, SKControlType type, float value);
-
-// Set the stretch "factor" of the string (0.0 - 1.0).
-void tStifKarp_setStretch (tStifKarp* const, float stretch );
-
-// Set the pluck or "excitation" position along the string (0.0 - 1.0).
-void tStifKarp_setPickupPosition (tStifKarp* const, float position );
-
-// Set the base loop gain.
-void tStifKarp_setBaseLoopGain (tStifKarp* const, float aGain );
-
-// tStifKarp utilities.
-float tStifKarp_getLastOut (tStifKarp* const);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_STRING_H_INCLUDED
-
-//==============================================================================
--- a/LEAF/Inc/leaf-tables.h
+++ b/LEAF/Inc/leaf-tables.h
@@ -6,8 +6,8 @@
==============================================================================*/
-#ifndef LEAF_WAVETABLES_H_INCLUDED
-#define LEAF_WAVETABLES_H_INCLUDED
+#ifndef LEAF_TABLES_H_INCLUDED
+#define LEAF_TABLES_H_INCLUDED
#ifdef __cplusplus
extern "C" {
@@ -95,6 +95,6 @@
}
#endif
-#endif // LEAF_WAVETABLES_H_INCLUDED
+#endif // LEAF_TABLES_H_INCLUDED
//==============================================================================
--- a/LEAF/Inc/leaf-utilities.h
+++ /dev/null
@@ -1,483 +1,0 @@
-/*
- ==============================================================================
-
- LEAFUtilities.h
- Created: 20 Jan 2017 12:02:17pm
- Author: Michael R Mulshine
-
- ==============================================================================
-*/
-
-#ifndef LEAFUTILITIES_H_INCLUDED
-#define LEAFUTILITIES_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-#include "leaf-math.h"
-#include "leaf-filter.h"
-#include "leaf-delay.h"
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-// STACK implementation (fixed size)
-#define STACK_SIZE 128
-typedef struct _tStack
-{
- int data[STACK_SIZE];
- uint16_t pos;
- uint16_t size;
- uint16_t capacity;
- oBool ordered;
-
-} tStack;
-
-void tStack_init (tStack* const);
-void tStack_free (tStack* const);
-
-void tStack_setCapacity (tStack* const, uint16_t cap);
-int tStack_addIfNotAlreadyThere (tStack* const, uint16_t item);
-void tStack_add (tStack* const, uint16_t item);
-int tStack_remove (tStack* const, uint16_t item);
-void tStack_clear (tStack* const);
-int tStack_first (tStack* const);
-int tStack_getSize (tStack* const);
-int tStack_contains (tStack* const, uint16_t item);
-int tStack_next (tStack* const);
-int tStack_get (tStack* const, int which);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* Ramp */
-typedef struct _tRamp {
- float inc;
- float inv_sr_ms;
- float minimum_time;
- float curr,dest;
- float time;
- int samples_per_tick;
-
-} tRamp;
-
-void tRamp_init (tRamp* const, float time, int samplesPerTick);
-void tRamp_free (tRamp* const);
-
-float tRamp_tick (tRamp* const);
-float tRamp_sample (tRamp* const);
-int tRamp_setTime (tRamp* const, float time);
-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
-{
- float tauAttack, tauRelease;
- float T, R, W, M; // Threshold, compression Ratio, decibel Width of knee transition, decibel Make-up gain
-
- float x_G[2], y_G[2], x_T[2], y_T[2];
-
- oBool isActive;
-
-}tCompressor;
-
-void tCompressor_init (tCompressor* const);
-void tCompressor_free (tCompressor* const);
-float tCompressor_tick (tCompressor* const, float input);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* Attack-Decay envelope */
-typedef struct _tEnvelope {
-
- const float *exp_buff;
- const float *inc_buff;
- uint32_t buff_size;
-
- float next;
-
- float attackInc, decayInc, rampInc;
-
- oBool inAttack, inDecay, inRamp;
-
- oBool loop;
-
- float gain, rampPeak;
-
- float attackPhase, decayPhase, rampPhase;
-
-} tEnvelope;
-
-void tEnvelope_init (tEnvelope* const, float attack, float decay, oBool loop);
-void tEnvelope_free (tEnvelope* const);
-
-float tEnvelope_tick (tEnvelope* const);
-int tEnvelope_setAttack (tEnvelope* const, float attack);
-int tEnvelope_setDecay (tEnvelope* const, float decay);
-int tEnvelope_loop (tEnvelope* const, oBool loop);
-int tEnvelope_on (tEnvelope* const, float velocity);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* ADSR */
-typedef struct _tADSR
-{
- const float *exp_buff;
- const float *inc_buff;
- uint32_t buff_size;
-
- float next;
-
- float attackInc, decayInc, releaseInc, rampInc;
-
- oBool inAttack, inDecay, inSustain, inRelease, inRamp;
-
- float sustain, gain, rampPeak, releasePeak;
-
- float attackPhase, decayPhase, releasePhase, rampPhase;
-
-} tADSR;
-
-void tADSR_init (tADSR* const, float attack, float decay, float sustain, float release);
-void tADSR_free (tADSR* const);
-
-float tADSR_tick (tADSR* const);
-int tADSR_setAttack (tADSR* const, float attack);
-int tADSR_setDecay (tADSR* const, float decay);
-int tADSR_setSustain(tADSR* const, float sustain);
-int tADSR_setRelease(tADSR* const, float release);
-int tADSR_on (tADSR* const, float velocity);
-int tADSR_off (tADSR* const);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* Envelope Follower */
-typedef struct _tEnvelopeFollower
-{
- float y;
- float a_thresh;
- float d_coeff;
-
-} tEnvelopeFollower;
-
-void tEnvelopeFollower_init (tEnvelopeFollower* const, float attackThreshold, float decayCoeff);
-void tEnvelopeFollower_free (tEnvelopeFollower* const);
-
-float tEnvelopeFollower_tick (tEnvelopeFollower* const, float x);
-int tEnvelopeFollower_decayCoeff (tEnvelopeFollower* const, float decayCoeff);
-int tEnvelopeFollower_attackThresh (tEnvelopeFollower* const, float attackThresh);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* tAtkDtk */
-#define DEFBLOCKSIZE 1024
-#define DEFTHRESHOLD 6
-#define DEFATTACK 10
-#define DEFRELEASE 10
-
-typedef struct _tAtkDtk
-{
- float env;
-
- //Attack & Release times in msec
- int atk;
- int rel;
-
- //Attack & Release coefficients based on times
- float atk_coeff;
- float rel_coeff;
-
- int blocksize;
- int samplerate;
-
- //RMS amplitude of previous block - used to decide if attack is present
- float prevAmp;
-
- float threshold;
-} tAtkDtk;
-
-void tAtkDtk_init (tAtkDtk* const, int blocksize);
-void tAtkDtk_init_expanded (tAtkDtk* const, int blocksize, int atk, int rel);
-void tAtkDtk_free (tAtkDtk* const);
-
-// set expected input blocksize
-void tAtkDtk_setBlocksize (tAtkDtk* const, int size);
-
-// change atkDetector sample rate
-void tAtkDtk_setSamplerate (tAtkDtk* const, int inRate);
-
-// set attack time and coeff
-void tAtkDtk_setAtk (tAtkDtk* const, int inAtk);
-
-// set release time and coeff
-void tAtkDtk_setRel (tAtkDtk* const, int inRel);
-
-// set level above which values are identified as attacks
-void tAtkDtk_setThreshold (tAtkDtk* const, float thres);
-
-// 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
-#define INITVSTAKEN 64
-#define ENV_WINDOW_SIZE 1024
-#define ENV_HOP_SIZE 256
-
-typedef struct _tEnv
-{
- float buf[ENV_WINDOW_SIZE + INITVSTAKEN];
- uint16_t x_phase; /* number of points since last output */
- uint16_t x_period; /* requested period of output */
- uint16_t x_realperiod; /* period rounded up to vecsize multiple */
- uint16_t x_npoints; /* analysis window size in samples */
- float x_result; /* result to output */
- float x_sumbuf[MAXOVERLAP]; /* summing buffer */
- float x_f;
- uint16_t windowSize, hopSize, blockSize;
- uint16_t x_allocforvs; /* extra buffer for DSP vector size */
-} tEnv;
-
-void tEnv_init (tEnv* const, int windowSize, int hopSize, int blockSize);
-void tEnv_free (tEnv* const);
-float tEnv_tick (tEnv* const);
-void tEnv_processBlock (tEnv* const, float* in);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-/* tSOLAD : pitch shifting algorithm that underlies tPitchShifter etc */
-#define LOOPSIZE (2048*2) // (4096*2) // loop size must be power of two
-#define LOOPMASK (LOOPSIZE - 1)
-#define PITCHFACTORDEFAULT 1.0f
-#define INITPERIOD 64.0f
-#define MAXPERIOD (float)((LOOPSIZE - w->blocksize) * 0.8f)
-#define MINPERIOD 8.0f
-
-typedef struct _tSOLAD
-{
- uint16_t timeindex; // current reference time, write index
- uint16_t blocksize; // signal input / output block size
- float pitchfactor; // pitch factor between 0.25 and 4
- float readlag; // read pointer's lag behind write pointer
- float period; // period length in input signal
- float jump; // read pointer jump length and direction
- float xfadelength; // crossfade length expressed at input sample rate
- float xfadevalue; // crossfade phase and value
-
- float* delaybuf;
-
-} tSOLAD;
-
-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);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-// tSNAC: period detector
-#define SNAC_FRAME_SIZE 1024 // default analysis framesize // should be the same as (or smaller than?) PS_FRAME_SIZE
-#define DEFOVERLAP 1 // default overlap
-#define DEFBIAS 0.2f // default bias
-#define DEFMINRMS 0.003f // default minimum RMS
-#define SEEK 0.85f // seek-length as ratio of framesize
-
-typedef struct _tSNAC
-{
- float* inputbuf;
- float* processbuf;
- float* spectrumbuf;
- float* biasbuf;
- uint16_t timeindex;
- uint16_t framesize;
- uint16_t overlap;
- uint16_t periodindex;
-
- float periodlength;
- float fidelity;
- float biasfactor;
- float minrms;
-
-} tSNAC;
-
-void tSNAC_init (tSNAC* const, int overlaparg); // constructor
-void tSNAC_free (tSNAC* const); // destructor
-
-void tSNAC_ioSamples (tSNAC *s, float *in, float *out, int size);
-void tSNAC_setOverlap (tSNAC *s, int lap);
-void tSNAC_setBias (tSNAC *s, float bias);
-void tSNAC_setMinRMS (tSNAC *s, float rms);
-
-/*To get freq, perform SAMPLE_RATE/snac_getperiod() */
-float tSNAC_getPeriod (tSNAC *s);
-float tSNAC_getfidelity (tSNAC *s);
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAFUTILITIES_H_INCLUDED
-
-
--- a/LEAF/Inc/leaf-vocoder.h
+++ /dev/null
@@ -1,89 +1,0 @@
-/*==============================================================================
-
- leaf-vocoder.h
- Created: 20 Jan 2017 12:01:54pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#ifndef LEAF_VOCODER_H_INCLUDED
-#define LEAF_VOCODER_H_INCLUDED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-//==============================================================================
-
-/* tTalkbox */
-#define NUM_TALKBOX_PARAM 4
-
-typedef struct _tTalkbox
-{
- float param[NUM_TALKBOX_PARAM];
-
- int bufsize;
- float* car0;
- float* car1;
- float* window;
- float* buf0;
- float* buf1;
-
- float emphasis;
- int32_t K, N, O, pos;
- float wet, dry, FX;
- float d0, d1, d2, d3, d4;
- float u0, u1, u2, u3, u4;
-
-} tTalkbox;
-
-void tTalkbox_init (tTalkbox* const, int bufsize);
-void tTalkbox_free (tTalkbox* const);
-float tTalkbox_tick (tTalkbox* const, float synth, float voice);
-void tTalkbox_update (tTalkbox* const);
-void tTalkbox_suspend (tTalkbox* const);
-void tTalkbox_lpcDurbin (float *r, int p, float *k, float *g);
-void tTalkbox_lpc (float *buf, float *car, int32_t n, int32_t o);
-void tTalkbox_setQuality (tTalkbox* const, float quality);
-
-//==============================================================================
-
-/* tVocoder */
-#define NUM_VOCODER_PARAM 8
-#define NBANDS 16
-
-typedef struct _tVocoder
-{
- float param[NUM_VOCODER_PARAM];
-
- float gain; //output level
- float thru, high; //hf thru
- float kout; //downsampled output
- int32_t kval; //downsample counter
- int32_t nbnd; //number of bands
-
- //filter coeffs and buffers - seems it's faster to leave this global than make local copy
- float f[NBANDS][13]; //[0-8][0 1 2 | 0 1 2 3 | 0 1 2 3 | val rate]
-
-} tVocoder;
-
-void tVocoder_init (tVocoder* const);
-void tVocoder_free (tVocoder* const);
-float tVocoder_tick (tVocoder* const, float synth, float voice);
-void tVocoder_update (tVocoder* const);
-void tVocoder_suspend (tVocoder* const);
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_VOCODER_H_INCLUDED
-
-//==============================================================================
--- a/LEAF/Inc/leaf-wavefolder.h
+++ /dev/null
@@ -1,48 +1,0 @@
-/*==============================================================================
-
- leaf-wavefolder.h
- Created: 30 Nov 2018 11:57:05am
- Author: airship
-
-==============================================================================*/
-
-#ifndef LEAF_WAVEFOLDER_H_INCLUDED
-#define LEAF_WAVEFOLDER_H_INCLUDED
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//==============================================================================
-
-#include "leaf-global.h"
-#include "leaf-math.h"
-
-//==============================================================================
-
-/* tLockhartWavefolder */
-
-typedef struct _tLockhartWavefolder
-{
- double Ln1;
- double Fn1;
- float xn1;
-
-} tLockhartWavefolder;
-
-void tLockhartWavefolder_init (tLockhartWavefolder* const);
-void tLockhartWavefolder_free (tLockhartWavefolder* const);
-
-float tLockhartWavefolder_tick (tLockhartWavefolder* const, float samp);
-
-
-//==============================================================================
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // LEAF_WAVEFOLDER_H_INCLUDED
-
-//==============================================================================
--- a/LEAF/Src/leaf-808.c
+++ /dev/null
@@ -1,460 +1,0 @@
-/*==============================================================================
-
- leaf-808.c
- Created: 30 Nov 2018 10:24:21am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-808.h"
-
-#else
-
-#include "../Inc/leaf-808.h"
-
-#endif
-
-// ----------------- COWBELL ----------------------------//
-
-void t808Cowbell_init(t808Cowbell* const cowbell, int useStick) {
-
- tSquare_init(&cowbell->p[0]);
- tSquare_setFreq(&cowbell->p[0], 540.0f);
-
- tSquare_init(&cowbell->p[1]);
- tSquare_setFreq(&cowbell->p[1], 1.48148f * 540.0f);
-
- cowbell->oscMix = 0.5f;
-
- tSVF_init(&cowbell->bandpassOsc, SVFTypeBandpass, 2500, 1.0f);
-
- tSVF_init(&cowbell->bandpassStick, SVFTypeBandpass, 1800, 1.0f);
-
- tEnvelope_init(&cowbell->envGain, 5.0f, 100.0f, OFALSE);
-
- tEnvelope_init(&cowbell->envFilter, 5.0, 100.0f, OFALSE);
-
- tHighpass_init(&cowbell->highpass, 1000.0f);
-
- tNoise_init(&cowbell->stick, WhiteNoise);
-
- tEnvelope_init(&cowbell->envStick, 5.0f, 5.0f, 0);
-
- cowbell->useStick = useStick;
-}
-
-void t808Cowebell_free(t808Cowbell* const cowbell)
-{
- tSquare_free(&cowbell->p[0]);
- tSquare_free(&cowbell->p[1]);
- tSVF_free(&cowbell->bandpassOsc);
- tSVF_free(&cowbell->bandpassStick);
- tEnvelope_free(&cowbell->envGain);
- tEnvelope_free(&cowbell->envFilter);
- tHighpass_free(&cowbell->highpass);
- tNoise_free(&cowbell->stick);
- tEnvelope_free(&cowbell->envStick);
-}
-
-void t808Cowbell_on(t808Cowbell* const cowbell, float vel)
-{
- tEnvelope_on(&cowbell->envGain, vel);
-
- if (cowbell->useStick)
- tEnvelope_on(&cowbell->envStick,vel);
-}
-
-float t808Cowbell_tick(t808Cowbell* const cowbell) {
-
- float sample = 0.0f;
-
- // Mix oscillators.
- sample = (cowbell->oscMix * tSquare_tick(&cowbell->p[0])) + ((1.0f-cowbell->oscMix) * tSquare_tick(&cowbell->p[1]));
-
- // Filter dive and filter.
- tSVF_setFreq(&cowbell->bandpassOsc, cowbell->filterCutoff + 1000.0f * tEnvelope_tick(&cowbell->envFilter));
- sample = tSVF_tick(&cowbell->bandpassOsc,sample);
-
- sample *= (0.9f * tEnvelope_tick(&cowbell->envGain));
-
- if (cowbell->useStick)
- sample += (0.1f * tEnvelope_tick(&cowbell->envStick) * tSVF_tick(&cowbell->bandpassStick, tNoise_tick(&cowbell->stick)));
-
-
- sample = tHighpass_tick(&cowbell->highpass, sample);
-
- return sample;
-}
-
-void t808Cowbell_setDecay(t808Cowbell* const cowbell, float decay)
-{
- tEnvelope_setDecay(&cowbell->envGain,decay);
-}
-
-void t808Cowbell_setHighpassFreq(t808Cowbell *cowbell, float freq)
-{
- tHighpass_setFreq(&cowbell->highpass,freq);
-}
-
-void t808Cowbell_setBandpassFreq(t808Cowbell* const cowbell, float freq)
-{
- cowbell->filterCutoff = freq;
-}
-
-void t808Cowbell_setFreq(t808Cowbell* const cowbell, float freq)
-{
-
- tSquare_setFreq(&cowbell->p[0],freq);
- tSquare_setFreq(&cowbell->p[1],1.48148f*freq);
-}
-
-void t808Cowbell_setOscMix(t808Cowbell* const cowbell, float oscMix)
-{
- cowbell->oscMix = oscMix;
-}
-
-void t808Cowbell_setStick(t808Cowbell* const cowbell, int useStick)
-{
- cowbell->useStick = useStick;
-}
-
-// ----------------- HIHAT ----------------------------//
-
-void t808Hihat_init(t808Hihat* const hihat)
-{
- for (int i = 0; i < 6; i++)
- {
- tSquare_init(&hihat->p[i]);
- }
-
- tNoise_init(&hihat->stick, PinkNoise);
- tNoise_init(&hihat->n, WhiteNoise);
-
- // need to fix SVF to be generic
- tSVF_init(&hihat->bandpassStick, SVFTypeBandpass,2500.0f,1.2f);
- tSVF_init(&hihat->bandpassOsc, SVFTypeBandpass,3500.0f,0.3f);
-
- tEnvelope_init(&hihat->envGain, 0.0f, 50.0f, OFALSE);
- tEnvelope_init(&hihat->envStick, 0.0f, 7.0f, OFALSE);
-
-
- tHighpass_init(&hihat->highpass, 7000.0f);
-
- hihat->freq = 40.0f;
- hihat->stretch = 0.0f;
-
- tSquare_setFreq(&hihat->p[0], 2.0f * hihat->freq);
- tSquare_setFreq(&hihat->p[1], 3.00f * hihat->freq);
- tSquare_setFreq(&hihat->p[2], 4.16f * hihat->freq);
- tSquare_setFreq(&hihat->p[3], 5.43f * hihat->freq);
- tSquare_setFreq(&hihat->p[4], 6.79f * hihat->freq);
- tSquare_setFreq(&hihat->p[5], 8.21f * hihat->freq);
-}
-
-void t808Hihat_free(t808Hihat* const hihat)
-{
- for (int i = 0; i < 6; i++)
- {
- tSquare_free(&hihat->p[i]);
- }
-
- tNoise_free(&hihat->stick);
- tNoise_free(&hihat->n);
-
- // need to fix SVF to be generic
- tSVF_free(&hihat->bandpassStick);
- tSVF_free(&hihat->bandpassOsc);
- tEnvelope_free(&hihat->envGain);
- tEnvelope_free(&hihat->envStick);
-
- tHighpass_free(&hihat->highpass);
-}
-
-void t808Hihat_on(t808Hihat* const hihat, float vel) {
-
- tEnvelope_on(&hihat->envGain, vel);
- tEnvelope_on(&hihat->envStick, vel);
-
-}
-
-void t808Hihat_setOscNoiseMix(t808Hihat* const hihat, float oscNoiseMix) {
-
- hihat->oscNoiseMix = oscNoiseMix;
-
-}
-
-float t808Hihat_tick(t808Hihat* const hihat) {
-
- float sample = 0.0f;
- float gainScale = 0.1666f;
-
-
- float myNoise = tNoise_tick(&hihat->n);
-
- tSquare_setFreq(&hihat->p[0], ((2.0f + hihat->stretch) * hihat->freq));
- tSquare_setFreq(&hihat->p[1], ((3.00f + hihat->stretch) * hihat->freq));
- tSquare_setFreq(&hihat->p[2], ((4.16f + hihat->stretch) * hihat->freq));
- tSquare_setFreq(&hihat->p[3], ((5.43f + hihat->stretch) * hihat->freq));
- tSquare_setFreq(&hihat->p[4], ((6.79f + hihat->stretch) * hihat->freq));
- tSquare_setFreq(&hihat->p[5], ((8.21f + hihat->stretch) * hihat->freq));
-
- for (int i = 0; i < 6; i++)
- {
- sample += tSquare_tick(&hihat->p[i]);
- }
-
- sample *= gainScale;
-
- sample = (hihat->oscNoiseMix * sample) + ((1.0f-hihat->oscNoiseMix) * myNoise);
-
- sample = tSVF_tick(&hihat->bandpassOsc, sample);
-
- float myGain = tEnvelope_tick(&hihat->envGain);
- sample *= (myGain*myGain);//square the output gain envelope
- sample = tHighpass_tick(&hihat->highpass, sample);
- sample += ((0.5f * tEnvelope_tick(&hihat->envStick)) * tSVF_tick(&hihat->bandpassStick, tNoise_tick(&hihat->stick)));
- sample = tanhf(sample * 2.0f);
-
- return sample;
-}
-
-void t808Hihat_setDecay(t808Hihat* const hihat, float decay)
-{
- tEnvelope_setDecay(&hihat->envGain,decay);
-}
-
-void t808Hihat_setHighpassFreq(t808Hihat* const hihat, float freq)
-{
- tHighpass_setFreq(&hihat->highpass,freq);
-}
-
-void t808Hihat_setStretch(t808Hihat* const hihat, float stretch)
-{
- hihat->stretch = stretch;
-}
-
-void t808Hihat_setFM(t808Hihat* const hihat, float FM_amount)
-{
- hihat->FM_amount = FM_amount;
-}
-
-void t808Hihat_setOscBandpassFreq(t808Hihat* const hihat, float freq)
-{
- tSVF_setFreq(&hihat->bandpassOsc,freq);
-}
-
-void t808Hihat_setOscBandpassQ(t808Hihat* const hihat, float Q)
-{
- tSVF_setQ(&hihat->bandpassOsc,Q);
-}
-
-void t808Hihat_setStickBandPassFreq(t808Hihat* const hihat, float freq)
-{
- tSVF_setFreq(&hihat->bandpassStick,freq);
-}
-
-void t808Hihat_setStickBandPassQ(t808Hihat* const hihat, float Q)
-{
- tSVF_setQ(&hihat->bandpassStick,Q);
-}
-
-
-
-void t808Hihat_setOscFreq(t808Hihat* const hihat, float freq)
-{
- hihat->freq = freq;
-}
-
-// ----------------- SNARE ----------------------------//
-
-void t808Snare_init(t808Snare* const snare)
-{
- float ratio[2] = {1.0, 1.5};
- for (int i = 0; i < 2; i++)
- {
- tTriangle_init(&snare->tone[i]);
-
- tTriangle_setFreq(&snare->tone[i], ratio[i] * 400.0f);
- tSVF_init(&snare->toneLowpass[i], SVFTypeLowpass, 4000, 1.0f);
- tEnvelope_init(&snare->toneEnvOsc[i], 0.0f, 50.0f, OFALSE);
- tEnvelope_init(&snare->toneEnvGain[i], 1.0f, 150.0f, OFALSE);
- tEnvelope_init(&snare->toneEnvFilter[i], 1.0f, 2000.0f, OFALSE);
-
- snare->toneGain[i] = 0.5f;
- }
-
- snare->tone1Freq = ratio[0] * 100.0f;
- snare->tone2Freq = ratio[1] * 100.0f;
- snare->noiseFilterFreq = 3000.0f;
- tNoise_init(&snare->noiseOsc, WhiteNoise);
- tSVF_init(&snare->noiseLowpass, SVFTypeLowpass, 12000.0f, 0.8f);
- tEnvelope_init(&snare->noiseEnvGain, 0.0f, 100.0f, OFALSE);
- tEnvelope_init(&snare->noiseEnvFilter, 0.0f, 1000.0f, OFALSE);
- snare->noiseGain = 1.0f;
-}
-
-void t808Snare_free (t808Snare* const snare)
-{
- for (int i = 0; i < 2; i++)
- {
- tTriangle_free(&snare->tone[i]);
- tSVF_free(&snare->toneLowpass[i]);
- tEnvelope_free(&snare->toneEnvOsc[i]);
- tEnvelope_free(&snare->toneEnvGain[i]);
- tEnvelope_free(&snare->toneEnvFilter[i]);
- }
-
-
- tNoise_free(&snare->noiseOsc);
- tSVF_free(&snare->noiseLowpass);
- tEnvelope_free(&snare->noiseEnvGain);
- tEnvelope_free(&snare->noiseEnvFilter);
-}
-
-void t808Snare_on(t808Snare* const snare, float vel)
-{
- for (int i = 0; i < 2; i++)
- {
- tEnvelope_on(&snare->toneEnvOsc[i], vel);
- tEnvelope_on(&snare->toneEnvGain[i], vel);
- tEnvelope_on(&snare->toneEnvFilter[i], vel);
- }
-
- tEnvelope_on(&snare->noiseEnvGain, vel);
- tEnvelope_on(&snare->noiseEnvFilter, vel);
-}
-
-void t808Snare_setTone1Freq(t808Snare* const snare, float freq)
-{
- snare->tone1Freq = freq;
- tTriangle_setFreq(&snare->tone[0], freq);
-
-}
-
-void t808Snare_setTone2Freq(t808Snare* const snare, float freq)
-{
- snare->tone2Freq = freq;
- tTriangle_setFreq(&snare->tone[1],freq);
-}
-
-void t808Snare_setTone1Decay(t808Snare* const snare, float decay)
-{
- tEnvelope_setDecay(&snare->toneEnvGain[0],decay);
-}
-
-void t808Snare_setTone2Decay(t808Snare* const snare, float decay)
-{
- tEnvelope_setDecay(&snare->toneEnvGain[1],decay);
-}
-
-void t808Snare_setNoiseDecay(t808Snare* const snare, float decay)
-{
- tEnvelope_setDecay(&snare->noiseEnvGain,decay);
-}
-
-void t808Snare_setToneNoiseMix(t808Snare* const snare, float toneNoiseMix)
-{
- snare->toneNoiseMix = toneNoiseMix;
-}
-
-void t808Snare_setNoiseFilterFreq(t808Snare* const snare, float noiseFilterFreq)
-{
- snare->noiseFilterFreq = noiseFilterFreq;
-}
-
-void t808Snare_setNoiseFilterQ(t808Snare* const snare, float noiseFilterQ)
-{
- tSVF_setQ(&snare->noiseLowpass, noiseFilterQ);
-}
-
-static float tone[2];
-
-float t808Snare_tick(t808Snare* const snare)
-{
- for (int i = 0; i < 2; i++)
- {
- tTriangle_setFreq(&snare->tone[i], snare->tone1Freq + (20.0f * tEnvelope_tick(&snare->toneEnvOsc[i])));
- tone[i] = tTriangle_tick(&snare->tone[i]);
-
- tSVF_setFreq(&snare->toneLowpass[i], 2000.0f + (500.0f * tEnvelope_tick(&snare->toneEnvFilter[i])));
- tone[i] = tSVF_tick(&snare->toneLowpass[i], tone[i]) * tEnvelope_tick(&snare->toneEnvGain[i]);
- }
-
- float noise = tNoise_tick(&snare->noiseOsc);
- tSVF_setFreq(&snare->noiseLowpass, snare->noiseFilterFreq + (1000.0f * tEnvelope_tick(&snare->noiseEnvFilter)));
- noise = tSVF_tick(&snare->noiseLowpass, noise) * tEnvelope_tick(&snare->noiseEnvGain);
-
- float sample = (snare->toneNoiseMix)*(tone[0] * snare->toneGain[0] + tone[1] * snare->toneGain[1]) + (1.0f-snare->toneNoiseMix) * (noise * snare->noiseGain);
- sample = tanhf(sample * 2.0f);
- return sample;
-}
-
-// ----------------- KICK ----------------------------//
-
-void t808Kick_init (t808Kick* const kick)
-{
- tCycle_init(&kick->tone);
- kick->toneInitialFreq = 40.0f;
- kick->sighAmountInHz = 7.0f;
- kick->chirpRatioMinusOne = 3.3f;
- tCycle_setFreq(&kick->tone, 50.0f);
- tSVF_init(&kick->toneLowpass, SVFTypeLowpass, 2000.0f, 0.5f);
- tEnvelope_init(&kick->toneEnvOscChirp, 0.0f, 20.0f, OFALSE);
- tEnvelope_init(&kick->toneEnvOscSigh, 0.0f, 2500.0f, OFALSE);
- tEnvelope_init(&kick->toneEnvGain, 0.0f, 800.0f, OFALSE);
- tNoise_init(&kick->noiseOsc, PinkNoise);
- tEnvelope_init(&kick->noiseEnvGain, 0.0f, 1.0f, OFALSE);
- kick->noiseGain = 0.3f;
-}
-
-void t808Kick_free (t808Kick* const kick)
-{
- tCycle_free(&kick->tone);
- tSVF_free(&kick->toneLowpass);
- tEnvelope_free(&kick->toneEnvOscChirp);
- tEnvelope_free(&kick->toneEnvOscSigh);
- tEnvelope_free(&kick->toneEnvGain);
- tNoise_free(&kick->noiseOsc);
- tEnvelope_free(&kick->noiseEnvGain);
-}
-
-float t808Kick_tick (t808Kick* const kick)
-{
- tCycle_setFreq(&kick->tone, (kick->toneInitialFreq * (1.0f + (kick->chirpRatioMinusOne * tEnvelope_tick(&kick->toneEnvOscChirp)))) + (kick->sighAmountInHz * tEnvelope_tick(&kick->toneEnvOscSigh)));
- float sample = tCycle_tick(&kick->tone) * tEnvelope_tick(&kick->toneEnvGain);
- sample+= tNoise_tick(&kick->noiseOsc) * tEnvelope_tick(&kick->noiseEnvGain);
- //add distortion here
- sample = tSVF_tick(&kick->toneLowpass, sample);
- return sample;
-}
-
-void t808Kick_on (t808Kick* const kick, float vel)
-{
- tEnvelope_on(&kick->toneEnvOscChirp, vel);
- tEnvelope_on(&kick->toneEnvOscSigh, vel);
- tEnvelope_on(&kick->toneEnvGain, vel);
- tEnvelope_on(&kick->noiseEnvGain, vel);
-
-}
-void t808Kick_setToneFreq (t808Kick* const kick, float freq)
-{
- kick->toneInitialFreq = freq;
-
-}
-
-void t808Kick_setToneDecay (t808Kick* const kick, float decay)
-{
- tEnvelope_setDecay(&kick->toneEnvGain,decay);
- tEnvelope_setDecay(&kick->toneEnvGain,decay * 3.0f);
-}
-
-void t808Kick_setNoiseDecay (t808Kick* const kick, float decay);
-void t808Kick_setSighAmount (t808Kick* const kick, float sigh);
-void t808Kick_setChirpAmount (t808Kick* const kick, float chirp);
-void t808Kick_setToneNoiseMix (t808Kick* const kick, float toneNoiseMix);
-void t808Kick_setNoiseFilterFreq (t808Kick* const kick, float noiseFilterFreq);
-void t808Kick_setNoiseFilterQ (t808Kick* const kick, float noiseFilterQ);
-
-
--- a/LEAF/Src/leaf-WDF.c
+++ /dev/null
@@ -1,469 +1,0 @@
-/*
- * leaf-WDF.c
- *
- * Created on: Sep 25, 2019
- * Author: jeffsnyder
- */
-
-
-#include "../Inc/leaf-WDF.h"
-
-static float get_port_resistance_for_resistor(tWDF* const r);
-static float get_port_resistance_for_capacitor(tWDF* const r);
-static float get_port_resistance_for_inductor(tWDF* const r);
-static float get_port_resistance_for_resistive(tWDF* const r);
-static float get_port_resistance_for_inverter(tWDF* const r);
-static float get_port_resistance_for_series(tWDF* const r);
-static float get_port_resistance_for_parallel(tWDF* const r);
-static float get_port_resistance_for_root(tWDF* const r);
-
-static void set_incident_wave_for_leaf(tWDF* const r, float incident_wave, float input);
-static void set_incident_wave_for_leaf_inverted(tWDF* const r, float incident_wave, float input);
-static void set_incident_wave_for_inverter(tWDF* const r, float incident_wave, float input);
-static void set_incident_wave_for_series(tWDF* const r, float incident_wave, float input);
-static void set_incident_wave_for_parallel(tWDF* const r, float incident_wave, float input);
-
-static float get_reflected_wave_for_resistor(tWDF* const r, float input);
-static float get_reflected_wave_for_capacitor(tWDF* const r, float input);
-static float get_reflected_wave_for_resistive(tWDF* const r, float input);
-static float get_reflected_wave_for_inverter(tWDF* const r, float input);
-static float get_reflected_wave_for_series(tWDF* const r, float input);
-static float get_reflected_wave_for_parallel(tWDF* const r, float input);
-
-static float get_reflected_wave_for_ideal(tWDF* const n, float input, float incident_wave);
-static float get_reflected_wave_for_diode(tWDF* const n, float input, float incident_wave);
-static float get_reflected_wave_for_diode_pair(tWDF* const n, float input, float incident_wave);
-
-//WDF
-void tWDF_init(tWDF* const r, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR)
-{
- r->type = type;
- r->child_left = rL;
- r->child_right = rR;
- r->incident_wave_up = 0.0f;
- r->incident_wave_left = 0.0f;
- r->incident_wave_right = 0.0f;
- r->reflected_wave_up = 0.0f;
- r->reflected_wave_left = 0.0f;
- r->reflected_wave_right = 0.0f;
- r->sample_rate = leaf.sampleRate;
- r->value = value;
-
- tWDF* child;
- if (r->child_left != NULL) child = r->child_left;
- else child = r->child_right;
-
- if (r->type == Resistor)
- {
- r->port_resistance_up = r->value;
- r->port_conductance_up = 1.0f / r->value;
-
- r->get_port_resistance = &get_port_resistance_for_resistor;
- r->get_reflected_wave_up = &get_reflected_wave_for_resistor;
- r->set_incident_wave = &set_incident_wave_for_leaf;
- }
- else if (r->type == Capacitor)
- {
- r->port_conductance_up = r->sample_rate * 2.0f * r->value;
- r->port_resistance_up = 1.0f / r->port_conductance_up; //based on trapezoidal discretization
-
- r->get_port_resistance = &get_port_resistance_for_capacitor;
- r->get_reflected_wave_up = &get_reflected_wave_for_capacitor;
- r->set_incident_wave = &set_incident_wave_for_leaf;
- }
- else if (r->type == Inductor)
- {
- r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_port_resistance = &get_port_resistance_for_inductor;
- r->get_reflected_wave_up = &get_reflected_wave_for_capacitor; // same as capacitor
- r->set_incident_wave = &set_incident_wave_for_leaf_inverted;
- }
- else if (r->type == ResistiveSource)
- {
- r->port_resistance_up = r->value;
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_port_resistance = &get_port_resistance_for_resistive;
- r->get_reflected_wave_up = &get_reflected_wave_for_resistive;
- r->set_incident_wave = &set_incident_wave_for_leaf;
- }
- else if (r->type == Inverter)
- {
- r->port_resistance_up = tWDF_getPortResistance(r->child_left);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_port_resistance = &get_port_resistance_for_inverter;
- r->get_reflected_wave_up = &get_reflected_wave_for_inverter;
- r->set_incident_wave = &set_incident_wave_for_inverter;
- }
- else if (r->type == SeriesAdaptor)
- {
- r->port_resistance_left = tWDF_getPortResistance(r->child_left);
- r->port_resistance_right = tWDF_getPortResistance(r->child_right);
- r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
- r->port_conductance_up = 1.0f / r->port_resistance_up;
- r->port_conductance_left = 1.0f / r->port_resistance_left;
- r->port_conductance_right = 1.0f / r->port_resistance_right;
- r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
-
- r->get_port_resistance = &get_port_resistance_for_series;
- r->get_reflected_wave_up = &get_reflected_wave_for_series;
- r->set_incident_wave = &set_incident_wave_for_series;
- }
- else if (r->type == ParallelAdaptor)
- {
- r->port_resistance_left = tWDF_getPortResistance(r->child_left);
- r->port_resistance_right = tWDF_getPortResistance(r->child_right);
- r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
- r->port_conductance_left = 1.0f / r->port_resistance_left;
- r->port_conductance_right = 1.0f / r->port_resistance_right;
- r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
-
- r->get_port_resistance = &get_port_resistance_for_parallel;
- r->get_reflected_wave_up = &get_reflected_wave_for_parallel;
- r->set_incident_wave = &set_incident_wave_for_parallel;
- }
- else if (r->type == IdealSource)
- {
- r->port_resistance_up = tWDF_getPortResistance(child);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_reflected_wave_down = &get_reflected_wave_for_ideal;
- r->get_port_resistance = &get_port_resistance_for_root;
- }
- else if (r->type == Diode)
- {
- r->port_resistance_up = tWDF_getPortResistance(child);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_reflected_wave_down = &get_reflected_wave_for_diode;
- r->get_port_resistance = &get_port_resistance_for_root;
- }
- else if (r->type == DiodePair)
- {
- r->port_resistance_up = tWDF_getPortResistance(child);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- r->get_reflected_wave_down = &get_reflected_wave_for_diode_pair;
- r->get_port_resistance = &get_port_resistance_for_root;
- }
-}
-
-void tWDF_free(tWDF* const r)
-{
-
-}
-
-float tWDF_tick(tWDF* const r, float sample, tWDF* const outputPoint, uint8_t paramsChanged)
-{
- tWDF* child;
- if (r->child_left != NULL) child = r->child_left;
- else child = r->child_right;
-
- //step 0 : update port resistances if something changed
- if (paramsChanged) tWDF_getPortResistance(r);
-
- //step 1 : set inputs to what they should be
- float input = sample;
-
- //step 2 : scan the waves up the tree
- r->incident_wave_up = tWDF_getReflectedWaveUp(child, input);
-
- //step 3 : do root scattering computation
- r->reflected_wave_up = tWDF_getReflectedWaveDown(r, input, r->incident_wave_up);
-
- //step 4 : propogate waves down the tree
- tWDF_setIncidentWave(child, r->reflected_wave_up, input);
-
- //step 5 : grab whatever voltages or currents we want as outputs
- return tWDF_getVoltage(outputPoint);
-}
-
-void tWDF_setValue(tWDF* const r, float value)
-{
- r->value = value;
-}
-
-void tWDF_setSampleRate(tWDF* const r, float sample_rate)
-{
- r->sample_rate = sample_rate;
-}
-
-uint8_t tWDF_isLeaf(tWDF* const r)
-{
- if (r->child_left == NULL && r->child_right == NULL) return 1;
- return 0;
-}
-
-float tWDF_getPortResistance(tWDF* const r)
-{
- return r->get_port_resistance(r);
-}
-
-void tWDF_setIncidentWave(tWDF* const r, float incident_wave, float input)
-{
- r->set_incident_wave(r, incident_wave, input);
-}
-
-float tWDF_getReflectedWaveUp(tWDF* const r, float input)
-{
- return r->get_reflected_wave_up(r, input);
-}
-
-float tWDF_getReflectedWaveDown(tWDF* const r, float input, float incident_wave)
-{
- return r->get_reflected_wave_down(r, input, incident_wave);
-}
-
-float tWDF_getVoltage(tWDF* const r)
-{
- return ((r->incident_wave_up * 0.5f) + (r->reflected_wave_up * 0.5f));
-}
-
-float tWDF_getCurrent(tWDF* const r)
-{
- return (((r->incident_wave_up * 0.5f) - (r->reflected_wave_up * 0.5f)) * r->port_conductance_up);
-}
-
-//============ Static Functions to be Pointed To ====================
-//===================================================================
-//============ Get and Calculate Port Resistances ===================
-
-static float get_port_resistance_for_resistor(tWDF* const r)
-{
- r->port_resistance_up = r->value;
- r->port_conductance_up = 1.0f / r->value;
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_capacitor(tWDF* const r)
-{
- r->port_conductance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
- r->port_resistance_up = (1.0f / r->port_conductance_up);
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_inductor(tWDF* const r)
-{
- r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
- r->port_conductance_up = (1.0f / r->port_resistance_up);
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_resistive(tWDF* const r)
-{
- r->port_resistance_up = r->value;
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_inverter(tWDF* const r)
-{
- r->port_resistance_up = tWDF_getPortResistance(r->child_left);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_series(tWDF* const r)
-{
- r->port_resistance_left = tWDF_getPortResistance(r->child_left);
- r->port_resistance_right = tWDF_getPortResistance(r->child_right);
- r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
- r->port_conductance_up = 1.0f / r->port_resistance_up;
- r->port_conductance_left = 1.0f / r->port_resistance_left;
- r->port_conductance_right = 1.0f / r->port_resistance_right;
- r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_parallel(tWDF* const r)
-{
- r->port_resistance_left = tWDF_getPortResistance(r->child_left);
- r->port_resistance_right = tWDF_getPortResistance(r->child_right);
- r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
- r->port_conductance_left = 1.0f / r->port_resistance_left;
- r->port_conductance_right = 1.0f / r->port_resistance_right;
- r->gamma_zero = 1.0f / (r->port_conductance_right + r->port_conductance_left);
-
- return r->port_resistance_up;
-}
-
-static float get_port_resistance_for_root(tWDF* const r)
-{
- tWDF* child;
- if (r->child_left != NULL) child = r->child_left;
- else child = r->child_right;
-
- r->port_resistance_up = tWDF_getPortResistance(child);
- r->port_conductance_up = 1.0f / r->port_resistance_up;
-
- return r->port_resistance_up;
-}
-
-//===================================================================
-//================ Set Incident Waves ===============================
-
-static void set_incident_wave_for_leaf(tWDF* const r, float incident_wave, float input)
-{
- r->incident_wave_up = incident_wave;
-}
-
-static void set_incident_wave_for_leaf_inverted(tWDF* const r, float incident_wave, float input)
-{
- r->incident_wave_up = -1.0f * incident_wave;
-}
-
-static void set_incident_wave_for_inverter(tWDF* const r, float incident_wave, float input)
-{
- r->incident_wave_up = incident_wave;
- tWDF_setIncidentWave(r->child_left, -1.0f * incident_wave, input);
-}
-
-static void set_incident_wave_for_series(tWDF* const r, float incident_wave, float input)
-{
- r->incident_wave_up = incident_wave;
- float gamma_left = r->port_resistance_left * r->gamma_zero;
- float gamma_right = r->port_resistance_right * r->gamma_zero;
- float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
- float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
-// downPorts[0]->b = yl * ( downPorts[0]->a * ((1.0 / yl) - 1) - downPorts[1]->a - descendingWave );
-// downPorts[1]->b = yr * ( downPorts[1]->a * ((1.0 / yr) - 1) - downPorts[0]->a - descendingWave );
- tWDF_setIncidentWave(r->child_left, (-1.0f * gamma_left * incident_wave) + (gamma_right * left_wave) - (gamma_left * right_wave), input);
- tWDF_setIncidentWave(r->child_right, (-1.0f * gamma_right * incident_wave) + (gamma_left * right_wave) - (gamma_right * left_wave), input);
- // From rt-wdf
-// tWDF_setIncidentWave(r->child_left, gamma_left * (left_wave * ((1.0f / gamma_left) - 1.0f) - right_wave - incident_wave));
-// tWDF_setIncidentWave(r->child_right, gamma_right * (right_wave * ((1.0f / gamma_right) - 1.0f) - left_wave - incident_wave));
-
-}
-
-static void set_incident_wave_for_parallel(tWDF* const r, float incident_wave, float input)
-{
- r->incident_wave_up = incident_wave;
- float gamma_left = r->port_conductance_left * r->gamma_zero;
- float gamma_right = r->port_conductance_right * r->gamma_zero;
- float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
- float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
-// downPorts[0]->b = ( ( dl - 1 ) * downPorts[0]->a + dr * downPorts[1]->a + du * descendingWave );
-// downPorts[1]->b = ( dl * downPorts[0]->a + ( dr - 1 ) * downPorts[1]->a + du * descendingWave );
- tWDF_setIncidentWave(r->child_left, (gamma_left - 1.0f) * left_wave + gamma_right * right_wave + incident_wave, input);
- tWDF_setIncidentWave(r->child_right, gamma_left * left_wave + (gamma_right - 1.0f) * right_wave + incident_wave, input);
-}
-
-//===================================================================
-//================ Get Reflected Waves ==============================
-
-static float get_reflected_wave_for_resistor(tWDF* const r, float input)
-{
- r->reflected_wave_up = 0.0f;
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_capacitor(tWDF* const r, float input)
-{
- r->reflected_wave_up = r->incident_wave_up;
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_resistive(tWDF* const r, float input)
-{
- r->reflected_wave_up = input;
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_inverter(tWDF* const r, float input)
-{
- r->reflected_wave_up = -1.0f * tWDF_getReflectedWaveUp(r->child_left, input);
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_series(tWDF* const r, float input)
-{
- //-( downPorts[0]->a + downPorts[1]->a );
- r->reflected_wave_up = (-1.0f * (tWDF_getReflectedWaveUp(r->child_left, input) + tWDF_getReflectedWaveUp(r->child_right, input)));
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_parallel(tWDF* const r, float input)
-{
- float gamma_left = r->port_conductance_left * r->gamma_zero;
- float gamma_right = r->port_conductance_right * r->gamma_zero;
- //return ( dl * downPorts[0]->a + dr * downPorts[1]->a );
- r->reflected_wave_up = (gamma_left * tWDF_getReflectedWaveUp(r->child_left, input) + gamma_right * tWDF_getReflectedWaveUp(r->child_right, input));
- return r->reflected_wave_up;
-}
-
-static float get_reflected_wave_for_ideal(tWDF* const n, float input, float incident_wave)
-{
- return (2.0f * input) - incident_wave;
-}
-
-#define l2A 0.1640425613334452f
-#define l2B -1.098865286222744f
-#define l2Y 3.148297929334117f
-#define l2K -2.213475204444817f
-static float log2Approximation(float x)
-{
- return (l2A * x*x*x) + (l2B * x*x) + (l2Y * x) + l2K;
-}
-
-#define wX1 -3.684303659906469f
-#define wX2 1.972967391708859f
-#define wA 9.451797158780131e-3f
-#define wB 0.1126446405111627f
-#define wY 0.4451353886588814f
-#define wK 0.5836596684310648f
-static float wrightOmega3(float x)
-{
- if (x <= wX1)
- {
- return 0;
- }
- else if (x < wX2)
- {
- return (wA * x*x*x) + (wB * x*x) + (wY * x) + wK;
- }
- else
- {
- return x - logf(x);
- }
-}
-
-static float wrightOmegaApproximation(float x)
-{
- float w3 = wrightOmega3(x);
- return w3 - ((w3 - expf(x - w3)) / (w3 + 1.0f));
-}
-
-static float lambertW(float a, float r, float I, float iVT)
-{
- return wrightOmegaApproximation(((a + r*I) * iVT) + log((r * I) * iVT));
-}
-
-#define Is_DIODE 2.52e-9f
-#define VT_DIODE 0.02585f
-static float get_reflected_wave_for_diode(tWDF* const n, float input, float incident_wave)
-{
- float a = incident_wave;
- float r = n->port_resistance_up;
- return a + 2.0f*r*Is_DIODE - 2.0f*VT_DIODE*lambertW(a, r, Is_DIODE, 1.0f/VT_DIODE);
-}
-
-static float get_reflected_wave_for_diode_pair(tWDF* const n, float input, float incident_wave)
-{
- float a = incident_wave;
- float sgn = 0.0f;
- if (a > 0.0f) sgn = 1.0f;
- else if (a < 0.0f) sgn = -1.0f;
- float r = n->port_resistance_up;
- return a + 2 * sgn * (r*Is_DIODE - VT_DIODE*lambertW(sgn*a, r, Is_DIODE, 1.0f/VT_DIODE));
-}
--- /dev/null
+++ b/LEAF/Src/leaf-analysis.c
@@ -1,0 +1,733 @@
+/*==============================================================================
+
+ leaf-analysis.c
+ Created: 30 Nov 2018 11:56:49am
+ Author: airship
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-analysis.h"
+#include "..\Externals\d_fft_mayer.h"
+
+#else
+
+#include "../Inc/leaf-analysis.h"
+#include "../Externals/d_fft_mayer.h"
+
+#endif
+
+//===========================================================================
+/* Envelope Follower */
+//===========================================================================
+
+void tEnvelopeFollower_init(tEnvelopeFollower* const e, float attackThreshold, float decayCoeff)
+{
+ e->y = 0.0f;
+ e->a_thresh = attackThreshold;
+ e->d_coeff = decayCoeff;
+}
+
+void tEnvelopeFollower_free(tEnvelopeFollower* const e)
+{
+
+}
+
+float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x)
+{
+ if (x < 0.0f ) x = -x; /* Absolute value. */
+
+ if ((x >= ef->y) && (x > ef->a_thresh)) ef->y = x; /* If we hit a peak, ride the peak to the top. */
+ else ef->y = ef->y * ef->d_coeff; /* Else, exponential decay of output. */
+
+ //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision?
+ //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive
+
+ if( ef->y < VSF) ef->y = 0.0f;
+
+ return ef->y;
+}
+
+int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff)
+{
+ return ef->d_coeff = decayCoeff;
+}
+
+int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh)
+{
+ return ef->a_thresh = attackThresh;
+}
+
+
+
+
+
+//===========================================================================
+/* Power Follower */
+//===========================================================================
+void tPowerFollower_init(tPowerFollower* const p, float factor)
+{
+ p->curr=0.0f;
+ p->factor=factor;
+ p->oneminusfactor=1.0f-factor;
+}
+
+void tPowerFollower_free(tPowerFollower* const p)
+{
+
+}
+
+int tPowerFollower_setFactor(tPowerFollower* 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 tPowerFollower_tick(tPowerFollower* const p, float input)
+{
+ p->curr = p->factor*input*input+p->oneminusfactor*p->curr;
+ return p->curr;
+}
+
+float tPowerFollower_sample(tPowerFollower* const p)
+{
+ return p->curr;
+}
+
+
+
+
+//===========================================================================
+/* ---------------- env~ - simple envelope follower. ----------------- */
+//===========================================================================
+
+void tEnvPD_init(tEnvPD* const x, int ws, int hs, int bs)
+{
+ int period = hs, npoints = ws;
+
+ int i;
+
+ if (npoints < 1) npoints = 1024;
+ if (period < 1) period = npoints/2;
+ if (period < npoints / MAXOVERLAP + 1)
+ period = npoints / MAXOVERLAP + 1;
+
+ x->x_npoints = npoints;
+ x->x_phase = 0;
+ x->x_period = period;
+
+ x->windowSize = npoints;
+ x->hopSize = period;
+ x->blockSize = bs;
+
+ for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
+ for (i = 0; i < npoints; i++)
+ x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints;
+ for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0;
+
+ x->x_f = 0;
+
+ x->x_allocforvs = INITVSTAKEN;
+
+ // ~ ~ ~ dsp ~ ~ ~
+ if (x->x_period % x->blockSize)
+ {
+ x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize);
+ }
+ else
+ {
+ x->x_realperiod = x->x_period;
+ }
+ // ~ ~ ~ ~ ~ ~ ~ ~
+}
+
+void tEnvPD_free (tEnvPD* const x)
+{
+
+}
+
+float tEnvPD_tick (tEnvPD* const x)
+{
+ return powtodb(x->x_result);
+}
+
+void tEnvPD_processBlock(tEnvPD* const x, float* in)
+{
+ int n = x->blockSize;
+
+ int count;
+ t_sample *sump;
+ in += n;
+ for (count = x->x_phase, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ {
+ t_sample *hp = x->buf + count;
+ t_sample *fp = in;
+ t_sample sum = *sump;
+ int i;
+
+ for (i = 0; i < n; i++)
+ {
+ fp--;
+ sum += *hp++ * (*fp * *fp);
+ }
+ *sump = sum;
+ }
+ sump[0] = 0;
+ x->x_phase -= n;
+ if (x->x_phase < 0)
+ {
+ x->x_result = x->x_sumbuf[0];
+ for (count = x->x_realperiod, sump = x->x_sumbuf;
+ count < x->x_npoints; count += x->x_realperiod, sump++)
+ sump[0] = sump[1];
+ sump[0] = 0;
+ x->x_phase = x->x_realperiod - n;
+ }
+}
+
+//===========================================================================
+// ATTACKDETECTION
+//===========================================================================
+/********Private function prototypes**********/
+static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel);
+static void atkdtk_envelope(tAttackDetection* const a, float *in);
+
+/********Constructor/Destructor***************/
+
+void tAttackDetection_init(tAttackDetection* const a, int blocksize)
+{
+ atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE);
+}
+
+void tAttackDetection_init_expanded(tAttackDetection* const a, int blocksize, int atk, int rel)
+{
+ atkdtk_init(a, blocksize, atk, rel);
+}
+
+void tAttackDetection_free(tAttackDetection *a)
+{
+
+}
+
+/*******Public Functions***********/
+
+
+void tAttackDetection_setBlocksize(tAttackDetection* const a, int size)
+{
+
+ if(!((size==64)|(size==128)|(size==256)|(size==512)|(size==1024)|(size==2048)))
+ size = DEFBLOCKSIZE;
+ a->blocksize = size;
+
+ return;
+
+}
+
+void tAttackDetection_setSamplerate(tAttackDetection* const a, int inRate)
+{
+ a->samplerate = inRate;
+
+ //Reset atk and rel to recalculate coeff
+ tAttackDetection_setAtk(a, a->atk);
+ tAttackDetection_setRel(a, a->rel);
+
+ return;
+}
+
+void tAttackDetection_setThreshold(tAttackDetection* const a, float thres)
+{
+ a->threshold = thres;
+ return;
+}
+
+void tAttackDetection_setAtk(tAttackDetection* const a, int inAtk)
+{
+ a->atk = inAtk;
+ a->atk_coeff = pow(0.01, 1.0/(a->atk * a->samplerate * 0.001));
+
+ return;
+}
+
+void tAttackDetection_setRel(tAttackDetection* const a, int inRel)
+{
+ a->rel = inRel;
+ a->rel_coeff = pow(0.01, 1.0/(a->rel * a->samplerate * 0.001));
+
+ return;
+}
+
+
+int tAttackDetection_detect(tAttackDetection* const a, float *in)
+{
+ int result;
+
+ atkdtk_envelope(a, in);
+
+ if(a->env >= a->prevAmp*2) //2 times greater = 6dB increase
+ result = 1;
+ else
+ result = 0;
+
+ a->prevAmp = a->env;
+
+ return result;
+
+}
+
+/*******Private Functions**********/
+
+static void atkdtk_init(tAttackDetection* const a, int blocksize, int atk, int rel)
+{
+ a->env = 0;
+ a->blocksize = blocksize;
+ a->threshold = DEFTHRESHOLD;
+ a->samplerate = leaf.sampleRate;
+ a->prevAmp = 0;
+
+ a->env = 0;
+
+ tAttackDetection_setAtk(a, atk);
+ tAttackDetection_setRel(a, rel);
+}
+
+static void atkdtk_envelope(tAttackDetection* const a, float *in)
+{
+ int i = 0;
+ float tmp;
+ for(i = 0; i < a->blocksize; ++i){
+ tmp = fastabs(in[i]);
+
+ if(tmp > a->env)
+ a->env = a->atk_coeff * (a->env - tmp) + tmp;
+ else
+ a->env = a->rel_coeff * (a->env - tmp) + tmp;
+ }
+
+}
+
+//===========================================================================
+// PERIODDETECTION
+//===========================================================================
+void tPeriodDetection_init (tPeriodDetection* const p, float* in, float* out, int bufSize, int frameSize)
+{
+ p->inBuffer = in;
+ p->outBuffer = out;
+ p->bufSize = bufSize;
+ p->frameSize = frameSize;
+ p->framesPerBuffer = p->bufSize / p->frameSize;
+ p->curBlock = 1;
+ p->lastBlock = 0;
+ p->index = 0;
+
+ p->hopSize = DEFHOPSIZE;
+ p->windowSize = DEFWINDOWSIZE;
+ p->fba = FBA;
+
+ tEnvPD_init(&p->env, p->windowSize, p->hopSize, p->frameSize);
+
+ tSNAC_init(&p->snac, DEFOVERLAP);
+
+ p->timeConstant = DEFTIMECONSTANT;
+ p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant);
+}
+
+void tPeriodDetection_free (tPeriodDetection* const p)
+{
+ tEnvPD_free(&p->env);
+ tSNAC_free(&p->snac);
+}
+
+float tPeriodDetection_findPeriod (tPeriodDetection* p, float sample)
+{
+ int i, iLast;
+
+ i = (p->curBlock*p->frameSize);
+ iLast = (p->lastBlock*p->frameSize)+p->index;
+
+ p->i = i;
+ p->iLast = iLast;
+
+ p->inBuffer[i+p->index] = sample;
+
+ p->index++;
+ p->indexstore = p->index;
+ if (p->index >= p->frameSize)
+ {
+ p->index = 0;
+
+ tEnvPD_processBlock(&p->env, &(p->inBuffer[i]));
+
+ tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize);
+ p->period = tSNAC_getPeriod(&p->snac);
+
+ p->curBlock++;
+ if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0;
+ p->lastBlock++;
+ if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0;
+ }
+
+ // changed from period to p->period
+ return p->period;
+}
+
+void tPeriodDetection_setHopSize(tPeriodDetection* p, int hs)
+{
+ p->hopSize = hs;
+}
+
+void tPeriodDetection_setWindowSize(tPeriodDetection* p, int ws)
+{
+ p->windowSize = ws;
+}
+
+
+
+
+
+
+
+
+
+//===========================================================================
+// SNAC
+//===========================================================================
+/******************************************************************************/
+/***************************** private procedures *****************************/
+/******************************************************************************/
+
+#define REALFFT mayer_realfft
+#define REALIFFT mayer_realifft
+
+static void snac_analyzeframe(tSNAC* const s);
+static void snac_autocorrelation(tSNAC* const s);
+static void snac_normalize(tSNAC* const s);
+static void snac_pickpeak(tSNAC* const s);
+static void snac_periodandfidelity(tSNAC* const s);
+static void snac_biasbuf(tSNAC* const s);
+static float snac_spectralpeak(tSNAC* const s, float periodlength);
+
+
+/******************************************************************************/
+/******************************** constructor, destructor *********************/
+/******************************************************************************/
+
+
+void tSNAC_init(tSNAC* const s, int overlaparg)
+{
+ s->biasfactor = DEFBIAS;
+ s->timeindex = 0;
+ s->periodindex = 0;
+ s->periodlength = 0.;
+ s->fidelity = 0.;
+ s->minrms = DEFMINRMS;
+ s->framesize = SNAC_FRAME_SIZE;
+
+ s->inputbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE);
+ s->processbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE * 2));
+ s->spectrumbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE / 2));
+ s->biasbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE);
+
+ snac_biasbuf(s);
+ tSNAC_setOverlap(s, overlaparg);
+}
+
+void tSNAC_free(tSNAC* const s)
+{
+ leaf_free(s->inputbuf);
+ leaf_free(s->processbuf);
+ leaf_free(s->spectrumbuf);
+ leaf_free(s->biasbuf);
+}
+/******************************************************************************/
+/************************** public access functions****************************/
+/******************************************************************************/
+
+
+void tSNAC_ioSamples(tSNAC* const s, float *in, float *out, int size)
+{
+ int timeindex = s->timeindex;
+ int mask = s->framesize - 1;
+ int outindex = 0;
+ float *inputbuf = s->inputbuf;
+ float *processbuf = s->processbuf;
+
+ // call analysis function when it is time
+ if(!(timeindex & (s->framesize / s->overlap - 1))) snac_analyzeframe(s);
+
+ while(size--)
+ {
+ inputbuf[timeindex] = *in++;
+ out[outindex++] = processbuf[timeindex++];
+ timeindex &= mask;
+ }
+ s->timeindex = timeindex;
+}
+
+void tSNAC_setOverlap(tSNAC* const s, int lap)
+{
+ if(!((lap==1)|(lap==2)|(lap==4)|(lap==8))) lap = DEFOVERLAP;
+ s->overlap = lap;
+}
+
+
+void tSNAC_setBias(tSNAC* const s, float bias)
+{
+ if(bias > 1.) bias = 1.;
+ if(bias < 0.) bias = 0.;
+ s->biasfactor = bias;
+ snac_biasbuf(s);
+ return;
+}
+
+
+void tSNAC_setMinRMS(tSNAC* const s, float rms)
+{
+ if(rms > 1.) rms = 1.;
+ if(rms < 0.) rms = 0.;
+ s->minrms = rms;
+ return;
+}
+
+
+float tSNAC_getPeriod(tSNAC* const s)
+{
+ return(s->periodlength);
+}
+
+
+float tSNAC_getFidelity(tSNAC* const s)
+{
+ return(s->fidelity);
+}
+
+
+/******************************************************************************/
+/***************************** private procedures *****************************/
+/******************************************************************************/
+
+
+// main analysis function
+static void snac_analyzeframe(tSNAC* const s)
+{
+ int n, tindex = s->timeindex;
+ int framesize = s->framesize;
+ int mask = framesize - 1;
+ float norm = 1. / sqrt((float)(framesize * 2));
+
+ float *inputbuf = s->inputbuf;
+ float *processbuf = s->processbuf;
+
+ // copy input to processing buffers
+ for(n=0; n<framesize; n++)
+ {
+ processbuf[n] = inputbuf[tindex] * norm;
+ tindex++;
+ tindex &= mask;
+ }
+
+ // zeropadding
+ for(n=framesize; n<(framesize<<1); n++) processbuf[n] = 0.;
+
+ // call analysis procedures
+ snac_autocorrelation(s);
+ snac_normalize(s);
+ snac_pickpeak(s);
+ snac_periodandfidelity(s);
+}
+
+
+static void snac_autocorrelation(tSNAC* const s)
+{
+ int n, m;
+ int framesize = s->framesize;
+ int fftsize = framesize * 2;
+ float *processbuf = s->processbuf;
+ float *spectrumbuf = s->spectrumbuf;
+
+ REALFFT(fftsize, processbuf);
+
+ // compute power spectrum
+ processbuf[0] *= processbuf[0]; // DC
+ processbuf[framesize] *= processbuf[framesize]; // Nyquist
+
+ for(n=1; n<framesize; n++)
+ {
+ processbuf[n] = processbuf[n] * processbuf[n]
+ + processbuf[fftsize-n] * processbuf[fftsize-n]; // imag coefficients appear reversed
+ processbuf[fftsize-n] = 0.;
+ }
+
+ // store power spectrum up to SR/4 for possible later use
+ for(m=0; m<(framesize>>1); m++)
+ {
+ spectrumbuf[m] = processbuf[m];
+ }
+
+ // transform power spectrum to autocorrelation function
+ REALIFFT(fftsize, processbuf);
+ return;
+}
+
+
+static void snac_normalize(tSNAC* const s)
+{
+ int framesize = s->framesize;
+ int framesizeplustimeindex = s->framesize + s->timeindex;
+ int timeindexminusone = s->timeindex - 1;
+ int n, m;
+ int mask = framesize - 1;
+ int seek = framesize * SEEK;
+ float *inputbuf = s->inputbuf;
+ float *processbuf= s->processbuf;
+ float signal1, signal2;
+
+ // minimum RMS implemented as minimum autocorrelation at index 0
+ // functionally equivalent to white noise floor
+ float rms = s->minrms / sqrt(1.0f / (float)framesize);
+ float minrzero = rms * rms;
+ float rzero = processbuf[0];
+ if(rzero < minrzero) rzero = minrzero;
+ double normintegral = (double)rzero * 2.;
+
+ // normalize biased autocorrelation function
+ // inputbuf is circular buffer: timeindex may be non-zero when overlap > 1
+ processbuf[0] = 1;
+ for(n=1, m=s->timeindex+1; n<seek; n++, m++)
+ {
+ signal1 = inputbuf[(n + timeindexminusone)&mask];
+ signal2 = inputbuf[(framesizeplustimeindex - n)&mask];
+ normintegral -= (double)(signal1 * signal1 + signal2 * signal2);
+ processbuf[n] /= (float)normintegral * 0.5f;
+ }
+
+ // flush instable function tail
+ for(n = seek; n<framesize; n++) processbuf[n] = 0.;
+ return;
+}
+
+
+static void snac_periodandfidelity(tSNAC* const s)
+{
+ float periodlength;
+
+ if(s->periodindex)
+ {
+ periodlength = (float)s->periodindex +
+ interpolate3phase(s->processbuf, s->periodindex);
+ if(periodlength < 8) periodlength = snac_spectralpeak(s, periodlength);
+ s->periodlength = periodlength;
+ s->fidelity = interpolate3max(s->processbuf, s->periodindex);
+ }
+ return;
+}
+
+// select the peak which most probably represents period length
+static void snac_pickpeak(tSNAC* const s)
+{
+ int n, peakindex=0;
+ int seek = s->framesize * SEEK;
+ float *processbuf= s->processbuf;
+ float maxvalue = 0.;
+ float biasedpeak;
+ float *biasbuf = s->biasbuf;
+
+ // skip main lobe
+ for(n=1; n<seek; n++)
+ {
+ if(processbuf[n] < 0.) break;
+ }
+
+ // find interpolated / biased maximum in SNAC function
+ // interpolation finds the 'real maximum'
+ // biasing favours the first candidate
+ for(; n<seek-1; n++)
+ {
+ if(processbuf[n] >= processbuf[n-1])
+ {
+ if(processbuf[n] > processbuf[n+1]) // we have a local peak
+ {
+ biasedpeak = interpolate3max(processbuf, n) * biasbuf[n];
+
+ if(biasedpeak > maxvalue)
+ {
+ maxvalue = biasedpeak;
+ peakindex = n;
+ }
+ }
+ }
+ }
+ s->periodindex = peakindex;
+ return;
+}
+
+
+// verify period length via frequency domain (up till SR/4)
+// frequency domain is more precise than lag domain for period lengths < 8
+// argument 'periodlength' is initial estimation from autocorrelation
+static float snac_spectralpeak(tSNAC* const s, float periodlength)
+{
+ if(periodlength < 4.) return periodlength;
+
+ float max = 0.;
+ int n, startbin, stopbin, peakbin = 0;
+ int spectrumsize = s->framesize>>1;
+ float *spectrumbuf = s->spectrumbuf;
+ float peaklocation = (float)(s->framesize * 2.) / periodlength;
+
+ startbin = (int)(peaklocation * 0.8 + 0.5);
+ if(startbin < 1) startbin = 1;
+ stopbin = (int)(peaklocation * 1.25 + 0.5);
+ if(stopbin >= spectrumsize - 1) stopbin = spectrumsize - 1;
+
+ for(n=startbin; n<stopbin; n++)
+ {
+ if(spectrumbuf[n] >= spectrumbuf[n-1])
+ {
+ if(spectrumbuf[n] > spectrumbuf[n+1])
+ {
+ if(spectrumbuf[n] > max)
+ {
+ max = spectrumbuf[n];
+ peakbin = n;
+ }
+ }
+ }
+ }
+
+ // calculate amplitudes in peak region
+ for(n=(peakbin-1); n<(peakbin+2); n++)
+ {
+ spectrumbuf[n] = sqrt(spectrumbuf[n]);
+ }
+
+ peaklocation = (float)peakbin + interpolate3phase(spectrumbuf, peakbin);
+ periodlength = (float)(s->framesize * 2.0f) / peaklocation;
+
+ return periodlength;
+}
+
+
+// modified logarithmic bias function
+static void snac_biasbuf(tSNAC* const s)
+{
+ int n;
+ int maxperiod = (int)(s->framesize * (float)SEEK);
+ float bias = s->biasfactor / log((float)(maxperiod - 4));
+ float *biasbuf = s->biasbuf;
+
+ for(n=0; n<5; n++) // periods < 5 samples can't be tracked
+ {
+ biasbuf[n] = 0.;
+ }
+
+ for(n=5; n<maxperiod; n++)
+ {
+ biasbuf[n] = 1.0f - (float)log(n - 4) * bias;
+ }
+}
+
--- a/LEAF/Src/leaf-crusher.c
+++ /dev/null
@@ -1,84 +1,0 @@
-/*==============================================================================
-
- leaf-crusher.c
- Created: 30 Nov 2018 11:56:49am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-crusher.h"
-
-#else
-
-#include "../Inc/leaf-crusher.h"
-
-#endif
-
-//==============================================================================
-
-#define SCALAR 5000.f
-
-void tCrusher_init (tCrusher* const c)
-{
- c->op = 4;
- c->div = SCALAR;
- c->rnd = 0.25f;
- c->srr = 0.25f;
-
- c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
-}
-
-void tCrusher_free (tCrusher* const c)
-{
-
-}
-
-float tCrusher_tick (tCrusher* const c, float input)
-{
- float sample = input;
-
- sample *= SCALAR; // SCALAR is 5000 by default
-
- sample = (int32_t) sample;
-
- sample /= c->div;
-
- sample = LEAF_bitwise_xor(sample, c->op << 23);
-
- sample = LEAF_clip(-1.f, sample, 1.f);
-
- sample = LEAF_round(sample, c->rnd);
-
- sample = LEAF_reduct(sample, c->srr);
-
- return sample * c->gain;
-
-}
-
-void tCrusher_setOperation (tCrusher* const c, float op)
-{
- c->op = (uint32_t) (op * 8.0f);
-}
-
-// 0.0 - 1.0
-void tCrusher_setQuality (tCrusher* const c, float val)
-{
- val = LEAF_clip(0.0f, val, 1.0f);
-
- c->div = 0.01f + val * SCALAR;
-
- c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
-}
-
-// what decimal to round to
-void tCrusher_setRound (tCrusher* const c, float rnd)
-{
- c->rnd = fabsf(rnd);
-}
-
-void tCrusher_setSamplingRatio (tCrusher* const c, float ratio)
-{
- c->srr = ratio;
-}
--- a/LEAF/Src/leaf-delay.c
+++ b/LEAF/Src/leaf-delay.c
@@ -127,8 +127,8 @@
return d->gain;
}
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayL ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tDelayL_init (tDelayL* const d, float delay, uint32_t maxDelay)
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ LinearDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tLinearDelay_init (tLinearDelay* const d, float delay, uint32_t maxDelay)
{
d->maxDelay = maxDelay;
@@ -146,15 +146,15 @@
d->inPoint = 0;
d->outPoint = 0;
- tDelayL_setDelay(d, d->delay);
+ tLinearDelay_setDelay(d, d->delay);
}
-void tDelayL_free(tDelayL* const d)
+void tLinearDelay_free(tLinearDelay* const d)
{
leaf_free(d->buff);
}
-float tDelayL_tick (tDelayL* const d, float input)
+float tLinearDelay_tick (tLinearDelay* const d, float input)
{
d->buff[d->inPoint] = input * d->gain;
@@ -176,7 +176,7 @@
return d->lastOut;
}
-void tDelayL_tickIn (tDelayL* const d, float input)
+void tLinearDelay_tickIn (tLinearDelay* const d, float input)
{
d->buff[d->inPoint] = input * d->gain;
@@ -184,7 +184,7 @@
if (++(d->inPoint) == d->maxDelay ) d->inPoint = 0;
}
-float tDelayL_tickOut (tDelayL* const d)
+float tLinearDelay_tickOut (tLinearDelay* const d)
{
uint32_t idx = (uint32_t) d->outPoint;
@@ -200,7 +200,7 @@
return d->lastOut;
}
-int tDelayL_setDelay (tDelayL* const d, float delay)
+int tLinearDelay_setDelay (tLinearDelay* const d, float delay)
{
d->delay = LEAF_clip(0.0f, delay, d->maxDelay);
@@ -219,7 +219,7 @@
return 0;
}
-float tDelayL_tapOut (tDelayL* const d, float tapDelay)
+float tLinearDelay_tapOut (tLinearDelay* const d, float tapDelay)
{
float tap = (float) d->inPoint - tapDelay - 1.f;
@@ -244,7 +244,7 @@
}
-void tDelayL_tapIn (tDelayL* const d, float value, uint32_t tapDelay)
+void tLinearDelay_tapIn (tLinearDelay* const d, float value, uint32_t tapDelay)
{
int32_t tap = d->inPoint - tapDelay - 1;
@@ -254,7 +254,7 @@
d->buff[tap] = value;
}
-float tDelayL_addTo (tDelayL* const d, float value, uint32_t tapDelay)
+float tLinearDelay_addTo (tLinearDelay* const d, float value, uint32_t tapDelay)
{
int32_t tap = d->inPoint - tapDelay - 1;
@@ -264,34 +264,34 @@
return (d->buff[tap] += value);
}
-float tDelayL_getDelay (tDelayL *d)
+float tLinearDelay_getDelay (tLinearDelay *d)
{
return d->delay;
}
-float tDelayL_getLastOut (tDelayL* const d)
+float tLinearDelay_getLastOut (tLinearDelay* const d)
{
return d->lastOut;
}
-float tDelayL_getLastIn (tDelayL* const d)
+float tLinearDelay_getLastIn (tLinearDelay* const d)
{
return d->lastIn;
}
-void tDelayL_setGain (tDelayL* const d, float gain)
+void tLinearDelay_setGain (tLinearDelay* const d, float gain)
{
if (gain < 0.0f) d->gain = 0.0f;
else d->gain = gain;
}
-float tDelayL_getGain (tDelayL* const d)
+float tLinearDelay_getGain (tLinearDelay* const d)
{
return d->gain;
}
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ DelayA ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tDelayA_init (tDelayA* const d, float delay, uint32_t maxDelay)
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ AllpassDelay ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tAllpassDelay_init (tAllpassDelay* const d, float delay, uint32_t maxDelay)
{
d->maxDelay = maxDelay;
@@ -309,17 +309,17 @@
d->inPoint = 0;
d->outPoint = 0;
- tDelayA_setDelay(d, d->delay);
+ tAllpassDelay_setDelay(d, d->delay);
d->apInput = 0.0f;
}
-void tDelayA_free(tDelayA* const d)
+void tAllpassDelay_free(tAllpassDelay* const d)
{
leaf_free(d->buff);
}
-float tDelayA_tick (tDelayA* const d, float input)
+float tAllpassDelay_tick (tAllpassDelay* const d, float input)
{
d->buff[d->inPoint] = input * d->gain;
@@ -340,7 +340,7 @@
return d->lastOut;
}
-int tDelayA_setDelay (tDelayA* const d, float delay)
+int tAllpassDelay_setDelay (tAllpassDelay* const d, float delay)
{
d->delay = LEAF_clip(0.5f, delay, d->maxDelay);
@@ -373,7 +373,7 @@
return 0;
}
-float tDelayA_tapOut (tDelayA* const d, uint32_t tapDelay)
+float tAllpassDelay_tapOut (tAllpassDelay* const d, uint32_t tapDelay)
{
int32_t tap = d->inPoint - tapDelay - 1;
@@ -384,7 +384,7 @@
}
-void tDelayA_tapIn (tDelayA* const d, float value, uint32_t tapDelay)
+void tAllpassDelay_tapIn (tAllpassDelay* const d, float value, uint32_t tapDelay)
{
int32_t tap = d->inPoint - tapDelay - 1;
@@ -394,7 +394,7 @@
d->buff[tap] = value;
}
-float tDelayA_addTo (tDelayA* const d, float value, uint32_t tapDelay)
+float tAllpassDelay_addTo (tAllpassDelay* const d, float value, uint32_t tapDelay)
{
int32_t tap = d->inPoint - tapDelay - 1;
@@ -404,28 +404,28 @@
return (d->buff[tap] += value);
}
-float tDelayA_getDelay (tDelayA* const d)
+float tAllpassDelay_getDelay (tAllpassDelay* const d)
{
return d->delay;
}
-float tDelayA_getLastOut (tDelayA* const d)
+float tAllpassDelay_getLastOut (tAllpassDelay* const d)
{
return d->lastOut;
}
-float tDelayA_getLastIn (tDelayA* const d)
+float tAllpassDelay_getLastIn (tAllpassDelay* const d)
{
return d->lastIn;
}
-void tDelayA_setGain (tDelayA* const d, float gain)
+void tAllpassDelay_setGain (tAllpassDelay* const d, float gain)
{
if (gain < 0.0f) d->gain = 0.0f;
else d->gain = gain;
}
-float tDelayA_getGain (tDelayA* const d)
+float tAllpassDelay_getGain (tAllpassDelay* const d)
{
return d->gain;
}
--- /dev/null
+++ b/LEAF/Src/leaf-distortion.c
@@ -1,0 +1,407 @@
+//
+// 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-distortion.h"
+#include "..\Inc\leaf-tables.h"
+#else
+
+
+#include "../Inc/leaf-distortion.h"
+#include "../Inc/leaf-tables.h"
+
+#endif
+
+//============================================================================================================
+// WAVEFOLDER
+//============================================================================================================
+void tLockhartWavefolder_init(tLockhartWavefolder* const w)
+{
+ w->Ln1 = 0.0;
+ w->Fn1 = 0.0;
+ w->xn1 = 0.0f;
+}
+
+void tLockhardWavefolder_free(tLockhartWavefolder* const w)
+{
+
+}
+
+double tLockhartWavefolderLambert(double x, double ln)
+{
+ double thresh, w, expw, p, r, s, err;
+ // Error threshold
+ thresh = 10e-6;
+ // Initial guess (use previous value)
+ w = ln;
+
+ // Haley's method (Sec. 4.2 of the paper)
+ for(int i=0; i<100; i+=1) {
+
+ expw = exp(w);
+
+ p = w*expw - x;
+ r = (w+1.0)*expw;
+ s = (w+2.0)/(2.0*(w+1.0)); err = (p/(r-(p*s)));
+
+ if (fabs(err)<thresh) {
+ break;
+ }
+ if (isnan(err))
+ {
+ break;
+ }
+
+ w = w - err;
+ }
+ return w;
+}
+
+float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp)
+{
+
+ 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 Ln = tLockhartWavefolderLambert(u,w->Ln1);
+ double Fn = (0.5*VT/b)*(Ln*(Ln + 2.0)) - 0.5*a*samp*samp;
+
+ // Check for ill-conditioning
+ if (fabs(samp-w->xn1)<thresh) {
+
+ // Compute Averaged Wavefolder Output
+ double xn = 0.5*(samp+w->xn1);
+ u = d*exp(l*b*xn);
+ Ln = tLockhartWavefolderLambert(u,w->Ln1);
+ out = (float) (l*VT*Ln - a*xn);
+ if (isnan(out))
+ {
+ ;
+ }
+
+ }
+ else {
+
+ // Apply AA Form
+ out = (float) ((Fn-w->Fn1)/(samp-w->xn1));
+ if (isnan(out))
+ {
+ ;
+ }
+ }
+
+ // Update States
+ w->Ln1 = Ln;
+ w->Fn1 = Fn;
+ w->xn1 = samp;
+
+ return out;
+}
+
+//============================================================================================================
+// CRUSHER
+//============================================================================================================
+#define SCALAR 5000.f
+
+void tCrusher_init (tCrusher* const c)
+{
+ c->op = 4;
+ c->div = SCALAR;
+ c->rnd = 0.25f;
+ c->srr = 0.25f;
+
+ c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
+}
+
+void tCrusher_free (tCrusher* const c)
+{
+
+}
+
+float tCrusher_tick (tCrusher* const c, float input)
+{
+ float sample = input;
+
+ sample *= SCALAR; // SCALAR is 5000 by default
+
+ sample = (int32_t) sample;
+
+ sample /= c->div;
+
+ sample = LEAF_bitwise_xor(sample, c->op << 23);
+
+ sample = LEAF_clip(-1.f, sample, 1.f);
+
+ sample = LEAF_round(sample, c->rnd);
+
+ sample = LEAF_reduct(sample, c->srr);
+
+ return sample * c->gain;
+
+}
+
+void tCrusher_setOperation (tCrusher* const c, float op)
+{
+ c->op = (uint32_t) (op * 8.0f);
+}
+
+// 0.0 - 1.0
+void tCrusher_setQuality (tCrusher* const c, float val)
+{
+ val = LEAF_clip(0.0f, val, 1.0f);
+
+ c->div = 0.01f + val * SCALAR;
+
+ c->gain = (c->div / SCALAR) * 0.7f + 0.3f;
+}
+
+// what decimal to round to
+void tCrusher_setRound (tCrusher* const c, float rnd)
+{
+ c->rnd = fabsf(rnd);
+}
+
+void tCrusher_setSamplingRatio (tCrusher* const c, float ratio)
+{
+ c->srr = ratio;
+}
+
+
+//============================================================================================================
+// Oversampler
+//============================================================================================================
+// Latency is equal to the phase length (numTaps / ratio)
+void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality)
+{
+ uint8_t offset = 0;
+ if (extraQuality) offset = 6;
+ if (ratio == 2 || ratio == 4 ||
+ ratio == 8 || ratio == 16 ||
+ ratio == 32 || ratio == 64) {
+ os->ratio = ratio;
+ int idx = (int)(log2f(os->ratio))-1+offset;
+ os->numTaps = firNumTaps[idx];
+ os->phaseLength = os->numTaps / os->ratio;
+ os->pCoeffs = (float*) firCoeffs[idx];
+ os->upState = leaf_alloc(sizeof(float) * os->phaseLength);
+ os->downState = leaf_alloc(sizeof(float) * os->phaseLength);
+ }
+}
+
+void tOversampler_free(tOversampler* const os)
+{
+ leaf_free(os->upState);
+ leaf_free(os->downState);
+}
+
+float tOversampler_tick(tOversampler* const os, float input, float (*effectTick)(float))
+{
+ float buf[os->ratio];
+
+ tOversampler_upsample(os, input, buf);
+
+ for (int i = 0; i < os->ratio; ++i) {
+ buf[i] = effectTick(buf[i]);
+ }
+
+ return tOversampler_downsample(os, buf);
+}
+
+// From CMSIS DSP Library
+void tOversampler_upsample(tOversampler* const os, float input, float* output)
+{
+ float *pState = os->upState; /* State pointer */
+ const float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
+ float *pStateCur;
+ float *ptr1; /* Temporary pointer for state buffer */
+ const float *ptr2; /* Temporary pointer for coefficient buffer */
+ float sum0; /* Accumulators */
+ uint32_t i, tapCnt; /* Loop counters */
+ uint32_t phaseLen = os->phaseLength; /* Length of each polyphase filter component */
+ uint32_t j;
+
+ /* os->pState buffer contains previous frame (phaseLen - 1) samples */
+ /* pStateCur points to the location where the new input data should be written */
+ pStateCur = os->upState + (phaseLen - 1U);
+
+ /* Copy new input sample into the state buffer */
+ *pStateCur = input;
+
+ /* Address modifier index of coefficient buffer */
+ j = 1U;
+
+ /* Loop over the Interpolation factor. */
+ i = os->ratio;
+
+ while (i > 0U)
+ {
+ /* Set accumulator to zero */
+ sum0 = 0.0f;
+
+ /* Initialize state pointer */
+ ptr1 = pState;
+
+ /* Initialize coefficient pointer */
+ ptr2 = pCoeffs + (os->ratio - j);
+
+ /* Loop over the polyPhase length.
+ Repeat until we've computed numTaps-(4*os->L) coefficients. */
+
+ /* Initialize tapCnt with number of samples */
+ tapCnt = phaseLen;
+
+ while (tapCnt > 0U)
+ {
+ /* Perform the multiply-accumulate */
+ sum0 += *ptr1++ * *ptr2;
+
+ /* Upsampling is done by stuffing L-1 zeros between each sample.
+ * So instead of multiplying zeros with coefficients,
+ * Increment the coefficient pointer by interpolation factor times. */
+ ptr2 += os->ratio;
+
+ /* Decrement loop counter */
+ tapCnt--;
+ }
+
+ /* The result is in the accumulator, store in the destination buffer. */
+ *output++ = sum0 * os->ratio;
+
+ /* Increment the address modifier index of coefficient buffer */
+ j++;
+
+ /* Decrement the loop counter */
+ i--;
+ }
+
+ /* Advance the state pointer by 1
+ * to process the next group of interpolation factor number samples */
+ pState = pState + 1;
+
+ /* Processing is complete.
+ Now copy the last phaseLen - 1 samples to the satrt of the state buffer.
+ This prepares the state buffer for the next function call. */
+
+ /* Points to the start of the state buffer */
+ pStateCur = os->upState;
+
+ /* Initialize tapCnt with number of samples */
+ tapCnt = (phaseLen - 1U);
+
+ /* Copy data */
+ while (tapCnt > 0U)
+ {
+ *pStateCur++ = *pState++;
+
+ /* Decrement loop counter */
+ tapCnt--;
+ }
+}
+
+// From CMSIS DSP Library
+float tOversampler_downsample(tOversampler *const os, float* input)
+{
+ float *pState = os->downState; /* State pointer */
+ const float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
+ float *pStateCur; /* Points to the current sample of the state */
+ float *px0; /* Temporary pointer for state buffer */
+ const float *pb; /* Temporary pointer for coefficient buffer */
+ float x0, c0; /* Temporary variables to hold state and coefficient values */
+ float acc0; /* Accumulator */
+ uint32_t numTaps = os->numTaps; /* Number of filter coefficients in the filter */
+ uint32_t i, tapCnt;
+ float output;
+
+ /* os->pState buffer contains previous frame (numTaps - 1) samples */
+ /* pStateCur points to the location where the new input data should be written */
+ pStateCur = os->downState + (numTaps - 1U);
+
+ /* Copy decimation factor number of new input samples into the state buffer */
+ i = os->ratio;
+
+ do
+ {
+ *pStateCur++ = *input++;
+
+ } while (--i);
+
+ /* Set accumulator to zero */
+ acc0 = 0.0f;
+
+ /* Initialize state pointer */
+ px0 = pState;
+
+ /* Initialize coeff pointer */
+ pb = pCoeffs;
+
+ /* Initialize tapCnt with number of taps */
+ tapCnt = numTaps;
+
+ while (tapCnt > 0U)
+ {
+ /* Read coefficients */
+ c0 = *pb++;
+
+ /* Fetch 1 state variable */
+ x0 = *px0++;
+
+ /* Perform the multiply-accumulate */
+ acc0 += x0 * c0;
+
+ /* Decrement loop counter */
+ tapCnt--;
+ }
+
+ /* Advance the state pointer by the decimation factor
+ * to process the next group of decimation factor number samples */
+ pState = pState + os->ratio;
+
+ /* The result is in the accumulator, store in the destination buffer. */
+ output = acc0;
+
+ /* Processing is complete.
+ Now copy the last numTaps - 1 samples to the satrt of the state buffer.
+ This prepares the state buffer for the next function call. */
+
+ /* Points to the start of the state buffer */
+ pStateCur = os->downState;
+
+ /* Initialize tapCnt with number of taps */
+ tapCnt = (numTaps - 1U);
+
+ /* Copy data */
+ while (tapCnt > 0U)
+ {
+ *pStateCur++ = *pState++;
+
+ /* Decrement loop counter */
+ tapCnt--;
+ }
+
+ return output;
+}
+
+int tOversampler_getLatency(tOversampler* const os)
+{
+ return os->phaseLength;
+}
--- /dev/null
+++ b/LEAF/Src/leaf-dynamics.c
@@ -1,0 +1,172 @@
+/*==============================================================================
+
+ leaf-dynamics.c
+ Created: 30 Nov 2018 11:56:49am
+ Author: airship
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-dynamics.h"
+
+#else
+
+#include "../Inc/leaf-dynamics.h"
+
+#endif
+
+//==============================================================================
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compressor ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+
+/*
+ tCompressor* tCompressorInit(int tauAttack, int tauRelease)
+ {
+ tCompressor* c = &leaf.tCompressorRegistry[leaf.registryIndex[T_COMPRESSOR]++];
+
+ c->tauAttack = tauAttack;
+ c->tauRelease = tauRelease;
+
+ c->x_G[0] = 0.0f, c->x_G[1] = 0.0f,
+ c->y_G[0] = 0.0f, c->y_G[1] = 0.0f,
+ c->x_T[0] = 0.0f, c->x_T[1] = 0.0f,
+ c->y_T[0] = 0.0f, c->y_T[1] = 0.0f;
+
+ c->T = 0.0f; // Threshold
+ c->R = 1.0f; // compression Ratio
+ c->M = 0.0f; // decibel Make-up gain
+ c->W = 0.0f; // decibel Width of knee transition
+
+ return c;
+ }
+ */
+void tCompressor_init(tCompressor* const c)
+{
+ c->tauAttack = 100;
+ c->tauRelease = 100;
+
+ c->isActive = OFALSE;
+
+ c->T = 0.0f; // Threshold
+ c->R = 0.5f; // compression Ratio
+ c->M = 3.0f; // decibel Width of knee transition
+ c->W = 1.0f; // decibel Make-up gain
+}
+
+void tCompressor_free(tCompressor* const c)
+{
+
+}
+
+int ccount = 0;
+float tCompressor_tick(tCompressor* const c, float in)
+{
+ float slope, overshoot;
+ float alphaAtt, alphaRel;
+
+ float in_db = 20.0f * log10f( fmaxf( fabsf( in), 0.000001f)), out_db = 0.0f;
+
+ c->y_T[1] = c->y_T[0];
+
+ slope = c->R - 1.0f; // feed-forward topology; was 1/C->R - 1
+
+ overshoot = in_db - c->T;
+
+
+ if (overshoot <= -(c->W * 0.5f))
+ {
+ out_db = in_db;
+ c->isActive = OFALSE;
+ }
+ else if ((overshoot > -(c->W * 0.5f)) && (overshoot < (c->W * 0.5f)))
+ {
+ out_db = in_db + slope * (powf((overshoot + c->W*0.5f),2) / (2.0f * c->W)); // .^ 2 ???
+ c->isActive = OTRUE;
+ }
+ else if (overshoot >= (c->W * 0.5f))
+ {
+ out_db = in_db + slope * overshoot;
+ c->isActive = OTRUE;
+ }
+
+
+
+ c->x_T[0] = out_db - in_db;
+
+ alphaAtt = expf(-1.0f/(0.001f * c->tauAttack * leaf.sampleRate));
+ alphaRel = expf(-1.0f/(0.001f * c->tauRelease * leaf.sampleRate));
+
+ if (c->x_T[0] > c->y_T[1])
+ c->y_T[0] = alphaAtt * c->y_T[1] + (1-alphaAtt) * c->x_T[0];
+ else
+ c->y_T[0] = alphaRel * c->y_T[1] + (1-alphaRel) * c->x_T[0];
+
+ float attenuation = powf(10.0f, ((c->M - c->y_T[0])/20.0f));
+
+ /*
+ if (++ccount > 5000)
+ {
+
+ ccount = 0;
+ DBG(".5width: " + String(c->W * 0.5f));
+ DBG("slope: " + String(slope) + " overshoot: " + String(overshoot));
+ DBG("attenuation: " + String(attenuation));
+ }
+ */
+ return attenuation * in;
+
+
+}
+
+/* Feedback Leveler */
+
+void tFeedbackLeveler_init(tFeedbackLeveler* const p, float targetLevel, float factor, float strength, int mode)
+{
+ p->curr=0.0f;
+ p->targetLevel=targetLevel;
+ tPowerFollower_init(&p->pwrFlw,factor);
+ p->mode=mode;
+ p->strength=strength;
+}
+
+void tFeedbackLeveler_free(tFeedbackLeveler* const p)
+{
+ tPowerFollower_free(&p->pwrFlw);
+}
+
+void tFeedbackLeveler_setStrength(tFeedbackLeveler* const p, float strength)
+{ // strength is how strongly level diff is affecting the amp ratio
+ // try 0.125 for a start
+ p->strength=strength;
+}
+
+void tFeedbackLeveler_setFactor(tFeedbackLeveler* const p, float factor)
+{
+ tPowerFollower_setFactor(&p->pwrFlw,factor);
+}
+
+void tFeedbackLeveler_setMode(tFeedbackLeveler* const p, int mode)
+{ // 0 for decaying with upwards lev limiting, 1 for constrained absolute level (also downwards limiting)
+ p->mode=mode;
+}
+
+float tFeedbackLeveler_tick(tFeedbackLeveler* const p, float input)
+{
+ float levdiff=(tPowerFollower_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 tFeedbackLeveler_sample(tFeedbackLeveler* const p)
+{
+ return p->curr;
+}
+
+
+void tFeedbackLeveler_setTargetLevel (tFeedbackLeveler* const p, float TargetLevel)
+{
+ p->targetLevel=TargetLevel;
+}
+
--- /dev/null
+++ b/LEAF/Src/leaf-effects.c
@@ -1,0 +1,1393 @@
+/*==============================================================================
+
+ leaf-vocoder.c
+ Created: 20 Jan 2017 12:01:54pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-effects.c"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-effects.h"
+#include "../leaf.h"
+
+#endif
+
+
+
+//============================================================================================================
+// TALKBOX
+//============================================================================================================
+
+void tTalkbox_init(tTalkbox* const v, int bufsize)
+{
+ v->param[0] = 0.5f; //wet
+ v->param[1] = 0.0f; //dry
+ v->param[2] = 0; // Swap
+ v->param[3] = 1.0f; //quality
+
+ v->bufsize = bufsize;
+
+ v->car0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
+ v->car1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
+ v->window = (float*) leaf_alloc(sizeof(float) * v->bufsize);
+ v->buf0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
+ v->buf1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
+
+ tTalkbox_update(v);
+}
+
+void tTalkbox_free(tTalkbox* const v)
+{
+ leaf_free(v->car0);
+ leaf_free(v->car1);
+ leaf_free(v->window);
+ leaf_free(v->buf0);
+ leaf_free(v->buf1);
+}
+
+void tTalkbox_update(tTalkbox* const v) ///update internal parameters...
+{
+ float fs = leaf.sampleRate;
+ if(fs < 8000.0f) fs = 8000.0f;
+ if(fs > 96000.0f) fs = 96000.0f;
+
+ int32_t n = (int32_t)(0.01633f * fs);
+ if(n > v->bufsize) n = v->bufsize;
+
+ //O = (VstInt32)(0.0005f * fs);
+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs);
+
+ if(n != v->N) //recalc hanning window
+ {
+ v->N = n;
+ float dp = TWO_PI / v->N;
+ float p = 0.0f;
+ for(n=0; n<v->N; n++)
+ {
+ v->window[n] = 0.5f - 0.5f * cosf(p);
+ p += dp;
+ }
+ }
+ v->wet = 0.5f * v->param[0] * v->param[0];
+ v->dry = 2.0f * v->param[1] * v->param[1];
+}
+
+void tTalkbox_suspend(tTalkbox* const v) ///clear any buffers...
+{
+ v->pos = v->K = 0;
+ v->emphasis = 0.0f;
+ v->FX = 0;
+
+ v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f;
+ v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f;
+
+ for (int32_t i = 0; i < v->bufsize; i++)
+ {
+ v->buf0[i] = 0;
+ v->buf1[i] = 0;
+ v->car0[i] = 0;
+ v->car1[i] = 0;
+ }
+}
+
+
+#define ORD_MAX 100 // Was 50. Increasing this gets rid of glitchiness, lowering it breaks it; not sure how it affects performance
+void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o)
+{
+ float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x;
+ int32_t i, j, nn=n;
+
+ for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
+ {
+ z[j] = r[j] = 0.0f;
+ for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
+ }
+ r[0] *= 1.001f; //stability fix
+
+ float min = 0.00001f;
+ if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; }
+
+ tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs
+
+ for(i=0; i<=o; i++)
+ {
+ if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f;
+ }
+
+ for(i=0; i<n; i++)
+ {
+ x = G * car[i];
+ for(j=o; j>0; j--) //lattice filter
+ {
+ x -= k[j] * z[j-1];
+ z[j] = z[j-1] + k[j] * x;
+ }
+ buf[i] = z[0] = x; //output buf[] will be windowed elsewhere
+ }
+}
+
+
+void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g)
+{
+ int i, j;
+ float a[ORD_MAX], at[ORD_MAX], e=r[0];
+
+ for(i=0; i<=p; i++) a[i] = at[i] = 0.0f; //probably don't need to clear at[] or k[]
+
+ for(i=1; i<=p; i++)
+ {
+ k[i] = -r[i];
+
+ for(j=1; j<i; j++)
+ {
+ at[j] = a[j];
+ k[i] -= a[j] * r[i-j];
+ }
+ if(fabs(e) < 1.0e-20f) { e = 0.0f; break; }
+ k[i] /= e; // This might be costing us
+
+ a[i] = k[i];
+ for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
+
+ e *= 1.0f - k[i] * k[i];
+ }
+
+ if(e < 1.0e-20f) e = 0.0f;
+ *g = sqrtf(e);
+}
+
+float tTalkbox_tick(tTalkbox* const v, float synth, float voice)
+{
+
+ int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N;
+ float e=v->emphasis, w, o, x, dr, fx=v->FX;
+ float p, q, h0=0.3f, h1=0.77f;
+
+ o = voice;
+ x = synth;
+
+ dr = o;
+
+ p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p;
+ q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q;
+ v->d4 = x;
+ x = p + q;
+
+ if(v->K++)
+ {
+ v->K = 0;
+
+ v->car0[p0] = v->car1[p1] = x; //carrier input
+
+ x = o - e; e = o; //6dB/oct pre-emphasis
+
+ w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows
+ if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O); p0 = 0; }
+
+ w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w;
+ if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O); p1 = 0; }
+ }
+
+ p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p;
+ q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q;
+ v->u4 = fx;
+ x = p + q;
+
+ o = x;
+
+ v->emphasis = e;
+ v->pos = p0;
+ v->FX = fx;
+
+ float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]);
+ if(fabs(v->d0) < den) v->d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?)
+ if(fabs(v->d1) < den) v->d1 = 0.0f;
+ if(fabs(v->d2) < den) v->d2 = 0.0f;
+ if(fabs(v->d3) < den) v->d3 = 0.0f;
+ if(fabs(v->u0) < den) v->u0 = 0.0f;
+ if(fabs(v->u1) < den) v->u1 = 0.0f;
+ if(fabs(v->u2) < den) v->u2 = 0.0f;
+ if(fabs(v->u3) < den) v->u3 = 0.0f;
+ return o;
+}
+
+void tTalkbox_setQuality(tTalkbox* const v, float quality)
+{
+ v->param[3] = quality;
+ v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate);
+}
+
+
+//============================================================================================================
+// VOCODER
+//============================================================================================================
+
+void tVocoder_init (tVocoder* const v)
+{
+ v->param[0] = 0.33f; //input select
+ v->param[1] = 0.50f; //output dB
+ v->param[2] = 0.40f; //hi thru
+ v->param[3] = 0.40f; //hi band
+ v->param[4] = 0.16f; //envelope
+ v->param[5] = 0.55f; //filter q
+ v->param[6] = 0.6667f;//freq range
+ v->param[7] = 0.33f; //num bands
+
+ tVocoder_update(v);
+}
+
+void tVocoder_free (tVocoder* const v)
+{
+
+}
+
+void tVocoder_update (tVocoder* const v)
+{
+ float tpofs = 6.2831853f * leaf.invSampleRate;
+
+ float rr, th, re;
+
+ float sh;
+
+ int32_t i;
+
+ v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f);
+
+ v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]);
+ v->high = v->param[3] * v->param[3] * v->param[3] * v->thru;
+ v->thru *= v->param[2] * v->param[2] * v->param[2];
+
+ if(v->param[7]<0.5f)
+ {
+ v->nbnd=8;
+ re=0.003f;
+ v->f[1][2] = 3000.0f;
+ v->f[2][2] = 2200.0f;
+ v->f[3][2] = 1500.0f;
+ v->f[4][2] = 1080.0f;
+ v->f[5][2] = 700.0f;
+ v->f[6][2] = 390.0f;
+ v->f[7][2] = 190.0f;
+ }
+ else
+ {
+ v->nbnd=16;
+ re=0.0015f;
+ v->f[ 1][2] = 5000.0f; //+1000
+ v->f[ 2][2] = 4000.0f; //+750
+ v->f[ 3][2] = 3250.0f; //+500
+ v->f[ 4][2] = 2750.0f; //+450
+ v->f[ 5][2] = 2300.0f; //+300
+ v->f[ 6][2] = 2000.0f; //+250
+ v->f[ 7][2] = 1750.0f; //+250
+ v->f[ 8][2] = 1500.0f; //+250
+ v->f[ 9][2] = 1250.0f; //+250
+ v->f[10][2] = 1000.0f; //+250
+ v->f[11][2] = 750.0f; //+210
+ v->f[12][2] = 540.0f; //+190
+ v->f[13][2] = 350.0f; //+155
+ v->f[14][2] = 195.0f; //+100
+ v->f[15][2] = 95.0f;
+ }
+
+ if(v->param[4]<0.05f) //freeze
+ {
+ for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f;
+ }
+ else
+ {
+ v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed
+
+ rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion
+ for(i=1;i<v->nbnd;i++)
+ {
+ v->f[i][12] = (float)(0.025 - rr * (double)i);
+ if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12];
+ }
+ v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate
+ }
+
+ rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]);
+ sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift
+
+ for(i=1;i<v->nbnd;i++)
+ {
+ v->f[i][2] *= sh;
+ th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
+ v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0
+ v->f[i][1] = (float)(-rr * rr); //a1
+ //was .98
+ v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks
+ th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
+ v->f[i][2] = (float)(2.0 * rr * cos(th));
+ }
+}
+
+float tVocoder_tick (tVocoder* const v, float synth, float voice)
+{
+ float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp;
+ uint32_t i, k = v->kval, nb = v->nbnd;
+
+ a = voice; //speech
+ b = synth; //synth
+
+ tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis
+ v->f[0][7] = a;
+ a = tmp;
+
+ if(tmp<0.0f) tmp = -tmp;
+ v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope
+ o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru
+
+ v->f[0][3] = b; //integrate carrier for HF band
+
+ if(++k & 0x1) //this block runs at half sample rate
+ {
+ oo = 0.0f;
+ aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson
+ v->f[0][9] = v->f[0][8]; v->f[0][8] = a;
+ bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4];
+ v->f[0][5] = v->f[0][4]; v->f[0][4] = b;
+
+ for(i=1; i<nb; i++) //filter bank: 4th-order band pass
+ {
+ tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb;
+ v->f[i][4] = v->f[i][3];
+ v->f[i][3] = tmp;
+ tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6];
+ v->f[i][6] = v->f[i][5];
+ v->f[i][5] = tmp;
+
+ tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa;
+ v->f[i][8] = v->f[i][7];
+ v->f[i][7] = tmp;
+ tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10];
+ v->f[i][10] = v->f[i][9];
+ v->f[i][9] = tmp;
+
+ if(tmp<0.0f) tmp = -tmp;
+ v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp);
+ oo += v->f[i][5] * v->f[i][11];
+ }
+ }
+ o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz)
+
+ v->kout = oo;
+ v->kval = k & 0x1;
+ if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal
+
+ for(i=1;i<nb;i++)
+ if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10)
+ for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals
+
+ if(fabs(o)>10.0f) tVocoder_suspend(v); //catch instability
+
+ return o;
+
+}
+
+void tVocoder_suspend (tVocoder* const v)
+{
+ int32_t i, j;
+
+ for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes
+ v->kout = 0.0f;
+ v->kval = 0;
+}
+
+//============================================================================================================
+// PITCHSHIFTER
+//============================================================================================================
+static int pitchshifter_attackdetect(tPitchShifter* ps);
+
+void tPitchShifter_init(tPitchShifter* const ps, float* in, float* out, 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;
+
+ ps->hopSize = DEFHOPSIZE;
+ ps->windowSize = DEFWINDOWSIZE;
+ ps->fba = FBA;
+
+ tEnvPD_init(&ps->env, ps->windowSize, ps->hopSize, ps->frameSize);
+
+ tSNAC_init(&ps->snac, DEFOVERLAP);
+
+ tSOLAD_init(&ps->sola);
+
+ tHighpass_init(&ps->hp, HPFREQ);
+
+ tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
+
+ tPitchShifter_setTimeConstant(ps, DEFTIMECONSTANT);
+}
+
+void tPitchShifter_free(tPitchShifter* const ps)
+{
+ tEnvPD_free(&ps->env);
+ tSNAC_free(&ps->snac);
+ tSOLAD_free(&ps->sola);
+ tHighpass_free(&ps->hp);
+}
+
+float tPitchShifter_tick(tPitchShifter* ps, float sample)
+{
+ 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)
+ {
+ 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);
+
+ }
+
+ return out;
+}
+
+float tPitchShifterToFreq_tick(tPitchShifter* ps, float sample, float freq)
+{
+ 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)
+ {
+ 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;
+ }
+
+ return out;
+}
+
+float tPitchShifterToFunc_tick(tPitchShifter* ps, float sample, float (*fun)(float))
+{
+ 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)
+ {
+ 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;
+ }
+
+ return out;
+}
+
+void tPitchShifter_ioSamples(tPitchShifter* ps, float* in, float* out, int size)
+{
+ float period;
+
+ tEnvPD_processBlock(&ps->env, in);
+
+ if(pitchshifter_attackdetect(ps) == 1)
+ {
+ ps->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+ }
+
+ tSNAC_ioSamples(&ps->snac, in, out, size);
+ period = tSNAC_getPeriod(&ps->snac);
+
+ 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)
+ {
+ out[cc] = tHighpass_tick(&ps->hp, out[cc]);
+ }
+}
+
+void tPitchShifter_ioSamples_toFreq(tPitchShifter* ps, float* in, float* out, int size, float toFreq)
+{
+ float period;
+
+ tEnvPD_processBlock(&ps->env, in);
+
+ if(pitchshifter_attackdetect(ps) == 1)
+ {
+ ps->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+ }
+
+ 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]);
+ }
+}
+
+void tPitchShifter_ioSamples_toPeriod(tPitchShifter* ps, float* in, float* out, int size, float toPeriod)
+{
+ float period;
+
+ tEnvPD_processBlock(&ps->env, in);
+
+ if(pitchshifter_attackdetect(ps) == 1)
+ {
+ ps->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+ }
+
+ 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]);
+ }
+}
+
+void tPitchShifter_ioSamples_toFunc(tPitchShifter* ps, float* in, float* out, int size, float (*fun)(float))
+{
+ float period;
+
+ tEnvPD_processBlock(&ps->env, in);
+
+ if(pitchshifter_attackdetect(ps) == 1)
+ {
+ ps->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->windowSize);
+ }
+
+ tSNAC_ioSamples(&ps->snac, in, out, size);
+ 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, in, out, size);
+
+ for (int cc = 0; cc < size; ++cc)
+ {
+ out[cc] = tHighpass_tick(&ps->hp, out[cc]);
+ }
+}
+
+void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf)
+{
+ ps->pitchFactor = pf;
+}
+
+void tPitchShifter_setTimeConstant(tPitchShifter* ps, float tc)
+{
+ ps->timeConstant = tc;
+ ps->radius = expf(-1000.0f * ps->hopSize * leaf.invSampleRate / ps->timeConstant);
+}
+
+void tPitchShifter_setHopSize(tPitchShifter* ps, int hs)
+{
+ ps->hopSize = hs;
+}
+
+void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws)
+{
+ ps->windowSize = ws;
+}
+
+float tPitchShifter_getPeriod(tPitchShifter* ps)
+{
+ return tSNAC_getPeriod(&ps->snac);
+}
+
+static int pitchshifter_attackdetect(tPitchShifter* ps)
+{
+ 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;
+}
+
+
+//============================================================================================================
+// PITCHSHIFT
+//============================================================================================================
+
+static int pitchshift_attackdetect(tPitchShift* ps)
+{
+ float envout;
+
+ envout = tEnvPD_tick(&ps->p->env);
+
+ if (envout >= 1.0f)
+ {
+ ps->p->lastmax = ps->p->max;
+ if (envout > ps->p->max)
+ {
+ ps->p->max = envout;
+ }
+ else
+ {
+ ps->p->deltamax = envout - ps->p->max;
+ ps->p->max = ps->p->max * ps->radius;
+ }
+ ps->p->deltamax = ps->p->max - ps->p->lastmax;
+ }
+
+ ps->p->fba = ps->p->fba ? (ps->p->fba - 1) : 0;
+
+ 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)
+{
+ ps->p = p;
+
+ ps->outBuffer = out;
+ ps->bufSize = bufSize;
+ ps->frameSize = p->frameSize;
+ ps->framesPerBuffer = ps->bufSize / ps->frameSize;
+ ps->curBlock = 1;
+ ps->lastBlock = 0;
+ ps->index = 0;
+ ps->pitchFactor = 1.0f;
+
+ tSOLAD_init(&ps->sola);
+
+ tHighpass_init(&ps->hp, HPFREQ);
+
+ tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
+}
+
+void tPitchShift_free(tPitchShift* const ps)
+{
+ tSOLAD_free(&ps->sola);
+ tHighpass_free(&ps->hp);
+}
+
+void tPitchShift_setPitchFactor(tPitchShift* ps, float pf)
+{
+ ps->pitchFactor = pf;
+}
+
+float tPitchShift_shift (tPitchShift* ps)
+{
+ float period, out;
+ int i, iLast;
+
+ i = ps->p->i;
+ iLast = ps->p->iLast;
+
+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
+
+ if (ps->p->indexstore >= ps->frameSize)
+ {
+ period = ps->p->period;
+
+ if(pitchshift_attackdetect(ps) == 1)
+ {
+ ps->p->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
+ }
+
+ tSOLAD_setPeriod(&ps->sola, period);
+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
+
+ tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
+ }
+
+ return out;
+}
+
+float tPitchShift_shiftToFreq (tPitchShift* ps, float freq)
+{
+ float period, out;
+ int i, iLast;
+
+ i = ps->p->i;
+ iLast = ps->p->iLast;
+
+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
+
+ if (ps->p->indexstore >= ps->frameSize)
+ {
+ period = ps->p->period;
+
+ if(pitchshift_attackdetect(ps) == 1)
+ {
+ ps->p->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
+ }
+
+ tSOLAD_setPeriod(&ps->sola, period);
+
+ ps->pitchFactor = period*freq*leaf.invSampleRate;
+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
+
+ tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
+ }
+ return out;
+}
+
+float tPitchShift_shiftToFunc (tPitchShift* ps, float (*fun)(float))
+{
+ float period, out;
+ int i, iLast;
+
+ i = ps->p->i;
+ iLast = ps->p->iLast;
+
+ out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
+
+ if (ps->p->indexstore >= ps->frameSize)
+ {
+ period = ps->p->period;
+
+ if(pitchshift_attackdetect(ps) == 1)
+ {
+ ps->p->fba = 5;
+ tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
+ }
+
+ tSOLAD_setPeriod(&ps->sola, period);
+
+ ps->pitchFactor = period/fun(period);
+ tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
+
+ tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
+
+ ps->curBlock++;
+ if (ps->curBlock >= ps->p->framesPerBuffer) ps->curBlock = 0;
+ ps->lastBlock++;
+ if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
+ }
+
+ return out;
+}
+
+//============================================================================================================
+// SOLAD
+//============================================================================================================
+/******************************************************************************/
+/***************** static function declarations *******************************/
+/******************************************************************************/
+
+static void solad_init(tSOLAD *w);
+static inline float read_sample(tSOLAD *w, float floatindex);
+static void pitchdown(tSOLAD *w, float *out);
+static void pitchup(tSOLAD *w, float *out);
+
+/******************************************************************************/
+/***************** public access functions ************************************/
+/******************************************************************************/
+
+// init
+void tSOLAD_init(tSOLAD* const w)
+{
+ w->pitchfactor = 1.;
+ w->delaybuf = (float*) leaf_alloc(sizeof(float) * (LOOPSIZE+16));
+ solad_init(w);
+}
+
+void tSOLAD_free(tSOLAD* const w)
+{
+}
+
+// send one block of input samples, receive one block of output samples
+void tSOLAD_ioSamples(tSOLAD* const w, float* in, float* out, int blocksize)
+{
+ int i = w->timeindex;
+ int n = w->blocksize = blocksize;
+
+ if(!i) w->delaybuf[LOOPSIZE] = in[0]; // copy one sample for interpolation
+ while(n--) w->delaybuf[i++] = *in++; // copy one input block to delay buffer
+
+ if(w->pitchfactor > 1) pitchup(w, out);
+ else pitchdown(w, out);
+
+ w->timeindex += blocksize;
+ w->timeindex &= LOOPMASK;
+}
+
+// set periodicity analysis data
+void tSOLAD_setPeriod(tSOLAD* const w, float period)
+{
+ if(period > MAXPERIOD) period = MAXPERIOD;
+ if(period > MINPERIOD) w->period = period; // ignore period when too small
+}
+
+// set pitch factor between 0.25 and 4
+void tSOLAD_setPitchFactor(tSOLAD* const w, float pitchfactor)
+{
+ if(pitchfactor < 0.25) pitchfactor = 0.25;
+ else if(pitchfactor > 4.) pitchfactor = 4.;
+ w->pitchfactor = pitchfactor;
+}
+
+// force readpointer lag
+void tSOLAD_setReadLag(tSOLAD* const w, float readlag)
+{
+ if(readlag < 0) readlag = 0;
+ if(readlag < w->readlag) // do not jump backward, only forward
+ {
+ w->jump = w->readlag - readlag;
+ w->readlag = readlag;
+ w->xfadelength = readlag;
+ w->xfadevalue = 1;
+ }
+}
+
+// reset state variables
+void tSOLAD_resetState(tSOLAD* const w)
+{
+ int n = LOOPSIZE + 1;
+ float *buf = w->delaybuf;
+
+ while(n--) *buf++ = 0;
+ solad_init(w);
+}
+
+/******************************************************************************/
+/******************** private procedures **************************************/
+/******************************************************************************/
+
+/*
+ Function pitchdown() is called to read samples from the delay buffer when pitch
+ factor is between 0.25 and 1. The read pointer lags behind because of the slowed
+ down speed, and it must jump forward towards the write pointer soon as there is
+ sufficient space to jump. That is, if there is at least one period of the input
+ signal between read pointer and write pointer. When short periods follow up on
+ long periods, the read pointer may have space to jump over more than one period
+ lenghts. Jump length must be [periodlength ^ 2] in any case.
+
+ A linear crossfade function joins the jump-from point with the jump-to point.
+ The crossfade must be completed before another read pointer jump is allowed.
+ Length of the crossfade function is stored as a number of samples in terms of
+ the input sample rate. This length is dynamically translated
+ to a crossfade length expressed in output reading rate, according to pitch
+ factor which can change before the crossfade is completed. Crossfade length does
+ not cover an invariable length in periods for all pitch transposition factors.
+ For pitch factors from 0.5 till 1, crossfade length is stretched in the
+ output just as much as the signal itself, as crossfade speed is set to equal
+ pitch factor. For pitch factors below 0.5, the read pointer wants to jump
+ forward before one period is read, therefore the crossfade length as expressed
+ in output periods must be shorter. Crossfade speed is set to [1 - pitchfactor]
+ for those cases. Pitch factor 0.5 is the natural switch point between crossfade
+ speeds [pitchfactor] and [1 - pitchfactor] because 0.5 == 1 - 0.5. The crossfade
+ speed modification for pitch factors below 0.5 also means that much of the
+ original signal content will be skipped.
+ */
+
+
+static void pitchdown(tSOLAD* const w, float *out)
+{
+ int n = w->blocksize;
+ float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values!
+ float pitchfactor = w->pitchfactor;
+ float period = w->period;
+ float readlag = w->readlag;
+ float readlagstep = 1 - pitchfactor;
+ float jump = w->jump;
+ float xfadevalue = w->xfadevalue;
+ float xfadelength = w->xfadelength;
+ float xfadespeed, xfadestep, readindex, outputsample;
+
+ if(pitchfactor > 0.5) xfadespeed = pitchfactor;
+ else xfadespeed = 1 - pitchfactor;
+ xfadestep = xfadespeed / xfadelength;
+
+ while(n--)
+ {
+ if(readlag > period) // check if read pointer may jump forward...
+ {
+ if(xfadevalue <= 0) // ...but do not interrupt crossfade
+ {
+ jump = period; // jump forward
+ while((jump * 2) < readlag) jump *= 2; // use available space
+ readlag -= jump; // reduce read pointer lag
+ xfadevalue = 1; // start crossfade
+ xfadelength = period - 1;
+ xfadestep = xfadespeed / xfadelength;
+ }
+ }
+
+ readindex = refindex - readlag;
+ outputsample = read_sample(w, readindex);
+
+ if(xfadevalue > 0)
+ {
+ outputsample *= (1 - xfadevalue); // fadein
+ outputsample += read_sample(w, readindex - jump) * xfadevalue; // fadeout
+ xfadevalue -= xfadestep;
+ }
+
+ *out++ = outputsample;
+ refindex += 1;
+ readlag += readlagstep;
+ }
+
+ w->jump = jump; // state variables
+ w->readlag = readlag;
+ w->xfadevalue = xfadevalue;
+ w->xfadelength = xfadelength;
+}
+
+
+/*
+ Function pitchup() for pitch factors above 1 is more complicated than
+ pitchdown(). The read pointer increments faster than the write pointer and a
+ backward jump must happen in time, reckoning with the crossfade region. The read
+ pointer backward jump length is always one period. In order to minimize the area
+ of signal duplicates, crossfade length is aimed at [period / pitchfactor].
+ This leads to a crossfade speed of [pitchfactor * pitchfactor].
+
+ Some samples for the fade out (but not all of them) must already be in the
+ buffer, otherwise we will run out of input samples before the crossfade is
+ completed. The ratio of past samples and future samples for a crossfade of any
+ length is as follows:
+
+ past samples: xfadelength * (1 - 1 / pitchfactor)
+ future samples: xfadelength * (1 / pitchfactor)
+
+ For example in the case of pitch factor 1.5 this would be:
+
+ past samples: xfadelength * (1 - 1 / 1.5) = xfadelength * 1 / 3
+ future samples: xfadelength * (1 / 1.5) = xfadelength * 2 / 3
+
+ In the case of pitch factor 4 this would be:
+
+ past samples: xfadelength * (1 - 1 / 4) = xfadelength * 3 / 4
+ future samples: xfadelength * (1 / 4) = xfadelength * 1 / 4
+
+ The read pointer lag must therefore preserve a minimum dependent on pitch
+ factor. The minimum is called 'limit' here:
+
+ limit = period * (pitchfactor - 1) / pitchfactor * pitchfactor
+
+ Components of this expression are combined to reuse them in operations, while
+ (pitchfactor - 1) is changed to (pitchfactor - 0.99) to avoid numerical
+ resolution issues for pitch factors slightly above 1:
+
+ xfadespeed = pitchfactor * pitchfactor
+ limitfactor = (pitchfactor - 0.99) / xfadespeed
+ limit = period * limitfactor
+
+ When read lag is smaller than this limit, the read pointer must preferably
+ jump backward, unless a previous crossfade is not yet completed. Crossfades must
+ preferably be completed, unless the read pointer lag becomes smaller than zero.
+ With fluctuating period lengths and pitch factors, the readpointer lag limit may
+ change from one input block to the next in such a way that the actual lag is
+ suddenly much smaller than the limit, and the intended crossfade length can not
+ be applied. Therefore the crossfade length is simply calculated from the
+ available amount of samples for all cases, like so:
+
+ xfadelength = readlag / limitfactor
+
+ For most occurrences, this will amount to a crossfade length reduced to
+ [period / pitchfactor] in the output for pitch factors above 1, while in some
+ cases it will be considerably shorter. Fortunately, an incidental aberration of
+ the intended crossfade length hardly ever creates an audible artifact. The
+ reason to specify preferred crossfade length according to pitch factor is to
+ minimize the impression of echoes without sacrificing too much of the signal
+ content. The readpointer jump length remains one period in any case.
+
+ Sometimes, the input signal periodicity may decrease substantially between one
+ signal block and the next. In such cases it may be possible for the read pointer
+ to jump forward and reduce latency. For every signal block, a check on this
+ possibility is done. A previous crossfade must be completed before a forward
+ jump is allowed.
+ */
+static void pitchup(tSOLAD* const w, float *out)
+{
+ int n = w->blocksize;
+ float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values
+ float pitchfactor = w->pitchfactor;
+ float period = w->period;
+ float readlag = w->readlag;
+ float jump = w->jump;
+ float xfadevalue = w->xfadevalue;
+ float xfadelength = w->xfadelength;
+
+ float readlagstep = pitchfactor - 1;
+ float xfadespeed = pitchfactor * pitchfactor;
+ float xfadestep = xfadespeed / xfadelength;
+ float limitfactor = (pitchfactor - (float)0.99) / xfadespeed;
+ float limit = period * limitfactor;
+ float readindex, outputsample;
+
+ if((readlag > (period + 2 * limit)) & (xfadevalue < 0))
+ {
+ jump = period; // jump forward
+ while((jump * 2) < (readlag - 2 * limit)) jump *= 2; // use available space
+ readlag -= jump; // reduce read pointer lag
+ xfadevalue = 1; // start crossfade
+ xfadelength = period - 1;
+ xfadestep = xfadespeed / xfadelength;
+ }
+
+ while(n--)
+ {
+ if(readlag < limit) // check if read pointer should jump backward...
+ {
+ if((xfadevalue < 0) | (readlag < 0)) // ...but try not to interrupt crossfade
+ {
+ xfadelength = readlag / limitfactor;
+ if(xfadelength < 1) xfadelength = 1;
+ xfadestep = xfadespeed / xfadelength;
+
+ jump = -period; // jump backward
+ readlag += period; // increase read pointer lag
+ xfadevalue = 1; // start crossfade
+ }
+ }
+
+ readindex = refindex - readlag;
+ outputsample = read_sample(w, readindex);
+
+ if(xfadevalue > 0)
+ {
+ outputsample *= (1 - xfadevalue);
+ outputsample += read_sample(w, readindex - jump) * xfadevalue;
+ xfadevalue -= xfadestep;
+ }
+
+ *out++ = outputsample;
+ refindex += 1;
+ readlag -= readlagstep;
+ }
+
+ w->readlag = readlag; // state variables
+ w->jump = jump;
+ w->xfadelength = xfadelength;
+ w->xfadevalue = xfadevalue;
+}
+
+// read one sample from delay buffer, with linear interpolation
+static inline float read_sample(tSOLAD* const w, float floatindex)
+{
+ int index = (int)floatindex;
+ float fraction = floatindex - (float)index;
+ float *buf = w->delaybuf;
+ index &= LOOPMASK;
+
+ return (buf[index] + (fraction * (buf[index+1] - buf[index])));
+}
+
+static void solad_init(tSOLAD* const w)
+{
+ w->timeindex = 0;
+ w->xfadevalue = -1;
+ w->period = INITPERIOD;
+ w->readlag = INITPERIOD;
+ w->blocksize = INITPERIOD;
+}
+//============================================================================================================
+// FORMANTSHIFTER
+//============================================================================================================
+
+void tFormantShifter_init(tFormantShifter* const fs, int bufsize, int order)
+{
+ fs->ford = order;
+ fs->bufsize = bufsize;
+ fs->fk = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->fb = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->fc = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->frb = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->frc = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->fsig = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->fsmooth = (float*) leaf_alloc(sizeof(float) * fs->ford);
+ fs->ftvec = (float*) leaf_alloc(sizeof(float) * fs->ford);
+
+ fs->fbuff = (float**) leaf_alloc(sizeof(float*) * fs->ford);
+ for (int i = 0; i < fs->ford; i++)
+ {
+ fs->fbuff[i] = (float*) leaf_alloc(sizeof(float) * fs->bufsize);
+ }
+
+
+ fs->falph = powf(0.001f, 80.0f / (leaf.sampleRate));
+ fs->flamb = -(0.8517f*sqrt(atanf(0.06583f*leaf.sampleRate))-0.1916f);
+ fs->fhp = 0.0f;
+ fs->flp = 0.0f;
+ fs->flpa = powf(0.001f, 10.0f / (leaf.sampleRate));
+ fs->fmute = 1.0f;
+ fs->fmutealph = powf(0.001f, 1.0f / (leaf.sampleRate));
+ fs->cbi = 0;
+}
+
+void tFormantShifter_free(tFormantShifter* const fs)
+{
+ leaf_free(fs->fk);
+ leaf_free(fs->fb);
+ leaf_free(fs->fc);
+ leaf_free(fs->frb);
+ leaf_free(fs->frc);
+ leaf_free(fs->fsig);
+ leaf_free(fs->fsmooth);
+ leaf_free(fs->ftvec);
+ for (int i = 0; i < fs->ford; i++)
+ {
+ leaf_free(fs->fbuff[i]);
+ }
+ leaf_free(fs->fbuff);
+}
+
+
+float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp)
+{
+ return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp);
+}
+
+float tFormantShifter_remove(tFormantShifter* fs, float in)
+{
+ float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, fk;
+ int ti4;
+ ford = fs->ford;
+ falph = fs->falph;
+ foma = (1.0f - falph);
+ flpa = fs->flpa;
+ flamb = fs->flamb;
+
+ tf = in;
+ ti4 = fs->cbi;
+
+ fa = tf - fs->fhp;
+ fs->fhp = tf;
+ fb = fa;
+ for(int i = 0; i < ford; i++)
+ {
+ fs->fsig[i] = fa*fa*foma + fs->fsig[i]*falph;
+ fc = (fb - fs->fc[i])*flamb + fs->fb[i];
+ fs->fc[i] = fc;
+ fs->fb[i] = fb;
+ fk = fa*fc*foma + fs->fk[i]*falph;
+ fs->fk[i] = fk;
+ tf = fk/(fs->fsig[i] + 0.000001f);
+ tf = tf*foma + fs->fsmooth[i]*falph;
+ fs->fsmooth[i] = tf;
+ fs->fbuff[i][ti4] = tf;
+ fb = fc - tf*fa;
+ fa = fa - tf*fc;
+ }
+ fs->cbi++;
+ if(fs->cbi >= fs->bufsize)
+ {
+ fs->cbi = 0;
+ }
+
+ return fa;
+}
+
+float tFormantShifter_add(tFormantShifter* fs, float in, float fwarp)
+{
+ float fa, fb, fc, foma, 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 = exp2(fwarp/2.0f) * (1+flamb)/(1-flamb);
+ frlamb = (tf-1)/(tf+1);
+ ti4 = fs->cbi;
+
+ tf2 = in;
+ fa = 0;
+ fb = fa;
+ for (int i=0; i<ford; i++)
+ {
+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
+ tf = fs->fbuff[i][ti4];
+ fb = fc - tf*fa;
+ fs->ftvec[i] = tf*fc;
+ fa = fa - fs->ftvec[i];
+ }
+ tf = -fa;
+ for (int i=ford-1; i>=0; i--)
+ {
+ tf = tf + fs->ftvec[i];
+ }
+ f0resp = tf;
+
+ // second time: compute 1-response
+ fa = 1;
+ fb = fa;
+ for (int i=0; i<ford; i++)
+ {
+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
+ tf = fs->fbuff[i][ti4];
+ fb = fc - tf*fa;
+ fs->ftvec[i] = tf*fc;
+ fa = fa - fs->ftvec[i];
+ }
+ tf = -fa;
+ for (int i=ford-1; i>=0; i--)
+ {
+ tf = tf + fs->ftvec[i];
+ }
+ f1resp = tf;
+
+ // now solve equations for output, based on 0-response and 1-response
+ tf = (float)2*tf2;
+ tf2 = tf;
+ tf = ((float)1 - f1resp + f0resp);
+ if (tf!=0)
+ {
+ tf2 = (tf2 + f0resp) / tf;
+ }
+ else
+ {
+ tf2 = 0;
+ }
+
+ // third time: update delay registers
+ fa = tf2;
+ fb = fa;
+ for (int i=0; i<ford; i++)
+ {
+ fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
+ fs->frc[i] = fc;
+ fs->frb[i] = fb;
+ tf = fs->fbuff[i][ti4];
+ fb = fc - tf*fa;
+ fa = fa - tf*fc;
+ }
+ tf = tf2;
+ tf = tf + flpa * fs->flp; // lowpass post-emphasis filter
+ fs->flp = tf;
+
+ // Bring up the gain slowly when formant correction goes from disabled
+ // to enabled, while things stabilize.
+ if (fs->fmute>0.5)
+ {
+ tf = tf*(fs->fmute - 0.5)*2;
+ }
+ else
+ {
+ tf = 0;
+ }
+ tf2 = fs->fmutealph;
+ fs->fmute = (1-tf2) + tf2*fs->fmute;
+ // now tf is signal output
+ // ...and we're done messing with formants
+
+ return tf;
+}
--- /dev/null
+++ b/LEAF/Src/leaf-electrical.c
@@ -1,0 +1,480 @@
+/*
+ * leaf-electrical.c
+ *
+ * Created on: Sep 25, 2019
+ * Author: jeffsnyder
+ */
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-electrical.h"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-electrical.h"
+#include "../leaf.h"
+
+#endif
+
+//==============================================================================
+
+static float get_port_resistance_for_resistor(tWDF* const r);
+static float get_port_resistance_for_capacitor(tWDF* const r);
+static float get_port_resistance_for_inductor(tWDF* const r);
+static float get_port_resistance_for_resistive(tWDF* const r);
+static float get_port_resistance_for_inverter(tWDF* const r);
+static float get_port_resistance_for_series(tWDF* const r);
+static float get_port_resistance_for_parallel(tWDF* const r);
+static float get_port_resistance_for_root(tWDF* const r);
+
+static void set_incident_wave_for_leaf(tWDF* const r, float incident_wave, float input);
+static void set_incident_wave_for_leaf_inverted(tWDF* const r, float incident_wave, float input);
+static void set_incident_wave_for_inverter(tWDF* const r, float incident_wave, float input);
+static void set_incident_wave_for_series(tWDF* const r, float incident_wave, float input);
+static void set_incident_wave_for_parallel(tWDF* const r, float incident_wave, float input);
+
+static float get_reflected_wave_for_resistor(tWDF* const r, float input);
+static float get_reflected_wave_for_capacitor(tWDF* const r, float input);
+static float get_reflected_wave_for_resistive(tWDF* const r, float input);
+static float get_reflected_wave_for_inverter(tWDF* const r, float input);
+static float get_reflected_wave_for_series(tWDF* const r, float input);
+static float get_reflected_wave_for_parallel(tWDF* const r, float input);
+
+static float get_reflected_wave_for_ideal(tWDF* const n, float input, float incident_wave);
+static float get_reflected_wave_for_diode(tWDF* const n, float input, float incident_wave);
+static float get_reflected_wave_for_diode_pair(tWDF* const n, float input, float incident_wave);
+
+//WDF
+void tWDF_init(tWDF* const r, WDFComponentType type, float value, tWDF* const rL, tWDF* const rR)
+{
+ r->type = type;
+ r->child_left = rL;
+ r->child_right = rR;
+ r->incident_wave_up = 0.0f;
+ r->incident_wave_left = 0.0f;
+ r->incident_wave_right = 0.0f;
+ r->reflected_wave_up = 0.0f;
+ r->reflected_wave_left = 0.0f;
+ r->reflected_wave_right = 0.0f;
+ r->sample_rate = leaf.sampleRate;
+ r->value = value;
+
+ tWDF* child;
+ if (r->child_left != NULL) child = r->child_left;
+ else child = r->child_right;
+
+ if (r->type == Resistor)
+ {
+ r->port_resistance_up = r->value;
+ r->port_conductance_up = 1.0f / r->value;
+
+ r->get_port_resistance = &get_port_resistance_for_resistor;
+ r->get_reflected_wave_up = &get_reflected_wave_for_resistor;
+ r->set_incident_wave = &set_incident_wave_for_leaf;
+ }
+ else if (r->type == Capacitor)
+ {
+ r->port_conductance_up = r->sample_rate * 2.0f * r->value;
+ r->port_resistance_up = 1.0f / r->port_conductance_up; //based on trapezoidal discretization
+
+ r->get_port_resistance = &get_port_resistance_for_capacitor;
+ r->get_reflected_wave_up = &get_reflected_wave_for_capacitor;
+ r->set_incident_wave = &set_incident_wave_for_leaf;
+ }
+ else if (r->type == Inductor)
+ {
+ r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_port_resistance = &get_port_resistance_for_inductor;
+ r->get_reflected_wave_up = &get_reflected_wave_for_capacitor; // same as capacitor
+ r->set_incident_wave = &set_incident_wave_for_leaf_inverted;
+ }
+ else if (r->type == ResistiveSource)
+ {
+ r->port_resistance_up = r->value;
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_port_resistance = &get_port_resistance_for_resistive;
+ r->get_reflected_wave_up = &get_reflected_wave_for_resistive;
+ r->set_incident_wave = &set_incident_wave_for_leaf;
+ }
+ else if (r->type == Inverter)
+ {
+ r->port_resistance_up = tWDF_getPortResistance(r->child_left);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_port_resistance = &get_port_resistance_for_inverter;
+ r->get_reflected_wave_up = &get_reflected_wave_for_inverter;
+ r->set_incident_wave = &set_incident_wave_for_inverter;
+ }
+ else if (r->type == SeriesAdaptor)
+ {
+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
+ r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+ r->port_conductance_left = 1.0f / r->port_resistance_left;
+ r->port_conductance_right = 1.0f / r->port_resistance_right;
+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
+
+ r->get_port_resistance = &get_port_resistance_for_series;
+ r->get_reflected_wave_up = &get_reflected_wave_for_series;
+ r->set_incident_wave = &set_incident_wave_for_series;
+ }
+ else if (r->type == ParallelAdaptor)
+ {
+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
+ r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+ r->port_conductance_left = 1.0f / r->port_resistance_left;
+ r->port_conductance_right = 1.0f / r->port_resistance_right;
+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
+
+ r->get_port_resistance = &get_port_resistance_for_parallel;
+ r->get_reflected_wave_up = &get_reflected_wave_for_parallel;
+ r->set_incident_wave = &set_incident_wave_for_parallel;
+ }
+ else if (r->type == IdealSource)
+ {
+ r->port_resistance_up = tWDF_getPortResistance(child);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_reflected_wave_down = &get_reflected_wave_for_ideal;
+ r->get_port_resistance = &get_port_resistance_for_root;
+ }
+ else if (r->type == Diode)
+ {
+ r->port_resistance_up = tWDF_getPortResistance(child);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_reflected_wave_down = &get_reflected_wave_for_diode;
+ r->get_port_resistance = &get_port_resistance_for_root;
+ }
+ else if (r->type == DiodePair)
+ {
+ r->port_resistance_up = tWDF_getPortResistance(child);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ r->get_reflected_wave_down = &get_reflected_wave_for_diode_pair;
+ r->get_port_resistance = &get_port_resistance_for_root;
+ }
+}
+
+void tWDF_free(tWDF* const r)
+{
+
+}
+
+float tWDF_tick(tWDF* const r, float sample, tWDF* const outputPoint, uint8_t paramsChanged)
+{
+ tWDF* child;
+ if (r->child_left != NULL) child = r->child_left;
+ else child = r->child_right;
+
+ //step 0 : update port resistances if something changed
+ if (paramsChanged) tWDF_getPortResistance(r);
+
+ //step 1 : set inputs to what they should be
+ float input = sample;
+
+ //step 2 : scan the waves up the tree
+ r->incident_wave_up = tWDF_getReflectedWaveUp(child, input);
+
+ //step 3 : do root scattering computation
+ r->reflected_wave_up = tWDF_getReflectedWaveDown(r, input, r->incident_wave_up);
+
+ //step 4 : propogate waves down the tree
+ tWDF_setIncidentWave(child, r->reflected_wave_up, input);
+
+ //step 5 : grab whatever voltages or currents we want as outputs
+ return tWDF_getVoltage(outputPoint);
+}
+
+void tWDF_setValue(tWDF* const r, float value)
+{
+ r->value = value;
+}
+
+void tWDF_setSampleRate(tWDF* const r, float sample_rate)
+{
+ r->sample_rate = sample_rate;
+}
+
+uint8_t tWDF_isLeaf(tWDF* const r)
+{
+ if (r->child_left == NULL && r->child_right == NULL) return 1;
+ return 0;
+}
+
+float tWDF_getPortResistance(tWDF* const r)
+{
+ return r->get_port_resistance(r);
+}
+
+void tWDF_setIncidentWave(tWDF* const r, float incident_wave, float input)
+{
+ r->set_incident_wave(r, incident_wave, input);
+}
+
+float tWDF_getReflectedWaveUp(tWDF* const r, float input)
+{
+ return r->get_reflected_wave_up(r, input);
+}
+
+float tWDF_getReflectedWaveDown(tWDF* const r, float input, float incident_wave)
+{
+ return r->get_reflected_wave_down(r, input, incident_wave);
+}
+
+float tWDF_getVoltage(tWDF* const r)
+{
+ return ((r->incident_wave_up * 0.5f) + (r->reflected_wave_up * 0.5f));
+}
+
+float tWDF_getCurrent(tWDF* const r)
+{
+ return (((r->incident_wave_up * 0.5f) - (r->reflected_wave_up * 0.5f)) * r->port_conductance_up);
+}
+
+//============ Static Functions to be Pointed To ====================
+//===================================================================
+//============ Get and Calculate Port Resistances ===================
+
+static float get_port_resistance_for_resistor(tWDF* const r)
+{
+ r->port_resistance_up = r->value;
+ r->port_conductance_up = 1.0f / r->value;
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_capacitor(tWDF* const r)
+{
+ r->port_conductance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
+ r->port_resistance_up = (1.0f / r->port_conductance_up);
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_inductor(tWDF* const r)
+{
+ r->port_resistance_up = r->sample_rate * 2.0f * r->value; //based on trapezoidal discretization
+ r->port_conductance_up = (1.0f / r->port_resistance_up);
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_resistive(tWDF* const r)
+{
+ r->port_resistance_up = r->value;
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_inverter(tWDF* const r)
+{
+ r->port_resistance_up = tWDF_getPortResistance(r->child_left);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_series(tWDF* const r)
+{
+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
+ r->port_resistance_up = r->port_resistance_left + r->port_resistance_right;
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+ r->port_conductance_left = 1.0f / r->port_resistance_left;
+ r->port_conductance_right = 1.0f / r->port_resistance_right;
+ r->gamma_zero = 1.0f / (r->port_resistance_right + r->port_resistance_left);
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_parallel(tWDF* const r)
+{
+ r->port_resistance_left = tWDF_getPortResistance(r->child_left);
+ r->port_resistance_right = tWDF_getPortResistance(r->child_right);
+ r->port_resistance_up = (r->port_resistance_left * r->port_resistance_right) / (r->port_resistance_left + r->port_resistance_right);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+ r->port_conductance_left = 1.0f / r->port_resistance_left;
+ r->port_conductance_right = 1.0f / r->port_resistance_right;
+ r->gamma_zero = 1.0f / (r->port_conductance_right + r->port_conductance_left);
+
+ return r->port_resistance_up;
+}
+
+static float get_port_resistance_for_root(tWDF* const r)
+{
+ tWDF* child;
+ if (r->child_left != NULL) child = r->child_left;
+ else child = r->child_right;
+
+ r->port_resistance_up = tWDF_getPortResistance(child);
+ r->port_conductance_up = 1.0f / r->port_resistance_up;
+
+ return r->port_resistance_up;
+}
+
+//===================================================================
+//================ Set Incident Waves ===============================
+
+static void set_incident_wave_for_leaf(tWDF* const r, float incident_wave, float input)
+{
+ r->incident_wave_up = incident_wave;
+}
+
+static void set_incident_wave_for_leaf_inverted(tWDF* const r, float incident_wave, float input)
+{
+ r->incident_wave_up = -1.0f * incident_wave;
+}
+
+static void set_incident_wave_for_inverter(tWDF* const r, float incident_wave, float input)
+{
+ r->incident_wave_up = incident_wave;
+ tWDF_setIncidentWave(r->child_left, -1.0f * incident_wave, input);
+}
+
+static void set_incident_wave_for_series(tWDF* const r, float incident_wave, float input)
+{
+ r->incident_wave_up = incident_wave;
+ float gamma_left = r->port_resistance_left * r->gamma_zero;
+ float gamma_right = r->port_resistance_right * r->gamma_zero;
+ float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
+ float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
+// downPorts[0]->b = yl * ( downPorts[0]->a * ((1.0 / yl) - 1) - downPorts[1]->a - descendingWave );
+// downPorts[1]->b = yr * ( downPorts[1]->a * ((1.0 / yr) - 1) - downPorts[0]->a - descendingWave );
+ tWDF_setIncidentWave(r->child_left, (-1.0f * gamma_left * incident_wave) + (gamma_right * left_wave) - (gamma_left * right_wave), input);
+ tWDF_setIncidentWave(r->child_right, (-1.0f * gamma_right * incident_wave) + (gamma_left * right_wave) - (gamma_right * left_wave), input);
+ // From rt-wdf
+// tWDF_setIncidentWave(r->child_left, gamma_left * (left_wave * ((1.0f / gamma_left) - 1.0f) - right_wave - incident_wave));
+// tWDF_setIncidentWave(r->child_right, gamma_right * (right_wave * ((1.0f / gamma_right) - 1.0f) - left_wave - incident_wave));
+
+}
+
+static void set_incident_wave_for_parallel(tWDF* const r, float incident_wave, float input)
+{
+ r->incident_wave_up = incident_wave;
+ float gamma_left = r->port_conductance_left * r->gamma_zero;
+ float gamma_right = r->port_conductance_right * r->gamma_zero;
+ float left_wave = tWDF_getReflectedWaveUp(r->child_left, input);
+ float right_wave = tWDF_getReflectedWaveUp(r->child_right, input);
+// downPorts[0]->b = ( ( dl - 1 ) * downPorts[0]->a + dr * downPorts[1]->a + du * descendingWave );
+// downPorts[1]->b = ( dl * downPorts[0]->a + ( dr - 1 ) * downPorts[1]->a + du * descendingWave );
+ tWDF_setIncidentWave(r->child_left, (gamma_left - 1.0f) * left_wave + gamma_right * right_wave + incident_wave, input);
+ tWDF_setIncidentWave(r->child_right, gamma_left * left_wave + (gamma_right - 1.0f) * right_wave + incident_wave, input);
+}
+
+//===================================================================
+//================ Get Reflected Waves ==============================
+
+static float get_reflected_wave_for_resistor(tWDF* const r, float input)
+{
+ r->reflected_wave_up = 0.0f;
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_capacitor(tWDF* const r, float input)
+{
+ r->reflected_wave_up = r->incident_wave_up;
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_resistive(tWDF* const r, float input)
+{
+ r->reflected_wave_up = input;
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_inverter(tWDF* const r, float input)
+{
+ r->reflected_wave_up = -1.0f * tWDF_getReflectedWaveUp(r->child_left, input);
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_series(tWDF* const r, float input)
+{
+ //-( downPorts[0]->a + downPorts[1]->a );
+ r->reflected_wave_up = (-1.0f * (tWDF_getReflectedWaveUp(r->child_left, input) + tWDF_getReflectedWaveUp(r->child_right, input)));
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_parallel(tWDF* const r, float input)
+{
+ float gamma_left = r->port_conductance_left * r->gamma_zero;
+ float gamma_right = r->port_conductance_right * r->gamma_zero;
+ //return ( dl * downPorts[0]->a + dr * downPorts[1]->a );
+ r->reflected_wave_up = (gamma_left * tWDF_getReflectedWaveUp(r->child_left, input) + gamma_right * tWDF_getReflectedWaveUp(r->child_right, input));
+ return r->reflected_wave_up;
+}
+
+static float get_reflected_wave_for_ideal(tWDF* const n, float input, float incident_wave)
+{
+ return (2.0f * input) - incident_wave;
+}
+
+#define l2A 0.1640425613334452f
+#define l2B -1.098865286222744f
+#define l2Y 3.148297929334117f
+#define l2K -2.213475204444817f
+static float log2Approximation(float x)
+{
+ return (l2A * x*x*x) + (l2B * x*x) + (l2Y * x) + l2K;
+}
+
+#define wX1 -3.684303659906469f
+#define wX2 1.972967391708859f
+#define wA 9.451797158780131e-3f
+#define wB 0.1126446405111627f
+#define wY 0.4451353886588814f
+#define wK 0.5836596684310648f
+static float wrightOmega3(float x)
+{
+ if (x <= wX1)
+ {
+ return 0;
+ }
+ else if (x < wX2)
+ {
+ return (wA * x*x*x) + (wB * x*x) + (wY * x) + wK;
+ }
+ else
+ {
+ return x - logf(x);
+ }
+}
+
+static float wrightOmegaApproximation(float x)
+{
+ float w3 = wrightOmega3(x);
+ return w3 - ((w3 - expf(x - w3)) / (w3 + 1.0f));
+}
+
+static float lambertW(float a, float r, float I, float iVT)
+{
+ return wrightOmegaApproximation(((a + r*I) * iVT) + log((r * I) * iVT));
+}
+
+#define Is_DIODE 2.52e-9f
+#define VT_DIODE 0.02585f
+static float get_reflected_wave_for_diode(tWDF* const n, float input, float incident_wave)
+{
+ float a = incident_wave;
+ float r = n->port_resistance_up;
+ return a + 2.0f*r*Is_DIODE - 2.0f*VT_DIODE*lambertW(a, r, Is_DIODE, 1.0f/VT_DIODE);
+}
+
+static float get_reflected_wave_for_diode_pair(tWDF* const n, float input, float incident_wave)
+{
+ float a = incident_wave;
+ float sgn = 0.0f;
+ if (a > 0.0f) sgn = 1.0f;
+ else if (a < 0.0f) sgn = -1.0f;
+ float r = n->port_resistance_up;
+ return a + 2 * sgn * (r*Is_DIODE - VT_DIODE*lambertW(sgn*a, r, Is_DIODE, 1.0f/VT_DIODE));
+}
--- /dev/null
+++ b/LEAF/Src/leaf-envelopes.c
@@ -1,0 +1,629 @@
+/*
+ ==============================================================================
+
+ leaf-envelopes.c
+ Created: 20 Jan 2017 12:02:17pm
+ Author: Michael R Mulshine
+
+ ==============================================================================
+*/
+
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-envelopes.h"
+#include "..\Inc\leaf-tables.h"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-envelopes.h"
+#include "../Inc/leaf-tables.h"
+#include "../leaf.h"
+
+#endif
+
+#define LOGTEN 2.302585092994
+
+float mtof(float f)
+{
+ if (f <= -1500.0f) return(0);
+ else if (f > 1499.0f) return(mtof(1499.0f));
+ else return (8.17579891564f * expf(0.0577622650f * f));
+}
+
+float ftom(float f)
+{
+ return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
+}
+
+float powtodb(float f)
+{
+ if (f <= 0) return (0);
+ else
+ {
+ float val = 100 + 10.f/LOGTEN * logf(f);
+ return (val < 0 ? 0 : val);
+ }
+}
+
+float rmstodb(float f)
+{
+ if (f <= 0) return (0);
+ else
+ {
+ float val = 100 + 20.f/LOGTEN * log(f);
+ return (val < 0 ? 0 : val);
+ }
+}
+
+float dbtopow(float f)
+{
+ if (f <= 0)
+ return(0);
+ else
+ {
+ if (f > 870.0f)
+ f = 870.0f;
+ return (expf((LOGTEN * 0.1f) * (f-100.0f)));
+ }
+}
+
+float dbtorms(float f)
+{
+ if (f <= 0)
+ return(0);
+ else
+ {
+ if (f > 485.0f)
+ f = 485.0f;
+ }
+ return (expf((LOGTEN * 0.05f) * (f-100.0f)));
+}
+
+
+
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Envelope ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tEnvelope_init(tEnvelope* const env, float attack, float decay, oBool loop)
+{
+ env->exp_buff = exp_decay;
+ env->inc_buff = attack_decay_inc;
+ env->buff_size = sizeof(exp_decay);
+
+ env->loop = loop;
+
+ if (attack > 8192.0f)
+ attack = 8192.0f;
+ if (attack < 0.0f)
+ attack = 0.0f;
+
+ if (decay > 8192.0f)
+ decay = 8192.0f;
+ if (decay < 0.0f)
+ decay = 0.0f;
+
+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
+
+ if (attackIndex < 0)
+ attackIndex = 0;
+ if (decayIndex < 0)
+ decayIndex = 0;
+ if (rampIndex < 0)
+ rampIndex = 0;
+
+ env->inRamp = OFALSE;
+ env->inAttack = OFALSE;
+ env->inDecay = OFALSE;
+
+ env->attackInc = env->inc_buff[attackIndex];
+ env->decayInc = env->inc_buff[decayIndex];
+ env->rampInc = env->inc_buff[rampIndex];
+
+}
+
+void tEnvelope_free(tEnvelope* const env)
+{
+
+}
+
+int tEnvelope_setAttack(tEnvelope* const env, float attack)
+{
+ int32_t attackIndex;
+
+ if (attack < 0.0f) {
+ attackIndex = 0.0f;
+ } else if (attack < 8192.0f) {
+ attackIndex = ((int32_t)(attack * 8.0f))-1;
+ } else {
+ attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
+ }
+
+ env->attackInc = env->inc_buff[attackIndex];
+
+ return 0;
+}
+
+int tEnvelope_setDecay(tEnvelope* const env, float decay)
+{
+ int32_t decayIndex;
+
+ if (decay < 0.0f) {
+ decayIndex = 0.0f;
+ } else if (decay < 8192.0f) {
+ decayIndex = ((int32_t)(decay * 8.0f)) - 1;
+ } else {
+ decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
+ }
+
+ env->decayInc = env->inc_buff[decayIndex];
+
+ return 0;
+}
+
+int tEnvelope_loop(tEnvelope* const env, oBool loop)
+{
+ env->loop = loop;
+
+ return 0;
+}
+
+
+int tEnvelope_on(tEnvelope* const env, float velocity)
+{
+ if (env->inAttack || env->inDecay) // In case envelope retriggered while it is still happening.
+ {
+ env->rampPhase = 0;
+ env->inRamp = OTRUE;
+ env->rampPeak = env->next;
+ }
+ else // Normal start.
+ {
+ env->inAttack = OTRUE;
+ }
+
+
+ env->attackPhase = 0;
+ env->decayPhase = 0;
+ env->inDecay = OFALSE;
+ env->gain = velocity;
+
+ return 0;
+}
+
+float tEnvelope_tick(tEnvelope* const env)
+{
+ if (env->inRamp)
+ {
+ if (env->rampPhase > UINT16_MAX)
+ {
+ env->inRamp = OFALSE;
+ env->inAttack = OTRUE;
+ env->next = 0.0f;
+ }
+ else
+ {
+ env->next = env->rampPeak * env->exp_buff[(uint32_t)env->rampPhase];
+ }
+
+ env->rampPhase += env->rampInc;
+ }
+
+ if (env->inAttack)
+ {
+
+ // If attack done, time to turn around.
+ if (env->attackPhase > UINT16_MAX)
+ {
+ env->inDecay = OTRUE;
+ env->inAttack = OFALSE;
+ env->next = env->gain * 1.0f;
+ }
+ else
+ {
+ // do interpolation !
+ env->next = env->gain * env->exp_buff[UINT16_MAX - (uint32_t)env->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
+ }
+
+ // Increment envelope attack.
+ env->attackPhase += env->attackInc;
+
+ }
+
+ if (env->inDecay)
+ {
+
+ // If decay done, finish.
+ if (env->decayPhase >= UINT16_MAX)
+ {
+ env->inDecay = OFALSE;
+
+ if (env->loop)
+ {
+ env->attackPhase = 0;
+ env->decayPhase = 0;
+ env->inAttack = OTRUE;
+ }
+ else
+ {
+ env->next = 0.0f;
+ }
+
+ } else {
+
+ env->next = env->gain * (env->exp_buff[(uint32_t)env->decayPhase]); // do interpolation !
+ }
+
+ // Increment envelope decay;
+ env->decayPhase += env->decayInc;
+ }
+
+ return env->next;
+}
+
+/* ADSR */
+void tADSR_init(tADSR* const adsr, float attack, float decay, float sustain, float release)
+{
+ adsr->exp_buff = exp_decay;
+ adsr->inc_buff = attack_decay_inc;
+ adsr->buff_size = sizeof(exp_decay);
+
+ if (attack > 8192.0f)
+ attack = 8192.0f;
+ if (attack < 0.0f)
+ attack = 0.0f;
+
+ if (decay > 8192.0f)
+ decay = 8192.0f;
+ if (decay < 0.0f)
+ decay = 0.0f;
+
+ if (sustain > 1.0f)
+ sustain = 1.0f;
+ if (sustain < 0.0f)
+ sustain = 0.0f;
+
+ if (release > 8192.0f)
+ release = 8192.0f;
+ if (release < 0.0f)
+ release = 0.0f;
+
+ int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
+ int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
+ int16_t releaseIndex = ((int16_t)(release * 8.0f))-1;
+ int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
+
+ if (attackIndex < 0)
+ attackIndex = 0;
+ if (decayIndex < 0)
+ decayIndex = 0;
+ if (releaseIndex < 0)
+ releaseIndex = 0;
+ if (rampIndex < 0)
+ rampIndex = 0;
+
+ adsr->inRamp = OFALSE;
+ adsr->inAttack = OFALSE;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OFALSE;
+
+ adsr->sustain = sustain;
+
+ adsr->attackInc = adsr->inc_buff[attackIndex];
+ adsr->decayInc = adsr->inc_buff[decayIndex];
+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
+ adsr->rampInc = adsr->inc_buff[rampIndex];
+}
+
+void tADSR_free(tADSR* const adsr)
+{
+
+}
+
+int tADSR_setAttack(tADSR* const adsr, float attack)
+{
+ int32_t attackIndex;
+
+ if (attack < 0.0f) {
+ attackIndex = 0.0f;
+ } else if (attack < 8192.0f) {
+ attackIndex = ((int32_t)(attack * 8.0f))-1;
+ } else {
+ attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
+ }
+
+ adsr->attackInc = adsr->inc_buff[attackIndex];
+
+ return 0;
+}
+
+int tADSR_detDecay(tADSR* const adsr, float decay)
+{
+ int32_t decayIndex;
+
+ if (decay < 0.0f) {
+ decayIndex = 0.0f;
+ } else if (decay < 8192.0f) {
+ decayIndex = ((int32_t)(decay * 8.0f)) - 1;
+ } else {
+ decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
+ }
+
+ adsr->decayInc = adsr->inc_buff[decayIndex];
+
+ return 0;
+}
+
+int tADSR_setSustain(tADSR *const adsr, float sustain)
+{
+ if (sustain > 1.0f) adsr->sustain = 1.0f;
+ else if (sustain < 0.0f) adsr->sustain = 0.0f;
+ else adsr->sustain = sustain;
+
+ return 0;
+}
+
+int tADSR_setRelease(tADSR* const adsr, float release)
+{
+ int32_t releaseIndex;
+
+ if (release < 0.0f) {
+ releaseIndex = 0.0f;
+ } else if (release < 8192.0f) {
+ releaseIndex = ((int32_t)(release * 8.0f)) - 1;
+ } else {
+ releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
+ }
+
+ adsr->releaseInc = adsr->inc_buff[releaseIndex];
+
+ return 0;
+}
+
+int tADSR_on(tADSR* const adsr, float velocity)
+{
+ if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
+ {
+ adsr->rampPhase = 0;
+ adsr->inRamp = OTRUE;
+ adsr->rampPeak = adsr->next;
+ }
+ else // Normal start.
+ {
+ adsr->inAttack = OTRUE;
+ }
+
+ adsr->attackPhase = 0;
+ adsr->decayPhase = 0;
+ adsr->releasePhase = 0;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OFALSE;
+ adsr->gain = velocity;
+
+ return 0;
+}
+
+int tADSR_off(tADSR* const adsr)
+{
+ if (adsr->inRelease) return 0;
+
+ adsr->inAttack = OFALSE;
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OFALSE;
+ adsr->inRelease = OTRUE;
+
+ adsr->releasePeak = adsr->next;
+
+ return 0;
+}
+
+float tADSR_tick(tADSR* const adsr)
+{
+ if (adsr->inRamp)
+ {
+ if (adsr->rampPhase > UINT16_MAX)
+ {
+ adsr->inRamp = OFALSE;
+ adsr->inAttack = OTRUE;
+ adsr->next = 0.0f;
+ }
+ else
+ {
+ adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
+ }
+
+ adsr->rampPhase += adsr->rampInc;
+ }
+
+ if (adsr->inAttack)
+ {
+
+ // If attack done, time to turn around.
+ if (adsr->attackPhase > UINT16_MAX)
+ {
+ adsr->inDecay = OTRUE;
+ adsr->inAttack = OFALSE;
+ adsr->next = adsr->gain * 1.0f;
+ }
+ else
+ {
+ // do interpolation !
+ adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
+ }
+
+ // Increment ADSR attack.
+ adsr->attackPhase += adsr->attackInc;
+
+ }
+
+ if (adsr->inDecay)
+ {
+
+ // If decay done, sustain.
+ if (adsr->decayPhase >= UINT16_MAX)
+ {
+ adsr->inDecay = OFALSE;
+ adsr->inSustain = OTRUE;
+ adsr->next = adsr->gain * adsr->sustain;
+ }
+
+ else
+ {
+ adsr->next = adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1 - adsr->sustain))); // do interpolation !
+ }
+
+ // Increment ADSR decay.
+ adsr->decayPhase += adsr->decayInc;
+ }
+
+ if (adsr->inRelease)
+ {
+ // If release done, finish.
+ if (adsr->releasePhase >= UINT16_MAX)
+ {
+ adsr->inRelease = OFALSE;
+ adsr->next = 0.0f;
+ }
+ else {
+
+ adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation !
+ }
+
+ // Increment envelope release;
+ adsr->releasePhase += adsr->releaseInc;
+ }
+
+ return adsr->next;
+}
+
+/* Ramp */
+void tRamp_init(tRamp* const ramp, float time, int samples_per_tick)
+{
+ ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f);
+ ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick;
+ ramp->curr = 0.0f;
+ ramp->dest = 0.0f;
+
+ if (time < ramp->minimum_time)
+ {
+ ramp->time = ramp->minimum_time;
+ }
+ else
+ {
+ ramp->time = time;
+ }
+
+ ramp->samples_per_tick = samples_per_tick;
+ ramp->inc = ((ramp->dest - ramp->curr) / ramp->time * ramp->inv_sr_ms) * (float)ramp->samples_per_tick;
+}
+
+void tRamp_free(tRamp* const ramp)
+{
+
+}
+
+int tRamp_setTime(tRamp* const r, float time)
+{
+ if (time < r->minimum_time)
+ {
+ r->time = r->minimum_time;
+ }
+ else
+ {
+ r->time = time;
+ }
+ r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
+ return 0;
+}
+
+int tRamp_setDest(tRamp* const r, float dest)
+{
+ r->dest = dest;
+ r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
+ return 0;
+}
+
+int tRamp_setVal(tRamp* const r, float val)
+{
+ r->curr = val;
+ r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
+ return 0;
+}
+
+float tRamp_tick(tRamp* const r) {
+
+ 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;
+}
+
+float tRamp_sample(tRamp* const r) {
+
+ return r->curr;
+}
+
+void tRampSampleRateChanged(tRamp* const r)
+{
+ 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;
+}
+
+void tExpSmooth_free(tExpSmooth* const smooth)
+{
+
+}
+
+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;
+}
+
--- a/LEAF/Src/leaf-filter.c
+++ /dev/null
@@ -1,843 +1,0 @@
-/*==============================================================================
-
- leaf-filter.c
- Created: 20 Jan 2017 12:01:10pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-filter.h"
-#include "..\Inc\leaf-tables.h"
-#include "..\leaf.h"
-
-#else
-
-#include "../Inc/leaf-filter.h"
-#include "../Inc/leaf-tables.h"
-#include "../leaf.h"
-
-#endif
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tAllpass_init(tAllpass* const f, float initDelay, uint32_t maxDelay)
-{
- f->gain = 0.7f;
-
- f->lastOut = 0.0f;
-
- tDelayL_init(&f->delay, initDelay, maxDelay);
-}
-
-void tAllpass_free(tAllpass* const f)
-{
- tDelayL_free(&f->delay);
-}
-
-void tAllpass_setDelay(tAllpass* const f, float delay)
-{
- tDelayL_setDelay(&f->delay, delay);
-}
-
-void tAllpass_setGain(tAllpass* const f, float gain)
-{
- f->gain = gain;
-}
-
-float tAllpass_tick(tAllpass* const f, float input)
-{
- float s1 = (-f->gain) * f->lastOut + input;
-
- float s2 = tDelayL_tick(&f->delay, s1) + (f->gain) * input;
-
- f->lastOut = s2;
-
- return f->lastOut;
-}
-
-void tButterworth_init(tButterworth* const f, int N, float f1, float f2)
-{
- f->f1 = f1;
- f->f2 = f2;
- f->gain = 1.0f;
-
- f->N = N;
-
- if (f->N > NUM_SVF_BW) f->N = NUM_SVF_BW;
-
- for(int i = 0; i < N/2; ++i)
- {
- tSVF_init(&f->low[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
- tSVF_init(&f->high[i], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
- }
-}
-
-void tButterworth_free(tButterworth* const f)
-{
- for(int i = 0; i < f->N/2; ++i)
- {
- tSVF_free(&f->low[i]);
- tSVF_free(&f->high[i]);
- }
-}
-
-float tButterworth_tick(tButterworth* const f, float samp)
-{
- for(int i = 0; i < ((f->N)/2); ++i)
- {
- samp = tSVF_tick(&f->low[i],samp);
- samp = tSVF_tick(&f->high[i],samp);
- }
- return samp;
-}
-
-void tButterworth_setF1(tButterworth* const f, float f1)
-{
- f->f1 = f1;
- for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->low[i], f1);
-}
-
-void tButterworth_setF2(tButterworth* const f, float f2)
-{
- f->f2 = f2;
- for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->high[i], f2);
-}
-
-void tButterworth_setFreqs(tButterworth* const f, float f1, float f2)
-{
- f->f1 = f1;
- f->f2 = f2;
- for(int i = 0; i < ((f->N)/2); ++i)
- {
- tSVF_setFreq(&f->low[i], f1);
- tSVF_setFreq(&f->high[i], f2);
- }
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OneZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tOneZero_init(tOneZero* const f, float theZero)
-{
- f->gain = 1.0f;
- f->lastIn = 0.0f;
- f->lastOut = 0.0f;
- tOneZero_setZero(f, theZero);
-}
-
-void tOneZero_free(tOneZero* const f)
-{
-
-}
-
-float tOneZero_tick(tOneZero* const f, float input)
-{
- float in = input * f->gain;
- float out = f->b1 * f->lastIn + f->b0 * in;
-
- f->lastIn = in;
-
- return out;
-}
-
-void tOneZero_setZero(tOneZero* const f, float theZero)
-{
- if (theZero > 0.0f) f->b0 = 1.0f / (1.0f + theZero);
- else f->b0 = 1.0f / (1.0f - theZero);
-
- f->b1 = -theZero * f->b0;
-
-}
-
-void tOneZero_setB0(tOneZero* const f, float b0)
-{
- f->b0 = b0;
-}
-
-void tOneZero_setB1(tOneZero* const f, float b1)
-{
- f->b1 = b1;
-}
-
-void tOneZero_setCoefficients(tOneZero* const f, float b0, float b1)
-{
- f->b0 = b0;
- f->b1 = b1;
-}
-
-void tOneZero_setGain(tOneZero *f, float gain)
-{
- f->gain = gain;
-}
-
-float tOneZero_getPhaseDelay(tOneZero* const f, float frequency )
-{
- if ( frequency <= 0.0f) frequency = 0.05f;
-
- f->frequency = frequency;
-
- float omegaT = 2 * PI * frequency * leaf.invSampleRate;
- float real = 0.0, imag = 0.0;
-
- real += f->b0;
-
- real += f->b1 * cosf(omegaT);
- imag -= f->b1 * sinf(omegaT);
-
- real *= f->gain;
- imag *= f->gain;
-
- float phase = atan2f( imag, real );
-
- real = 0.0; imag = 0.0;
-
- phase -= atan2f( imag, real );
-
- phase = fmodf( -phase, 2 * PI );
-
- return phase / omegaT;
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tTwoZero_init(tTwoZero* const f)
-{
- f->gain = 1.0f;
- f->lastIn[0] = 0.0f;
- f->lastIn[1] = 0.0f;
-}
-
-void tTwoZero_free(tTwoZero* const f)
-{
-
-}
-
-float tTwoZero_tick(tTwoZero* const f, float input)
-{
- float in = input * f->gain;
- float out = f->b2 * f->lastIn[1] + f->b1 * f->lastIn[0] + f->b0 * in;
-
- f->lastIn[1] = f->lastIn[0];
- f->lastIn[0] = in;
-
- return out;
-}
-
-void tTwoZero_setNotch(tTwoZero* const f, float freq, float radius)
-{
- // Should also deal with frequency being > half sample rate / nyquist. See STK
- if (freq < 0.0f) freq = 0.0f;
- if (radius < 0.0f) radius = 0.0f;
-
- f->frequency = freq;
- f->radius = radius;
-
- f->b2 = radius * radius;
- f->b1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
-
- // Normalize the filter gain. From STK.
- if ( f->b1 > 0.0f ) // Maximum at z = 0.
- f->b0 = 1.0f / ( 1.0f + f->b1 + f->b2 );
- else // Maximum at z = -1.
- f->b0 = 1.0f / ( 1.0f - f->b1 + f->b2 );
- f->b1 *= f->b0;
- f->b2 *= f->b0;
-
-}
-
-void tTwoZero_setB0(tTwoZero* const f, float b0)
-{
- f->b0 = b0;
-}
-
-void tTwoZero_setB1(tTwoZero* const f, float b1)
-{
- f->b1 = b1;
-}
-
-void tTwoZero_setCoefficients(tTwoZero* const f, float b0, float b1, float b2)
-{
- f->b0 = b0;
- f->b1 = b1;
- f->b2 = b2;
-}
-
-void tTwoZero_setGain(tTwoZero* const f, float gain)
-{
- f->gain = gain;
-}
-
-void tTwoZeroSampleRateChanged(tTwoZero* const f)
-{
- tTwoZero_setNotch(f, f->frequency, f->radius);
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tOnePole_init(tOnePole* const f, float freq)
-{
- f->gain = 1.0f;
- f->a0 = 1.0;
-
- tOnePole_setFreq(f, freq);
-
- f->lastIn = 0.0f;
- f->lastOut = 0.0f;
-}
-
-void tOnePole_free(tOnePole* const f)
-{
-
-}
-
-void tOnePole_setB0(tOnePole* const f, float b0)
-{
- f->b0 = b0;
-}
-
-void tOnePole_setA1(tOnePole* const f, float a1)
-{
- if (a1 >= 1.0f) a1 = 0.999999f;
-
- f->a1 = a1;
-}
-
-void tOnePole_setPole(tOnePole* const f, float thePole)
-{
- if (thePole >= 1.0f) thePole = 0.999999f;
-
- // Normalize coefficients for peak unity gain.
- if (thePole > 0.0f) f->b0 = (1.0f - thePole);
- else f->b0 = (1.0f + thePole);
-
- f->a1 = -thePole;
-}
-
-void tOnePole_setFreq (tOnePole* const f, float freq)
-{
- f->b0 = freq * TWO_PI * leaf.invSampleRate;
-
- f->b0 = LEAF_clip(0.0f, f->b0, 1.0f);
-
- f->a1 = 1.0f - f->b0;
-}
-
-void tOnePole_setCoefficients(tOnePole* const f, float b0, float a1)
-{
- if (a1 >= 1.0f) a1 = 0.999999f;
-
- f->b0 = b0;
- f->a1 = a1;
-}
-
-void tOnePole_setGain(tOnePole* const f, float gain)
-{
- f->gain = gain;
-}
-
-float tOnePole_tick(tOnePole* const f, float input)
-{
- float in = input * f->gain;
- float out = (f->b0 * in) + (f->a1 * f->lastOut);
-
- f->lastIn = in;
- f->lastOut = out;
-
- return out;
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoPole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tTwoPole_init(tTwoPole* const f)
-{
- f->gain = 1.0f;
- f->a0 = 1.0;
- f->b0 = 1.0;
-
- f->lastOut[0] = 0.0f;
- f->lastOut[1] = 0.0f;
-}
-
-void tTwoPole_free(tTwoPole* const f)
-{
-
-}
-
-float tTwoPole_tick(tTwoPole* const f, float input)
-{
- float in = input * f->gain;
- float out = (f->b0 * in) - (f->a1 * f->lastOut[0]) - (f->a2 * f->lastOut[1]);
-
- f->lastOut[1] = f->lastOut[0];
- f->lastOut[0] = out;
-
- return out;
-}
-
-void tTwoPole_setB0(tTwoPole* const f, float b0)
-{
- f->b0 = b0;
-}
-
-void tTwoPole_setA1(tTwoPole* const f, float a1)
-{
- f->a1 = a1;
-}
-
-void tTwoPole_setA2(tTwoPole* const f, float a2)
-{
- f->a2 = a2;
-}
-
-
-void tTwoPole_setResonance(tTwoPole* const f, float frequency, float radius, oBool normalize)
-{
- if (frequency < 0.0f) frequency = 0.0f; // need to also handle when frequency > nyquist
- if (radius < 0.0f) radius = 0.0f;
- if (radius >= 1.0f) radius = 0.999999f;
-
- f->radius = radius;
- f->frequency = frequency;
- f->normalize = normalize;
-
- f->a2 = radius * radius;
- f->a1 = -2.0f * radius * cos(TWO_PI * frequency * leaf.invSampleRate);
-
- 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) );
- }
-}
-
-void tTwoPole_setCoefficients(tTwoPole* const f, float b0, float a1, float a2)
-{
- f->b0 = b0;
- f->a1 = a1;
- f->a2 = a2;
-}
-
-void tTwoPole_setGain(tTwoPole* const f, float gain)
-{
- f->gain = gain;
-}
-
-void tTwoPoleSampleRateChanged (tTwoPole* const f)
-{
- f->a2 = f->radius * f->radius;
- f->a1 = -2.0f * f->radius * cos(TWO_PI * f->frequency * leaf.invSampleRate);
-
- 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) );
- }
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PoleZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tPoleZero_init(tPoleZero* const f)
-{
- f->gain = 1.0f;
- f->b0 = 1.0;
- f->a0 = 1.0;
-
- f->lastIn = 0.0f;
- f->lastOut = 0.0f;
-}
-
-void tPoleZero_free(tPoleZero* const f)
-{
-
-}
-
-void tPoleZero_setB0(tPoleZero* const pzf, float b0)
-{
- pzf->b0 = b0;
-}
-
-void tPoleZero_setB1(tPoleZero* const pzf, float b1)
-{
- pzf->b1 = b1;
-}
-
-void tPoleZero_setA1(tPoleZero* const pzf, float a1)
-{
- if (a1 >= 1.0f) // a1 should be less than 1.0
- {
- a1 = 0.999999f;
- }
-
- pzf->a1 = a1;
-}
-
-void tPoleZero_setCoefficients(tPoleZero* const pzf, float b0, float b1, float a1)
-{
- if (a1 >= 1.0f) // a1 should be less than 1.0
- {
- a1 = 0.999999f;
- }
-
- pzf->b0 = b0;
- pzf->b1 = b1;
- pzf->a1 = a1;
-}
-
-void tPoleZero_setAllpass(tPoleZero* const pzf, float coeff)
-{
- if (coeff >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
- {
- coeff = 0.999999f;
- }
-
- pzf->b0 = coeff;
- pzf->b1 = 1.0f;
- pzf->a0 = 1.0f;
- pzf->a1 = coeff;
-}
-
-void tPoleZero_setBlockZero(tPoleZero* const pzf, float thePole)
-{
- if (thePole >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
- {
- thePole = 0.999999f;
- }
-
- pzf->b0 = 1.0f;
- pzf->b1 = -1.0f;
- pzf->a0 = 1.0f;
- pzf->a1 = -thePole;
-}
-
-void tPoleZero_setGain(tPoleZero* const pzf, float gain)
-{
- pzf->gain = gain;
-}
-
-float tPoleZero_tick(tPoleZero* const pzf, float input)
-{
- float in = input * pzf->gain;
- float out = (pzf->b0 * in) + (pzf->b1 * pzf->lastIn) - (pzf->a1 * pzf->lastOut);
-
- pzf->lastIn = in;
- pzf->lastOut = out;
-
- return out;
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ BiQuad Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tBiQuad_init(tBiQuad* const f)
-{
- f->gain = 1.0f;
-
- f->b0 = 0.0f;
- f->a0 = 0.0f;
-
- f->lastIn[0] = 0.0f;
- f->lastIn[1] = 0.0f;
- f->lastOut[0] = 0.0f;
- f->lastOut[1] = 0.0f;
-}
-
-void tBiQuad_free(tBiQuad* const f)
-{
-
-}
-
-float tBiQuad_tick(tBiQuad* const f, float input)
-{
- float in = input * f->gain;
- float out = f->b0 * in + f->b1 * f->lastIn[0] + f->b2 * f->lastIn[1];
- out -= f->a2 * f->lastOut[1] + f->a1 * f->lastOut[0];
-
- f->lastIn[1] = f->lastIn[0];
- f->lastIn[0] = in;
-
- f->lastOut[1] = f->lastOut[0];
- f->lastOut[0] = out;
-
- return out;
-}
-
-void tBiQuad_setResonance(tBiQuad* const f, float freq, float radius, oBool normalize)
-{
- // Should also deal with frequency being > half sample rate / nyquist. See STK
- if (freq < 0.0f) freq = 0.0f;
- if (radius < 0.0f) radius = 0.0f;
- if (radius >= 1.0f) radius = 1.0f;
-
- f->frequency = freq;
- f->radius = radius;
- f->normalize = normalize;
-
- f->a2 = radius * radius;
- f->a1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate);
-
- if (normalize)
- {
- f->b0 = 0.5f - 0.5f * f->a2;
- f->b1 = 0.0f;
- f->b2 = -f->b0;
- }
-}
-
-void tBiQuad_setNotch(tBiQuad* const f, float freq, float radius)
-{
- // Should also deal with frequency being > half sample rate / nyquist. See STK
- if (freq < 0.0f) freq = 0.0f;
- 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
-
- // Does not attempt to normalize filter gain.
-}
-
-void tBiQuad_setEqualGainZeros(tBiQuad* const f)
-{
- f->b0 = 1.0f;
- f->b1 = 0.0f;
- f->b2 = -1.0f;
-}
-
-void tBiQuad_setB0(tBiQuad* const f, float b0)
-{
- f->b0 = b0;
-}
-
-void tBiQuad_setB1(tBiQuad* const f, float b1)
-{
- f->b1 = b1;
-}
-
-void tBiQuad_setB2(tBiQuad* const f, float b2)
-{
- f->b2 = b2;
-}
-
-void tBiQuad_setA1(tBiQuad* const f, float a1)
-{
- f->a1 = a1;
-}
-
-void tBiQuad_setA2(tBiQuad* const f, float a2)
-{
- f->a2 = a2;
-}
-
-void tBiQuad_setCoefficients(tBiQuad* const f, float b0, float b1, float b2, float a1, float a2)
-{
- f->b0 = b0;
- f->b1 = b1;
- f->b2 = b2;
- f->a1 = a1;
- f->a2 = a2;
-}
-
-void tBiQuad_setGain(tBiQuad* const f, float gain)
-{
- f->gain = gain;
-}
-
-void tBiQuadSampleRateChanged(tBiQuad* const f)
-{
- f->a2 = f->radius * f->radius;
- f->a1 = -2.0f * f->radius * cosf(TWO_PI * f->frequency * leaf.invSampleRate);
-
- if (f->normalize)
- {
- f->b0 = 0.5f - 0.5f * f->a2;
- f->b1 = 0.0f;
- f->b2 = -f->b0;
- }
-}
-
-/* Highpass */
-void tHighpass_init(tHighpass* const f, float freq)
-{
- f->R = (1.0f-((freq * 2.0f * 3.14f)* leaf.invSampleRate));
- f->ys = 0.0f;
- f->xs = 0.0f;
-
- f->frequency = freq;
-}
-
-void tHighpass_free(tHighpass* const f)
-{
-
-}
-
-void tHighpass_setFreq(tHighpass* const f, float freq)
-{
- f->frequency = freq;
- f->R = (1.0f-((freq * 2.0f * 3.14f) * leaf.invSampleRate));
-
-}
-
-float tHighpass_getFreq(tHighpass* const f)
-{
- return f->frequency;
-}
-
-// From JOS DC Blocker
-float tHighpass_tick(tHighpass* const f, float x)
-{
- f->ys = x - f->xs + f->R * f->ys;
- f->xs = x;
- return f->ys;
-}
-
-void tHighpassSampleRateChanged(tHighpass* const f)
-{
- f->R = (1.0f-((f->frequency * 2.0f * 3.14f) * leaf.invSampleRate));
-}
-
-float tSVF_tick(tSVF* const svf, float v0)
-{
- float v1,v2,v3;
- v3 = v0 - svf->ic2eq;
- v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
- v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
- svf->ic1eq = (2.0f * v1) - svf->ic1eq;
- svf->ic2eq = (2.0f * v2) - svf->ic2eq;
-
- if (svf->type == SVFTypeLowpass) return v2;
- else if (svf->type == SVFTypeBandpass) return v1;
- else if (svf->type == SVFTypeHighpass) return v0 - (svf->k * v1) - v2;
- else if (svf->type == SVFTypeNotch) return v0 - (svf->k * v1);
- else if (svf->type == SVFTypePeak) return v0 - (svf->k * v1) - (2.0f * v2);
- else return 0.0f;
-
-}
-
-// Less efficient, more accurate version of SVF, in which cutoff frequency is taken as floating point Hz value and tanh
-// is calculated when frequency changes.
-void tSVF_init(tSVF* const svf, SVFType type, float freq, float Q)
-{
- svf->type = type;
-
- svf->ic1eq = 0;
- 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;
-}
-
-void tSVF_free(tSVF* const svf)
-{
-
-}
-
-int tSVF_setFreq(tSVF* const svf, float freq)
-{
- svf->g = tanf(PI * freq * leaf.invSampleRate);
- svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
- svf->a2 = svf->g * svf->a1;
- svf->a3 = svf->g * svf->a2;
-
- return 0;
-}
-
-int tSVF_setQ(tSVF* const svf, float Q)
-{
- svf->k = 1.0f/Q;
- svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
- svf->a2 = svf->g * svf->a1;
- svf->a3 = svf->g * svf->a2;
-
- return 0;
-}
-
-// Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable.
-void tSVFE_init(tSVFE* const svf, SVFType type, uint16_t input, float Q)
-{
- svf->type = type;
-
- svf->ic1eq = 0;
- 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;
-}
-
-void tSVFE_free(tSVFE* const svf)
-{
-
-}
-
-float tSVFE_tick(tSVFE* const svf, float v0)
-{
- float v1,v2,v3;
- v3 = v0 - svf->ic2eq;
- v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
- v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
- svf->ic1eq = (2.0f * v1) - svf->ic1eq;
- svf->ic2eq = (2.0f * v2) - svf->ic2eq;
-
- if (svf->type == SVFTypeLowpass) return v2;
- else if (svf->type == SVFTypeBandpass) return v1;
- else if (svf->type == SVFTypeHighpass) return v0 - (svf->k * v1) - v2;
- else if (svf->type == SVFTypeNotch) return v0 - (svf->k * v1);
- else if (svf->type == SVFTypePeak) return v0 - (svf->k * v1) - (2.0f * v2);
- else return 0.0f;
-
-}
-
-int tSVFE_setFreq(tSVFE* const svf, uint16_t input)
-{
- svf->g = filtertan[input];
- svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
- svf->a2 = svf->g * svf->a1;
- svf->a3 = svf->g * svf->a2;
-
- return 0;
-}
-
-int tSVFE_setQ(tSVFE* const svf, float Q)
-{
- svf->k = 1.0f/Q;
- svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
- svf->a2 = svf->g * svf->a1;
- svf->a3 = svf->g * svf->a2;
-
- return 0;
-}
-
-void tFIR_init(tFIR* const fir, float* coeffs, int numTaps){
- fir->numTaps = numTaps;
- fir->coeff = coeffs;
- fir->past = (float*)leaf_alloc(sizeof(float) * fir->numTaps);
- for (int i = 0; i < fir->numTaps; ++i) fir->past[i] = 0.0f;
-}
-
-float tFIR_tick(tFIR* const fir, float input){
- fir->past[0] = input;
- float y = 0.0f;
- for (int i = 0; i < fir->numTaps; ++i) y += fir->past[i]*fir->coeff[i];
- for (int i = fir->numTaps-1; i > 0; --i) fir->past[i] = fir->past[i-1];
- return y;
-}
-
-void tFIR_free(tFIR* const fir)
-{
- leaf_free(fir->past);
-}
--- /dev/null
+++ b/LEAF/Src/leaf-filters.c
@@ -1,0 +1,843 @@
+/*==============================================================================
+
+ leaf-filter.c
+ Created: 20 Jan 2017 12:01:10pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-filters.h"
+#include "..\Inc\leaf-tables.h"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-filters.h"
+#include "../Inc/leaf-tables.h"
+#include "../leaf.h"
+
+#endif
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tAllpass_init(tAllpass* const f, float initDelay, uint32_t maxDelay)
+{
+ f->gain = 0.7f;
+
+ f->lastOut = 0.0f;
+
+ tLinearDelay_init(&f->delay, initDelay, maxDelay);
+}
+
+void tAllpass_free(tAllpass* const f)
+{
+ tLinearDelay_free(&f->delay);
+}
+
+void tAllpass_setDelay(tAllpass* const f, float delay)
+{
+ tLinearDelay_setDelay(&f->delay, delay);
+}
+
+void tAllpass_setGain(tAllpass* const f, float gain)
+{
+ f->gain = gain;
+}
+
+float tAllpass_tick(tAllpass* const f, float input)
+{
+ float s1 = (-f->gain) * f->lastOut + input;
+
+ float s2 = tLinearDelay_tick(&f->delay, s1) + (f->gain) * input;
+
+ f->lastOut = s2;
+
+ return f->lastOut;
+}
+
+void tButterworth_init(tButterworth* const f, int N, float f1, float f2)
+{
+ f->f1 = f1;
+ f->f2 = f2;
+ f->gain = 1.0f;
+
+ f->N = N;
+
+ if (f->N > NUM_SVF_BW) f->N = NUM_SVF_BW;
+
+ for(int i = 0; i < N/2; ++i)
+ {
+ tSVF_init(&f->low[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
+ tSVF_init(&f->high[i], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)));
+ }
+}
+
+void tButterworth_free(tButterworth* const f)
+{
+ for(int i = 0; i < f->N/2; ++i)
+ {
+ tSVF_free(&f->low[i]);
+ tSVF_free(&f->high[i]);
+ }
+}
+
+float tButterworth_tick(tButterworth* const f, float samp)
+{
+ for(int i = 0; i < ((f->N)/2); ++i)
+ {
+ samp = tSVF_tick(&f->low[i],samp);
+ samp = tSVF_tick(&f->high[i],samp);
+ }
+ return samp;
+}
+
+void tButterworth_setF1(tButterworth* const f, float f1)
+{
+ f->f1 = f1;
+ for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->low[i], f1);
+}
+
+void tButterworth_setF2(tButterworth* const f, float f2)
+{
+ f->f2 = f2;
+ for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->high[i], f2);
+}
+
+void tButterworth_setFreqs(tButterworth* const f, float f1, float f2)
+{
+ f->f1 = f1;
+ f->f2 = f2;
+ for(int i = 0; i < ((f->N)/2); ++i)
+ {
+ tSVF_setFreq(&f->low[i], f1);
+ tSVF_setFreq(&f->high[i], f2);
+ }
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OneZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tOneZero_init(tOneZero* const f, float theZero)
+{
+ f->gain = 1.0f;
+ f->lastIn = 0.0f;
+ f->lastOut = 0.0f;
+ tOneZero_setZero(f, theZero);
+}
+
+void tOneZero_free(tOneZero* const f)
+{
+
+}
+
+float tOneZero_tick(tOneZero* const f, float input)
+{
+ float in = input * f->gain;
+ float out = f->b1 * f->lastIn + f->b0 * in;
+
+ f->lastIn = in;
+
+ return out;
+}
+
+void tOneZero_setZero(tOneZero* const f, float theZero)
+{
+ if (theZero > 0.0f) f->b0 = 1.0f / (1.0f + theZero);
+ else f->b0 = 1.0f / (1.0f - theZero);
+
+ f->b1 = -theZero * f->b0;
+
+}
+
+void tOneZero_setB0(tOneZero* const f, float b0)
+{
+ f->b0 = b0;
+}
+
+void tOneZero_setB1(tOneZero* const f, float b1)
+{
+ f->b1 = b1;
+}
+
+void tOneZero_setCoefficients(tOneZero* const f, float b0, float b1)
+{
+ f->b0 = b0;
+ f->b1 = b1;
+}
+
+void tOneZero_setGain(tOneZero *f, float gain)
+{
+ f->gain = gain;
+}
+
+float tOneZero_getPhaseDelay(tOneZero* const f, float frequency )
+{
+ if ( frequency <= 0.0f) frequency = 0.05f;
+
+ f->frequency = frequency;
+
+ float omegaT = 2 * PI * frequency * leaf.invSampleRate;
+ float real = 0.0, imag = 0.0;
+
+ real += f->b0;
+
+ real += f->b1 * cosf(omegaT);
+ imag -= f->b1 * sinf(omegaT);
+
+ real *= f->gain;
+ imag *= f->gain;
+
+ float phase = atan2f( imag, real );
+
+ real = 0.0; imag = 0.0;
+
+ phase -= atan2f( imag, real );
+
+ phase = fmodf( -phase, 2 * PI );
+
+ return phase / omegaT;
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tTwoZero_init(tTwoZero* const f)
+{
+ f->gain = 1.0f;
+ f->lastIn[0] = 0.0f;
+ f->lastIn[1] = 0.0f;
+}
+
+void tTwoZero_free(tTwoZero* const f)
+{
+
+}
+
+float tTwoZero_tick(tTwoZero* const f, float input)
+{
+ float in = input * f->gain;
+ float out = f->b2 * f->lastIn[1] + f->b1 * f->lastIn[0] + f->b0 * in;
+
+ f->lastIn[1] = f->lastIn[0];
+ f->lastIn[0] = in;
+
+ return out;
+}
+
+void tTwoZero_setNotch(tTwoZero* const f, float freq, float radius)
+{
+ // Should also deal with frequency being > half sample rate / nyquist. See STK
+ if (freq < 0.0f) freq = 0.0f;
+ if (radius < 0.0f) radius = 0.0f;
+
+ f->frequency = freq;
+ f->radius = radius;
+
+ f->b2 = radius * radius;
+ f->b1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate); // OPTIMIZE with LOOKUP or APPROXIMATION
+
+ // Normalize the filter gain. From STK.
+ if ( f->b1 > 0.0f ) // Maximum at z = 0.
+ f->b0 = 1.0f / ( 1.0f + f->b1 + f->b2 );
+ else // Maximum at z = -1.
+ f->b0 = 1.0f / ( 1.0f - f->b1 + f->b2 );
+ f->b1 *= f->b0;
+ f->b2 *= f->b0;
+
+}
+
+void tTwoZero_setB0(tTwoZero* const f, float b0)
+{
+ f->b0 = b0;
+}
+
+void tTwoZero_setB1(tTwoZero* const f, float b1)
+{
+ f->b1 = b1;
+}
+
+void tTwoZero_setCoefficients(tTwoZero* const f, float b0, float b1, float b2)
+{
+ f->b0 = b0;
+ f->b1 = b1;
+ f->b2 = b2;
+}
+
+void tTwoZero_setGain(tTwoZero* const f, float gain)
+{
+ f->gain = gain;
+}
+
+void tTwoZeroSampleRateChanged(tTwoZero* const f)
+{
+ tTwoZero_setNotch(f, f->frequency, f->radius);
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ OnePole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tOnePole_init(tOnePole* const f, float freq)
+{
+ f->gain = 1.0f;
+ f->a0 = 1.0;
+
+ tOnePole_setFreq(f, freq);
+
+ f->lastIn = 0.0f;
+ f->lastOut = 0.0f;
+}
+
+void tOnePole_free(tOnePole* const f)
+{
+
+}
+
+void tOnePole_setB0(tOnePole* const f, float b0)
+{
+ f->b0 = b0;
+}
+
+void tOnePole_setA1(tOnePole* const f, float a1)
+{
+ if (a1 >= 1.0f) a1 = 0.999999f;
+
+ f->a1 = a1;
+}
+
+void tOnePole_setPole(tOnePole* const f, float thePole)
+{
+ if (thePole >= 1.0f) thePole = 0.999999f;
+
+ // Normalize coefficients for peak unity gain.
+ if (thePole > 0.0f) f->b0 = (1.0f - thePole);
+ else f->b0 = (1.0f + thePole);
+
+ f->a1 = -thePole;
+}
+
+void tOnePole_setFreq (tOnePole* const f, float freq)
+{
+ f->b0 = freq * TWO_PI * leaf.invSampleRate;
+
+ f->b0 = LEAF_clip(0.0f, f->b0, 1.0f);
+
+ f->a1 = 1.0f - f->b0;
+}
+
+void tOnePole_setCoefficients(tOnePole* const f, float b0, float a1)
+{
+ if (a1 >= 1.0f) a1 = 0.999999f;
+
+ f->b0 = b0;
+ f->a1 = a1;
+}
+
+void tOnePole_setGain(tOnePole* const f, float gain)
+{
+ f->gain = gain;
+}
+
+float tOnePole_tick(tOnePole* const f, float input)
+{
+ float in = input * f->gain;
+ float out = (f->b0 * in) + (f->a1 * f->lastOut);
+
+ f->lastIn = in;
+ f->lastOut = out;
+
+ return out;
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ TwoPole Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tTwoPole_init(tTwoPole* const f)
+{
+ f->gain = 1.0f;
+ f->a0 = 1.0;
+ f->b0 = 1.0;
+
+ f->lastOut[0] = 0.0f;
+ f->lastOut[1] = 0.0f;
+}
+
+void tTwoPole_free(tTwoPole* const f)
+{
+
+}
+
+float tTwoPole_tick(tTwoPole* const f, float input)
+{
+ float in = input * f->gain;
+ float out = (f->b0 * in) - (f->a1 * f->lastOut[0]) - (f->a2 * f->lastOut[1]);
+
+ f->lastOut[1] = f->lastOut[0];
+ f->lastOut[0] = out;
+
+ return out;
+}
+
+void tTwoPole_setB0(tTwoPole* const f, float b0)
+{
+ f->b0 = b0;
+}
+
+void tTwoPole_setA1(tTwoPole* const f, float a1)
+{
+ f->a1 = a1;
+}
+
+void tTwoPole_setA2(tTwoPole* const f, float a2)
+{
+ f->a2 = a2;
+}
+
+
+void tTwoPole_setResonance(tTwoPole* const f, float frequency, float radius, oBool normalize)
+{
+ if (frequency < 0.0f) frequency = 0.0f; // need to also handle when frequency > nyquist
+ if (radius < 0.0f) radius = 0.0f;
+ if (radius >= 1.0f) radius = 0.999999f;
+
+ f->radius = radius;
+ f->frequency = frequency;
+ f->normalize = normalize;
+
+ f->a2 = radius * radius;
+ f->a1 = -2.0f * radius * cos(TWO_PI * frequency * leaf.invSampleRate);
+
+ 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) );
+ }
+}
+
+void tTwoPole_setCoefficients(tTwoPole* const f, float b0, float a1, float a2)
+{
+ f->b0 = b0;
+ f->a1 = a1;
+ f->a2 = a2;
+}
+
+void tTwoPole_setGain(tTwoPole* const f, float gain)
+{
+ f->gain = gain;
+}
+
+void tTwoPoleSampleRateChanged (tTwoPole* const f)
+{
+ f->a2 = f->radius * f->radius;
+ f->a1 = -2.0f * f->radius * cos(TWO_PI * f->frequency * leaf.invSampleRate);
+
+ 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) );
+ }
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PoleZero Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tPoleZero_init(tPoleZero* const f)
+{
+ f->gain = 1.0f;
+ f->b0 = 1.0;
+ f->a0 = 1.0;
+
+ f->lastIn = 0.0f;
+ f->lastOut = 0.0f;
+}
+
+void tPoleZero_free(tPoleZero* const f)
+{
+
+}
+
+void tPoleZero_setB0(tPoleZero* const pzf, float b0)
+{
+ pzf->b0 = b0;
+}
+
+void tPoleZero_setB1(tPoleZero* const pzf, float b1)
+{
+ pzf->b1 = b1;
+}
+
+void tPoleZero_setA1(tPoleZero* const pzf, float a1)
+{
+ if (a1 >= 1.0f) // a1 should be less than 1.0
+ {
+ a1 = 0.999999f;
+ }
+
+ pzf->a1 = a1;
+}
+
+void tPoleZero_setCoefficients(tPoleZero* const pzf, float b0, float b1, float a1)
+{
+ if (a1 >= 1.0f) // a1 should be less than 1.0
+ {
+ a1 = 0.999999f;
+ }
+
+ pzf->b0 = b0;
+ pzf->b1 = b1;
+ pzf->a1 = a1;
+}
+
+void tPoleZero_setAllpass(tPoleZero* const pzf, float coeff)
+{
+ if (coeff >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
+ {
+ coeff = 0.999999f;
+ }
+
+ pzf->b0 = coeff;
+ pzf->b1 = 1.0f;
+ pzf->a0 = 1.0f;
+ pzf->a1 = coeff;
+}
+
+void tPoleZero_setBlockZero(tPoleZero* const pzf, float thePole)
+{
+ if (thePole >= 1.0f) // allpass coefficient >= 1.0 makes filter unstable
+ {
+ thePole = 0.999999f;
+ }
+
+ pzf->b0 = 1.0f;
+ pzf->b1 = -1.0f;
+ pzf->a0 = 1.0f;
+ pzf->a1 = -thePole;
+}
+
+void tPoleZero_setGain(tPoleZero* const pzf, float gain)
+{
+ pzf->gain = gain;
+}
+
+float tPoleZero_tick(tPoleZero* const pzf, float input)
+{
+ float in = input * pzf->gain;
+ float out = (pzf->b0 * in) + (pzf->b1 * pzf->lastIn) - (pzf->a1 * pzf->lastOut);
+
+ pzf->lastIn = in;
+ pzf->lastOut = out;
+
+ return out;
+}
+
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ BiQuad Filter ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tBiQuad_init(tBiQuad* const f)
+{
+ f->gain = 1.0f;
+
+ f->b0 = 0.0f;
+ f->a0 = 0.0f;
+
+ f->lastIn[0] = 0.0f;
+ f->lastIn[1] = 0.0f;
+ f->lastOut[0] = 0.0f;
+ f->lastOut[1] = 0.0f;
+}
+
+void tBiQuad_free(tBiQuad* const f)
+{
+
+}
+
+float tBiQuad_tick(tBiQuad* const f, float input)
+{
+ float in = input * f->gain;
+ float out = f->b0 * in + f->b1 * f->lastIn[0] + f->b2 * f->lastIn[1];
+ out -= f->a2 * f->lastOut[1] + f->a1 * f->lastOut[0];
+
+ f->lastIn[1] = f->lastIn[0];
+ f->lastIn[0] = in;
+
+ f->lastOut[1] = f->lastOut[0];
+ f->lastOut[0] = out;
+
+ return out;
+}
+
+void tBiQuad_setResonance(tBiQuad* const f, float freq, float radius, oBool normalize)
+{
+ // Should also deal with frequency being > half sample rate / nyquist. See STK
+ if (freq < 0.0f) freq = 0.0f;
+ if (radius < 0.0f) radius = 0.0f;
+ if (radius >= 1.0f) radius = 1.0f;
+
+ f->frequency = freq;
+ f->radius = radius;
+ f->normalize = normalize;
+
+ f->a2 = radius * radius;
+ f->a1 = -2.0f * radius * cosf(TWO_PI * freq * leaf.invSampleRate);
+
+ if (normalize)
+ {
+ f->b0 = 0.5f - 0.5f * f->a2;
+ f->b1 = 0.0f;
+ f->b2 = -f->b0;
+ }
+}
+
+void tBiQuad_setNotch(tBiQuad* const f, float freq, float radius)
+{
+ // Should also deal with frequency being > half sample rate / nyquist. See STK
+ if (freq < 0.0f) freq = 0.0f;
+ 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
+
+ // Does not attempt to normalize filter gain.
+}
+
+void tBiQuad_setEqualGainZeros(tBiQuad* const f)
+{
+ f->b0 = 1.0f;
+ f->b1 = 0.0f;
+ f->b2 = -1.0f;
+}
+
+void tBiQuad_setB0(tBiQuad* const f, float b0)
+{
+ f->b0 = b0;
+}
+
+void tBiQuad_setB1(tBiQuad* const f, float b1)
+{
+ f->b1 = b1;
+}
+
+void tBiQuad_setB2(tBiQuad* const f, float b2)
+{
+ f->b2 = b2;
+}
+
+void tBiQuad_setA1(tBiQuad* const f, float a1)
+{
+ f->a1 = a1;
+}
+
+void tBiQuad_setA2(tBiQuad* const f, float a2)
+{
+ f->a2 = a2;
+}
+
+void tBiQuad_setCoefficients(tBiQuad* const f, float b0, float b1, float b2, float a1, float a2)
+{
+ f->b0 = b0;
+ f->b1 = b1;
+ f->b2 = b2;
+ f->a1 = a1;
+ f->a2 = a2;
+}
+
+void tBiQuad_setGain(tBiQuad* const f, float gain)
+{
+ f->gain = gain;
+}
+
+void tBiQuadSampleRateChanged(tBiQuad* const f)
+{
+ f->a2 = f->radius * f->radius;
+ f->a1 = -2.0f * f->radius * cosf(TWO_PI * f->frequency * leaf.invSampleRate);
+
+ if (f->normalize)
+ {
+ f->b0 = 0.5f - 0.5f * f->a2;
+ f->b1 = 0.0f;
+ f->b2 = -f->b0;
+ }
+}
+
+/* Highpass */
+void tHighpass_init(tHighpass* const f, float freq)
+{
+ f->R = (1.0f-((freq * 2.0f * 3.14f)* leaf.invSampleRate));
+ f->ys = 0.0f;
+ f->xs = 0.0f;
+
+ f->frequency = freq;
+}
+
+void tHighpass_free(tHighpass* const f)
+{
+
+}
+
+void tHighpass_setFreq(tHighpass* const f, float freq)
+{
+ f->frequency = freq;
+ f->R = (1.0f-((freq * 2.0f * 3.14f) * leaf.invSampleRate));
+
+}
+
+float tHighpass_getFreq(tHighpass* const f)
+{
+ return f->frequency;
+}
+
+// From JOS DC Blocker
+float tHighpass_tick(tHighpass* const f, float x)
+{
+ f->ys = x - f->xs + f->R * f->ys;
+ f->xs = x;
+ return f->ys;
+}
+
+void tHighpassSampleRateChanged(tHighpass* const f)
+{
+ f->R = (1.0f-((f->frequency * 2.0f * 3.14f) * leaf.invSampleRate));
+}
+
+float tSVF_tick(tSVF* const svf, float v0)
+{
+ float v1,v2,v3;
+ v3 = v0 - svf->ic2eq;
+ v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
+ v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
+ svf->ic1eq = (2.0f * v1) - svf->ic1eq;
+ svf->ic2eq = (2.0f * v2) - svf->ic2eq;
+
+ if (svf->type == SVFTypeLowpass) return v2;
+ else if (svf->type == SVFTypeBandpass) return v1;
+ else if (svf->type == SVFTypeHighpass) return v0 - (svf->k * v1) - v2;
+ else if (svf->type == SVFTypeNotch) return v0 - (svf->k * v1);
+ else if (svf->type == SVFTypePeak) return v0 - (svf->k * v1) - (2.0f * v2);
+ else return 0.0f;
+
+}
+
+// Less efficient, more accurate version of SVF, in which cutoff frequency is taken as floating point Hz value and tanh
+// is calculated when frequency changes.
+void tSVF_init(tSVF* const svf, SVFType type, float freq, float Q)
+{
+ svf->type = type;
+
+ svf->ic1eq = 0;
+ 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;
+}
+
+void tSVF_free(tSVF* const svf)
+{
+
+}
+
+int tSVF_setFreq(tSVF* const svf, float freq)
+{
+ svf->g = tanf(PI * freq * leaf.invSampleRate);
+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+ svf->a2 = svf->g * svf->a1;
+ svf->a3 = svf->g * svf->a2;
+
+ return 0;
+}
+
+int tSVF_setQ(tSVF* const svf, float Q)
+{
+ svf->k = 1.0f/Q;
+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+ svf->a2 = svf->g * svf->a1;
+ svf->a3 = svf->g * svf->a2;
+
+ return 0;
+}
+
+// Efficient version of tSVF where frequency is set based on 12-bit integer input for lookup in tanh wavetable.
+void tEfficientSVF_init(tEfficientSVF* const svf, SVFType type, uint16_t input, float Q)
+{
+ svf->type = type;
+
+ svf->ic1eq = 0;
+ 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;
+}
+
+void tEfficientSVF_free(tEfficientSVF* const svf)
+{
+
+}
+
+float tEfficientSVF_tick(tEfficientSVF* const svf, float v0)
+{
+ float v1,v2,v3;
+ v3 = v0 - svf->ic2eq;
+ v1 = (svf->a1 * svf->ic1eq) + (svf->a2 * v3);
+ v2 = svf->ic2eq + (svf->a2 * svf->ic1eq) + (svf->a3 * v3);
+ svf->ic1eq = (2.0f * v1) - svf->ic1eq;
+ svf->ic2eq = (2.0f * v2) - svf->ic2eq;
+
+ if (svf->type == SVFTypeLowpass) return v2;
+ else if (svf->type == SVFTypeBandpass) return v1;
+ else if (svf->type == SVFTypeHighpass) return v0 - (svf->k * v1) - v2;
+ else if (svf->type == SVFTypeNotch) return v0 - (svf->k * v1);
+ else if (svf->type == SVFTypePeak) return v0 - (svf->k * v1) - (2.0f * v2);
+ else return 0.0f;
+
+}
+
+int tEfficientSVF_setFreq(tEfficientSVF* const svf, uint16_t input)
+{
+ svf->g = filtertan[input];
+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+ svf->a2 = svf->g * svf->a1;
+ svf->a3 = svf->g * svf->a2;
+
+ return 0;
+}
+
+int tEfficientSVF_setQ(tEfficientSVF* const svf, float Q)
+{
+ svf->k = 1.0f/Q;
+ svf->a1 = 1.0f/(1.0f + svf->g * (svf->g + svf->k));
+ svf->a2 = svf->g * svf->a1;
+ svf->a3 = svf->g * svf->a2;
+
+ return 0;
+}
+
+void tFIR_init(tFIR* const fir, float* coeffs, int numTaps){
+ fir->numTaps = numTaps;
+ fir->coeff = coeffs;
+ fir->past = (float*)leaf_alloc(sizeof(float) * fir->numTaps);
+ for (int i = 0; i < fir->numTaps; ++i) fir->past[i] = 0.0f;
+}
+
+float tFIR_tick(tFIR* const fir, float input){
+ fir->past[0] = input;
+ float y = 0.0f;
+ for (int i = 0; i < fir->numTaps; ++i) y += fir->past[i]*fir->coeff[i];
+ for (int i = fir->numTaps-1; i > 0; --i) fir->past[i] = fir->past[i-1];
+ return y;
+}
+
+void tFIR_free(tFIR* const fir)
+{
+ leaf_free(fir->past);
+}
--- a/LEAF/Src/leaf-formant.c
+++ /dev/null
@@ -1,206 +1,0 @@
-/*==============================================================================
-
- leaf-formant.c
- Created: 30 Nov 2018 11:03:30am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-formant.h"
-#else
-
-#include "../Inc/leaf-formant.h"
-
-#endif
-
-
-void tFormantShifter_init(tFormantShifter* const fs, int bufsize, int order)
-{
- fs->ford = order;
- fs->bufsize = bufsize;
- fs->fk = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->fb = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->fc = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->frb = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->frc = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->fsig = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->fsmooth = (float*) leaf_alloc(sizeof(float) * fs->ford);
- fs->ftvec = (float*) leaf_alloc(sizeof(float) * fs->ford);
-
- fs->fbuff = (float**) leaf_alloc(sizeof(float*) * fs->ford);
- for (int i = 0; i < fs->ford; i++)
- {
- fs->fbuff[i] = (float*) leaf_alloc(sizeof(float) * fs->bufsize);
- }
-
-
- fs->falph = powf(0.001f, 80.0f / (leaf.sampleRate));
- fs->flamb = -(0.8517f*sqrt(atanf(0.06583f*leaf.sampleRate))-0.1916f);
- fs->fhp = 0.0f;
- fs->flp = 0.0f;
- fs->flpa = powf(0.001f, 10.0f / (leaf.sampleRate));
- fs->fmute = 1.0f;
- fs->fmutealph = powf(0.001f, 1.0f / (leaf.sampleRate));
- fs->cbi = 0;
-}
-
-void tFormantShifter_free(tFormantShifter* const fs)
-{
- leaf_free(fs->fk);
- leaf_free(fs->fb);
- leaf_free(fs->fc);
- leaf_free(fs->frb);
- leaf_free(fs->frc);
- leaf_free(fs->fsig);
- leaf_free(fs->fsmooth);
- leaf_free(fs->ftvec);
- for (int i = 0; i < fs->ford; i++)
- {
- leaf_free(fs->fbuff[i]);
- }
- leaf_free(fs->fbuff);
-}
-
-
-float tFormantShifter_tick(tFormantShifter* fs, float in, float fwarp)
-{
- return tFormantShifter_add(fs, tFormantShifter_remove(fs, in), fwarp);
-}
-
-float tFormantShifter_remove(tFormantShifter* fs, float in)
-{
- float fa, fb, fc, foma, falph, ford, flpa, flamb, tf, fk;
- int ti4;
- ford = fs->ford;
- falph = fs->falph;
- foma = (1.0f - falph);
- flpa = fs->flpa;
- flamb = fs->flamb;
-
- tf = in;
- ti4 = fs->cbi;
-
- fa = tf - fs->fhp;
- fs->fhp = tf;
- fb = fa;
- for(int i = 0; i < ford; i++)
- {
- fs->fsig[i] = fa*fa*foma + fs->fsig[i]*falph;
- fc = (fb - fs->fc[i])*flamb + fs->fb[i];
- fs->fc[i] = fc;
- fs->fb[i] = fb;
- fk = fa*fc*foma + fs->fk[i]*falph;
- fs->fk[i] = fk;
- tf = fk/(fs->fsig[i] + 0.000001f);
- tf = tf*foma + fs->fsmooth[i]*falph;
- fs->fsmooth[i] = tf;
- fs->fbuff[i][ti4] = tf;
- fb = fc - tf*fa;
- fa = fa - tf*fc;
- }
- fs->cbi++;
- if(fs->cbi >= fs->bufsize)
- {
- fs->cbi = 0;
- }
-
- return fa;
-}
-
-float tFormantShifter_add(tFormantShifter* fs, float in, float fwarp)
-{
- float fa, fb, fc, foma, 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 = exp2(fwarp/2.0f) * (1+flamb)/(1-flamb);
- frlamb = (tf-1)/(tf+1);
- ti4 = fs->cbi;
-
- tf2 = in;
- fa = 0;
- fb = fa;
- for (int i=0; i<ford; i++)
- {
- fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
- tf = fs->fbuff[i][ti4];
- fb = fc - tf*fa;
- fs->ftvec[i] = tf*fc;
- fa = fa - fs->ftvec[i];
- }
- tf = -fa;
- for (int i=ford-1; i>=0; i--)
- {
- tf = tf + fs->ftvec[i];
- }
- f0resp = tf;
-
- // second time: compute 1-response
- fa = 1;
- fb = fa;
- for (int i=0; i<ford; i++)
- {
- fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
- tf = fs->fbuff[i][ti4];
- fb = fc - tf*fa;
- fs->ftvec[i] = tf*fc;
- fa = fa - fs->ftvec[i];
- }
- tf = -fa;
- for (int i=ford-1; i>=0; i--)
- {
- tf = tf + fs->ftvec[i];
- }
- f1resp = tf;
-
- // now solve equations for output, based on 0-response and 1-response
- tf = (float)2*tf2;
- tf2 = tf;
- tf = ((float)1 - f1resp + f0resp);
- if (tf!=0)
- {
- tf2 = (tf2 + f0resp) / tf;
- }
- else
- {
- tf2 = 0;
- }
-
- // third time: update delay registers
- fa = tf2;
- fb = fa;
- for (int i=0; i<ford; i++)
- {
- fc = (fb-fs->frc[i])*frlamb + fs->frb[i];
- fs->frc[i] = fc;
- fs->frb[i] = fb;
- tf = fs->fbuff[i][ti4];
- fb = fc - tf*fa;
- fa = fa - tf*fc;
- }
- tf = tf2;
- tf = tf + flpa * fs->flp; // lowpass post-emphasis filter
- fs->flp = tf;
-
- // Bring up the gain slowly when formant correction goes from disabled
- // to enabled, while things stabilize.
- if (fs->fmute>0.5)
- {
- tf = tf*(fs->fmute - 0.5)*2;
- }
- else
- {
- tf = 0;
- }
- tf2 = fs->fmutealph;
- fs->fmute = (1-tf2) + tf2*fs->fmute;
- // now tf is signal output
- // ...and we're done messing with formants
-
- return tf;
-}
--- /dev/null
+++ b/LEAF/Src/leaf-instruments.c
@@ -1,0 +1,460 @@
+/*==============================================================================
+
+ leaf-instruments.c
+ Created: 30 Nov 2018 10:24:21am
+ Author: airship
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-instruments.h"
+
+#else
+
+#include "../Inc/leaf-instruments.h"
+
+#endif
+
+// ----------------- COWBELL ----------------------------//
+
+void t808Cowbell_init(t808Cowbell* const cowbell, int useStick) {
+
+ tSquare_init(&cowbell->p[0]);
+ tSquare_setFreq(&cowbell->p[0], 540.0f);
+
+ tSquare_init(&cowbell->p[1]);
+ tSquare_setFreq(&cowbell->p[1], 1.48148f * 540.0f);
+
+ cowbell->oscMix = 0.5f;
+
+ tSVF_init(&cowbell->bandpassOsc, SVFTypeBandpass, 2500, 1.0f);
+
+ tSVF_init(&cowbell->bandpassStick, SVFTypeBandpass, 1800, 1.0f);
+
+ tEnvelope_init(&cowbell->envGain, 5.0f, 100.0f, OFALSE);
+
+ tEnvelope_init(&cowbell->envFilter, 5.0, 100.0f, OFALSE);
+
+ tHighpass_init(&cowbell->highpass, 1000.0f);
+
+ tNoise_init(&cowbell->stick, WhiteNoise);
+
+ tEnvelope_init(&cowbell->envStick, 5.0f, 5.0f, 0);
+
+ cowbell->useStick = useStick;
+}
+
+void t808Cowebell_free(t808Cowbell* const cowbell)
+{
+ tSquare_free(&cowbell->p[0]);
+ tSquare_free(&cowbell->p[1]);
+ tSVF_free(&cowbell->bandpassOsc);
+ tSVF_free(&cowbell->bandpassStick);
+ tEnvelope_free(&cowbell->envGain);
+ tEnvelope_free(&cowbell->envFilter);
+ tHighpass_free(&cowbell->highpass);
+ tNoise_free(&cowbell->stick);
+ tEnvelope_free(&cowbell->envStick);
+}
+
+void t808Cowbell_on(t808Cowbell* const cowbell, float vel)
+{
+ tEnvelope_on(&cowbell->envGain, vel);
+
+ if (cowbell->useStick)
+ tEnvelope_on(&cowbell->envStick,vel);
+}
+
+float t808Cowbell_tick(t808Cowbell* const cowbell) {
+
+ float sample = 0.0f;
+
+ // Mix oscillators.
+ sample = (cowbell->oscMix * tSquare_tick(&cowbell->p[0])) + ((1.0f-cowbell->oscMix) * tSquare_tick(&cowbell->p[1]));
+
+ // Filter dive and filter.
+ tSVF_setFreq(&cowbell->bandpassOsc, cowbell->filterCutoff + 1000.0f * tEnvelope_tick(&cowbell->envFilter));
+ sample = tSVF_tick(&cowbell->bandpassOsc,sample);
+
+ sample *= (0.9f * tEnvelope_tick(&cowbell->envGain));
+
+ if (cowbell->useStick)
+ sample += (0.1f * tEnvelope_tick(&cowbell->envStick) * tSVF_tick(&cowbell->bandpassStick, tNoise_tick(&cowbell->stick)));
+
+
+ sample = tHighpass_tick(&cowbell->highpass, sample);
+
+ return sample;
+}
+
+void t808Cowbell_setDecay(t808Cowbell* const cowbell, float decay)
+{
+ tEnvelope_setDecay(&cowbell->envGain,decay);
+}
+
+void t808Cowbell_setHighpassFreq(t808Cowbell *cowbell, float freq)
+{
+ tHighpass_setFreq(&cowbell->highpass,freq);
+}
+
+void t808Cowbell_setBandpassFreq(t808Cowbell* const cowbell, float freq)
+{
+ cowbell->filterCutoff = freq;
+}
+
+void t808Cowbell_setFreq(t808Cowbell* const cowbell, float freq)
+{
+
+ tSquare_setFreq(&cowbell->p[0],freq);
+ tSquare_setFreq(&cowbell->p[1],1.48148f*freq);
+}
+
+void t808Cowbell_setOscMix(t808Cowbell* const cowbell, float oscMix)
+{
+ cowbell->oscMix = oscMix;
+}
+
+void t808Cowbell_setStick(t808Cowbell* const cowbell, int useStick)
+{
+ cowbell->useStick = useStick;
+}
+
+// ----------------- HIHAT ----------------------------//
+
+void t808Hihat_init(t808Hihat* const hihat)
+{
+ for (int i = 0; i < 6; i++)
+ {
+ tSquare_init(&hihat->p[i]);
+ }
+
+ tNoise_init(&hihat->stick, PinkNoise);
+ tNoise_init(&hihat->n, WhiteNoise);
+
+ // need to fix SVF to be generic
+ tSVF_init(&hihat->bandpassStick, SVFTypeBandpass,2500.0f,1.2f);
+ tSVF_init(&hihat->bandpassOsc, SVFTypeBandpass,3500.0f,0.3f);
+
+ tEnvelope_init(&hihat->envGain, 0.0f, 50.0f, OFALSE);
+ tEnvelope_init(&hihat->envStick, 0.0f, 7.0f, OFALSE);
+
+
+ tHighpass_init(&hihat->highpass, 7000.0f);
+
+ hihat->freq = 40.0f;
+ hihat->stretch = 0.0f;
+
+ tSquare_setFreq(&hihat->p[0], 2.0f * hihat->freq);
+ tSquare_setFreq(&hihat->p[1], 3.00f * hihat->freq);
+ tSquare_setFreq(&hihat->p[2], 4.16f * hihat->freq);
+ tSquare_setFreq(&hihat->p[3], 5.43f * hihat->freq);
+ tSquare_setFreq(&hihat->p[4], 6.79f * hihat->freq);
+ tSquare_setFreq(&hihat->p[5], 8.21f * hihat->freq);
+}
+
+void t808Hihat_free(t808Hihat* const hihat)
+{
+ for (int i = 0; i < 6; i++)
+ {
+ tSquare_free(&hihat->p[i]);
+ }
+
+ tNoise_free(&hihat->stick);
+ tNoise_free(&hihat->n);
+
+ // need to fix SVF to be generic
+ tSVF_free(&hihat->bandpassStick);
+ tSVF_free(&hihat->bandpassOsc);
+ tEnvelope_free(&hihat->envGain);
+ tEnvelope_free(&hihat->envStick);
+
+ tHighpass_free(&hihat->highpass);
+}
+
+void t808Hihat_on(t808Hihat* const hihat, float vel) {
+
+ tEnvelope_on(&hihat->envGain, vel);
+ tEnvelope_on(&hihat->envStick, vel);
+
+}
+
+void t808Hihat_setOscNoiseMix(t808Hihat* const hihat, float oscNoiseMix) {
+
+ hihat->oscNoiseMix = oscNoiseMix;
+
+}
+
+float t808Hihat_tick(t808Hihat* const hihat) {
+
+ float sample = 0.0f;
+ float gainScale = 0.1666f;
+
+
+ float myNoise = tNoise_tick(&hihat->n);
+
+ tSquare_setFreq(&hihat->p[0], ((2.0f + hihat->stretch) * hihat->freq));
+ tSquare_setFreq(&hihat->p[1], ((3.00f + hihat->stretch) * hihat->freq));
+ tSquare_setFreq(&hihat->p[2], ((4.16f + hihat->stretch) * hihat->freq));
+ tSquare_setFreq(&hihat->p[3], ((5.43f + hihat->stretch) * hihat->freq));
+ tSquare_setFreq(&hihat->p[4], ((6.79f + hihat->stretch) * hihat->freq));
+ tSquare_setFreq(&hihat->p[5], ((8.21f + hihat->stretch) * hihat->freq));
+
+ for (int i = 0; i < 6; i++)
+ {
+ sample += tSquare_tick(&hihat->p[i]);
+ }
+
+ sample *= gainScale;
+
+ sample = (hihat->oscNoiseMix * sample) + ((1.0f-hihat->oscNoiseMix) * myNoise);
+
+ sample = tSVF_tick(&hihat->bandpassOsc, sample);
+
+ float myGain = tEnvelope_tick(&hihat->envGain);
+ sample *= (myGain*myGain);//square the output gain envelope
+ sample = tHighpass_tick(&hihat->highpass, sample);
+ sample += ((0.5f * tEnvelope_tick(&hihat->envStick)) * tSVF_tick(&hihat->bandpassStick, tNoise_tick(&hihat->stick)));
+ sample = tanhf(sample * 2.0f);
+
+ return sample;
+}
+
+void t808Hihat_setDecay(t808Hihat* const hihat, float decay)
+{
+ tEnvelope_setDecay(&hihat->envGain,decay);
+}
+
+void t808Hihat_setHighpassFreq(t808Hihat* const hihat, float freq)
+{
+ tHighpass_setFreq(&hihat->highpass,freq);
+}
+
+void t808Hihat_setStretch(t808Hihat* const hihat, float stretch)
+{
+ hihat->stretch = stretch;
+}
+
+void t808Hihat_setFM(t808Hihat* const hihat, float FM_amount)
+{
+ hihat->FM_amount = FM_amount;
+}
+
+void t808Hihat_setOscBandpassFreq(t808Hihat* const hihat, float freq)
+{
+ tSVF_setFreq(&hihat->bandpassOsc,freq);
+}
+
+void t808Hihat_setOscBandpassQ(t808Hihat* const hihat, float Q)
+{
+ tSVF_setQ(&hihat->bandpassOsc,Q);
+}
+
+void t808Hihat_setStickBandPassFreq(t808Hihat* const hihat, float freq)
+{
+ tSVF_setFreq(&hihat->bandpassStick,freq);
+}
+
+void t808Hihat_setStickBandPassQ(t808Hihat* const hihat, float Q)
+{
+ tSVF_setQ(&hihat->bandpassStick,Q);
+}
+
+
+
+void t808Hihat_setOscFreq(t808Hihat* const hihat, float freq)
+{
+ hihat->freq = freq;
+}
+
+// ----------------- SNARE ----------------------------//
+
+void t808Snare_init(t808Snare* const snare)
+{
+ float ratio[2] = {1.0, 1.5};
+ for (int i = 0; i < 2; i++)
+ {
+ tTriangle_init(&snare->tone[i]);
+
+ tTriangle_setFreq(&snare->tone[i], ratio[i] * 400.0f);
+ tSVF_init(&snare->toneLowpass[i], SVFTypeLowpass, 4000, 1.0f);
+ tEnvelope_init(&snare->toneEnvOsc[i], 0.0f, 50.0f, OFALSE);
+ tEnvelope_init(&snare->toneEnvGain[i], 1.0f, 150.0f, OFALSE);
+ tEnvelope_init(&snare->toneEnvFilter[i], 1.0f, 2000.0f, OFALSE);
+
+ snare->toneGain[i] = 0.5f;
+ }
+
+ snare->tone1Freq = ratio[0] * 100.0f;
+ snare->tone2Freq = ratio[1] * 100.0f;
+ snare->noiseFilterFreq = 3000.0f;
+ tNoise_init(&snare->noiseOsc, WhiteNoise);
+ tSVF_init(&snare->noiseLowpass, SVFTypeLowpass, 12000.0f, 0.8f);
+ tEnvelope_init(&snare->noiseEnvGain, 0.0f, 100.0f, OFALSE);
+ tEnvelope_init(&snare->noiseEnvFilter, 0.0f, 1000.0f, OFALSE);
+ snare->noiseGain = 1.0f;
+}
+
+void t808Snare_free (t808Snare* const snare)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ tTriangle_free(&snare->tone[i]);
+ tSVF_free(&snare->toneLowpass[i]);
+ tEnvelope_free(&snare->toneEnvOsc[i]);
+ tEnvelope_free(&snare->toneEnvGain[i]);
+ tEnvelope_free(&snare->toneEnvFilter[i]);
+ }
+
+
+ tNoise_free(&snare->noiseOsc);
+ tSVF_free(&snare->noiseLowpass);
+ tEnvelope_free(&snare->noiseEnvGain);
+ tEnvelope_free(&snare->noiseEnvFilter);
+}
+
+void t808Snare_on(t808Snare* const snare, float vel)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ tEnvelope_on(&snare->toneEnvOsc[i], vel);
+ tEnvelope_on(&snare->toneEnvGain[i], vel);
+ tEnvelope_on(&snare->toneEnvFilter[i], vel);
+ }
+
+ tEnvelope_on(&snare->noiseEnvGain, vel);
+ tEnvelope_on(&snare->noiseEnvFilter, vel);
+}
+
+void t808Snare_setTone1Freq(t808Snare* const snare, float freq)
+{
+ snare->tone1Freq = freq;
+ tTriangle_setFreq(&snare->tone[0], freq);
+
+}
+
+void t808Snare_setTone2Freq(t808Snare* const snare, float freq)
+{
+ snare->tone2Freq = freq;
+ tTriangle_setFreq(&snare->tone[1],freq);
+}
+
+void t808Snare_setTone1Decay(t808Snare* const snare, float decay)
+{
+ tEnvelope_setDecay(&snare->toneEnvGain[0],decay);
+}
+
+void t808Snare_setTone2Decay(t808Snare* const snare, float decay)
+{
+ tEnvelope_setDecay(&snare->toneEnvGain[1],decay);
+}
+
+void t808Snare_setNoiseDecay(t808Snare* const snare, float decay)
+{
+ tEnvelope_setDecay(&snare->noiseEnvGain,decay);
+}
+
+void t808Snare_setToneNoiseMix(t808Snare* const snare, float toneNoiseMix)
+{
+ snare->toneNoiseMix = toneNoiseMix;
+}
+
+void t808Snare_setNoiseFilterFreq(t808Snare* const snare, float noiseFilterFreq)
+{
+ snare->noiseFilterFreq = noiseFilterFreq;
+}
+
+void t808Snare_setNoiseFilterQ(t808Snare* const snare, float noiseFilterQ)
+{
+ tSVF_setQ(&snare->noiseLowpass, noiseFilterQ);
+}
+
+static float tone[2];
+
+float t808Snare_tick(t808Snare* const snare)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ tTriangle_setFreq(&snare->tone[i], snare->tone1Freq + (20.0f * tEnvelope_tick(&snare->toneEnvOsc[i])));
+ tone[i] = tTriangle_tick(&snare->tone[i]);
+
+ tSVF_setFreq(&snare->toneLowpass[i], 2000.0f + (500.0f * tEnvelope_tick(&snare->toneEnvFilter[i])));
+ tone[i] = tSVF_tick(&snare->toneLowpass[i], tone[i]) * tEnvelope_tick(&snare->toneEnvGain[i]);
+ }
+
+ float noise = tNoise_tick(&snare->noiseOsc);
+ tSVF_setFreq(&snare->noiseLowpass, snare->noiseFilterFreq + (1000.0f * tEnvelope_tick(&snare->noiseEnvFilter)));
+ noise = tSVF_tick(&snare->noiseLowpass, noise) * tEnvelope_tick(&snare->noiseEnvGain);
+
+ float sample = (snare->toneNoiseMix)*(tone[0] * snare->toneGain[0] + tone[1] * snare->toneGain[1]) + (1.0f-snare->toneNoiseMix) * (noise * snare->noiseGain);
+ sample = tanhf(sample * 2.0f);
+ return sample;
+}
+
+// ----------------- KICK ----------------------------//
+
+void t808Kick_init (t808Kick* const kick)
+{
+ tCycle_init(&kick->tone);
+ kick->toneInitialFreq = 40.0f;
+ kick->sighAmountInHz = 7.0f;
+ kick->chirpRatioMinusOne = 3.3f;
+ tCycle_setFreq(&kick->tone, 50.0f);
+ tSVF_init(&kick->toneLowpass, SVFTypeLowpass, 2000.0f, 0.5f);
+ tEnvelope_init(&kick->toneEnvOscChirp, 0.0f, 20.0f, OFALSE);
+ tEnvelope_init(&kick->toneEnvOscSigh, 0.0f, 2500.0f, OFALSE);
+ tEnvelope_init(&kick->toneEnvGain, 0.0f, 800.0f, OFALSE);
+ tNoise_init(&kick->noiseOsc, PinkNoise);
+ tEnvelope_init(&kick->noiseEnvGain, 0.0f, 1.0f, OFALSE);
+ kick->noiseGain = 0.3f;
+}
+
+void t808Kick_free (t808Kick* const kick)
+{
+ tCycle_free(&kick->tone);
+ tSVF_free(&kick->toneLowpass);
+ tEnvelope_free(&kick->toneEnvOscChirp);
+ tEnvelope_free(&kick->toneEnvOscSigh);
+ tEnvelope_free(&kick->toneEnvGain);
+ tNoise_free(&kick->noiseOsc);
+ tEnvelope_free(&kick->noiseEnvGain);
+}
+
+float t808Kick_tick (t808Kick* const kick)
+{
+ tCycle_setFreq(&kick->tone, (kick->toneInitialFreq * (1.0f + (kick->chirpRatioMinusOne * tEnvelope_tick(&kick->toneEnvOscChirp)))) + (kick->sighAmountInHz * tEnvelope_tick(&kick->toneEnvOscSigh)));
+ float sample = tCycle_tick(&kick->tone) * tEnvelope_tick(&kick->toneEnvGain);
+ sample+= tNoise_tick(&kick->noiseOsc) * tEnvelope_tick(&kick->noiseEnvGain);
+ //add distortion here
+ sample = tSVF_tick(&kick->toneLowpass, sample);
+ return sample;
+}
+
+void t808Kick_on (t808Kick* const kick, float vel)
+{
+ tEnvelope_on(&kick->toneEnvOscChirp, vel);
+ tEnvelope_on(&kick->toneEnvOscSigh, vel);
+ tEnvelope_on(&kick->toneEnvGain, vel);
+ tEnvelope_on(&kick->noiseEnvGain, vel);
+
+}
+void t808Kick_setToneFreq (t808Kick* const kick, float freq)
+{
+ kick->toneInitialFreq = freq;
+
+}
+
+void t808Kick_setToneDecay (t808Kick* const kick, float decay)
+{
+ tEnvelope_setDecay(&kick->toneEnvGain,decay);
+ tEnvelope_setDecay(&kick->toneEnvGain,decay * 3.0f);
+}
+
+void t808Kick_setNoiseDecay (t808Kick* const kick, float decay);
+void t808Kick_setSighAmount (t808Kick* const kick, float sigh);
+void t808Kick_setChirpAmount (t808Kick* const kick, float chirp);
+void t808Kick_setToneNoiseMix (t808Kick* const kick, float toneNoiseMix);
+void t808Kick_setNoiseFilterFreq (t808Kick* const kick, float noiseFilterFreq);
+void t808Kick_setNoiseFilterQ (t808Kick* const kick, float noiseFilterQ);
+
+
--- a/LEAF/Src/leaf-math.c
+++ b/LEAF/Src/leaf-math.c
@@ -355,3 +355,5 @@
return out;
}
+
+
--- a/LEAF/Src/leaf-midi.c
+++ b/LEAF/Src/leaf-midi.c
@@ -305,3 +305,216 @@
return (poly->voices[voice][0] > 0) ? 1 : 0;
}
+
+//====================================================================================
+/* Stack */
+//====================================================================================
+
+void tStack_init(tStack* const ns)
+{
+ ns->ordered = OFALSE;
+ ns->size = 0;
+ ns->pos = 0;
+ ns->capacity = STACK_SIZE;
+
+ for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1;
+}
+
+void tStack_free(tStack* const ns)
+{
+
+}
+
+// If stack contains note, returns index. Else returns -1;
+int tStack_contains(tStack* const ns, uint16_t noteVal)
+{
+ for (int i = 0; i < ns->size; i++)
+ {
+ if (ns->data[i] == noteVal) return i;
+ }
+ return -1;
+}
+
+void tStack_add(tStack* const ns, uint16_t noteVal)
+{
+ uint8_t j;
+
+ int whereToInsert = 0;
+ if (ns->ordered)
+ {
+ for (j = 0; j < ns->size; j++)
+ {
+ if (noteVal > ns->data[j])
+ {
+ if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
+ {
+ whereToInsert = j+1;
+ break;
+ }
+ }
+ }
+ }
+
+ //first move notes that are already in the stack one position to the right
+ for (j = ns->size; j > whereToInsert; j--)
+ {
+ ns->data[j] = ns->data[(j - 1)];
+ }
+
+ //then, insert the new note into the front of the stack
+ ns->data[whereToInsert] = noteVal;
+
+ ns->size++;
+}
+
+int tStack_addIfNotAlreadyThere(tStack* const ns, uint16_t noteVal)
+{
+ uint8_t j;
+
+ int added = 0;
+
+ if (tStack_contains(ns, noteVal) == -1)
+ {
+ int whereToInsert = 0;
+ if (ns->ordered)
+ {
+ for (j = 0; j < ns->size; j++)
+ {
+ if (noteVal > ns->data[j])
+ {
+ if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
+ {
+ whereToInsert = j+1;
+ break;
+ }
+ }
+ }
+ }
+
+ //first move notes that are already in the stack one position to the right
+ for (j = ns->size; j > whereToInsert; j--)
+ {
+ ns->data[j] = ns->data[(j - 1)];
+ }
+
+ //then, insert the new note into the front of the stack
+ ns->data[whereToInsert] = noteVal;
+
+ ns->size++;
+
+ added = 1;
+ }
+
+ return added;
+}
+
+
+// Remove noteVal. return 1 if removed, 0 if not
+int tStack_remove(tStack* const ns, uint16_t noteVal)
+{
+ uint8_t k;
+ int foundIndex = tStack_contains(ns, noteVal);
+ int removed = 0;
+
+ if (foundIndex >= 0)
+ {
+ for (k = 0; k < (ns->size - foundIndex); k++)
+ {
+ if ((k+foundIndex) >= (ns->capacity - 1))
+ {
+ ns->data[k + foundIndex] = -1;
+ }
+ else
+ {
+ ns->data[k + foundIndex] = ns->data[k + foundIndex + 1];
+ if ((k + foundIndex) == (ns->size - 1))
+ {
+ ns->data[k + foundIndex + 1] = -1;
+ }
+ }
+
+ }
+ // in case it got put on the stack multiple times
+ foundIndex--;
+ ns->size--;
+ removed = 1;
+ }
+
+
+
+ return removed;
+}
+
+// Doesn't change size of data types
+void tStack_setCapacity(tStack* const ns, uint16_t cap)
+{
+ if (cap <= 0)
+ ns->capacity = 1;
+ else if (cap <= STACK_SIZE)
+ ns->capacity = cap;
+ else
+ ns->capacity = STACK_SIZE;
+
+ for (int i = cap; i < STACK_SIZE; i++)
+ {
+ if ((int)ns->data[i] != -1)
+ {
+ ns->data[i] = -1;
+ ns->size -= 1;
+ }
+ }
+
+ if (ns->pos >= cap)
+ {
+ ns->pos = 0;
+ }
+}
+
+int tStack_getSize(tStack* const ns)
+{
+ return ns->size;
+}
+
+void tStack_clear(tStack* const ns)
+{
+ for (int i = 0; i < STACK_SIZE; i++)
+ {
+ ns->data[i] = -1;
+ }
+ ns->pos = 0;
+ ns->size = 0;
+}
+
+// Next item in order of addition to stack. Return 0-31 if there is a next item to move to. Returns -1 otherwise.
+int tStack_next(tStack* const ns)
+{
+ int step = 0;
+ if (ns->size != 0) // if there is at least one note in the stack
+ {
+ if (ns->pos > 0) // if you're not at the most recent note (first one), then go backward in the array (moving from earliest to latest)
+ {
+ ns->pos--;
+ }
+ else
+ {
+ ns->pos = (ns->size - 1); // if you are the most recent note, go back to the earliest note in the array
+ }
+
+ step = ns->data[ns->pos];
+ return step;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+int tStack_get(tStack* const ns, int which)
+{
+ return ns->data[which];
+}
+
+int tStack_first(tStack* const ns)
+{
+ return ns->data[0];
+}
--- a/LEAF/Src/leaf-oscillator.c
+++ /dev/null
@@ -1,638 +1,0 @@
-/*==============================================================================
-
- leaf-oscillator.c
- Created: 20 Jan 2017 12:00:58pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-tables.h"
-#include "..\Inc\leaf-oscillator.h"
-#include "..\leaf.h"
-
-#else
-
-#include "../Inc/leaf-tables.h"
-#include "../Inc/leaf-oscillator.h"
-#include "../leaf.h"
-
-#endif
-
-void tNeuronSampleRateChanged(tNeuron* n)
-{
-
-}
-
-void tNeuron_init(tNeuron* const n)
-{
- tPoleZero_init(&n->f);
-
- tPoleZero_setBlockZero(&n->f, 0.99f);
-
- n->timeStep = 1.0f / 50.0f;
-
- n->current = 0.0f; // 100.0f for sound
- n->voltage = 0.0f;
-
- n->mode = NeuronNormal;
-
- n->P[0] = 0.0f;
- n->P[1] = 0.0f;
- n->P[2] = 1.0f;
-
- n->V[0] = -12.0f;
- n->V[1] = 115.0f;
- n->V[2] = 10.613f;
-
- n->gK = 36.0f;
- n->gN = 120.0f;
- n->gL = 0.3f;
- n->C = 1.0f;
-
- n->rate[2] = n->gL/n->C;
-}
-
-void tNeuron_free(tNeuron* const n)
-{
- tPoleZero_free(&n->f);
-}
-
-void tNeuron_reset(tNeuron* const n)
-{
-
- tPoleZero_setBlockZero(&n->f, 0.99f);
-
- n->timeStep = 1.0f / 50.0f;
-
- n->current = 0.0f; // 100.0f for sound
- n->voltage = 0.0f;
-
- n->mode = NeuronNormal;
-
- n->P[0] = 0.0f;
- n->P[1] = 0.0f;
- n->P[2] = 1.0f;
-
- n->V[0] = -12.0f;
- n->V[1] = 115.0f;
- n->V[2] = 10.613f;
-
- n->gK = 36.0f;
- n->gN = 120.0f;
- n->gL = 0.3f;
- n->C = 1.0f;
-
- n->rate[2] = n->gL/n->C;
-}
-
-
-void tNeuron_setV1(tNeuron* const n, float V1)
-{
- n->V[0] = V1;
-}
-
-
-void tNeuron_setV2(tNeuron* const n, float V2)
-{
- n->V[1] = V2;
-}
-
-void tNeuron_setV3(tNeuron* const n, float V3)
-{
- n->V[2] = V3;
-}
-
-void tNeuron_setTimeStep(tNeuron* const n, float timeStep)
-{
- n->timeStep = timeStep;
-}
-
-void tNeuron_setK(tNeuron* const n, float K)
-{
- n->gK = K;
-}
-
-void tNeuron_setL(tNeuron* const n, float L)
-{
- n->gL = L;
- n->rate[2] = n->gL/n->C;
-}
-
-void tNeuron_setN(tNeuron* const n, float N)
-{
- n->gN = N;
-}
-
-void tNeuron_setC(tNeuron* const n, float C)
-{
- n->C = C;
- n->rate[2] = n->gL/n->C;
-}
-
-float tNeuron_tick(tNeuron* const n)
-{
- float output = 0.0f;
- float voltage = n->voltage;
-
- n->alpha[0] = (0.01f * (10.0f - voltage)) / (expf((10.0f - voltage)/10.0f) - 1.0f);
- n->alpha[1] = (0.1f * (25.0f-voltage)) / (expf((25.0f-voltage)/10.0f) - 1.0f);
- n->alpha[2] = (0.07f * expf((-1.0f * voltage)/20.0f));
-
- n->beta[0] = (0.125f * expf((-1.0f* voltage)/80.0f));
- n->beta[1] = (4.0f * expf((-1.0f * voltage)/18.0f));
- n->beta[2] = (1.0f / (expf((30.0f-voltage)/10.0f) + 1.0f));
-
- for (int i = 0; i < 3; i++)
- {
- n->P[i] = (n->alpha[i] * n->timeStep) + ((1.0f - ((n->alpha[i] + n->beta[i]) * n->timeStep)) * n->P[i]);
-
- if (n->P[i] > 1.0f) n->P[i] = 0.0f;
- else if (n->P[i] < -1.0f) n->P[i] = 0.0f;
- }
- // rate[0]= k ; rate[1] = Na ; rate[2] = l
- n->rate[0] = ((n->gK * powf(n->P[0], 4.0f)) / n->C);
- n->rate[1] = ((n->gN * powf(n->P[1], 3.0f) * n->P[2]) / n->C);
-
- //calculate the final membrane voltage based on the computed variables
- n->voltage = voltage +
- (n->timeStep * n->current / n->C) -
- (n->timeStep * ( n->rate[0] * (voltage - n->V[0]) + n->rate[1] * (voltage - n->V[1]) + n->rate[2] * (voltage - n->V[2])));
-
- if (n->mode == NeuronTanh)
- {
- n->voltage = 100.0f * tanhf(0.01f * n->voltage);
- }
- else if (n->mode == NeuronAaltoShaper)
- {
- float shapeVoltage = 0.01f * n->voltage;
-
- float w, c, xc, xc2, xc4;
-
- float sqrt8 = 2.82842712475f;
-
- float wscale = 1.30612244898f;
- float m_drive = 1.0f;
-
- xc = LEAF_clip(-sqrt8, shapeVoltage, sqrt8);
-
- xc2 = xc*xc;
-
- c = 0.5f * shapeVoltage * (3.0f - (xc2));
-
- xc4 = xc2 * xc2;
-
- w = (1.0f - xc2 * 0.25f + xc4 * 0.015625f) * wscale;
-
- shapeVoltage = w * (c + 0.05f * xc2) * (m_drive + 0.75f);
-
- n->voltage = 100.0f * shapeVoltage;
- }
-
-
- if (n->voltage > 100.0f) n->voltage = 100.0f;
- else if (n->voltage < -100.) n->voltage = -100.0f;
-
- //(inputCurrent + (voltage - ((voltage * timeStep) / timeConstant)) + P[0] + P[1] + P[2]) => voltage;
- // now we should have a result
- //set the output voltage to the "step" ugen, which controls the DAC.
- output = n->voltage * 0.01f; // volts
-
- output = tPoleZero_tick(&n->f, output);
-
- return output;
-
-}
-
-void tNeuron_setMode (tNeuron* const n, NeuronMode mode)
-{
- n->mode = mode;
-}
-
-void tNeuron_setCurrent (tNeuron* const n, float current)
-{
- n->current = current;
-}
-
-// Cycle
-void tCycle_init(tCycle* const c)
-{
- c->inc = 0.0f;
- c->phase = 0.0f;
-}
-
-void tCycle_free(tCycle* const c)
-{
-
-}
-
-int tCycle_setFreq(tCycle* const c, float freq)
-{
- if (freq < 0.0f) freq = 0.0f;
-
- c->freq = freq;
- c->inc = freq * leaf.invSampleRate;
-
- return 0;
-}
-
-float tCycle_tick(tCycle* const c)
-{
- // Phasor increment
- c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
-
- // Wavetable synthesis
- float temp = SINE_TABLE_SIZE * c->phase;
- int intPart = (int)temp;
- float fracPart = temp - (float)intPart;
- float samp0 = sinewave[intPart];
- if (++intPart >= SINE_TABLE_SIZE) intPart = 0;
- float samp1 = sinewave[intPart];
- return (samp0 + (samp1 - samp0) * fracPart);
-}
-
-void tCycleSampleRateChanged (tCycle* const c)
-{
- c->inc = c->freq * leaf.invSampleRate;
-}
-
-/* Phasor */
-void tPhasorSampleRateChanged (tPhasor* const p)
-{
- p->inc = p->freq * leaf.invSampleRate;
-};
-
-void tPhasor_init(tPhasor* const p)
-{
- p->phase = 0.0f;
- p->inc = 0.0f;
-}
-
-void tPhasor_free(tPhasor* const p)
-{
-
-}
-
-int tPhasor_setFreq(tPhasor* const p, float freq)
-{
- if (freq < 0.0f) freq = 0.0f;
-
- p->freq = freq;
- p->inc = freq * leaf.invSampleRate;
-
- return 0;
-}
-
-float tPhasor_tick(tPhasor* const p)
-{
- p->phase += p->inc;
-
- if (p->phase >= 1.0f) p->phase -= 1.0f;
-
- return p->phase;
-}
-
-
-
-void tSawtooth_init(tSawtooth* const c)
-{
- c->inc = 0.0f;
- c->phase = 0.0f;
-}
-
-void tSawtooth_free(tSawtooth* const c)
-{
-
-}
-
-int tSawtooth_setFreq(tSawtooth* const c, float freq)
-{
- if (freq < 0.0f) freq = 0.0f;
-
- c->freq = freq;
- c->inc = freq * leaf.invSampleRate;
-
- return 0;
-}
-
-float tSawtooth_tick(tSawtooth* const c)
-{
- // Phasor increment
- c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
-
- float out = 0.0f;
- float w;
-
- int idx = (int)(c->phase * TRI_TABLE_SIZE);
-
- // Wavetable synthesis
-
- if (c->freq <= 20.0f)
- {
- out = sawtooth[T20][idx];
- }
- else if (c->freq <= 40.0f)
- {
- w = ((40.0f - c->freq) * INV_20);
- out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w));
- }
- else if (c->freq <= 80.0f)
- {
- w = ((80.0f - c->freq) * INV_40);
- out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w));
- }
- else if (c->freq <= 160.0f)
- {
- w = ((160.0f - c->freq) * INV_80);
- out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w));
- }
- else if (c->freq <= 320.0f)
- {
- w = ((320.0f - c->freq) * INV_160);
- out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w));
- }
- else if (c->freq <= 640.0f)
- {
- w = ((640.0f - c->freq) * INV_320);
- out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w));
- }
- else if (c->freq <= 1280.0f)
- {
- w = ((1280.0f - c->freq) * INV_640);
- out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w));
- }
- else if (c->freq <= 2560.0f)
- {
- w = ((2560.0f - c->freq) * INV_1280);
- out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w));
- }
- else if (c->freq <= 5120.0f)
- {
- w = ((5120.0f - c->freq) * INV_2560);
- out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w));
- }
- else if (c->freq <= 10240.0f)
- {
- w = ((10240.0f - c->freq) * INV_5120);
- out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w));
- }
- else if (c->freq <= 20480.0f)
- {
- w = ((20480.0f - c->freq) * INV_10240);
- out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w));
- }
- else
- {
- out = sawtooth[T20480][idx];
- }
-
- return out;
-}
-
-void tSawtoothSampleRateChanged (tSawtooth* const c)
-{
- c->inc = c->freq * leaf.invSampleRate;
-}
-
-/* Triangle */
-void tTriangle_start(tTriangle* const c)
-{
-
-}
-
-void tTriangle_init(tTriangle* const c)
-{
- c->inc = 0.0f;
- c->phase = 0.0f;
-}
-
-void tTriangle_free(tTriangle* const c)
-{
-
-}
-
-int tTriangle_setFreq(tTriangle* const c, float freq)
-{
- if (freq < 0.0f) freq = 0.0f;
-
- c->freq = freq;
- c->inc = freq * leaf.invSampleRate;
-
- return 0;
-}
-
-
-float tTriangle_tick(tTriangle* const c)
-{
- // Phasor increment
- c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
-
- float out = 0.0f;
- float w;
-
- int idx = (int)(c->phase * TRI_TABLE_SIZE);
-
- // Wavetable synthesis
-
- if (c->freq <= 20.0f)
- {
- out = triangle[T20][idx];
- }
- else if (c->freq <= 40.0f)
- {
- w = ((40.0f - c->freq) * INV_20);
- out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w));
- }
- else if (c->freq <= 80.0f)
- {
- w = ((80.0f - c->freq) * INV_40);
- out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w));
- }
- else if (c->freq <= 160.0f)
- {
- w = ((160.0f - c->freq) * INV_80);
- out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w));
- }
- else if (c->freq <= 320.0f)
- {
- w = ((320.0f - c->freq) * INV_160);
- out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w));
- }
- else if (c->freq <= 640.0f)
- {
- w = ((640.0f - c->freq) * INV_320);
- out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w));
- }
- else if (c->freq <= 1280.0f)
- {
- w = ((1280.0f - c->freq) * INV_640);
- out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w));
- }
- else if (c->freq <= 2560.0f)
- {
- w = ((2560.0f - c->freq) * INV_1280);
- out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w));
- }
- else if (c->freq <= 5120.0f)
- {
- w = ((5120.0f - c->freq) * INV_2560);
- out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w));
- }
- else if (c->freq <= 10240.0f)
- {
- w = ((10240.0f - c->freq) * INV_5120);
- out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w));
- }
- else if (c->freq <= 20480.0f)
- {
- w = ((20480.0f - c->freq) * INV_10240);
- out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w));
- }
- else
- {
- out = triangle[T20480][idx];
- }
-
- return out;
-}
-
-void tTriangleSampleRateChanged (tTriangle* const c)
-{
- c->inc = c->freq * leaf.invSampleRate;
-}
-
-/* Square */
-void tSquare_init(tSquare* const c)
-{
- c->inc = 0.0f;
- c->phase = 0.0f;
-}
-
-void tSquare_free(tSquare* const c)
-{
-
-}
-
-int tSquare_setFreq(tSquare* const c, float freq)
-{
- if (freq < 0.0f) freq = 0.0f;
-
- c->freq = freq;
- c->inc = freq * leaf.invSampleRate;
-
- return 0;
-}
-
-float tSquare_tick(tSquare* const c)
-{
- // Phasor increment
- c->phase += c->inc;
- while (c->phase >= 1.0f) c->phase -= 1.0f;
-
- float out = 0.0f;
- float w = 0.0f;
- int idx = (int)(c->phase * TRI_TABLE_SIZE);
-
- // Wavetable synthesis
-
- if (c->freq <= 20.0f)
- {
- out = squarewave[T20][idx];
- }
- else if (c->freq <= 40.0f)
- {
- w = ((40.0f - c->freq) * INV_20);
- out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w));
- }
- else if (c->freq <= 80.0f)
- {
- w = ((80.0f - c->freq) * INV_40);
- out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w));
- }
- else if (c->freq <= 160.0f)
- {
- w = ((160.0f - c->freq) * INV_80);
- out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w));
- }
- else if (c->freq <= 320.0f)
- {
- w = ((320.0f - c->freq) * INV_160);
- out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w));
- }
- else if (c->freq <= 640.0f)
- {
- w = ((640.0f - c->freq) * INV_320);
- out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w));
- }
- else if (c->freq <= 1280.0f)
- {
- w = ((1280.0f - c->freq) * INV_640);
- out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w));
- }
- else if (c->freq <= 2560.0f)
- {
- w = ((2560.0f - c->freq) * INV_1280);
- out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w));
- }
- else if (c->freq <= 5120.0f)
- {
- w = ((5120.0f - c->freq) * INV_2560);
- out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w));
- }
- else if (c->freq <= 10240.0f)
- {
- w = ((10240.0f - c->freq) * INV_5120);
- out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w));
- }
- else if (c->freq <= 20480.0f)
- {
- w = ((20480.0f - c->freq) * INV_10240);
- out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w));
- }
- else
- {
- out = squarewave[T20480][idx];
- }
-
- return out;
-}
-
-void tSquareSampleRateChanged (tSquare* const c)
-{
- c->inc = c->freq * leaf.invSampleRate;
-}
-
-/* Noise */
-void tNoise_init(tNoise* const n, NoiseType type)
-{
- n->type = type;
- n->rand = leaf.random;
-}
-
-void tNoise_free(tNoise* const n)
-{
-
-}
-
-float tNoise_tick(tNoise* const n)
-{
- float rand = (n->rand() * 2.0f) - 1.0f;
-
- if (n->type == PinkNoise)
- {
- float tmp;
- n->pinkb0 = 0.99765f * n->pinkb0 + rand * 0.0990460f;
- n->pinkb1 = 0.96300f * n->pinkb1 + rand * 0.2965164f;
- n->pinkb2 = 0.57000f * n->pinkb2 + rand * 1.0526913f;
- tmp = n->pinkb0 + n->pinkb1 + n->pinkb2 + rand * 0.1848f;
- return (tmp * 0.05f);
- }
- else // WhiteNoise
- {
- return rand;
- }
-}
--- /dev/null
+++ b/LEAF/Src/leaf-oscillators.c
@@ -1,0 +1,644 @@
+/*==============================================================================
+
+ leaf-oscillators.c
+ Created: 20 Jan 2017 12:00:58pm
+ Author: Michael R Mulshine
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-tables.h"
+#include "..\Inc\leaf-oscillators.h"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-tables.h"
+#include "../Inc/leaf-oscillators.h"
+#include "../leaf.h"
+
+#endif
+
+// Cycle
+void tCycle_init(tCycle* const c)
+{
+ c->inc = 0.0f;
+ c->phase = 0.0f;
+}
+
+void tCycle_free(tCycle* const c)
+{
+
+}
+
+int tCycle_setFreq(tCycle* const c, float freq)
+{
+ if (freq < 0.0f) freq = 0.0f;
+
+ c->freq = freq;
+ c->inc = freq * leaf.invSampleRate;
+
+ return 0;
+}
+
+float tCycle_tick(tCycle* const c)
+{
+ // Phasor increment
+ c->phase += c->inc;
+ while (c->phase >= 1.0f) c->phase -= 1.0f;
+
+ // Wavetable synthesis
+ float temp = SINE_TABLE_SIZE * c->phase;
+ int intPart = (int)temp;
+ float fracPart = temp - (float)intPart;
+ float samp0 = sinewave[intPart];
+ if (++intPart >= SINE_TABLE_SIZE) intPart = 0;
+ float samp1 = sinewave[intPart];
+ return (samp0 + (samp1 - samp0) * fracPart);
+}
+
+void tCycleSampleRateChanged (tCycle* const c)
+{
+ c->inc = c->freq * leaf.invSampleRate;
+}
+
+//========================================================================
+/* Triangle */
+void tTriangle_start(tTriangle* const c)
+{
+
+}
+
+void tTriangle_init(tTriangle* const c)
+{
+ c->inc = 0.0f;
+ c->phase = 0.0f;
+}
+
+void tTriangle_free(tTriangle* const c)
+{
+
+}
+
+int tTriangle_setFreq(tTriangle* const c, float freq)
+{
+ if (freq < 0.0f) freq = 0.0f;
+
+ c->freq = freq;
+ c->inc = freq * leaf.invSampleRate;
+
+ return 0;
+}
+
+
+float tTriangle_tick(tTriangle* const c)
+{
+ // Phasor increment
+ c->phase += c->inc;
+ while (c->phase >= 1.0f) c->phase -= 1.0f;
+
+ float out = 0.0f;
+ float w;
+
+ int idx = (int)(c->phase * TRI_TABLE_SIZE);
+
+ // Wavetable synthesis
+
+ if (c->freq <= 20.0f)
+ {
+ out = triangle[T20][idx];
+ }
+ else if (c->freq <= 40.0f)
+ {
+ w = ((40.0f - c->freq) * INV_20);
+ out = (triangle[T20][idx] * w) + (triangle[T40][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 80.0f)
+ {
+ w = ((80.0f - c->freq) * INV_40);
+ out = (triangle[T40][idx] * w) + (triangle[T80][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 160.0f)
+ {
+ w = ((160.0f - c->freq) * INV_80);
+ out = (triangle[T80][idx] * w) + (triangle[T160][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 320.0f)
+ {
+ w = ((320.0f - c->freq) * INV_160);
+ out = (triangle[T160][idx] * w) + (triangle[T320][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 640.0f)
+ {
+ w = ((640.0f - c->freq) * INV_320);
+ out = (triangle[T320][idx] * w) + (triangle[T640][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 1280.0f)
+ {
+ w = ((1280.0f - c->freq) * INV_640);
+ out = (triangle[T640][idx] * w) + (triangle[T1280][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 2560.0f)
+ {
+ w = ((2560.0f - c->freq) * INV_1280);
+ out = (triangle[T1280][idx] * w) + (triangle[T2560][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 5120.0f)
+ {
+ w = ((5120.0f - c->freq) * INV_2560);
+ out = (triangle[T2560][idx] * w) + (triangle[T5120][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 10240.0f)
+ {
+ w = ((10240.0f - c->freq) * INV_5120);
+ out = (triangle[T5120][idx] * w) + (triangle[T10240][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 20480.0f)
+ {
+ w = ((20480.0f - c->freq) * INV_10240);
+ out = (triangle[T10240][idx] * w) + (triangle[T20480][idx] * (1.0f - w));
+ }
+ else
+ {
+ out = triangle[T20480][idx];
+ }
+
+ return out;
+}
+
+void tTriangleSampleRateChanged (tTriangle* const c)
+{
+ c->inc = c->freq * leaf.invSampleRate;
+}
+
+//========================================================================
+/* Square */
+void tSquare_init(tSquare* const c)
+{
+ c->inc = 0.0f;
+ c->phase = 0.0f;
+}
+
+void tSquare_free(tSquare* const c)
+{
+
+}
+
+int tSquare_setFreq(tSquare* const c, float freq)
+{
+ if (freq < 0.0f) freq = 0.0f;
+
+ c->freq = freq;
+ c->inc = freq * leaf.invSampleRate;
+
+ return 0;
+}
+
+float tSquare_tick(tSquare* const c)
+{
+ // Phasor increment
+ c->phase += c->inc;
+ while (c->phase >= 1.0f) c->phase -= 1.0f;
+
+ float out = 0.0f;
+ float w = 0.0f;
+ int idx = (int)(c->phase * TRI_TABLE_SIZE);
+
+ // Wavetable synthesis
+
+ if (c->freq <= 20.0f)
+ {
+ out = squarewave[T20][idx];
+ }
+ else if (c->freq <= 40.0f)
+ {
+ w = ((40.0f - c->freq) * INV_20);
+ out = (squarewave[T20][idx] * w) + (squarewave[T40][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 80.0f)
+ {
+ w = ((80.0f - c->freq) * INV_40);
+ out = (squarewave[T40][idx] * w) + (squarewave[T80][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 160.0f)
+ {
+ w = ((160.0f - c->freq) * INV_80);
+ out = (squarewave[T80][idx] * w) + (squarewave[T160][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 320.0f)
+ {
+ w = ((320.0f - c->freq) * INV_160);
+ out = (squarewave[T160][idx] * w) + (squarewave[T320][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 640.0f)
+ {
+ w = ((640.0f - c->freq) * INV_320);
+ out = (squarewave[T320][idx] * w) + (squarewave[T640][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 1280.0f)
+ {
+ w = ((1280.0f - c->freq) * INV_640);
+ out = (squarewave[T640][idx] * w) + (squarewave[T1280][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 2560.0f)
+ {
+ w = ((2560.0f - c->freq) * INV_1280);
+ out = (squarewave[T1280][idx] * w) + (squarewave[T2560][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 5120.0f)
+ {
+ w = ((5120.0f - c->freq) * INV_2560);
+ out = (squarewave[T2560][idx] * w) + (squarewave[T5120][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 10240.0f)
+ {
+ w = ((10240.0f - c->freq) * INV_5120);
+ out = (squarewave[T5120][idx] * w) + (squarewave[T10240][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 20480.0f)
+ {
+ w = ((20480.0f - c->freq) * INV_10240);
+ out = (squarewave[T10240][idx] * w) + (squarewave[T20480][idx] * (1.0f - w));
+ }
+ else
+ {
+ out = squarewave[T20480][idx];
+ }
+
+ return out;
+}
+
+void tSquareSampleRateChanged (tSquare* const c)
+{
+ c->inc = c->freq * leaf.invSampleRate;
+}
+
+//=====================================================================
+// Sawtooth
+void tSawtooth_init(tSawtooth* const c)
+{
+ c->inc = 0.0f;
+ c->phase = 0.0f;
+}
+
+void tSawtooth_free(tSawtooth* const c)
+{
+
+}
+
+int tSawtooth_setFreq(tSawtooth* const c, float freq)
+{
+ if (freq < 0.0f) freq = 0.0f;
+
+ c->freq = freq;
+ c->inc = freq * leaf.invSampleRate;
+
+ return 0;
+}
+
+float tSawtooth_tick(tSawtooth* const c)
+{
+ // Phasor increment
+ c->phase += c->inc;
+ while (c->phase >= 1.0f) c->phase -= 1.0f;
+
+ float out = 0.0f;
+ float w;
+
+ int idx = (int)(c->phase * TRI_TABLE_SIZE);
+
+ // Wavetable synthesis
+
+ if (c->freq <= 20.0f)
+ {
+ out = sawtooth[T20][idx];
+ }
+ else if (c->freq <= 40.0f)
+ {
+ w = ((40.0f - c->freq) * INV_20);
+ out = (sawtooth[T20][idx] * w) + (sawtooth[T40][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 80.0f)
+ {
+ w = ((80.0f - c->freq) * INV_40);
+ out = (sawtooth[T40][idx] * w) + (sawtooth[T80][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 160.0f)
+ {
+ w = ((160.0f - c->freq) * INV_80);
+ out = (sawtooth[T80][idx] * w) + (sawtooth[T160][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 320.0f)
+ {
+ w = ((320.0f - c->freq) * INV_160);
+ out = (sawtooth[T160][idx] * w) + (sawtooth[T320][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 640.0f)
+ {
+ w = ((640.0f - c->freq) * INV_320);
+ out = (sawtooth[T320][idx] * w) + (sawtooth[T640][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 1280.0f)
+ {
+ w = ((1280.0f - c->freq) * INV_640);
+ out = (sawtooth[T640][idx] * w) + (sawtooth[T1280][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 2560.0f)
+ {
+ w = ((2560.0f - c->freq) * INV_1280);
+ out = (sawtooth[T1280][idx] * w) + (sawtooth[T2560][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 5120.0f)
+ {
+ w = ((5120.0f - c->freq) * INV_2560);
+ out = (sawtooth[T2560][idx] * w) + (sawtooth[T5120][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 10240.0f)
+ {
+ w = ((10240.0f - c->freq) * INV_5120);
+ out = (sawtooth[T5120][idx] * w) + (sawtooth[T10240][idx] * (1.0f - w));
+ }
+ else if (c->freq <= 20480.0f)
+ {
+ w = ((20480.0f - c->freq) * INV_10240);
+ out = (sawtooth[T10240][idx] * w) + (sawtooth[T20480][idx] * (1.0f - w));
+ }
+ else
+ {
+ out = sawtooth[T20480][idx];
+ }
+
+ return out;
+}
+
+void tSawtoothSampleRateChanged (tSawtooth* const c)
+{
+ c->inc = c->freq * leaf.invSampleRate;
+}
+
+//========================================================================
+/* Phasor */
+void tPhasorSampleRateChanged (tPhasor* const p)
+{
+ p->inc = p->freq * leaf.invSampleRate;
+};
+
+void tPhasor_init(tPhasor* const p)
+{
+ p->phase = 0.0f;
+ p->inc = 0.0f;
+}
+
+void tPhasor_free(tPhasor* const p)
+{
+
+}
+
+int tPhasor_setFreq(tPhasor* const p, float freq)
+{
+ if (freq < 0.0f) freq = 0.0f;
+
+ p->freq = freq;
+ p->inc = freq * leaf.invSampleRate;
+
+ return 0;
+}
+
+float tPhasor_tick(tPhasor* const p)
+{
+ p->phase += p->inc;
+
+ if (p->phase >= 1.0f) p->phase -= 1.0f;
+
+ return p->phase;
+}
+
+/* Noise */
+void tNoise_init(tNoise* const n, NoiseType type)
+{
+ n->type = type;
+ n->rand = leaf.random;
+}
+
+void tNoise_free(tNoise* const n)
+{
+
+}
+
+float tNoise_tick(tNoise* const n)
+{
+ float rand = (n->rand() * 2.0f) - 1.0f;
+
+ if (n->type == PinkNoise)
+ {
+ float tmp;
+ n->pinkb0 = 0.99765f * n->pinkb0 + rand * 0.0990460f;
+ n->pinkb1 = 0.96300f * n->pinkb1 + rand * 0.2965164f;
+ n->pinkb2 = 0.57000f * n->pinkb2 + rand * 1.0526913f;
+ tmp = n->pinkb0 + n->pinkb1 + n->pinkb2 + rand * 0.1848f;
+ return (tmp * 0.05f);
+ }
+ else // WhiteNoise
+ {
+ return rand;
+ }
+}
+
+//=================================================================================
+/* Neuron */
+
+void tNeuronSampleRateChanged(tNeuron* n)
+{
+
+}
+
+void tNeuron_init(tNeuron* const n)
+{
+ tPoleZero_init(&n->f);
+
+ tPoleZero_setBlockZero(&n->f, 0.99f);
+
+ n->timeStep = 1.0f / 50.0f;
+
+ n->current = 0.0f; // 100.0f for sound
+ n->voltage = 0.0f;
+
+ n->mode = NeuronNormal;
+
+ n->P[0] = 0.0f;
+ n->P[1] = 0.0f;
+ n->P[2] = 1.0f;
+
+ n->V[0] = -12.0f;
+ n->V[1] = 115.0f;
+ n->V[2] = 10.613f;
+
+ n->gK = 36.0f;
+ n->gN = 120.0f;
+ n->gL = 0.3f;
+ n->C = 1.0f;
+
+ n->rate[2] = n->gL/n->C;
+}
+
+void tNeuron_free(tNeuron* const n)
+{
+ tPoleZero_free(&n->f);
+}
+
+void tNeuron_reset(tNeuron* const n)
+{
+
+ tPoleZero_setBlockZero(&n->f, 0.99f);
+
+ n->timeStep = 1.0f / 50.0f;
+
+ n->current = 0.0f; // 100.0f for sound
+ n->voltage = 0.0f;
+
+ n->mode = NeuronNormal;
+
+ n->P[0] = 0.0f;
+ n->P[1] = 0.0f;
+ n->P[2] = 1.0f;
+
+ n->V[0] = -12.0f;
+ n->V[1] = 115.0f;
+ n->V[2] = 10.613f;
+
+ n->gK = 36.0f;
+ n->gN = 120.0f;
+ n->gL = 0.3f;
+ n->C = 1.0f;
+
+ n->rate[2] = n->gL/n->C;
+}
+
+
+void tNeuron_setV1(tNeuron* const n, float V1)
+{
+ n->V[0] = V1;
+}
+
+
+void tNeuron_setV2(tNeuron* const n, float V2)
+{
+ n->V[1] = V2;
+}
+
+void tNeuron_setV3(tNeuron* const n, float V3)
+{
+ n->V[2] = V3;
+}
+
+void tNeuron_setTimeStep(tNeuron* const n, float timeStep)
+{
+ n->timeStep = timeStep;
+}
+
+void tNeuron_setK(tNeuron* const n, float K)
+{
+ n->gK = K;
+}
+
+void tNeuron_setL(tNeuron* const n, float L)
+{
+ n->gL = L;
+ n->rate[2] = n->gL/n->C;
+}
+
+void tNeuron_setN(tNeuron* const n, float N)
+{
+ n->gN = N;
+}
+
+void tNeuron_setC(tNeuron* const n, float C)
+{
+ n->C = C;
+ n->rate[2] = n->gL/n->C;
+}
+
+float tNeuron_tick(tNeuron* const n)
+{
+ float output = 0.0f;
+ float voltage = n->voltage;
+
+ n->alpha[0] = (0.01f * (10.0f - voltage)) / (expf((10.0f - voltage)/10.0f) - 1.0f);
+ n->alpha[1] = (0.1f * (25.0f-voltage)) / (expf((25.0f-voltage)/10.0f) - 1.0f);
+ n->alpha[2] = (0.07f * expf((-1.0f * voltage)/20.0f));
+
+ n->beta[0] = (0.125f * expf((-1.0f* voltage)/80.0f));
+ n->beta[1] = (4.0f * expf((-1.0f * voltage)/18.0f));
+ n->beta[2] = (1.0f / (expf((30.0f-voltage)/10.0f) + 1.0f));
+
+ for (int i = 0; i < 3; i++)
+ {
+ n->P[i] = (n->alpha[i] * n->timeStep) + ((1.0f - ((n->alpha[i] + n->beta[i]) * n->timeStep)) * n->P[i]);
+
+ if (n->P[i] > 1.0f) n->P[i] = 0.0f;
+ else if (n->P[i] < -1.0f) n->P[i] = 0.0f;
+ }
+ // rate[0]= k ; rate[1] = Na ; rate[2] = l
+ n->rate[0] = ((n->gK * powf(n->P[0], 4.0f)) / n->C);
+ n->rate[1] = ((n->gN * powf(n->P[1], 3.0f) * n->P[2]) / n->C);
+
+ //calculate the final membrane voltage based on the computed variables
+ n->voltage = voltage +
+ (n->timeStep * n->current / n->C) -
+ (n->timeStep * ( n->rate[0] * (voltage - n->V[0]) + n->rate[1] * (voltage - n->V[1]) + n->rate[2] * (voltage - n->V[2])));
+
+ if (n->mode == NeuronTanh)
+ {
+ n->voltage = 100.0f * tanhf(0.01f * n->voltage);
+ }
+ else if (n->mode == NeuronAaltoShaper)
+ {
+ float shapeVoltage = 0.01f * n->voltage;
+
+ float w, c, xc, xc2, xc4;
+
+ float sqrt8 = 2.82842712475f;
+
+ float wscale = 1.30612244898f;
+ float m_drive = 1.0f;
+
+ xc = LEAF_clip(-sqrt8, shapeVoltage, sqrt8);
+
+ xc2 = xc*xc;
+
+ c = 0.5f * shapeVoltage * (3.0f - (xc2));
+
+ xc4 = xc2 * xc2;
+
+ w = (1.0f - xc2 * 0.25f + xc4 * 0.015625f) * wscale;
+
+ shapeVoltage = w * (c + 0.05f * xc2) * (m_drive + 0.75f);
+
+ n->voltage = 100.0f * shapeVoltage;
+ }
+
+
+ if (n->voltage > 100.0f) n->voltage = 100.0f;
+ else if (n->voltage < -100.) n->voltage = -100.0f;
+
+ //(inputCurrent + (voltage - ((voltage * timeStep) / timeConstant)) + P[0] + P[1] + P[2]) => voltage;
+ // now we should have a result
+ //set the output voltage to the "step" ugen, which controls the DAC.
+ output = n->voltage * 0.01f; // volts
+
+ output = tPoleZero_tick(&n->f, output);
+
+ return output;
+
+}
+
+void tNeuron_setMode (tNeuron* const n, NeuronMode mode)
+{
+ n->mode = mode;
+}
+
+void tNeuron_setCurrent (tNeuron* const n, float current)
+{
+ n->current = current;
+}
--- a/LEAF/Src/leaf-oversampler.c
+++ /dev/null
@@ -1,236 +1,0 @@
-//
-// 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"
-#include "..\Inc\leaf-tables.h"
-#else
-
-
-#include "../Inc/leaf-oversampler.h"
-#include "../Inc/leaf-tables.h"
-
-#endif
-
-// Oversampler
-// Latency is equal to the phase length (numTaps / ratio)
-void tOversampler_init(tOversampler* const os, int ratio, oBool extraQuality)
-{
- uint8_t offset = 0;
- if (extraQuality) offset = 6;
- if (ratio == 2 || ratio == 4 ||
- ratio == 8 || ratio == 16 ||
- ratio == 32 || ratio == 64) {
- os->ratio = ratio;
- int idx = (int)(log2f(os->ratio))-1+offset;
- os->numTaps = firNumTaps[idx];
- os->phaseLength = os->numTaps / os->ratio;
- os->pCoeffs = (float*) firCoeffs[idx];
- os->upState = leaf_alloc(sizeof(float) * os->phaseLength);
- os->downState = leaf_alloc(sizeof(float) * os->phaseLength);
- }
-}
-
-void tOversampler_free(tOversampler* const os)
-{
- leaf_free(os->upState);
- leaf_free(os->downState);
-}
-
-float tOversampler_tick(tOversampler* const os, float input, float (*effectTick)(float))
-{
- float buf[os->ratio];
-
- tOversampler_upsample(os, input, buf);
-
- for (int i = 0; i < os->ratio; ++i) {
- buf[i] = effectTick(buf[i]);
- }
-
- return tOversampler_downsample(os, buf);
-}
-
-// From CMSIS DSP Library
-void tOversampler_upsample(tOversampler* const os, float input, float* output)
-{
- float *pState = os->upState; /* State pointer */
- const float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
- float *pStateCur;
- float *ptr1; /* Temporary pointer for state buffer */
- const float *ptr2; /* Temporary pointer for coefficient buffer */
- float sum0; /* Accumulators */
- uint32_t i, tapCnt; /* Loop counters */
- uint32_t phaseLen = os->phaseLength; /* Length of each polyphase filter component */
- uint32_t j;
-
- /* os->pState buffer contains previous frame (phaseLen - 1) samples */
- /* pStateCur points to the location where the new input data should be written */
- pStateCur = os->upState + (phaseLen - 1U);
-
- /* Copy new input sample into the state buffer */
- *pStateCur = input;
-
- /* Address modifier index of coefficient buffer */
- j = 1U;
-
- /* Loop over the Interpolation factor. */
- i = os->ratio;
-
- while (i > 0U)
- {
- /* Set accumulator to zero */
- sum0 = 0.0f;
-
- /* Initialize state pointer */
- ptr1 = pState;
-
- /* Initialize coefficient pointer */
- ptr2 = pCoeffs + (os->ratio - j);
-
- /* Loop over the polyPhase length.
- Repeat until we've computed numTaps-(4*os->L) coefficients. */
-
- /* Initialize tapCnt with number of samples */
- tapCnt = phaseLen;
-
- while (tapCnt > 0U)
- {
- /* Perform the multiply-accumulate */
- sum0 += *ptr1++ * *ptr2;
-
- /* Upsampling is done by stuffing L-1 zeros between each sample.
- * So instead of multiplying zeros with coefficients,
- * Increment the coefficient pointer by interpolation factor times. */
- ptr2 += os->ratio;
-
- /* Decrement loop counter */
- tapCnt--;
- }
-
- /* The result is in the accumulator, store in the destination buffer. */
- *output++ = sum0 * os->ratio;
-
- /* Increment the address modifier index of coefficient buffer */
- j++;
-
- /* Decrement the loop counter */
- i--;
- }
-
- /* Advance the state pointer by 1
- * to process the next group of interpolation factor number samples */
- pState = pState + 1;
-
- /* Processing is complete.
- Now copy the last phaseLen - 1 samples to the satrt of the state buffer.
- This prepares the state buffer for the next function call. */
-
- /* Points to the start of the state buffer */
- pStateCur = os->upState;
-
- /* Initialize tapCnt with number of samples */
- tapCnt = (phaseLen - 1U);
-
- /* Copy data */
- while (tapCnt > 0U)
- {
- *pStateCur++ = *pState++;
-
- /* Decrement loop counter */
- tapCnt--;
- }
-}
-
-// From CMSIS DSP Library
-float tOversampler_downsample(tOversampler *const os, float* input)
-{
- float *pState = os->downState; /* State pointer */
- const float *pCoeffs = os->pCoeffs; /* Coefficient pointer */
- float *pStateCur; /* Points to the current sample of the state */
- float *px0; /* Temporary pointer for state buffer */
- const float *pb; /* Temporary pointer for coefficient buffer */
- float x0, c0; /* Temporary variables to hold state and coefficient values */
- float acc0; /* Accumulator */
- uint32_t numTaps = os->numTaps; /* Number of filter coefficients in the filter */
- uint32_t i, tapCnt;
- float output;
-
- /* os->pState buffer contains previous frame (numTaps - 1) samples */
- /* pStateCur points to the location where the new input data should be written */
- pStateCur = os->downState + (numTaps - 1U);
-
- /* Copy decimation factor number of new input samples into the state buffer */
- i = os->ratio;
-
- do
- {
- *pStateCur++ = *input++;
-
- } while (--i);
-
- /* Set accumulator to zero */
- acc0 = 0.0f;
-
- /* Initialize state pointer */
- px0 = pState;
-
- /* Initialize coeff pointer */
- pb = pCoeffs;
-
- /* Initialize tapCnt with number of taps */
- tapCnt = numTaps;
-
- while (tapCnt > 0U)
- {
- /* Read coefficients */
- c0 = *pb++;
-
- /* Fetch 1 state variable */
- x0 = *px0++;
-
- /* Perform the multiply-accumulate */
- acc0 += x0 * c0;
-
- /* Decrement loop counter */
- tapCnt--;
- }
-
- /* Advance the state pointer by the decimation factor
- * to process the next group of decimation factor number samples */
- pState = pState + os->ratio;
-
- /* The result is in the accumulator, store in the destination buffer. */
- output = acc0;
-
- /* Processing is complete.
- Now copy the last numTaps - 1 samples to the satrt of the state buffer.
- This prepares the state buffer for the next function call. */
-
- /* Points to the start of the state buffer */
- pStateCur = os->downState;
-
- /* Initialize tapCnt with number of taps */
- tapCnt = (numTaps - 1U);
-
- /* Copy data */
- while (tapCnt > 0U)
- {
- *pStateCur++ = *pState++;
-
- /* Decrement loop counter */
- tapCnt--;
- }
-
- return output;
-}
-
-int tOversampler_getLatency(tOversampler* const os)
-{
- return os->phaseLength;
-}
--- /dev/null
+++ b/LEAF/Src/leaf-physical.c
@@ -1,0 +1,596 @@
+/*==============================================================================
+
+ leaf-string.c
+ Created: 30 Nov 2018 10:41:42am
+ Author: airship
+
+==============================================================================*/
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-physical.h"
+
+#else
+
+#include "../Inc/leaf-physical.h"
+
+#endif
+
+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tPluck ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
+void tPluck_init (tPluck* const p, float lowestFrequency)
+{
+ if ( lowestFrequency <= 0.0f ) lowestFrequency = 10.0f;
+
+ tNoise_init(&p->noise, WhiteNoise);
+
+ tOnePole_init(&p->pickFilter, 0.0f);
+
+ tOneZero_init(&p->loopFilter, 0.0f);
+
+ tAllpassDelay_init(&p->delayLine, 0.0f, leaf.sampleRate * 2);
+
+ tPluck_setFrequency(p, 220.0f);
+}
+
+void tPluck_free (tPluck* const p)
+{
+ tNoise_free(&p->noise);
+ tOnePole_free(&p->pickFilter);
+ tOneZero_free(&p->loopFilter);
+ tAllpassDelay_free(&p->delayLine);
+}
+
+float tPluck_getLastOut (tPluck *p)
+{
+ return p->lastOut;
+}
+
+float tPluck_tick (tPluck *p)
+{
+ return (p->lastOut = 3.0f * tAllpassDelay_tick(&p->delayLine, tOneZero_tick(&p->loopFilter, tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain ) ));
+}
+
+void tPluck_pluck (tPluck* const p, float amplitude)
+{
+ if ( amplitude < 0.0f) amplitude = 0.0f;
+ else if (amplitude > 1.0f) amplitude = 1.0f;
+
+ tOnePole_setPole(&p->pickFilter, 0.999f - (amplitude * 0.15f));
+ tOnePole_setGain(&p->pickFilter, amplitude * 0.5f );
+
+ // Fill delay with noise additively with current contents.
+ for ( uint32_t i = 0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ )
+ tAllpassDelay_tick(&p->delayLine, 0.6f * tAllpassDelay_getLastOut(&p->delayLine) + tOnePole_tick(&p->pickFilter, tNoise_tick(&p->noise) ) );
+}
+
+// Start a note with the given frequency and amplitude.;
+void tPluck_noteOn (tPluck* const p, float frequency, float amplitude )
+{
+ p->lastFreq = frequency;
+ tPluck_setFrequency( p, frequency );
+ tPluck_pluck( p, amplitude );
+}
+
+// Stop a note with the given amplitude (speed of decay).
+void tPluck_noteOff (tPluck* const p, float amplitude )
+{
+ if ( amplitude < 0.0f) amplitude = 0.0f;
+ else if (amplitude > 1.0f) amplitude = 1.0f;
+
+ p->loopGain = 1.0f - amplitude;
+}
+
+// Set instrument parameters for a particular frequency.
+void tPluck_setFrequency (tPluck* const p, float frequency )
+{
+ if ( frequency <= 0.0f ) frequency = 0.001f;
+
+ // Delay = length - filter delay.
+ float delay = ( leaf.sampleRate / frequency ) - tOneZero_getPhaseDelay(&p->loopFilter, frequency );
+
+ tAllpassDelay_setDelay(&p->delayLine, delay );
+
+ p->loopGain = 0.99f + (frequency * 0.000005f);
+
+ if ( p->loopGain >= 0.999f ) p->loopGain = 0.999f;
+
+}
+
+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
+void tPluck_controlChange (tPluck* const p, int number, float value)
+{
+ return;
+}
+
+void tPluckSampleRateChanged(tPluck* const p)
+{
+ //tPluckSetFrequency(p, p->lastFreq);
+}
+
+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tKarplusStrong ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
+void tKarplusStrong_init (tKarplusStrong* const p, float lowestFrequency)
+{
+ if ( lowestFrequency <= 0.0f ) lowestFrequency = 8.0f;
+
+ tAllpassDelay_init(&p->delayLine, 0.0f, leaf.sampleRate * 2);
+
+ tLinearDelay_init(&p->combDelay, 0.0f, leaf.sampleRate * 2);
+
+ tOneZero_init(&p->filter, 0.0f);
+
+ tNoise_init(&p->noise, WhiteNoise);
+
+ for (int i = 0; i < 4; i++)
+ {
+ tBiQuad_init(&p->biquad[i]);
+ }
+
+ p->pluckAmplitude = 0.3f;
+ p->pickupPosition = 0.4f;
+
+ p->stretching = 0.9999f;
+ p->baseLoopGain = 0.995f;
+ p->loopGain = 0.999f;
+
+ tKarplusStrong_setFrequency( p, 220.0f );
+
+}
+
+void tKarplusStrong_free (tKarplusStrong* const p)
+{
+ tAllpassDelay_free(&p->delayLine);
+ tLinearDelay_free(&p->combDelay);
+ tOneZero_free(&p->filter);
+ tNoise_free(&p->noise);
+
+ for (int i = 0; i < 4; i++)
+ {
+ tBiQuad_free(&p->biquad[i]);
+ }
+}
+
+float tKarplusStrong_getLastOut (tKarplusStrong* const p)
+{
+ return p->lastOut;
+}
+
+float tKarplusStrong_tick (tKarplusStrong* const p)
+{
+ float temp = tAllpassDelay_getLastOut(&p->delayLine) * p->loopGain;
+
+ // Calculate allpass stretching.
+ for (int i=0; i<4; i++) temp = tBiQuad_tick(&p->biquad[i],temp);
+
+ // Moving average filter.
+ temp = tOneZero_tick(&p->filter, temp);
+
+ float out = tAllpassDelay_tick(&p->delayLine, temp);
+ out = out - tLinearDelay_tick(&p->combDelay, out);
+ p->lastOut = out;
+
+ return p->lastOut;
+}
+
+void tKarplusStrong_pluck (tKarplusStrong* const p, float amplitude)
+{
+ if ( amplitude < 0.0f) amplitude = 0.0f;
+ else if (amplitude > 1.0f) amplitude = 1.0f;
+
+ p->pluckAmplitude = amplitude;
+
+ for ( uint32_t i=0; i < (uint32_t)tAllpassDelay_getDelay(&p->delayLine); i++ )
+ {
+ // Fill delay with noise additively with current contents.
+ tAllpassDelay_tick(&p->delayLine, (tAllpassDelay_getLastOut(&p->delayLine) * 0.6f) + 0.4f * tNoise_tick(&p->noise) * p->pluckAmplitude );
+ //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) );
+ }
+}
+
+// Start a note with the given frequency and amplitude.;
+void tKarplusStrong_noteOn (tKarplusStrong* const p, float frequency, float amplitude )
+{
+ tKarplusStrong_setFrequency( p, frequency );
+ tKarplusStrong_pluck( p, amplitude );
+}
+
+// Stop a note with the given amplitude (speed of decay).
+void tKarplusStrong_noteOff (tKarplusStrong* const p, float amplitude )
+{
+ if ( amplitude < 0.0f) amplitude = 0.0f;
+ else if (amplitude > 1.0f) amplitude = 1.0f;
+
+ p->loopGain = 1.0f - amplitude;
+}
+
+// Set instrument parameters for a particular frequency.
+void tKarplusStrong_setFrequency (tKarplusStrong* const p, float frequency )
+{
+ if ( frequency <= 0.0f ) frequency = 0.001f;
+
+ p->lastFrequency = frequency;
+ p->lastLength = leaf.sampleRate / p->lastFrequency;
+ float delay = p->lastLength - 0.5f;
+ tAllpassDelay_setDelay(&p->delayLine, delay);
+
+ // MAYBE MODIFY LOOP GAINS
+ p->loopGain = p->baseLoopGain + (frequency * 0.000005f);
+ if (p->loopGain >= 1.0f) p->loopGain = 0.99999f;
+
+ tKarplusStrong_setStretch(p, p->stretching);
+
+ tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength );
+
+}
+
+// Set the stretch "factor" of the string (0.0 - 1.0).
+void tKarplusStrong_setStretch (tKarplusStrong* const p, float stretch )
+{
+ p->stretching = stretch;
+ float coefficient;
+ float freq = p->lastFrequency * 2.0f;
+ float dFreq = ( (0.5f * leaf.sampleRate) - freq ) * 0.25f;
+ float temp = 0.5f + (stretch * 0.5f);
+ if ( temp > 0.9999f ) temp = 0.9999f;
+
+ for ( int i=0; i<4; i++ )
+ {
+ coefficient = temp * temp;
+ tBiQuad_setA2(&p->biquad[i], coefficient);
+ tBiQuad_setB0(&p->biquad[i], coefficient);
+ tBiQuad_setB2(&p->biquad[i], 1.0f);
+
+ coefficient = -2.0f * temp * cos(TWO_PI * freq / leaf.sampleRate);
+ tBiQuad_setA1(&p->biquad[i], coefficient);
+ tBiQuad_setB1(&p->biquad[i], coefficient);
+
+ freq += dFreq;
+ }
+}
+
+// Set the pluck or "excitation" position along the string (0.0 - 1.0).
+void tKarplusStrong_setPickupPosition (tKarplusStrong* const p, float position )
+{
+ if (position < 0.0f) p->pickupPosition = 0.0f;
+ else if (position <= 1.0f) p->pickupPosition = position;
+ else p->pickupPosition = 1.0f;
+
+ tLinearDelay_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength);
+}
+
+// Set the base loop gain.
+void tKarplusStrong_setBaseLoopGain (tKarplusStrong* const p, float aGain )
+{
+ p->baseLoopGain = aGain;
+ p->loopGain = p->baseLoopGain + (p->lastFrequency * 0.000005f);
+ if ( p->loopGain > 0.99999f ) p->loopGain = 0.99999f;
+}
+
+// Perform the control change specified by \e number and \e value (0.0 - 128.0).
+void tKarplusStrong_controlChange (tKarplusStrong* const p, SKControlType type, float value)
+{
+ if ( value < 0.0f ) value = 0.0f;
+ else if (value > 128.0f) value = 128.0f;
+
+ float normalizedValue = value * INV_128;
+
+ if (type == SKPickPosition) // 4
+ tKarplusStrong_setPickupPosition( p, normalizedValue );
+ else if (type == SKStringDamping) // 11
+ tKarplusStrong_setBaseLoopGain( p, 0.97f + (normalizedValue * 0.03f) );
+ else if (type == SKDetune) // 1
+ tKarplusStrong_setStretch( p, 0.91f + (0.09f * (1.0f - normalizedValue)) );
+
+}
+
+void tKarplusStrongSampleRateChanged (tKarplusStrong* const c)
+{
+ tKarplusStrong_setFrequency(c, c->lastFrequency);
+ tKarplusStrong_setStretch(c, c->stretching);
+}
+
+/* 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);
+ tLinearDelay_init(&p->delayLine,p->waveLengthInSamples, 2400);
+ tOnePole_init(&p->bridgeFilter, dampFreq);
+ tHighpass_init(&p->DCblocker,13);
+ p->decay=decay;
+ tFeedbackLeveler_init(&p->fbLev, targetLev, levSmoothFactor, levStrength, levMode);
+ p->levMode=levMode;
+}
+
+void tSimpleLivingString_free(tSimpleLivingString* const p)
+{
+ tExpSmooth_free(&p->wlSmooth);
+ tLinearDelay_free(&p->delayLine);
+ tOnePole_free(&p->bridgeFilter);
+ tHighpass_free(&p->DCblocker);
+ tFeedbackLeveler_free(&p->fbLev);
+}
+
+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)
+{
+ tFeedbackLeveler_setTargetLevel(&p->fbLev, targetLev);
+ return 0;
+}
+
+int tSimpleLivingString_setLevSmoothFactor(tSimpleLivingString* const p, float levSmoothFactor)
+{
+ tFeedbackLeveler_setFactor(&p->fbLev, levSmoothFactor);
+ return 0;
+}
+
+int tSimpleLivingString_setLevStrength(tSimpleLivingString* const p, float levStrength)
+{
+ tFeedbackLeveler_setStrength(&p->fbLev, levStrength);
+ return 0;
+}
+
+int tSimpleLivingString_setLevMode(tSimpleLivingString* const p, int levMode)
+{
+ tFeedbackLeveler_setMode(&p->fbLev, levMode);
+ p->levMode=levMode;
+ return 0;
+}
+
+float tSimpleLivingString_tick(tSimpleLivingString* const p, float input)
+{
+ float stringOut=tOnePole_tick(&p->bridgeFilter,tLinearDelay_tickOut(&p->delayLine));
+ float stringInput=tHighpass_tick(&p->DCblocker, tFeedbackLeveler_tick(&p->fbLev, (p->levMode==0?p->decay*stringOut:stringOut)+input));
+ tLinearDelay_tickIn(&p->delayLine, stringInput);
+ tLinearDelay_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;
+ tLinearDelay_init(&p->delLF,p->waveLengthInSamples, 2400);
+ tLinearDelay_init(&p->delUF,p->waveLengthInSamples, 2400);
+ tLinearDelay_init(&p->delUB,p->waveLengthInSamples, 2400);
+ tLinearDelay_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;
+ tFeedbackLeveler_init(&p->fbLevU, targetLev, levSmoothFactor, levStrength, levMode);
+ tFeedbackLeveler_init(&p->fbLevL, targetLev, levSmoothFactor, levStrength, levMode);
+ p->levMode=levMode;
+}
+
+void tLivingString_free(tLivingString* const p)
+{
+ tExpSmooth_free(&p->wlSmooth);
+ tExpSmooth_free(&p->ppSmooth);
+ tLinearDelay_free(&p->delLF);
+ tLinearDelay_free(&p->delUF);
+ tLinearDelay_free(&p->delUB);
+ tLinearDelay_free(&p->delLB);
+ tOnePole_free(&p->bridgeFilter);
+ tOnePole_free(&p->nutFilter);
+ tOnePole_free(&p->prepFilterU);
+ tOnePole_free(&p->prepFilterL);
+ tHighpass_free(&p->DCblockerU);
+ tHighpass_free(&p->DCblockerL);
+ tFeedbackLeveler_free(&p->fbLevU);
+ tFeedbackLeveler_free(&p->fbLevL);
+}
+
+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)
+{
+ tFeedbackLeveler_setTargetLevel(&p->fbLevU, targetLev);
+ tFeedbackLeveler_setTargetLevel(&p->fbLevL, targetLev);
+ return 0;
+}
+
+int tLivingString_setLevSmoothFactor(tLivingString* const p, float levSmoothFactor)
+{
+ tFeedbackLeveler_setFactor(&p->fbLevU, levSmoothFactor);
+ tFeedbackLeveler_setFactor(&p->fbLevL, levSmoothFactor);
+ return 0;
+}
+
+int tLivingString_setLevStrength(tLivingString* const p, float levStrength)
+{
+ tFeedbackLeveler_setStrength(&p->fbLevU, levStrength);
+ tFeedbackLeveler_setStrength(&p->fbLevL, levStrength);
+ return 0;
+}
+
+int tLivingString_setLevMode(tLivingString* const p, int levMode)
+{
+ tFeedbackLeveler_setMode(&p->fbLevU, levMode);
+ tFeedbackLeveler_setMode(&p->fbLevL, levMode);
+ p->levMode=levMode;
+ return 0;
+}
+
+float tLivingString_tick(tLivingString* const p, float input)
+{
+ // from pickPos upwards=forwards
+ float fromLF=tLinearDelay_tickOut(&p->delLF);
+ float fromUF=tLinearDelay_tickOut(&p->delUF);
+ float fromUB=tLinearDelay_tickOut(&p->delUB);
+ float fromLB=tLinearDelay_tickOut(&p->delLB);
+ // into upper half of string, from nut, going backwards
+ float fromNut=-tFeedbackLeveler_tick(&p->fbLevU, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerU, tOnePole_tick(&p->nutFilter, fromUF)));
+ tLinearDelay_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;
+ tLinearDelay_tickIn(&p->delLB, intoLower);
+ // into lower half of string, from bridge
+ float fromBridge=-tFeedbackLeveler_tick(&p->fbLevL, (p->levMode==0?p->decay:1)*tHighpass_tick(&p->DCblockerL, tOnePole_tick(&p->bridgeFilter, fromLB)));
+ tLinearDelay_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;
+ tLinearDelay_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;
+ tLinearDelay_setDelay(&p->delLF, lowLen);
+ tLinearDelay_setDelay(&p->delLB, lowLen);
+ tLinearDelay_setDelay(&p->delUF, upLen);
+ tLinearDelay_setDelay(&p->delUB, upLen);
+ p->curr = fromBridge;
+ return p->curr;
+}
+
+float tLivingString_sample(tLivingString* const p)
+{
+ return p->curr;
+}
+
+///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;
+}
--- a/LEAF/Src/leaf-pitch.c
+++ /dev/null
@@ -1,563 +1,0 @@
-/*==============================================================================
-
- leaf-pitch.c
- Created: 30 Nov 2018 11:02:59am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-pitch.h"
-#else
-
-#include "../Inc/leaf-pitch.h"
-
-#endif
-
-static int pitchshifter_attackdetect(tPitchShifter* ps);
-
-void tPitchShifter_init(tPitchShifter* const ps, float* in, float* out, 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;
-
- ps->hopSize = DEFHOPSIZE;
- ps->windowSize = DEFWINDOWSIZE;
- ps->fba = FBA;
-
- tEnv_init(&ps->env, ps->windowSize, ps->hopSize, ps->frameSize);
-
- tSNAC_init(&ps->snac, DEFOVERLAP);
-
- tSOLAD_init(&ps->sola);
-
- tHighpass_init(&ps->hp, HPFREQ);
-
- tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
-
- tPitchShifter_setTimeConstant(ps, DEFTIMECONSTANT);
-}
-
-void tPitchShifter_free(tPitchShifter* const ps)
-{
- tEnv_free(&ps->env);
- tSNAC_free(&ps->snac);
- tSOLAD_free(&ps->sola);
- tHighpass_free(&ps->hp);
-}
-
-float tPitchShifter_tick(tPitchShifter* ps, float sample)
-{
- 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)
- {
- ps->index = 0;
-
- tEnv_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);
-
- }
-
- return out;
-}
-
-float tPitchShifterToFreq_tick(tPitchShifter* ps, float sample, float freq)
-{
- 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)
- {
- ps->index = 0;
-
- tEnv_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;
- }
-
- return out;
-}
-
-float tPitchShifterToFunc_tick(tPitchShifter* ps, float sample, float (*fun)(float))
-{
- 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)
- {
- ps->index = 0;
-
- tEnv_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;
- }
-
- return out;
-}
-
-void tPitchShifter_ioSamples(tPitchShifter* ps, float* in, float* out, int size)
-{
- float period;
-
- tEnv_processBlock(&ps->env, in);
-
- if(pitchshifter_attackdetect(ps) == 1)
- {
- ps->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->windowSize);
- }
-
- tSNAC_ioSamples(&ps->snac, in, out, size);
- period = tSNAC_getPeriod(&ps->snac);
-
- 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)
- {
- out[cc] = tHighpass_tick(&ps->hp, out[cc]);
- }
-}
-
-void tPitchShifter_ioSamples_toFreq(tPitchShifter* ps, float* in, float* out, int size, float toFreq)
-{
- float period;
-
- tEnv_processBlock(&ps->env, in);
-
- if(pitchshifter_attackdetect(ps) == 1)
- {
- ps->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->windowSize);
- }
-
- 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]);
- }
-}
-
-void tPitchShifter_ioSamples_toPeriod(tPitchShifter* ps, float* in, float* out, int size, float toPeriod)
-{
- float period;
-
- tEnv_processBlock(&ps->env, in);
-
- if(pitchshifter_attackdetect(ps) == 1)
- {
- ps->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->windowSize);
- }
-
- 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]);
- }
-}
-
-void tPitchShifter_ioSamples_toFunc(tPitchShifter* ps, float* in, float* out, int size, float (*fun)(float))
-{
- float period;
-
- tEnv_processBlock(&ps->env, in);
-
- if(pitchshifter_attackdetect(ps) == 1)
- {
- ps->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->windowSize);
- }
-
- tSNAC_ioSamples(&ps->snac, in, out, size);
- 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, in, out, size);
-
- for (int cc = 0; cc < size; ++cc)
- {
- out[cc] = tHighpass_tick(&ps->hp, out[cc]);
- }
-}
-
-void tPitchShifter_setPitchFactor(tPitchShifter* ps, float pf)
-{
- ps->pitchFactor = pf;
-}
-
-void tPitchShifter_setTimeConstant(tPitchShifter* ps, float tc)
-{
- ps->timeConstant = tc;
- ps->radius = expf(-1000.0f * ps->hopSize * leaf.invSampleRate / ps->timeConstant);
-}
-
-void tPitchShifter_setHopSize(tPitchShifter* ps, int hs)
-{
- ps->hopSize = hs;
-}
-
-void tPitchShifter_setWindowSize(tPitchShifter* ps, int ws)
-{
- ps->windowSize = ws;
-}
-
-float tPitchShifter_getPeriod(tPitchShifter* ps)
-{
- return tSNAC_getPeriod(&ps->snac);
-}
-
-static int pitchshifter_attackdetect(tPitchShifter* ps)
-{
- float envout;
-
- envout = tEnv_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;
-}
-
-
-void tPeriod_init (tPeriod* const p, float* in, float* out, int bufSize, int frameSize)
-{
- p->inBuffer = in;
- p->outBuffer = out;
- p->bufSize = bufSize;
- p->frameSize = frameSize;
- p->framesPerBuffer = p->bufSize / p->frameSize;
- p->curBlock = 1;
- p->lastBlock = 0;
- p->index = 0;
-
- p->hopSize = DEFHOPSIZE;
- p->windowSize = DEFWINDOWSIZE;
- p->fba = FBA;
-
- tEnv_init(&p->env, p->windowSize, p->hopSize, p->frameSize);
-
- tSNAC_init(&p->snac, DEFOVERLAP);
-
- p->timeConstant = DEFTIMECONSTANT;
- p->radius = expf(-1000.0f * p->hopSize * leaf.invSampleRate / p->timeConstant);
-}
-
-void tPeriod_free (tPeriod* const p)
-{
- tEnv_free(&p->env);
- tSNAC_free(&p->snac);
-}
-
-float tPeriod_findPeriod (tPeriod* p, float sample)
-{
- int i, iLast;
-
- i = (p->curBlock*p->frameSize);
- iLast = (p->lastBlock*p->frameSize)+p->index;
-
- p->i = i;
- p->iLast = iLast;
-
- p->inBuffer[i+p->index] = sample;
-
- p->index++;
- p->indexstore = p->index;
- if (p->index >= p->frameSize)
- {
- p->index = 0;
-
- tEnv_processBlock(&p->env, &(p->inBuffer[i]));
-
- tSNAC_ioSamples(&p->snac, &(p->inBuffer[i]), &(p->outBuffer[i]), p->frameSize);
- p->period = tSNAC_getPeriod(&p->snac);
-
- p->curBlock++;
- if (p->curBlock >= p->framesPerBuffer) p->curBlock = 0;
- p->lastBlock++;
- if (p->lastBlock >= p->framesPerBuffer) p->lastBlock = 0;
- }
-
- // changed from period to p->period
- return p->period;
-}
-
-void tPeriod_setHopSize(tPeriod* p, int hs)
-{
- p->hopSize = hs;
-}
-
-void tPeriod_setWindowSize(tPeriod* p, int ws)
-{
- p->windowSize = ws;
-}
-
-void tPitchShift_setPitchFactor(tPitchShift* ps, float pf)
-{
- ps->pitchFactor = pf;
-}
-
-static int pitchshift_attackdetect(tPitchShift* ps)
-{
- float envout;
-
- envout = tEnv_tick(&ps->p->env);
-
- if (envout >= 1.0f)
- {
- ps->p->lastmax = ps->p->max;
- if (envout > ps->p->max)
- {
- ps->p->max = envout;
- }
- else
- {
- ps->p->deltamax = envout - ps->p->max;
- ps->p->max = ps->p->max * ps->radius;
- }
- ps->p->deltamax = ps->p->max - ps->p->lastmax;
- }
-
- ps->p->fba = ps->p->fba ? (ps->p->fba - 1) : 0;
-
- return (ps->p->fba == 0 && (ps->p->max > 60 && ps->p->deltamax > 6)) ? 1 : 0;
-}
-
-void tPitchShift_init (tPitchShift* const ps, tPeriod* p, float* out, int bufSize)
-{
- ps->p = p;
-
- ps->outBuffer = out;
- ps->bufSize = bufSize;
- ps->frameSize = p->frameSize;
- ps->framesPerBuffer = ps->bufSize / ps->frameSize;
- ps->curBlock = 1;
- ps->lastBlock = 0;
- ps->index = 0;
- ps->pitchFactor = 1.0f;
-
- tSOLAD_init(&ps->sola);
-
- tHighpass_init(&ps->hp, HPFREQ);
-
- tSOLAD_setPitchFactor(&ps->sola, DEFPITCHRATIO);
-}
-
-void tPitchShift_free(tPitchShift* const ps)
-{
- tSOLAD_free(&ps->sola);
- tHighpass_free(&ps->hp);
-}
-
-float tPitchShift_shift (tPitchShift* ps)
-{
- float period, out;
- int i, iLast;
-
- i = ps->p->i;
- iLast = ps->p->iLast;
-
- out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-
- if (ps->p->indexstore >= ps->frameSize)
- {
- period = ps->p->period;
-
- if(pitchshift_attackdetect(ps) == 1)
- {
- ps->p->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
- }
-
- tSOLAD_setPeriod(&ps->sola, period);
- tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-
- tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
- }
-
- return out;
-}
-
-float tPitchShift_shiftToFreq (tPitchShift* ps, float freq)
-{
- float period, out;
- int i, iLast;
-
- i = ps->p->i;
- iLast = ps->p->iLast;
-
- out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-
- if (ps->p->indexstore >= ps->frameSize)
- {
- period = ps->p->period;
-
- if(pitchshift_attackdetect(ps) == 1)
- {
- ps->p->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
- }
-
- tSOLAD_setPeriod(&ps->sola, period);
-
- ps->pitchFactor = period*freq*leaf.invSampleRate;
- tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-
- tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
- }
- return out;
-}
-
-float tPitchShift_shiftToFunc (tPitchShift* ps, float (*fun)(float))
-{
- float period, out;
- int i, iLast;
-
- i = ps->p->i;
- iLast = ps->p->iLast;
-
- out = tHighpass_tick(&ps->hp, ps->outBuffer[iLast]);
-
- if (ps->p->indexstore >= ps->frameSize)
- {
- period = ps->p->period;
-
- if(pitchshift_attackdetect(ps) == 1)
- {
- ps->p->fba = 5;
- tSOLAD_setReadLag(&ps->sola, ps->p->windowSize);
- }
-
- tSOLAD_setPeriod(&ps->sola, period);
-
- ps->pitchFactor = period/fun(period);
- tSOLAD_setPitchFactor(&ps->sola, ps->pitchFactor);
-
- tSOLAD_ioSamples(&ps->sola, &(ps->p->inBuffer[i]), &(ps->outBuffer[i]), ps->frameSize);
-
- ps->curBlock++;
- if (ps->curBlock >= ps->p->framesPerBuffer) ps->curBlock = 0;
- ps->lastBlock++;
- if (ps->lastBlock >= ps->framesPerBuffer) ps->lastBlock = 0;
- }
-
- return out;
-}
--- a/LEAF/Src/leaf-reverb.c
+++ b/LEAF/Src/leaf-reverb.c
@@ -18,8 +18,8 @@
#endif
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tPRCRev_init(tPRCRev* const r, float t60)
+// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ PRCReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
+void tPRCReverb_init(tPRCReverb* const r, float t60)
{
if (t60 <= 0.0f) t60 = 0.001f;
@@ -47,13 +47,13 @@
tDelay_init(&r->allpassDelays[1], lengths[1], lengths[1] * 2);
tDelay_init(&r->combDelay, lengths[2], lengths[2] * 2);
- tPRCRev_setT60(r, t60);
+ tPRCReverb_setT60(r, t60);
r->allpassCoeff = 0.7f;
r->mix = 0.5f;
}
-void tPRCRev_free(tPRCRev* const r)
+void tPRCReverb_free(tPRCReverb* const r)
{
tDelay_free(&r->allpassDelays[0]);
tDelay_free(&r->allpassDelays[1]);
@@ -60,7 +60,7 @@
tDelay_free(&r->combDelay);
}
-void tPRCRev_setT60(tPRCRev* const r, float t60)
+void tPRCReverb_setT60(tPRCReverb* const r, float t60)
{
if ( t60 <= 0.0f ) t60 = 0.001f;
@@ -70,12 +70,12 @@
}
-void tPRCRev_setMix(tPRCRev* const r, float mix)
+void tPRCReverb_setMix(tPRCReverb* const r, float mix)
{
r->mix = mix;
}
-float tPRCRev_tick(tPRCRev* const r, float input)
+float tPRCReverb_tick(tPRCReverb* const r, float input)
{
float temp, temp0, temp1, temp2;
float out;
@@ -107,13 +107,13 @@
return out;
}
-void tPRCRevSampleRateChanged (tPRCRev* const r)
+void tPRCReverbSampleRateChanged (tPRCReverb* const r)
{
r->combCoeff = pow(10.0f, (-3.0f * tDelay_getDelay(&r->combDelay) * leaf.invSampleRate / r->t60 ));
}
-/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NRev ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
-void tNRev_init(tNRev* const r, float t60)
+/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ NReverb ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
+void tNReverb_init(tNReverb* const r, float t60)
{
if (t60 <= 0.0f) t60 = 0.001f;
@@ -150,12 +150,12 @@
tDelay_setDelay(&r->combDelays[i], lengths[i+2]);
}
- tNRev_setT60(r, t60);
+ tNReverb_setT60(r, t60);
r->allpassCoeff = 0.7f;
r->mix = 0.3f;
}
-void tNRev_free(tNRev* const r)
+void tNReverb_free(tNReverb* const r)
{
for (int i = 0; i < 6; i++)
{
@@ -168,7 +168,7 @@
}
}
-void tNRev_setT60(tNRev* const r, float t60)
+void tNReverb_setT60(tNReverb* const r, float t60)
{
if (t60 <= 0.0f) t60 = 0.001f;
@@ -178,12 +178,12 @@
}
-void tNRev_setMix(tNRev* const r, float mix)
+void tNReverb_setMix(tNReverb* const r, float mix)
{
r->mix = mix;
}
-float tNRev_tick(tNRev* const r, float input)
+float tNReverb_tick(tNReverb* const r, float input)
{
r->lastIn = input;
@@ -221,10 +221,10 @@
out = r->mix * ( -( r->allpassCoeff * temp2 ) + temp );
/*
- temp = tDelayLGetLastOut(&r->allpassDelays[5]);
+ temp = tLinearDelayGetLastOut(&r->allpassDelays[5]);
temp3 = r->allpassCoeff * temp;
temp3 += temp1;
- tDelayLTick(&r->allpassDelays[5], temp3 );
+ tLinearDelayTick(&r->allpassDelays[5], temp3 );
lastFrame_[1] = effectMix_*( - ( r->allpassCoeff * temp3 ) + temp );
*/
@@ -237,7 +237,7 @@
return out;
}
-void tNRevSampleRateChanged (tNRev* const r)
+void tNReverbSampleRateChanged (tNReverb* const r)
{
for (int i=0; i<6; i++) r->combCoeffs[i] = pow(10.0, (-3.0 * tDelay_getDelay(&r->combDelays[i]) * leaf.invSampleRate / r->t60 ));
}
@@ -250,7 +250,7 @@
float in_allpass_gains[4] = { 0.75f, 0.75f, 0.625f, 0.625f };
-void tDattorro_init (tDattorro* const r)
+void tDattorroReverb_init (tDattorroReverb* const r)
{
r->size_max = 2.0f;
r->size = 1.f;
@@ -298,20 +298,20 @@
// PARAMETERS
- tDattorro_setMix(r, 0.5f);
+ tDattorroReverb_setMix(r, 0.5f);
- tDattorro_setInputDelay(r, 0.f);
+ tDattorroReverb_setInputDelay(r, 0.f);
- tDattorro_setInputFilter(r, 10000.f);
+ tDattorroReverb_setInputFilter(r, 10000.f);
- tDattorro_setFeedbackFilter(r, 5000.f);
+ tDattorroReverb_setFeedbackFilter(r, 5000.f);
- tDattorro_setFeedbackGain(r, 0.4f);
+ tDattorroReverb_setFeedbackGain(r, 0.4f);
}
-void tDattorro_free (tDattorro* const r)
+void tDattorroReverb_free (tDattorroReverb* const r)
{
// INPUT
tTapeDelay_free(&r->in_delay);
@@ -349,7 +349,7 @@
tCycle_free(&r->f2_lfo);
}
-float tDattorro_tick (tDattorro* const r, float input)
+float tDattorroReverb_tick (tDattorroReverb* const r, float input)
{
// INPUT
float in_sample = tTapeDelay_tick(&r->in_delay, input);
@@ -449,12 +449,12 @@
return (input * (1.0f - r->mix) + sample * r->mix);
}
-void tDattorro_setMix (tDattorro* const r, float mix)
+void tDattorroReverb_setMix (tDattorroReverb* const r, float mix)
{
r->mix = LEAF_clip(0.0f, mix, 1.0f);
}
-void tDattorro_setSize (tDattorro* const r, float size)
+void tDattorroReverb_setSize (tDattorroReverb* const r, float size)
{
r->size = LEAF_clip(0.01f, size*r->size_max, r->size_max);
r->t = r->size * leaf.sampleRate * 0.001f;
@@ -483,7 +483,7 @@
tTapeDelay_setDelay(&r->f2_delay_3, SAMP(106.28f));
}
-void tDattorro_setInputDelay (tDattorro* const r, float preDelay)
+void tDattorroReverb_setInputDelay (tDattorroReverb* const r, float preDelay)
{
r->predelay = LEAF_clip(0.0f, preDelay, 200.0f);
@@ -490,7 +490,7 @@
tTapeDelay_setDelay(&r->in_delay, SAMP(r->predelay));
}
-void tDattorro_setInputFilter (tDattorro* const r, float freq)
+void tDattorroReverb_setInputFilter (tDattorroReverb* const r, float freq)
{
r->input_filter = LEAF_clip(0.0f, freq, 20000.0f);
@@ -497,7 +497,7 @@
tOnePole_setFreq(&r->in_filter, r->input_filter);
}
-void tDattorro_setFeedbackFilter (tDattorro* const r, float freq)
+void tDattorroReverb_setFeedbackFilter (tDattorroReverb* const r, float freq)
{
r->feedback_filter = LEAF_clip(0.0f, freq, 20000.0f);
@@ -505,7 +505,7 @@
tOnePole_setFreq(&r->f2_filter, r->feedback_filter);
}
-void tDattorro_setFeedbackGain (tDattorro* const r, float gain)
+void tDattorroReverb_setFeedbackGain (tDattorroReverb* const r, float gain)
{
r->feedback_gain = gain;
}
--- a/LEAF/Src/leaf-sample.c
+++ /dev/null
@@ -1,436 +1,0 @@
-/*
- ==============================================================================
-
- leaf-sample.c
- Created: 20 Jan 2017 12:02:17pm
- Author: Michael R Mulshine
-
- ==============================================================================
-*/
-
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-sample.h"
-#include "..\leaf.h"
-
-#else
-
-#include "../Inc/leaf-sample.h"
-#include "../leaf.h"
-
-#endif
-
-//==============================================================================
-
-void tBuffer_init (tBuffer* const s, uint32_t length)
-{
- s->buff = (float*) leaf_alloc( sizeof(float) * length);
-
-
- s->length = length;
- s->active = 0;
- s->idx = 0;
- s->mode = RecordOneShot;
-
- tBuffer_clear(s);
-}
-
-void tBuffer_free (tBuffer* const s)
-{
- leaf_free(s->buff);
-}
-
-void tBuffer_tick (tBuffer* const s, float sample)
-{
- if (s->active == 1)
- {
- s->buff[s->idx] = sample;
-
- s->idx += 1;
-
- if (s->idx >= s->length)
- {
- if (s->mode == RecordOneShot)
- {
- tBuffer_stop(s);
- }
- else if (s->mode == RecordLoop)
- {
- s->idx = 0;
- }
- }
- }
-}
-
-void tBuffer_read(tBuffer* const s, float* buff, uint32_t len)
-{
- for (int i = 0; i < s->length; i++)
- {
- if (i < len) s->buff[i] = buff[i];
- else s->buff[i] = 0.f;
- }
-}
-
-float tBuffer_get (tBuffer* const s, int idx)
-{
- if ((idx < 0) || (idx >= s->length)) return 0.f;
-
- return s->buff[idx];
-}
-
-void tBuffer_record(tBuffer* const s)
-{
- s->active = 1;
- s->idx = 0;
-}
-
-void tBuffer_stop(tBuffer* const s)
-{
- s->active = 0;
-}
-
-void tBuffer_setRecordMode (tBuffer* const s, RecordMode mode)
-{
- s->mode = mode;
-}
-
-void tBuffer_clear (tBuffer* const s)
-{
- for (int i = 0; i < s->length; i++)
- {
- s->buff[i] = 0.f;
- }
-}
-
-//================================tSampler=====================================
-
-void tSampler_init(tSampler* const p, tBuffer* const s)
-{
- p->samp = s;
-
- p->active = 0;
-
- p->start = 0;
- p->end = p->samp->length - 1;
-
- p->len = p->end - p->start;
-
- p->idx = 0.f;
- p->inc = 1.f;
- p->iinc = 1.f;
-
- p->dir = 1;
- p->flip = 1;
- p->bnf = 1;
-
- p->mode = PlayNormal;
-
- p->cfxlen = 500; // default 300 sample crossfade
-
- tRamp_init(&p->gain, 7.0f, 1);
- tRamp_setVal(&p->gain, 0.f);
-}
-
-void tSampler_free (tSampler* const p)
-{
- tRamp_free(&p->gain);
-}
-
-float tSampler_tick (tSampler* const p)
-{
- if (p->active == 0) return 0.f;
-
- if ((p->inc == 0.0f) || (p->len < 4))
- {
- return p->last;
- }
-
- float sample = 0.f;
- float cfxsample = 0.f;
- int numsamps;
- float g1 = 1.f, g2 = 0.f;
-
- float* buff = p->samp->buff;
-
- int dir = p->bnf * p->dir * p->flip;
-
- int idx;
- float alpha;
-
- if (dir > 0)
- {
- idx = (int) p->idx;
- alpha = p->idx - idx;
- }
- else
- {
- idx = (int) (p->idx+1.f); // we think this is because flooring on int works different when reading backwards
- alpha = (p->idx+1.f) - idx;
- }
-
- int32_t start = p->start, end = p->end;
- if (p->flip < 0)
- {
- start = p->end;
- end = p->start;
- }
-
- // Check dir (direction) to interpolate properly
- if (dir > 0)
- {
- // FORWARD NORMAL SAMPLE
- int i1 = ((idx-1) + p->len) % p->len;
- int i3 = (idx+1) % p->len;
- int i4 = (idx+2) % p->len;
-
- sample = LEAF_interpolate_hermite (buff[i1],
- buff[idx],
- buff[i3],
- buff[i4],
- alpha);
-
- // num samples to end of loop
- numsamps = (idx - start) / p->inc;
- //numsamps = (dir > 0) ? (end - idx) : (idx - start);
- //numsamps *= p->iinc;
-
- if (p->mode == PlayLoop)
- {
- if (numsamps <= p->cfxlen)
- {
- // CROSSFADE SAMPLE
- float idxx = p->idx - p->len;
- int cdx = ((int)(idxx) + p->len) % p->len;
-
- i1 = ((cdx-1) + p->len) % p->len;
- i3 = (cdx+1) % p->len;
- i4 = (cdx+2) % p->len;
-
- cfxsample = LEAF_interpolate_hermite (buff[i1],
- buff[cdx],
- buff[i3],
- buff[i4],
- alpha);
-
- g2 = (float) (p->cfxlen - numsamps) / (float) p->cfxlen;
- }
- }
- }
- else
- {
- // REVERSE
- int i1 = (idx+1) % p->len;
- int i3 = ((idx-1) + p->len) % p->len;
- int i4 = ((idx-2) + p->len) % p->len;
-
- sample = LEAF_interpolate_hermite (buff[i1],
- buff[idx],
- buff[i3],
- buff[i4],
- 1.0f-alpha);
-
- numsamps = (idx - start) / p->inc;
-
- if (p->mode == PlayLoop)
- {
- if (numsamps <= p->cfxlen)
- {
- // CROSSFADE SAMPLE
- float idxx = p->idx + p->len + 1.f;
- int cdx = ((int)(idxx)) % p->len;
- alpha = idxx - cdx;
-
- i1 = (cdx+1) % p->len;
- i3 = ((cdx-1) + p->len) % p->len;
- i4 = ((cdx-2) + p->len) % p->len;
-
- cfxsample = LEAF_interpolate_hermite (buff[i1],
- buff[cdx],
- buff[i3],
- buff[i4],
- 1.f-alpha);
-
- g2 = (float) (p->cfxlen - numsamps) / (float) p->cfxlen;
- }
- }
- }
-
- p->idx += (dir * p->inc);
-
- if (p->mode == PlayNormal)
- {
- if (numsamps < (0.007f * leaf.sampleRate))
- {
- tRamp_setDest(&p->gain, 0.f);
- p->active = -1;
- }
- }
- else if (p->mode == PlayLoop )
- {
- if (idx <= start)
- {
- p->idx += (float)(p->len);
- }
- else if (idx >= end)
- {
- p->idx -= (float)(p->len);
- }
- }
- else // == PlayBackAndForth
- {
- if (p->idx < start)
- {
- p->bnf = -p->bnf;
- p->idx = start;
- }
- else if (p->idx > end)
- {
- p->bnf = -p->bnf;
- p->idx = end;
- }
- }
-
- g1 = 1.f - g2;
-
- sample = sample * g1 + cfxsample * g2;
-
- sample = sample * tRamp_tick(&p->gain);
-
- if (p->active < 0)
- {
- if (tRamp_sample(&p->gain) <= 0.00001f)
- {
- if (p->retrigger == 1)
- {
- p->active = 1;
- p->retrigger = 0;
- tRamp_setDest(&p->gain, 1.f);
-
- if (p->dir > 0)
- {
- if (p->flip > 0) p->idx = p->start;
- else p->idx = p->end;
- }
- else
- {
- if (p->flip > 0) p->idx = p->end;
- else p->idx = p->start;
- }
- }
- else
- {
- p->active = 0;
- }
-
- }
- }
-
- p->last = sample;
-
- return p->last;
-}
-
-void tSampler_setSample (tSampler* const p, tBuffer* s)
-{
- p->samp = s;
-}
-
-void tSampler_setMode (tSampler* const p, PlayMode mode)
-{
- p->mode = mode;
-}
-
-void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length)
-{
- uint32_t cfxlen = LEAF_clip(0, length, 1000);
-
- //if (cfxlen > p->len) cfxlen = p->len * 0.25f;
-
- p->cfxlen = cfxlen;
-}
-
-void tSampler_play (tSampler* const p)
-{
- if (p->active != 0)
- {
- p->active = -1;
- p->retrigger = 1;
-
- tRamp_setDest(&p->gain, 0.f);
- }
- else
- {
- p->active = 1;
- p->retrigger = 0;
-
- tRamp_setDest(&p->gain, 1.f);
-
- if (p->dir > 0)
- {
- if (p->flip > 0) p->idx = p->start;
- else p->idx = p->end;
- }
- else
- {
- if (p->flip > 0) p->idx = p->end;
- else p->idx = p->start;
- }
- }
-}
-
-void tSampler_stop (tSampler* const p)
-{
- p->active = -1;
-
- tRamp_setDest(&p->gain, 0.f);
-}
-
-static void handleStartEndChange(tSampler* const p)
-{
- p->len = abs(p->end - p->start);
-
- //if (p->len < p->cfxlen) p->cfxlen = p->len * 0.9f;
-
- if (p->start > p->end)
- {
- p->flip = -1;
- }
- else
- {
- p->flip = 1;
- }
-}
-
-void tSampler_setStart (tSampler* const p, int32_t start)
-{
- p->start = LEAF_clipInt(0, start, (p->samp->length - 1));
-
- handleStartEndChange(p);
-}
-
-void tSampler_setEnd (tSampler* const p, int32_t end)
-{
- p->end = LEAF_clipInt(0, end, (p->samp->length - 1));
-
- handleStartEndChange(p);
-}
-
-void tSampler_setRate (tSampler* const p, float rate)
-{
- if (rate < 0.f)
- {
- rate = -rate;
- p->dir = -1;
- }
- else
- {
- p->dir = 1;
- }
-
- p->inc = LEAF_clip(0.f, rate, 8.0f);
- p->iinc = 1.f / p->inc;
-}
-
-
-//==============================================================================
--- /dev/null
+++ b/LEAF/Src/leaf-sampling.c
@@ -1,0 +1,436 @@
+/*
+ ==============================================================================
+
+ leaf-sampling.c
+ Created: 20 Jan 2017 12:02:17pm
+ Author: Michael R Mulshine
+
+ ==============================================================================
+*/
+
+
+#if _WIN32 || _WIN64
+
+#include "..\Inc\leaf-sampling.h"
+#include "..\leaf.h"
+
+#else
+
+#include "../Inc/leaf-sampling.h"
+#include "../leaf.h"
+
+#endif
+
+//==============================================================================
+
+void tBuffer_init (tBuffer* const s, uint32_t length)
+{
+ s->buff = (float*) leaf_alloc( sizeof(float) * length);
+
+
+ s->length = length;
+ s->active = 0;
+ s->idx = 0;
+ s->mode = RecordOneShot;
+
+ tBuffer_clear(s);
+}
+
+void tBuffer_free (tBuffer* const s)
+{
+ leaf_free(s->buff);
+}
+
+void tBuffer_tick (tBuffer* const s, float sample)
+{
+ if (s->active == 1)
+ {
+ s->buff[s->idx] = sample;
+
+ s->idx += 1;
+
+ if (s->idx >= s->length)
+ {
+ if (s->mode == RecordOneShot)
+ {
+ tBuffer_stop(s);
+ }
+ else if (s->mode == RecordLoop)
+ {
+ s->idx = 0;
+ }
+ }
+ }
+}
+
+void tBuffer_read(tBuffer* const s, float* buff, uint32_t len)
+{
+ for (int i = 0; i < s->length; i++)
+ {
+ if (i < len) s->buff[i] = buff[i];
+ else s->buff[i] = 0.f;
+ }
+}
+
+float tBuffer_get (tBuffer* const s, int idx)
+{
+ if ((idx < 0) || (idx >= s->length)) return 0.f;
+
+ return s->buff[idx];
+}
+
+void tBuffer_record(tBuffer* const s)
+{
+ s->active = 1;
+ s->idx = 0;
+}
+
+void tBuffer_stop(tBuffer* const s)
+{
+ s->active = 0;
+}
+
+void tBuffer_setRecordMode (tBuffer* const s, RecordMode mode)
+{
+ s->mode = mode;
+}
+
+void tBuffer_clear (tBuffer* const s)
+{
+ for (int i = 0; i < s->length; i++)
+ {
+ s->buff[i] = 0.f;
+ }
+}
+
+//================================tSampler=====================================
+
+void tSampler_init(tSampler* const p, tBuffer* const s)
+{
+ p->samp = s;
+
+ p->active = 0;
+
+ p->start = 0;
+ p->end = p->samp->length - 1;
+
+ p->len = p->end - p->start;
+
+ p->idx = 0.f;
+ p->inc = 1.f;
+ p->iinc = 1.f;
+
+ p->dir = 1;
+ p->flip = 1;
+ p->bnf = 1;
+
+ p->mode = PlayNormal;
+
+ p->cfxlen = 500; // default 300 sample crossfade
+
+ tRamp_init(&p->gain, 7.0f, 1);
+ tRamp_setVal(&p->gain, 0.f);
+}
+
+void tSampler_free (tSampler* const p)
+{
+ tRamp_free(&p->gain);
+}
+
+float tSampler_tick (tSampler* const p)
+{
+ if (p->active == 0) return 0.f;
+
+ if ((p->inc == 0.0f) || (p->len < 4))
+ {
+ return p->last;
+ }
+
+ float sample = 0.f;
+ float cfxsample = 0.f;
+ int numsamps;
+ float g1 = 1.f, g2 = 0.f;
+
+ float* buff = p->samp->buff;
+
+ int dir = p->bnf * p->dir * p->flip;
+
+ int idx;
+ float alpha;
+
+ if (dir > 0)
+ {
+ idx = (int) p->idx;
+ alpha = p->idx - idx;
+ }
+ else
+ {
+ idx = (int) (p->idx+1.f); // we think this is because flooring on int works different when reading backwards
+ alpha = (p->idx+1.f) - idx;
+ }
+
+ int32_t start = p->start, end = p->end;
+ if (p->flip < 0)
+ {
+ start = p->end;
+ end = p->start;
+ }
+
+ // Check dir (direction) to interpolate properly
+ if (dir > 0)
+ {
+ // FORWARD NORMAL SAMPLE
+ int i1 = ((idx-1) + p->len) % p->len;
+ int i3 = (idx+1) % p->len;
+ int i4 = (idx+2) % p->len;
+
+ sample = LEAF_interpolate_hermite (buff[i1],
+ buff[idx],
+ buff[i3],
+ buff[i4],
+ alpha);
+
+ // num samples to end of loop
+ numsamps = (idx - start) / p->inc;
+ //numsamps = (dir > 0) ? (end - idx) : (idx - start);
+ //numsamps *= p->iinc;
+
+ if (p->mode == PlayLoop)
+ {
+ if (numsamps <= p->cfxlen)
+ {
+ // CROSSFADE SAMPLE
+ float idxx = p->idx - p->len;
+ int cdx = ((int)(idxx) + p->len) % p->len;
+
+ i1 = ((cdx-1) + p->len) % p->len;
+ i3 = (cdx+1) % p->len;
+ i4 = (cdx+2) % p->len;
+
+ cfxsample = LEAF_interpolate_hermite (buff[i1],
+ buff[cdx],
+ buff[i3],
+ buff[i4],
+ alpha);
+
+ g2 = (float) (p->cfxlen - numsamps) / (float) p->cfxlen;
+ }
+ }
+ }
+ else
+ {
+ // REVERSE
+ int i1 = (idx+1) % p->len;
+ int i3 = ((idx-1) + p->len) % p->len;
+ int i4 = ((idx-2) + p->len) % p->len;
+
+ sample = LEAF_interpolate_hermite (buff[i1],
+ buff[idx],
+ buff[i3],
+ buff[i4],
+ 1.0f-alpha);
+
+ numsamps = (idx - start) / p->inc;
+
+ if (p->mode == PlayLoop)
+ {
+ if (numsamps <= p->cfxlen)
+ {
+ // CROSSFADE SAMPLE
+ float idxx = p->idx + p->len + 1.f;
+ int cdx = ((int)(idxx)) % p->len;
+ alpha = idxx - cdx;
+
+ i1 = (cdx+1) % p->len;
+ i3 = ((cdx-1) + p->len) % p->len;
+ i4 = ((cdx-2) + p->len) % p->len;
+
+ cfxsample = LEAF_interpolate_hermite (buff[i1],
+ buff[cdx],
+ buff[i3],
+ buff[i4],
+ 1.f-alpha);
+
+ g2 = (float) (p->cfxlen - numsamps) / (float) p->cfxlen;
+ }
+ }
+ }
+
+ p->idx += (dir * p->inc);
+
+ if (p->mode == PlayNormal)
+ {
+ if (numsamps < (0.007f * leaf.sampleRate))
+ {
+ tRamp_setDest(&p->gain, 0.f);
+ p->active = -1;
+ }
+ }
+ else if (p->mode == PlayLoop )
+ {
+ if (idx <= start)
+ {
+ p->idx += (float)(p->len);
+ }
+ else if (idx >= end)
+ {
+ p->idx -= (float)(p->len);
+ }
+ }
+ else // == PlayBackAndForth
+ {
+ if (p->idx < start)
+ {
+ p->bnf = -p->bnf;
+ p->idx = start;
+ }
+ else if (p->idx > end)
+ {
+ p->bnf = -p->bnf;
+ p->idx = end;
+ }
+ }
+
+ g1 = 1.f - g2;
+
+ sample = sample * g1 + cfxsample * g2;
+
+ sample = sample * tRamp_tick(&p->gain);
+
+ if (p->active < 0)
+ {
+ if (tRamp_sample(&p->gain) <= 0.00001f)
+ {
+ if (p->retrigger == 1)
+ {
+ p->active = 1;
+ p->retrigger = 0;
+ tRamp_setDest(&p->gain, 1.f);
+
+ if (p->dir > 0)
+ {
+ if (p->flip > 0) p->idx = p->start;
+ else p->idx = p->end;
+ }
+ else
+ {
+ if (p->flip > 0) p->idx = p->end;
+ else p->idx = p->start;
+ }
+ }
+ else
+ {
+ p->active = 0;
+ }
+
+ }
+ }
+
+ p->last = sample;
+
+ return p->last;
+}
+
+void tSampler_setSample (tSampler* const p, tBuffer* s)
+{
+ p->samp = s;
+}
+
+void tSampler_setMode (tSampler* const p, PlayMode mode)
+{
+ p->mode = mode;
+}
+
+void tSampler_setCrossfadeLength (tSampler* const p, uint32_t length)
+{
+ uint32_t cfxlen = LEAF_clip(0, length, 1000);
+
+ //if (cfxlen > p->len) cfxlen = p->len * 0.25f;
+
+ p->cfxlen = cfxlen;
+}
+
+void tSampler_play (tSampler* const p)
+{
+ if (p->active != 0)
+ {
+ p->active = -1;
+ p->retrigger = 1;
+
+ tRamp_setDest(&p->gain, 0.f);
+ }
+ else
+ {
+ p->active = 1;
+ p->retrigger = 0;
+
+ tRamp_setDest(&p->gain, 1.f);
+
+ if (p->dir > 0)
+ {
+ if (p->flip > 0) p->idx = p->start;
+ else p->idx = p->end;
+ }
+ else
+ {
+ if (p->flip > 0) p->idx = p->end;
+ else p->idx = p->start;
+ }
+ }
+}
+
+void tSampler_stop (tSampler* const p)
+{
+ p->active = -1;
+
+ tRamp_setDest(&p->gain, 0.f);
+}
+
+static void handleStartEndChange(tSampler* const p)
+{
+ p->len = abs(p->end - p->start);
+
+ //if (p->len < p->cfxlen) p->cfxlen = p->len * 0.9f;
+
+ if (p->start > p->end)
+ {
+ p->flip = -1;
+ }
+ else
+ {
+ p->flip = 1;
+ }
+}
+
+void tSampler_setStart (tSampler* const p, int32_t start)
+{
+ p->start = LEAF_clipInt(0, start, (p->samp->length - 1));
+
+ handleStartEndChange(p);
+}
+
+void tSampler_setEnd (tSampler* const p, int32_t end)
+{
+ p->end = LEAF_clipInt(0, end, (p->samp->length - 1));
+
+ handleStartEndChange(p);
+}
+
+void tSampler_setRate (tSampler* const p, float rate)
+{
+ if (rate < 0.f)
+ {
+ rate = -rate;
+ p->dir = -1;
+ }
+ else
+ {
+ p->dir = 1;
+ }
+
+ p->inc = LEAF_clip(0.f, rate, 8.0f);
+ p->iinc = 1.f / p->inc;
+}
+
+
+//==============================================================================
--- a/LEAF/Src/leaf-string.c
+++ /dev/null
@@ -1,289 +1,0 @@
-/*==============================================================================
-
- leaf-string.c
- Created: 30 Nov 2018 10:41:42am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-string.h"
-
-#else
-
-#include "../Inc/leaf-string.h"
-
-#endif
-
-/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tPluck ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
-void tPluck_init (tPluck* const p, float lowestFrequency)
-{
- if ( lowestFrequency <= 0.0f ) lowestFrequency = 10.0f;
-
- tNoise_init(&p->noise, WhiteNoise);
-
- tOnePole_init(&p->pickFilter, 0.0f);
-
- tOneZero_init(&p->loopFilter, 0.0f);
-
- tDelayA_init(&p->delayLine, 0.0f, leaf.sampleRate * 2);
-
- tPluck_setFrequency(p, 220.0f);
-}
-
-void tPluck_free (tPluck* const p)
-{
- tNoise_free(&p->noise);
- tOnePole_free(&p->pickFilter);
- tOneZero_free(&p->loopFilter);
- tDelayA_free(&p->delayLine);
-}
-
-float tPluck_getLastOut (tPluck *p)
-{
- return p->lastOut;
-}
-
-float tPluck_tick (tPluck *p)
-{
- return (p->lastOut = 3.0f * tDelayA_tick(&p->delayLine, tOneZero_tick(&p->loopFilter, tDelayA_getLastOut(&p->delayLine) * p->loopGain ) ));
-}
-
-void tPluck_pluck (tPluck* const p, float amplitude)
-{
- if ( amplitude < 0.0f) amplitude = 0.0f;
- else if (amplitude > 1.0f) amplitude = 1.0f;
-
- tOnePole_setPole(&p->pickFilter, 0.999f - (amplitude * 0.15f));
- tOnePole_setGain(&p->pickFilter, amplitude * 0.5f );
-
- // Fill delay with noise additively with current contents.
- for ( uint32_t i = 0; i < (uint32_t)tDelayA_getDelay(&p->delayLine); i++ )
- tDelayA_tick(&p->delayLine, 0.6f * tDelayA_getLastOut(&p->delayLine) + tOnePole_tick(&p->pickFilter, tNoise_tick(&p->noise) ) );
-}
-
-// Start a note with the given frequency and amplitude.;
-void tPluck_noteOn (tPluck* const p, float frequency, float amplitude )
-{
- p->lastFreq = frequency;
- tPluck_setFrequency( p, frequency );
- tPluck_pluck( p, amplitude );
-}
-
-// Stop a note with the given amplitude (speed of decay).
-void tPluck_noteOff (tPluck* const p, float amplitude )
-{
- if ( amplitude < 0.0f) amplitude = 0.0f;
- else if (amplitude > 1.0f) amplitude = 1.0f;
-
- p->loopGain = 1.0f - amplitude;
-}
-
-// Set instrument parameters for a particular frequency.
-void tPluck_setFrequency (tPluck* const p, float frequency )
-{
- if ( frequency <= 0.0f ) frequency = 0.001f;
-
- // Delay = length - filter delay.
- float delay = ( leaf.sampleRate / frequency ) - tOneZero_getPhaseDelay(&p->loopFilter, frequency );
-
- tDelayA_setDelay(&p->delayLine, delay );
-
- p->loopGain = 0.99f + (frequency * 0.000005f);
-
- if ( p->loopGain >= 0.999f ) p->loopGain = 0.999f;
-
-}
-
-// Perform the control change specified by \e number and \e value (0.0 - 128.0).
-void tPluck_controlChange (tPluck* const p, int number, float value)
-{
- return;
-}
-
-void tPluckSampleRateChanged(tPluck* const p)
-{
- //tPluckSetFrequency(p, p->lastFreq);
-}
-
-/* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ tStifKarp ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ */
-void tStifKarp_init (tStifKarp* const p, float lowestFrequency)
-{
- if ( lowestFrequency <= 0.0f ) lowestFrequency = 8.0f;
-
- tDelayA_init(&p->delayLine, 0.0f, leaf.sampleRate * 2);
-
- tDelayL_init(&p->combDelay, 0.0f, leaf.sampleRate * 2);
-
- tOneZero_init(&p->filter, 0.0f);
-
- tNoise_init(&p->noise, WhiteNoise);
-
- for (int i = 0; i < 4; i++)
- {
- tBiQuad_init(&p->biquad[i]);
- }
-
- p->pluckAmplitude = 0.3f;
- p->pickupPosition = 0.4f;
-
- p->stretching = 0.9999f;
- p->baseLoopGain = 0.995f;
- p->loopGain = 0.999f;
-
- tStifKarp_setFrequency( p, 220.0f );
-
-}
-
-void tStifKarp_free (tStifKarp* const p)
-{
- tDelayA_free(&p->delayLine);
- tDelayL_free(&p->combDelay);
- tOneZero_free(&p->filter);
- tNoise_free(&p->noise);
-
- for (int i = 0; i < 4; i++)
- {
- tBiQuad_free(&p->biquad[i]);
- }
-}
-
-float tStifKarp_getLastOut (tStifKarp* const p)
-{
- return p->lastOut;
-}
-
-float tStifKarp_tick (tStifKarp* const p)
-{
- float temp = tDelayA_getLastOut(&p->delayLine) * p->loopGain;
-
- // Calculate allpass stretching.
- for (int i=0; i<4; i++) temp = tBiQuad_tick(&p->biquad[i],temp);
-
- // Moving average filter.
- temp = tOneZero_tick(&p->filter, temp);
-
- float out = tDelayA_tick(&p->delayLine, temp);
- out = out - tDelayL_tick(&p->combDelay, out);
- p->lastOut = out;
-
- return p->lastOut;
-}
-
-void tStifKarp_pluck (tStifKarp* const p, float amplitude)
-{
- if ( amplitude < 0.0f) amplitude = 0.0f;
- else if (amplitude > 1.0f) amplitude = 1.0f;
-
- p->pluckAmplitude = amplitude;
-
- for ( uint32_t i=0; i < (uint32_t)tDelayA_getDelay(&p->delayLine); i++ )
- {
- // Fill delay with noise additively with current contents.
- tDelayA_tick(&p->delayLine, (tDelayA_getLastOut(&p->delayLine) * 0.6f) + 0.4f * tNoise_tick(&p->noise) * p->pluckAmplitude );
- //delayLine_.tick( combDelay_.tick((delayLine_.lastOut() * 0.6) + 0.4 * noise->tick() * pluckAmplitude_) );
- }
-}
-
-// Start a note with the given frequency and amplitude.;
-void tStifKarp_noteOn (tStifKarp* const p, float frequency, float amplitude )
-{
- tStifKarp_setFrequency( p, frequency );
- tStifKarp_pluck( p, amplitude );
-}
-
-// Stop a note with the given amplitude (speed of decay).
-void tStifKarp_noteOff (tStifKarp* const p, float amplitude )
-{
- if ( amplitude < 0.0f) amplitude = 0.0f;
- else if (amplitude > 1.0f) amplitude = 1.0f;
-
- p->loopGain = 1.0f - amplitude;
-}
-
-// Set instrument parameters for a particular frequency.
-void tStifKarp_setFrequency (tStifKarp* const p, float frequency )
-{
- if ( frequency <= 0.0f ) frequency = 0.001f;
-
- p->lastFrequency = frequency;
- p->lastLength = leaf.sampleRate / p->lastFrequency;
- float delay = p->lastLength - 0.5f;
- tDelayA_setDelay(&p->delayLine, delay);
-
- // MAYBE MODIFY LOOP GAINS
- p->loopGain = p->baseLoopGain + (frequency * 0.000005f);
- if (p->loopGain >= 1.0f) p->loopGain = 0.99999f;
-
- tStifKarp_setStretch(p, p->stretching);
-
- tDelayL_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength );
-
-}
-
-// Set the stretch "factor" of the string (0.0 - 1.0).
-void tStifKarp_setStretch (tStifKarp* const p, float stretch )
-{
- p->stretching = stretch;
- float coefficient;
- float freq = p->lastFrequency * 2.0f;
- float dFreq = ( (0.5f * leaf.sampleRate) - freq ) * 0.25f;
- float temp = 0.5f + (stretch * 0.5f);
- if ( temp > 0.9999f ) temp = 0.9999f;
-
- for ( int i=0; i<4; i++ )
- {
- coefficient = temp * temp;
- tBiQuad_setA2(&p->biquad[i], coefficient);
- tBiQuad_setB0(&p->biquad[i], coefficient);
- tBiQuad_setB2(&p->biquad[i], 1.0f);
-
- coefficient = -2.0f * temp * cos(TWO_PI * freq / leaf.sampleRate);
- tBiQuad_setA1(&p->biquad[i], coefficient);
- tBiQuad_setB1(&p->biquad[i], coefficient);
-
- freq += dFreq;
- }
-}
-
-// Set the pluck or "excitation" position along the string (0.0 - 1.0).
-void tStifKarp_setPickupPosition (tStifKarp* const p, float position )
-{
- if (position < 0.0f) p->pickupPosition = 0.0f;
- else if (position <= 1.0f) p->pickupPosition = position;
- else p->pickupPosition = 1.0f;
-
- tDelayL_setDelay(&p->combDelay, 0.5f * p->pickupPosition * p->lastLength);
-}
-
-// Set the base loop gain.
-void tStifKarp_setBaseLoopGain (tStifKarp* const p, float aGain )
-{
- p->baseLoopGain = aGain;
- p->loopGain = p->baseLoopGain + (p->lastFrequency * 0.000005f);
- if ( p->loopGain > 0.99999f ) p->loopGain = 0.99999f;
-}
-
-// Perform the control change specified by \e number and \e value (0.0 - 128.0).
-void tStifKarp_controlChange (tStifKarp* const p, SKControlType type, float value)
-{
- if ( value < 0.0f ) value = 0.0f;
- else if (value > 128.0f) value = 128.0f;
-
- float normalizedValue = value * INV_128;
-
- if (type == SKPickPosition) // 4
- tStifKarp_setPickupPosition( p, normalizedValue );
- else if (type == SKStringDamping) // 11
- tStifKarp_setBaseLoopGain( p, 0.97f + (normalizedValue * 0.03f) );
- else if (type == SKDetune) // 1
- tStifKarp_setStretch( p, 0.91f + (0.09f * (1.0f - normalizedValue)) );
-
-}
-
-void tStifKarpSampleRateChanged (tStifKarp* const c)
-{
- tStifKarp_setFrequency(c, c->lastFrequency);
- tStifKarp_setStretch(c, c->stretching);
-}
--- a/LEAF/Src/leaf-utilities.c
+++ /dev/null
@@ -1,2227 +1,0 @@
-/*
- ==============================================================================
-
- LEAFUtilities.c
- Created: 20 Jan 2017 12:02:17pm
- Author: Michael R Mulshine
-
- ==============================================================================
-*/
-
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-utilities.h"
-#include "..\Inc\leaf-tables.h"
-#include "..\leaf.h"
-#include "..\Inc\d_fft_mayer.h"
-
-#else
-
-#include "../Inc/leaf-utilities.h"
-#include "../Inc/leaf-tables.h"
-#include "../leaf.h"
-#include "../Externals/d_fft_mayer.h"
-
-#endif
-
-#define LOGTEN 2.302585092994
-
-float mtof(float f)
-{
- if (f <= -1500.0f) return(0);
- else if (f > 1499.0f) return(mtof(1499.0f));
- else return (8.17579891564f * expf(0.0577622650f * f));
-}
-
-float ftom(float f)
-{
- return (f > 0 ? 17.3123405046f * logf(.12231220585f * f) : -1500.0f);
-}
-
-float powtodb(float f)
-{
- if (f <= 0) return (0);
- else
- {
- float val = 100 + 10.f/LOGTEN * logf(f);
- return (val < 0 ? 0 : val);
- }
-}
-
-float rmstodb(float f)
-{
- if (f <= 0) return (0);
- else
- {
- float val = 100 + 20.f/LOGTEN * log(f);
- return (val < 0 ? 0 : val);
- }
-}
-
-float dbtopow(float f)
-{
- if (f <= 0)
- return(0);
- else
- {
- if (f > 870.0f)
- f = 870.0f;
- return (expf((LOGTEN * 0.1f) * (f-100.0f)));
- }
-}
-
-float dbtorms(float f)
-{
- if (f <= 0)
- return(0);
- else
- {
- if (f > 485.0f)
- f = 485.0f;
- }
- return (expf((LOGTEN * 0.05f) * (f-100.0f)));
-}
-
-/* ---------------- env~ - simple envelope follower. ----------------- */
-void tEnv_init(tEnv* const x, int ws, int hs, int bs)
-{
- int period = hs, npoints = ws;
-
- int i;
-
- if (npoints < 1) npoints = 1024;
- if (period < 1) period = npoints/2;
- if (period < npoints / MAXOVERLAP + 1)
- period = npoints / MAXOVERLAP + 1;
-
- x->x_npoints = npoints;
- x->x_phase = 0;
- x->x_period = period;
-
- x->windowSize = npoints;
- x->hopSize = period;
- x->blockSize = bs;
-
- for (i = 0; i < MAXOVERLAP; i++) x->x_sumbuf[i] = 0;
- for (i = 0; i < npoints; i++)
- x->buf[i] = (1.0f - cosf((2 * PI * i) / npoints))/npoints;
- for (; i < npoints+INITVSTAKEN; i++) x->buf[i] = 0;
-
- x->x_f = 0;
-
- x->x_allocforvs = INITVSTAKEN;
-
- // ~ ~ ~ dsp ~ ~ ~
- if (x->x_period % x->blockSize)
- {
- x->x_realperiod = x->x_period + x->blockSize - (x->x_period % x->blockSize);
- }
- else
- {
- x->x_realperiod = x->x_period;
- }
- // ~ ~ ~ ~ ~ ~ ~ ~
-}
-
-void tEnv_free (tEnv* const x)
-{
-
-}
-
-float tEnv_tick (tEnv* const x)
-{
- return powtodb(x->x_result);
-}
-
-void tEnv_processBlock(tEnv* const x, float* in)
-{
- int n = x->blockSize;
-
- int count;
- t_sample *sump;
- in += n;
- for (count = x->x_phase, sump = x->x_sumbuf;
- count < x->x_npoints; count += x->x_realperiod, sump++)
- {
- t_sample *hp = x->buf + count;
- t_sample *fp = in;
- t_sample sum = *sump;
- int i;
-
- for (i = 0; i < n; i++)
- {
- fp--;
- sum += *hp++ * (*fp * *fp);
- }
- *sump = sum;
- }
- sump[0] = 0;
- x->x_phase -= n;
- if (x->x_phase < 0)
- {
- x->x_result = x->x_sumbuf[0];
- for (count = x->x_realperiod, sump = x->x_sumbuf;
- count < x->x_npoints; count += x->x_realperiod, sump++)
- sump[0] = sump[1];
- sump[0] = 0;
- x->x_phase = x->x_realperiod - n;
- }
-}
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Compressor ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-
-/*
-tCompressor* tCompressorInit(int tauAttack, int tauRelease)
-{
- tCompressor* c = &leaf.tCompressorRegistry[leaf.registryIndex[T_COMPRESSOR]++];
-
- c->tauAttack = tauAttack;
- c->tauRelease = tauRelease;
-
- c->x_G[0] = 0.0f, c->x_G[1] = 0.0f,
- c->y_G[0] = 0.0f, c->y_G[1] = 0.0f,
- c->x_T[0] = 0.0f, c->x_T[1] = 0.0f,
- c->y_T[0] = 0.0f, c->y_T[1] = 0.0f;
-
- c->T = 0.0f; // Threshold
- c->R = 1.0f; // compression Ratio
- c->M = 0.0f; // decibel Make-up gain
- c->W = 0.0f; // decibel Width of knee transition
-
- return c;
-}
-*/
-void tCompressor_init(tCompressor* const c)
-{
- c->tauAttack = 100;
- c->tauRelease = 100;
-
- c->isActive = OFALSE;
-
- c->T = 0.0f; // Threshold
- c->R = 0.5f; // compression Ratio
- c->M = 3.0f; // decibel Width of knee transition
- c->W = 1.0f; // decibel Make-up gain
-}
-
-void tCompressor_free(tCompressor* const c)
-{
-
-}
-
-int ccount = 0;
-float tCompressor_tick(tCompressor* const c, float in)
-{
- float slope, overshoot;
- float alphaAtt, alphaRel;
-
- float in_db = 20.0f * log10f( fmaxf( fabsf( in), 0.000001f)), out_db = 0.0f;
-
- c->y_T[1] = c->y_T[0];
-
- slope = c->R - 1.0f; // feed-forward topology; was 1/C->R - 1
-
- overshoot = in_db - c->T;
-
-
- if (overshoot <= -(c->W * 0.5f))
- {
- out_db = in_db;
- c->isActive = OFALSE;
- }
- else if ((overshoot > -(c->W * 0.5f)) && (overshoot < (c->W * 0.5f)))
- {
- out_db = in_db + slope * (powf((overshoot + c->W*0.5f),2) / (2.0f * c->W)); // .^ 2 ???
- c->isActive = OTRUE;
- }
- else if (overshoot >= (c->W * 0.5f))
- {
- out_db = in_db + slope * overshoot;
- c->isActive = OTRUE;
- }
-
-
-
- c->x_T[0] = out_db - in_db;
-
- alphaAtt = expf(-1.0f/(0.001f * c->tauAttack * leaf.sampleRate));
- alphaRel = expf(-1.0f/(0.001f * c->tauRelease * leaf.sampleRate));
-
- if (c->x_T[0] > c->y_T[1])
- c->y_T[0] = alphaAtt * c->y_T[1] + (1-alphaAtt) * c->x_T[0];
- else
- c->y_T[0] = alphaRel * c->y_T[1] + (1-alphaRel) * c->x_T[0];
-
- float attenuation = powf(10.0f, ((c->M - c->y_T[0])/20.0f));
-
- /*
- if (++ccount > 5000)
- {
-
- ccount = 0;
- DBG(".5width: " + String(c->W * 0.5f));
- DBG("slope: " + String(slope) + " overshoot: " + String(overshoot));
- DBG("attenuation: " + String(attenuation));
- }
- */
- return attenuation * in;
-
-
-}
-
-// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Envelope ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ //
-void tEnvelope_init(tEnvelope* const env, float attack, float decay, oBool loop)
-{
- env->exp_buff = exp_decay;
- env->inc_buff = attack_decay_inc;
- env->buff_size = sizeof(exp_decay);
-
- env->loop = loop;
-
- if (attack > 8192.0f)
- attack = 8192.0f;
- if (attack < 0.0f)
- attack = 0.0f;
-
- if (decay > 8192.0f)
- decay = 8192.0f;
- if (decay < 0.0f)
- decay = 0.0f;
-
- int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
- int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
- int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
-
- if (attackIndex < 0)
- attackIndex = 0;
- if (decayIndex < 0)
- decayIndex = 0;
- if (rampIndex < 0)
- rampIndex = 0;
-
- env->inRamp = OFALSE;
- env->inAttack = OFALSE;
- env->inDecay = OFALSE;
-
- env->attackInc = env->inc_buff[attackIndex];
- env->decayInc = env->inc_buff[decayIndex];
- env->rampInc = env->inc_buff[rampIndex];
-
-}
-
-void tEnvelope_free(tEnvelope* const env)
-{
-
-}
-
-int tEnvelope_setAttack(tEnvelope* const env, float attack)
-{
- int32_t attackIndex;
-
- if (attack < 0.0f) {
- attackIndex = 0.0f;
- } else if (attack < 8192.0f) {
- attackIndex = ((int32_t)(attack * 8.0f))-1;
- } else {
- attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
- }
-
- env->attackInc = env->inc_buff[attackIndex];
-
- return 0;
-}
-
-int tEnvelope_setDecay(tEnvelope* const env, float decay)
-{
- int32_t decayIndex;
-
- if (decay < 0.0f) {
- decayIndex = 0.0f;
- } else if (decay < 8192.0f) {
- decayIndex = ((int32_t)(decay * 8.0f)) - 1;
- } else {
- decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
- }
-
- env->decayInc = env->inc_buff[decayIndex];
-
- return 0;
-}
-
-int tEnvelope_loop(tEnvelope* const env, oBool loop)
-{
- env->loop = loop;
-
- return 0;
-}
-
-
-int tEnvelope_on(tEnvelope* const env, float velocity)
-{
- if (env->inAttack || env->inDecay) // In case envelope retriggered while it is still happening.
- {
- env->rampPhase = 0;
- env->inRamp = OTRUE;
- env->rampPeak = env->next;
- }
- else // Normal start.
- {
- env->inAttack = OTRUE;
- }
-
-
- env->attackPhase = 0;
- env->decayPhase = 0;
- env->inDecay = OFALSE;
- env->gain = velocity;
-
- return 0;
-}
-
-float tEnvelope_tick(tEnvelope* const env)
-{
- if (env->inRamp)
- {
- if (env->rampPhase > UINT16_MAX)
- {
- env->inRamp = OFALSE;
- env->inAttack = OTRUE;
- env->next = 0.0f;
- }
- else
- {
- env->next = env->rampPeak * env->exp_buff[(uint32_t)env->rampPhase];
- }
-
- env->rampPhase += env->rampInc;
- }
-
- if (env->inAttack)
- {
-
- // If attack done, time to turn around.
- if (env->attackPhase > UINT16_MAX)
- {
- env->inDecay = OTRUE;
- env->inAttack = OFALSE;
- env->next = env->gain * 1.0f;
- }
- else
- {
- // do interpolation !
- env->next = env->gain * env->exp_buff[UINT16_MAX - (uint32_t)env->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
- }
-
- // Increment envelope attack.
- env->attackPhase += env->attackInc;
-
- }
-
- if (env->inDecay)
- {
-
- // If decay done, finish.
- if (env->decayPhase >= UINT16_MAX)
- {
- env->inDecay = OFALSE;
-
- if (env->loop)
- {
- env->attackPhase = 0;
- env->decayPhase = 0;
- env->inAttack = OTRUE;
- }
- else
- {
- env->next = 0.0f;
- }
-
- } else {
-
- env->next = env->gain * (env->exp_buff[(uint32_t)env->decayPhase]); // do interpolation !
- }
-
- // Increment envelope decay;
- env->decayPhase += env->decayInc;
- }
-
- return env->next;
-}
-
-/* ADSR */
-void tADSR_init(tADSR* const adsr, float attack, float decay, float sustain, float release)
-{
- adsr->exp_buff = exp_decay;
- adsr->inc_buff = attack_decay_inc;
- adsr->buff_size = sizeof(exp_decay);
-
- if (attack > 8192.0f)
- attack = 8192.0f;
- if (attack < 0.0f)
- attack = 0.0f;
-
- if (decay > 8192.0f)
- decay = 8192.0f;
- if (decay < 0.0f)
- decay = 0.0f;
-
- if (sustain > 1.0f)
- sustain = 1.0f;
- if (sustain < 0.0f)
- sustain = 0.0f;
-
- if (release > 8192.0f)
- release = 8192.0f;
- if (release < 0.0f)
- release = 0.0f;
-
- int16_t attackIndex = ((int16_t)(attack * 8.0f))-1;
- int16_t decayIndex = ((int16_t)(decay * 8.0f))-1;
- int16_t releaseIndex = ((int16_t)(release * 8.0f))-1;
- int16_t rampIndex = ((int16_t)(2.0f * 8.0f))-1;
-
- if (attackIndex < 0)
- attackIndex = 0;
- if (decayIndex < 0)
- decayIndex = 0;
- if (releaseIndex < 0)
- releaseIndex = 0;
- if (rampIndex < 0)
- rampIndex = 0;
-
- adsr->inRamp = OFALSE;
- adsr->inAttack = OFALSE;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OFALSE;
-
- adsr->sustain = sustain;
-
- adsr->attackInc = adsr->inc_buff[attackIndex];
- adsr->decayInc = adsr->inc_buff[decayIndex];
- adsr->releaseInc = adsr->inc_buff[releaseIndex];
- adsr->rampInc = adsr->inc_buff[rampIndex];
-}
-
-void tADSR_free(tADSR* const adsr)
-{
-
-}
-
-int tADSR_setAttack(tADSR* const adsr, float attack)
-{
- int32_t attackIndex;
-
- if (attack < 0.0f) {
- attackIndex = 0.0f;
- } else if (attack < 8192.0f) {
- attackIndex = ((int32_t)(attack * 8.0f))-1;
- } else {
- attackIndex = ((int32_t)(8192.0f * 8.0f))-1;
- }
-
- adsr->attackInc = adsr->inc_buff[attackIndex];
-
- return 0;
-}
-
-int tADSR_detDecay(tADSR* const adsr, float decay)
-{
- int32_t decayIndex;
-
- if (decay < 0.0f) {
- decayIndex = 0.0f;
- } else if (decay < 8192.0f) {
- decayIndex = ((int32_t)(decay * 8.0f)) - 1;
- } else {
- decayIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
- }
-
- adsr->decayInc = adsr->inc_buff[decayIndex];
-
- return 0;
-}
-
-int tADSR_setSustain(tADSR *const adsr, float sustain)
-{
- if (sustain > 1.0f) adsr->sustain = 1.0f;
- else if (sustain < 0.0f) adsr->sustain = 0.0f;
- else adsr->sustain = sustain;
-
- return 0;
-}
-
-int tADSR_setRelease(tADSR* const adsr, float release)
-{
- int32_t releaseIndex;
-
- if (release < 0.0f) {
- releaseIndex = 0.0f;
- } else if (release < 8192.0f) {
- releaseIndex = ((int32_t)(release * 8.0f)) - 1;
- } else {
- releaseIndex = ((int32_t)(8192.0f * 8.0f)) - 1;
- }
-
- adsr->releaseInc = adsr->inc_buff[releaseIndex];
-
- return 0;
-}
-
-int tADSR_on(tADSR* const adsr, float velocity)
-{
- if ((adsr->inAttack || adsr->inDecay) || (adsr->inSustain || adsr->inRelease)) // In case ADSR retriggered while it is still happening.
- {
- adsr->rampPhase = 0;
- adsr->inRamp = OTRUE;
- adsr->rampPeak = adsr->next;
- }
- else // Normal start.
- {
- adsr->inAttack = OTRUE;
- }
-
- adsr->attackPhase = 0;
- adsr->decayPhase = 0;
- adsr->releasePhase = 0;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OFALSE;
- adsr->gain = velocity;
-
- return 0;
-}
-
-int tADSR_off(tADSR* const adsr)
-{
- if (adsr->inRelease) return 0;
-
- adsr->inAttack = OFALSE;
- adsr->inDecay = OFALSE;
- adsr->inSustain = OFALSE;
- adsr->inRelease = OTRUE;
-
- adsr->releasePeak = adsr->next;
-
- return 0;
-}
-
-float tADSR_tick(tADSR* const adsr)
-{
- if (adsr->inRamp)
- {
- if (adsr->rampPhase > UINT16_MAX)
- {
- adsr->inRamp = OFALSE;
- adsr->inAttack = OTRUE;
- adsr->next = 0.0f;
- }
- else
- {
- adsr->next = adsr->rampPeak * adsr->exp_buff[(uint32_t)adsr->rampPhase];
- }
-
- adsr->rampPhase += adsr->rampInc;
- }
-
- if (adsr->inAttack)
- {
-
- // If attack done, time to turn around.
- if (adsr->attackPhase > UINT16_MAX)
- {
- adsr->inDecay = OTRUE;
- adsr->inAttack = OFALSE;
- adsr->next = adsr->gain * 1.0f;
- }
- else
- {
- // do interpolation !
- adsr->next = adsr->gain * adsr->exp_buff[UINT16_MAX - (uint32_t)adsr->attackPhase]; // inverted and backwards to get proper rising exponential shape/perception
- }
-
- // Increment ADSR attack.
- adsr->attackPhase += adsr->attackInc;
-
- }
-
- if (adsr->inDecay)
- {
-
- // If decay done, sustain.
- if (adsr->decayPhase >= UINT16_MAX)
- {
- adsr->inDecay = OFALSE;
- adsr->inSustain = OTRUE;
- adsr->next = adsr->gain * adsr->sustain;
- }
-
- else
- {
- adsr->next = adsr->gain * (adsr->sustain + ((adsr->exp_buff[(uint32_t)adsr->decayPhase]) * (1 - adsr->sustain))); // do interpolation !
- }
-
- // Increment ADSR decay.
- adsr->decayPhase += adsr->decayInc;
- }
-
- if (adsr->inRelease)
- {
- // If release done, finish.
- if (adsr->releasePhase >= UINT16_MAX)
- {
- adsr->inRelease = OFALSE;
- adsr->next = 0.0f;
- }
- else {
-
- adsr->next = adsr->releasePeak * (adsr->exp_buff[(uint32_t)adsr->releasePhase]); // do interpolation !
- }
-
- // Increment envelope release;
- adsr->releasePhase += adsr->releaseInc;
- }
-
- return adsr->next;
-}
-
-/* Envelope Follower */
-void tEnvelopeFollower_init(tEnvelopeFollower* const e, float attackThreshold, float decayCoeff)
-{
- e->y = 0.0f;
- e->a_thresh = attackThreshold;
- e->d_coeff = decayCoeff;
-}
-
-void tEnvelopeFollower_free(tEnvelopeFollower* const e)
-{
-
-}
-
-float tEnvelopeFollower_tick(tEnvelopeFollower* const ef, float x)
-{
- if (x < 0.0f ) x = -x; /* Absolute value. */
-
- if ((x >= ef->y) && (x > ef->a_thresh)) ef->y = x; /* If we hit a peak, ride the peak to the top. */
- else ef->y = ef->y * ef->d_coeff; /* Else, exponential decay of output. */
-
- //ef->y = envelope_pow[(uint16_t)(ef->y * (float)UINT16_MAX)] * ef->d_coeff; //not quite the right behavior - too much loss of precision?
- //ef->y = powf(ef->y, 1.000009f) * ef->d_coeff; // too expensive
-
- if( ef->y < VSF) ef->y = 0.0f;
-
- return ef->y;
-}
-
-int tEnvelopeFollower_decayCoeff(tEnvelopeFollower* const ef, float decayCoeff)
-{
- return ef->d_coeff = decayCoeff;
-}
-
-int tEnvelopeFollower_attackThresh(tEnvelopeFollower* const ef, float attackThresh)
-{
- return ef->a_thresh = attackThresh;
-}
-
-/* Ramp */
-void tRamp_init(tRamp* const ramp, float time, int samples_per_tick)
-{
- ramp->inv_sr_ms = 1.0f/(leaf.sampleRate*0.001f);
- ramp->minimum_time = ramp->inv_sr_ms * samples_per_tick;
- ramp->curr = 0.0f;
- ramp->dest = 0.0f;
-
- if (time < ramp->minimum_time)
- {
- ramp->time = ramp->minimum_time;
- }
- else
- {
- ramp->time = time;
- }
-
- ramp->samples_per_tick = samples_per_tick;
- ramp->inc = ((ramp->dest - ramp->curr) / ramp->time * ramp->inv_sr_ms) * (float)ramp->samples_per_tick;
-}
-
-void tRamp_free(tRamp* const ramp)
-{
-
-}
-
-int tRamp_setTime(tRamp* const r, float time)
-{
- if (time < r->minimum_time)
- {
- r->time = r->minimum_time;
- }
- else
- {
- r->time = time;
- }
- r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
- return 0;
-}
-
-int tRamp_setDest(tRamp* const r, float dest)
-{
- r->dest = dest;
- r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
- return 0;
-}
-
-int tRamp_setVal(tRamp* const r, float val)
-{
- r->curr = val;
- r->inc = ((r->dest-r->curr)/r->time * r->inv_sr_ms) * ((float)r->samples_per_tick);
- return 0;
-}
-
-float tRamp_tick(tRamp* const r) {
-
- 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;
-}
-
-float tRamp_sample(tRamp* const r) {
-
- return r->curr;
-}
-
-void tRampSampleRateChanged(tRamp* const r)
-{
- 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;
-}
-
-void tExpSmooth_free(tExpSmooth* const smooth)
-{
-
-}
-
-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;
-}
-
-void tPwrFollow_free(tPwrFollow* const p)
-{
-
-}
-
-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;
-}
-
-void tFBleveller_free(tFBleveller* const p)
-{
- tPwrFollow_free(&p->pwrFlw);
-}
-
-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;
-}
-
-void tSimpleLivingString_free(tSimpleLivingString* const p)
-{
- tExpSmooth_free(&p->wlSmooth);
- tDelayL_free(&p->delayLine);
- tOnePole_free(&p->bridgeFilter);
- tHighpass_free(&p->DCblocker);
- tFBleveller_free(&p->fbLev);
-}
-
-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;
-}
-
-void tLivingString_free(tLivingString* const p)
-{
- tExpSmooth_free(&p->wlSmooth);
- tExpSmooth_free(&p->ppSmooth);
- tDelayL_free(&p->delLF);
- tDelayL_free(&p->delUF);
- tDelayL_free(&p->delUB);
- tDelayL_free(&p->delLB);
- tOnePole_free(&p->bridgeFilter);
- tOnePole_free(&p->nutFilter);
- tOnePole_free(&p->prepFilterU);
- tOnePole_free(&p->prepFilterL);
- tHighpass_free(&p->DCblockerU);
- tHighpass_free(&p->DCblockerL);
- tFBleveller_free(&p->fbLevU);
- tFBleveller_free(&p->fbLevL);
-}
-
-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 */
-
-void tStack_init(tStack* const ns)
-{
- ns->ordered = OFALSE;
- ns->size = 0;
- ns->pos = 0;
- ns->capacity = STACK_SIZE;
-
- for (int i = 0; i < STACK_SIZE; i++) ns->data[i] = -1;
-}
-
-void tStack_free(tStack* const ns)
-{
-
-}
-
-// If stack contains note, returns index. Else returns -1;
-int tStack_contains(tStack* const ns, uint16_t noteVal)
-{
- for (int i = 0; i < ns->size; i++)
- {
- if (ns->data[i] == noteVal) return i;
- }
- return -1;
-}
-
-void tStack_add(tStack* const ns, uint16_t noteVal)
-{
- uint8_t j;
-
- int whereToInsert = 0;
- if (ns->ordered)
- {
- for (j = 0; j < ns->size; j++)
- {
- if (noteVal > ns->data[j])
- {
- if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
- {
- whereToInsert = j+1;
- break;
- }
- }
- }
- }
-
- //first move notes that are already in the stack one position to the right
- for (j = ns->size; j > whereToInsert; j--)
- {
- ns->data[j] = ns->data[(j - 1)];
- }
-
- //then, insert the new note into the front of the stack
- ns->data[whereToInsert] = noteVal;
-
- ns->size++;
-}
-
-int tStack_addIfNotAlreadyThere(tStack* const ns, uint16_t noteVal)
-{
- uint8_t j;
-
- int added = 0;
-
- if (tStack_contains(ns, noteVal) == -1)
- {
- int whereToInsert = 0;
- if (ns->ordered)
- {
- for (j = 0; j < ns->size; j++)
- {
- if (noteVal > ns->data[j])
- {
- if ((noteVal < ns->data[j+1]) || (ns->data[j+1] == -1))
- {
- whereToInsert = j+1;
- break;
- }
- }
- }
- }
-
- //first move notes that are already in the stack one position to the right
- for (j = ns->size; j > whereToInsert; j--)
- {
- ns->data[j] = ns->data[(j - 1)];
- }
-
- //then, insert the new note into the front of the stack
- ns->data[whereToInsert] = noteVal;
-
- ns->size++;
-
- added = 1;
- }
-
- return added;
-}
-
-
-// Remove noteVal. return 1 if removed, 0 if not
-int tStack_remove(tStack* const ns, uint16_t noteVal)
-{
- uint8_t k;
- int foundIndex = tStack_contains(ns, noteVal);
- int removed = 0;
-
- if (foundIndex >= 0)
- {
- for (k = 0; k < (ns->size - foundIndex); k++)
- {
- if ((k+foundIndex) >= (ns->capacity - 1))
- {
- ns->data[k + foundIndex] = -1;
- }
- else
- {
- ns->data[k + foundIndex] = ns->data[k + foundIndex + 1];
- if ((k + foundIndex) == (ns->size - 1))
- {
- ns->data[k + foundIndex + 1] = -1;
- }
- }
-
- }
- // in case it got put on the stack multiple times
- foundIndex--;
- ns->size--;
- removed = 1;
- }
-
-
-
- return removed;
-}
-
-// Doesn't change size of data types
-void tStack_setCapacity(tStack* const ns, uint16_t cap)
-{
- if (cap <= 0)
- ns->capacity = 1;
- else if (cap <= STACK_SIZE)
- ns->capacity = cap;
- else
- ns->capacity = STACK_SIZE;
-
- for (int i = cap; i < STACK_SIZE; i++)
- {
- if ((int)ns->data[i] != -1)
- {
- ns->data[i] = -1;
- ns->size -= 1;
- }
- }
-
- if (ns->pos >= cap)
- {
- ns->pos = 0;
- }
-}
-
-int tStack_getSize(tStack* const ns)
-{
- return ns->size;
-}
-
-void tStack_clear(tStack* const ns)
-{
- for (int i = 0; i < STACK_SIZE; i++)
- {
- ns->data[i] = -1;
- }
- ns->pos = 0;
- ns->size = 0;
-}
-
-// Next item in order of addition to stack. Return 0-31 if there is a next item to move to. Returns -1 otherwise.
-int tStack_next(tStack* const ns)
-{
- int step = 0;
- if (ns->size != 0) // if there is at least one note in the stack
- {
- if (ns->pos > 0) // if you're not at the most recent note (first one), then go backward in the array (moving from earliest to latest)
- {
- ns->pos--;
- }
- else
- {
- ns->pos = (ns->size - 1); // if you are the most recent note, go back to the earliest note in the array
- }
-
- step = ns->data[ns->pos];
- return step;
- }
- else
- {
- return -1;
- }
-}
-
-int tStack_get(tStack* const ns, int which)
-{
- return ns->data[which];
-}
-
-int tStack_first(tStack* const ns)
-{
- return ns->data[0];
-}
-/******************************************************************************/
-/***************** static function declarations *******************************/
-/******************************************************************************/
-
-static void solad_init(tSOLAD *w);
-static inline float read_sample(tSOLAD *w, float floatindex);
-static void pitchdown(tSOLAD *w, float *out);
-static void pitchup(tSOLAD *w, float *out);
-
-/******************************************************************************/
-/***************** public access functions ************************************/
-/******************************************************************************/
-
-// init
-void tSOLAD_init(tSOLAD* const w)
-{
- w->pitchfactor = 1.;
- w->delaybuf = (float*) leaf_alloc(sizeof(float) * (LOOPSIZE+16));
- solad_init(w);
-}
-
-void tSOLAD_free(tSOLAD* const w)
-{
-}
-
-// send one block of input samples, receive one block of output samples
-void tSOLAD_ioSamples(tSOLAD* const w, float* in, float* out, int blocksize)
-{
- int i = w->timeindex;
- int n = w->blocksize = blocksize;
-
- if(!i) w->delaybuf[LOOPSIZE] = in[0]; // copy one sample for interpolation
- while(n--) w->delaybuf[i++] = *in++; // copy one input block to delay buffer
-
- if(w->pitchfactor > 1) pitchup(w, out);
- else pitchdown(w, out);
-
- w->timeindex += blocksize;
- w->timeindex &= LOOPMASK;
-}
-
-// set periodicity analysis data
-void tSOLAD_setPeriod(tSOLAD* const w, float period)
-{
- if(period > MAXPERIOD) period = MAXPERIOD;
- if(period > MINPERIOD) w->period = period; // ignore period when too small
-}
-
-// set pitch factor between 0.25 and 4
-void tSOLAD_setPitchFactor(tSOLAD* const w, float pitchfactor)
-{
- if(pitchfactor < 0.25) pitchfactor = 0.25;
- else if(pitchfactor > 4.) pitchfactor = 4.;
- w->pitchfactor = pitchfactor;
-}
-
-// force readpointer lag
-void tSOLAD_setReadLag(tSOLAD* const w, float readlag)
-{
- if(readlag < 0) readlag = 0;
- if(readlag < w->readlag) // do not jump backward, only forward
- {
- w->jump = w->readlag - readlag;
- w->readlag = readlag;
- w->xfadelength = readlag;
- w->xfadevalue = 1;
- }
-}
-
-// reset state variables
-void tSOLAD_resetState(tSOLAD* const w)
-{
- int n = LOOPSIZE + 1;
- float *buf = w->delaybuf;
-
- while(n--) *buf++ = 0;
- solad_init(w);
-}
-
-/******************************************************************************/
-/******************** private procedures **************************************/
-/******************************************************************************/
-
-/*
- Function pitchdown() is called to read samples from the delay buffer when pitch
- factor is between 0.25 and 1. The read pointer lags behind because of the slowed
- down speed, and it must jump forward towards the write pointer soon as there is
- sufficient space to jump. That is, if there is at least one period of the input
- signal between read pointer and write pointer. When short periods follow up on
- long periods, the read pointer may have space to jump over more than one period
- lenghts. Jump length must be [periodlength ^ 2] in any case.
-
- A linear crossfade function joins the jump-from point with the jump-to point.
- The crossfade must be completed before another read pointer jump is allowed.
- Length of the crossfade function is stored as a number of samples in terms of
- the input sample rate. This length is dynamically translated
- to a crossfade length expressed in output reading rate, according to pitch
- factor which can change before the crossfade is completed. Crossfade length does
- not cover an invariable length in periods for all pitch transposition factors.
- For pitch factors from 0.5 till 1, crossfade length is stretched in the
- output just as much as the signal itself, as crossfade speed is set to equal
- pitch factor. For pitch factors below 0.5, the read pointer wants to jump
- forward before one period is read, therefore the crossfade length as expressed
- in output periods must be shorter. Crossfade speed is set to [1 - pitchfactor]
- for those cases. Pitch factor 0.5 is the natural switch point between crossfade
- speeds [pitchfactor] and [1 - pitchfactor] because 0.5 == 1 - 0.5. The crossfade
- speed modification for pitch factors below 0.5 also means that much of the
- original signal content will be skipped.
- */
-
-
-static void pitchdown(tSOLAD* const w, float *out)
-{
- int n = w->blocksize;
- float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values!
- float pitchfactor = w->pitchfactor;
- float period = w->period;
- float readlag = w->readlag;
- float readlagstep = 1 - pitchfactor;
- float jump = w->jump;
- float xfadevalue = w->xfadevalue;
- float xfadelength = w->xfadelength;
- float xfadespeed, xfadestep, readindex, outputsample;
-
- if(pitchfactor > 0.5) xfadespeed = pitchfactor;
- else xfadespeed = 1 - pitchfactor;
- xfadestep = xfadespeed / xfadelength;
-
- while(n--)
- {
- if(readlag > period) // check if read pointer may jump forward...
- {
- if(xfadevalue <= 0) // ...but do not interrupt crossfade
- {
- jump = period; // jump forward
- while((jump * 2) < readlag) jump *= 2; // use available space
- readlag -= jump; // reduce read pointer lag
- xfadevalue = 1; // start crossfade
- xfadelength = period - 1;
- xfadestep = xfadespeed / xfadelength;
- }
- }
-
- readindex = refindex - readlag;
- outputsample = read_sample(w, readindex);
-
- if(xfadevalue > 0)
- {
- outputsample *= (1 - xfadevalue); // fadein
- outputsample += read_sample(w, readindex - jump) * xfadevalue; // fadeout
- xfadevalue -= xfadestep;
- }
-
- *out++ = outputsample;
- refindex += 1;
- readlag += readlagstep;
- }
-
- w->jump = jump; // state variables
- w->readlag = readlag;
- w->xfadevalue = xfadevalue;
- w->xfadelength = xfadelength;
-}
-
-
-/*
- Function pitchup() for pitch factors above 1 is more complicated than
- pitchdown(). The read pointer increments faster than the write pointer and a
- backward jump must happen in time, reckoning with the crossfade region. The read
- pointer backward jump length is always one period. In order to minimize the area
- of signal duplicates, crossfade length is aimed at [period / pitchfactor].
- This leads to a crossfade speed of [pitchfactor * pitchfactor].
-
- Some samples for the fade out (but not all of them) must already be in the
- buffer, otherwise we will run out of input samples before the crossfade is
- completed. The ratio of past samples and future samples for a crossfade of any
- length is as follows:
-
- past samples: xfadelength * (1 - 1 / pitchfactor)
- future samples: xfadelength * (1 / pitchfactor)
-
- For example in the case of pitch factor 1.5 this would be:
-
- past samples: xfadelength * (1 - 1 / 1.5) = xfadelength * 1 / 3
- future samples: xfadelength * (1 / 1.5) = xfadelength * 2 / 3
-
- In the case of pitch factor 4 this would be:
-
- past samples: xfadelength * (1 - 1 / 4) = xfadelength * 3 / 4
- future samples: xfadelength * (1 / 4) = xfadelength * 1 / 4
-
- The read pointer lag must therefore preserve a minimum dependent on pitch
- factor. The minimum is called 'limit' here:
-
- limit = period * (pitchfactor - 1) / pitchfactor * pitchfactor
-
- Components of this expression are combined to reuse them in operations, while
- (pitchfactor - 1) is changed to (pitchfactor - 0.99) to avoid numerical
- resolution issues for pitch factors slightly above 1:
-
- xfadespeed = pitchfactor * pitchfactor
- limitfactor = (pitchfactor - 0.99) / xfadespeed
- limit = period * limitfactor
-
- When read lag is smaller than this limit, the read pointer must preferably
- jump backward, unless a previous crossfade is not yet completed. Crossfades must
- preferably be completed, unless the read pointer lag becomes smaller than zero.
- With fluctuating period lengths and pitch factors, the readpointer lag limit may
- change from one input block to the next in such a way that the actual lag is
- suddenly much smaller than the limit, and the intended crossfade length can not
- be applied. Therefore the crossfade length is simply calculated from the
- available amount of samples for all cases, like so:
-
- xfadelength = readlag / limitfactor
-
- For most occurrences, this will amount to a crossfade length reduced to
- [period / pitchfactor] in the output for pitch factors above 1, while in some
- cases it will be considerably shorter. Fortunately, an incidental aberration of
- the intended crossfade length hardly ever creates an audible artifact. The
- reason to specify preferred crossfade length according to pitch factor is to
- minimize the impression of echoes without sacrificing too much of the signal
- content. The readpointer jump length remains one period in any case.
-
- Sometimes, the input signal periodicity may decrease substantially between one
- signal block and the next. In such cases it may be possible for the read pointer
- to jump forward and reduce latency. For every signal block, a check on this
- possibility is done. A previous crossfade must be completed before a forward
- jump is allowed.
- */
-static void pitchup(tSOLAD* const w, float *out)
-{
- int n = w->blocksize;
- float refindex = (float)(w->timeindex + LOOPSIZE); // no negative values
- float pitchfactor = w->pitchfactor;
- float period = w->period;
- float readlag = w->readlag;
- float jump = w->jump;
- float xfadevalue = w->xfadevalue;
- float xfadelength = w->xfadelength;
-
- float readlagstep = pitchfactor - 1;
- float xfadespeed = pitchfactor * pitchfactor;
- float xfadestep = xfadespeed / xfadelength;
- float limitfactor = (pitchfactor - (float)0.99) / xfadespeed;
- float limit = period * limitfactor;
- float readindex, outputsample;
-
- if((readlag > (period + 2 * limit)) & (xfadevalue < 0))
- {
- jump = period; // jump forward
- while((jump * 2) < (readlag - 2 * limit)) jump *= 2; // use available space
- readlag -= jump; // reduce read pointer lag
- xfadevalue = 1; // start crossfade
- xfadelength = period - 1;
- xfadestep = xfadespeed / xfadelength;
- }
-
- while(n--)
- {
- if(readlag < limit) // check if read pointer should jump backward...
- {
- if((xfadevalue < 0) | (readlag < 0)) // ...but try not to interrupt crossfade
- {
- xfadelength = readlag / limitfactor;
- if(xfadelength < 1) xfadelength = 1;
- xfadestep = xfadespeed / xfadelength;
-
- jump = -period; // jump backward
- readlag += period; // increase read pointer lag
- xfadevalue = 1; // start crossfade
- }
- }
-
- readindex = refindex - readlag;
- outputsample = read_sample(w, readindex);
-
- if(xfadevalue > 0)
- {
- outputsample *= (1 - xfadevalue);
- outputsample += read_sample(w, readindex - jump) * xfadevalue;
- xfadevalue -= xfadestep;
- }
-
- *out++ = outputsample;
- refindex += 1;
- readlag -= readlagstep;
- }
-
- w->readlag = readlag; // state variables
- w->jump = jump;
- w->xfadelength = xfadelength;
- w->xfadevalue = xfadevalue;
-}
-
-// read one sample from delay buffer, with linear interpolation
-static inline float read_sample(tSOLAD* const w, float floatindex)
-{
- int index = (int)floatindex;
- float fraction = floatindex - (float)index;
- float *buf = w->delaybuf;
- index &= LOOPMASK;
-
- return (buf[index] + (fraction * (buf[index+1] - buf[index])));
-}
-
-static void solad_init(tSOLAD* const w)
-{
- w->timeindex = 0;
- w->xfadevalue = -1;
- w->period = INITPERIOD;
- w->readlag = INITPERIOD;
- w->blocksize = INITPERIOD;
-}
-
-/******************************************************************************/
-/***************************** private procedures *****************************/
-/******************************************************************************/
-
-#define REALFFT mayer_realfft
-#define REALIFFT mayer_realifft
-
-static void snac_analyzeframe(tSNAC* const s);
-static void snac_autocorrelation(tSNAC* const s);
-static void snac_normalize(tSNAC* const s);
-static void snac_pickpeak(tSNAC* const s);
-static void snac_periodandfidelity(tSNAC* const s);
-static void snac_biasbuf(tSNAC* const s);
-static float snac_spectralpeak(tSNAC* const s, float periodlength);
-
-
-/******************************************************************************/
-/******************************** constructor, destructor *********************/
-/******************************************************************************/
-
-
-void tSNAC_init(tSNAC* const s, int overlaparg)
-{
- s->biasfactor = DEFBIAS;
- s->timeindex = 0;
- s->periodindex = 0;
- s->periodlength = 0.;
- s->fidelity = 0.;
- s->minrms = DEFMINRMS;
- s->framesize = SNAC_FRAME_SIZE;
-
- s->inputbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE);
- s->processbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE * 2));
- s->spectrumbuf = (float*) leaf_alloc(sizeof(float) * (SNAC_FRAME_SIZE / 2));
- s->biasbuf = (float*) leaf_alloc(sizeof(float) * SNAC_FRAME_SIZE);
-
- snac_biasbuf(s);
- tSNAC_setOverlap(s, overlaparg);
-}
-
-void tSNAC_free(tSNAC* const s)
-{
- leaf_free(s->inputbuf);
- leaf_free(s->processbuf);
- leaf_free(s->spectrumbuf);
- leaf_free(s->biasbuf);
-}
-/******************************************************************************/
-/************************** public access functions****************************/
-/******************************************************************************/
-
-
-void tSNAC_ioSamples(tSNAC* const s, float *in, float *out, int size)
-{
- int timeindex = s->timeindex;
- int mask = s->framesize - 1;
- int outindex = 0;
- float *inputbuf = s->inputbuf;
- float *processbuf = s->processbuf;
-
- // call analysis function when it is time
- if(!(timeindex & (s->framesize / s->overlap - 1))) snac_analyzeframe(s);
-
- while(size--)
- {
- inputbuf[timeindex] = *in++;
- out[outindex++] = processbuf[timeindex++];
- timeindex &= mask;
- }
- s->timeindex = timeindex;
-}
-
-void tSNAC_setOverlap(tSNAC* const s, int lap)
-{
- if(!((lap==1)|(lap==2)|(lap==4)|(lap==8))) lap = DEFOVERLAP;
- s->overlap = lap;
-}
-
-
-void tSNAC_setBias(tSNAC* const s, float bias)
-{
- if(bias > 1.) bias = 1.;
- if(bias < 0.) bias = 0.;
- s->biasfactor = bias;
- snac_biasbuf(s);
- return;
-}
-
-
-void tSNAC_setMinRMS(tSNAC* const s, float rms)
-{
- if(rms > 1.) rms = 1.;
- if(rms < 0.) rms = 0.;
- s->minrms = rms;
- return;
-}
-
-
-float tSNAC_getPeriod(tSNAC* const s)
-{
- return(s->periodlength);
-}
-
-
-float tSNAC_getFidelity(tSNAC* const s)
-{
- return(s->fidelity);
-}
-
-
-/******************************************************************************/
-/***************************** private procedures *****************************/
-/******************************************************************************/
-
-
-// main analysis function
-static void snac_analyzeframe(tSNAC* const s)
-{
- int n, tindex = s->timeindex;
- int framesize = s->framesize;
- int mask = framesize - 1;
- float norm = 1. / sqrt((float)(framesize * 2));
-
- float *inputbuf = s->inputbuf;
- float *processbuf = s->processbuf;
-
- // copy input to processing buffers
- for(n=0; n<framesize; n++)
- {
- processbuf[n] = inputbuf[tindex] * norm;
- tindex++;
- tindex &= mask;
- }
-
- // zeropadding
- for(n=framesize; n<(framesize<<1); n++) processbuf[n] = 0.;
-
- // call analysis procedures
- snac_autocorrelation(s);
- snac_normalize(s);
- snac_pickpeak(s);
- snac_periodandfidelity(s);
-}
-
-
-static void snac_autocorrelation(tSNAC* const s)
-{
- int n, m;
- int framesize = s->framesize;
- int fftsize = framesize * 2;
- float *processbuf = s->processbuf;
- float *spectrumbuf = s->spectrumbuf;
-
- REALFFT(fftsize, processbuf);
-
- // compute power spectrum
- processbuf[0] *= processbuf[0]; // DC
- processbuf[framesize] *= processbuf[framesize]; // Nyquist
-
- for(n=1; n<framesize; n++)
- {
- processbuf[n] = processbuf[n] * processbuf[n]
- + processbuf[fftsize-n] * processbuf[fftsize-n]; // imag coefficients appear reversed
- processbuf[fftsize-n] = 0.;
- }
-
- // store power spectrum up to SR/4 for possible later use
- for(m=0; m<(framesize>>1); m++)
- {
- spectrumbuf[m] = processbuf[m];
- }
-
- // transform power spectrum to autocorrelation function
- REALIFFT(fftsize, processbuf);
- return;
-}
-
-
-static void snac_normalize(tSNAC* const s)
-{
- int framesize = s->framesize;
- int framesizeplustimeindex = s->framesize + s->timeindex;
- int timeindexminusone = s->timeindex - 1;
- int n, m;
- int mask = framesize - 1;
- int seek = framesize * SEEK;
- float *inputbuf = s->inputbuf;
- float *processbuf= s->processbuf;
- float signal1, signal2;
-
- // minimum RMS implemented as minimum autocorrelation at index 0
- // functionally equivalent to white noise floor
- float rms = s->minrms / sqrt(1.0f / (float)framesize);
- float minrzero = rms * rms;
- float rzero = processbuf[0];
- if(rzero < minrzero) rzero = minrzero;
- double normintegral = (double)rzero * 2.;
-
- // normalize biased autocorrelation function
- // inputbuf is circular buffer: timeindex may be non-zero when overlap > 1
- processbuf[0] = 1;
- for(n=1, m=s->timeindex+1; n<seek; n++, m++)
- {
- signal1 = inputbuf[(n + timeindexminusone)&mask];
- signal2 = inputbuf[(framesizeplustimeindex - n)&mask];
- normintegral -= (double)(signal1 * signal1 + signal2 * signal2);
- processbuf[n] /= (float)normintegral * 0.5f;
- }
-
- // flush instable function tail
- for(n = seek; n<framesize; n++) processbuf[n] = 0.;
- return;
-}
-
-
-static void snac_periodandfidelity(tSNAC* const s)
-{
- float periodlength;
-
- if(s->periodindex)
- {
- periodlength = (float)s->periodindex +
- interpolate3phase(s->processbuf, s->periodindex);
- if(periodlength < 8) periodlength = snac_spectralpeak(s, periodlength);
- s->periodlength = periodlength;
- s->fidelity = interpolate3max(s->processbuf, s->periodindex);
- }
- return;
-}
-
-// select the peak which most probably represents period length
-static void snac_pickpeak(tSNAC* const s)
-{
- int n, peakindex=0;
- int seek = s->framesize * SEEK;
- float *processbuf= s->processbuf;
- float maxvalue = 0.;
- float biasedpeak;
- float *biasbuf = s->biasbuf;
-
- // skip main lobe
- for(n=1; n<seek; n++)
- {
- if(processbuf[n] < 0.) break;
- }
-
- // find interpolated / biased maximum in SNAC function
- // interpolation finds the 'real maximum'
- // biasing favours the first candidate
- for(; n<seek-1; n++)
- {
- if(processbuf[n] >= processbuf[n-1])
- {
- if(processbuf[n] > processbuf[n+1]) // we have a local peak
- {
- biasedpeak = interpolate3max(processbuf, n) * biasbuf[n];
-
- if(biasedpeak > maxvalue)
- {
- maxvalue = biasedpeak;
- peakindex = n;
- }
- }
- }
- }
- s->periodindex = peakindex;
- return;
-}
-
-
-// verify period length via frequency domain (up till SR/4)
-// frequency domain is more precise than lag domain for period lengths < 8
-// argument 'periodlength' is initial estimation from autocorrelation
-static float snac_spectralpeak(tSNAC* const s, float periodlength)
-{
- if(periodlength < 4.) return periodlength;
-
- float max = 0.;
- int n, startbin, stopbin, peakbin = 0;
- int spectrumsize = s->framesize>>1;
- float *spectrumbuf = s->spectrumbuf;
- float peaklocation = (float)(s->framesize * 2.) / periodlength;
-
- startbin = (int)(peaklocation * 0.8 + 0.5);
- if(startbin < 1) startbin = 1;
- stopbin = (int)(peaklocation * 1.25 + 0.5);
- if(stopbin >= spectrumsize - 1) stopbin = spectrumsize - 1;
-
- for(n=startbin; n<stopbin; n++)
- {
- if(spectrumbuf[n] >= spectrumbuf[n-1])
- {
- if(spectrumbuf[n] > spectrumbuf[n+1])
- {
- if(spectrumbuf[n] > max)
- {
- max = spectrumbuf[n];
- peakbin = n;
- }
- }
- }
- }
-
- // calculate amplitudes in peak region
- for(n=(peakbin-1); n<(peakbin+2); n++)
- {
- spectrumbuf[n] = sqrt(spectrumbuf[n]);
- }
-
- peaklocation = (float)peakbin + interpolate3phase(spectrumbuf, peakbin);
- periodlength = (float)(s->framesize * 2.0f) / peaklocation;
-
- return periodlength;
-}
-
-
-// modified logarithmic bias function
-static void snac_biasbuf(tSNAC* const s)
-{
- int n;
- int maxperiod = (int)(s->framesize * (float)SEEK);
- float bias = s->biasfactor / log((float)(maxperiod - 4));
- float *biasbuf = s->biasbuf;
-
- for(n=0; n<5; n++) // periods < 5 samples can't be tracked
- {
- biasbuf[n] = 0.;
- }
-
- for(n=5; n<maxperiod; n++)
- {
- biasbuf[n] = 1.0f - (float)log(n - 4) * bias;
- }
-}
-
-/********Private function prototypes**********/
-static void atkdtk_init(tAtkDtk* const a, int blocksize, int atk, int rel);
-static void atkdtk_envelope(tAtkDtk* const a, float *in);
-
-/********Constructor/Destructor***************/
-
-void tAtkDtk_init(tAtkDtk* const a, int blocksize)
-{
- atkdtk_init(a, blocksize, DEFATTACK, DEFRELEASE);
-}
-
-void tAtkDtk_init_expanded(tAtkDtk* const a, int blocksize, int atk, int rel)
-{
- atkdtk_init(a, blocksize, atk, rel);
-}
-
-void tAtkDtk_free(tAtkDtk *a)
-{
-
-}
-
-/*******Public Functions***********/
-
-
-void tAtkDtk_setBlocksize(tAtkDtk* const a, int size)
-{
-
- if(!((size==64)|(size==128)|(size==256)|(size==512)|(size==1024)|(size==2048)))
- size = DEFBLOCKSIZE;
- a->blocksize = size;
-
- return;
-
-}
-
-void tAtkDtk_setSamplerate(tAtkDtk* const a, int inRate)
-{
- a->samplerate = inRate;
-
- //Reset atk and rel to recalculate coeff
- tAtkDtk_setAtk(a, a->atk);
- tAtkDtk_setRel(a, a->rel);
-
- return;
-}
-
-void tAtkDtk_setThreshold(tAtkDtk* const a, float thres)
-{
- a->threshold = thres;
- return;
-}
-
-void tAtkDtk_setAtk(tAtkDtk* const a, int inAtk)
-{
- a->atk = inAtk;
- a->atk_coeff = pow(0.01, 1.0/(a->atk * a->samplerate * 0.001));
-
- return;
-}
-
-void tAtkDtk_setRel(tAtkDtk* const a, int inRel)
-{
- a->rel = inRel;
- a->rel_coeff = pow(0.01, 1.0/(a->rel * a->samplerate * 0.001));
-
- return;
-}
-
-
-int tAtkDtk_detect(tAtkDtk* const a, float *in)
-{
- int result;
-
- atkdtk_envelope(a, in);
-
- if(a->env >= a->prevAmp*2) //2 times greater = 6dB increase
- result = 1;
- else
- result = 0;
-
- a->prevAmp = a->env;
-
- return result;
-
-}
-
-/*******Private Functions**********/
-
-static void atkdtk_init(tAtkDtk* const a, int blocksize, int atk, int rel)
-{
- a->env = 0;
- a->blocksize = blocksize;
- a->threshold = DEFTHRESHOLD;
- a->samplerate = leaf.sampleRate;
- a->prevAmp = 0;
-
- a->env = 0;
-
- tAtkDtk_setAtk(a, atk);
- tAtkDtk_setRel(a, rel);
-}
-
-static void atkdtk_envelope(tAtkDtk* const a, float *in)
-{
- int i = 0;
- float tmp;
- for(i = 0; i < a->blocksize; ++i){
- tmp = fastabs(in[i]);
-
- if(tmp > a->env)
- a->env = a->atk_coeff * (a->env - tmp) + tmp;
- else
- a->env = a->rel_coeff * (a->env - tmp) + tmp;
- }
-
-}
-
--- a/LEAF/Src/leaf-vocoder.c
+++ /dev/null
@@ -1,400 +1,0 @@
-/*==============================================================================
-
- leaf-vocoder.c
- Created: 20 Jan 2017 12:01:54pm
- Author: Michael R Mulshine
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-vocoder.h"
-#include "..\leaf.h"
-
-#else
-
-#include "../Inc/leaf-vocoder.h"
-#include "../leaf.h"
-
-#endif
-
-
-
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
- *
- *
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-void tTalkbox_init(tTalkbox* const v, int bufsize)
-{
- v->param[0] = 0.5f; //wet
- v->param[1] = 0.0f; //dry
- v->param[2] = 0; // Swap
- v->param[3] = 1.0f; //quality
-
- v->bufsize = bufsize;
-
- v->car0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
- v->car1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
- v->window = (float*) leaf_alloc(sizeof(float) * v->bufsize);
- v->buf0 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
- v->buf1 = (float*) leaf_alloc(sizeof(float) * v->bufsize);
-
- tTalkbox_update(v);
-}
-
-void tTalkbox_free(tTalkbox* const v)
-{
- leaf_free(v->car0);
- leaf_free(v->car1);
- leaf_free(v->window);
- leaf_free(v->buf0);
- leaf_free(v->buf1);
-}
-
-void tTalkbox_update(tTalkbox* const v) ///update internal parameters...
-{
- float fs = leaf.sampleRate;
- if(fs < 8000.0f) fs = 8000.0f;
- if(fs > 96000.0f) fs = 96000.0f;
-
- int32_t n = (int32_t)(0.01633f * fs);
- if(n > v->bufsize) n = v->bufsize;
-
- //O = (VstInt32)(0.0005f * fs);
- v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * fs);
-
- if(n != v->N) //recalc hanning window
- {
- v->N = n;
- float dp = TWO_PI / v->N;
- float p = 0.0f;
- for(n=0; n<v->N; n++)
- {
- v->window[n] = 0.5f - 0.5f * cosf(p);
- p += dp;
- }
- }
- v->wet = 0.5f * v->param[0] * v->param[0];
- v->dry = 2.0f * v->param[1] * v->param[1];
-}
-
-void tTalkbox_suspend(tTalkbox* const v) ///clear any buffers...
-{
- v->pos = v->K = 0;
- v->emphasis = 0.0f;
- v->FX = 0;
-
- v->u0 = v->u1 = v->u2 = v->u3 = v->u4 = 0.0f;
- v->d0 = v->d1 = v->d2 = v->d3 = v->d4 = 0.0f;
-
- for (int32_t i = 0; i < v->bufsize; i++)
- {
- v->buf0[i] = 0;
- v->buf1[i] = 0;
- v->car0[i] = 0;
- v->car1[i] = 0;
- }
-}
-
-
-#define ORD_MAX 100 // Was 50. Increasing this gets rid of glitchiness, lowering it breaks it; not sure how it affects performance
-void tTalkbox_lpc(float *buf, float *car, int32_t n, int32_t o)
-{
- float z[ORD_MAX], r[ORD_MAX], k[ORD_MAX], G, x;
- int32_t i, j, nn=n;
-
- for(j=0; j<=o; j++, nn--) //buf[] is already emphasized and windowed
- {
- z[j] = r[j] = 0.0f;
- for(i=0; i<nn; i++) r[j] += buf[i] * buf[i+j]; //autocorrelation
- }
- r[0] *= 1.001f; //stability fix
-
- float min = 0.00001f;
- if(r[0] < min) { for(i=0; i<n; i++) buf[i] = 0.0f; return; }
-
- tTalkbox_lpcDurbin(r, o, k, &G); //calc reflection coeffs
-
- for(i=0; i<=o; i++)
- {
- if(k[i] > 0.995f) k[i] = 0.995f; else if(k[i] < -0.995f) k[i] = -.995f;
- }
-
- for(i=0; i<n; i++)
- {
- x = G * car[i];
- for(j=o; j>0; j--) //lattice filter
- {
- x -= k[j] * z[j-1];
- z[j] = z[j-1] + k[j] * x;
- }
- buf[i] = z[0] = x; //output buf[] will be windowed elsewhere
- }
-}
-
-
-void tTalkbox_lpcDurbin(float *r, int p, float *k, float *g)
-{
- int i, j;
- float a[ORD_MAX], at[ORD_MAX], e=r[0];
-
- for(i=0; i<=p; i++) a[i] = at[i] = 0.0f; //probably don't need to clear at[] or k[]
-
- for(i=1; i<=p; i++)
- {
- k[i] = -r[i];
-
- for(j=1; j<i; j++)
- {
- at[j] = a[j];
- k[i] -= a[j] * r[i-j];
- }
- if(fabs(e) < 1.0e-20f) { e = 0.0f; break; }
- k[i] /= e; // This might be costing us
-
- a[i] = k[i];
- for(j=1; j<i; j++) a[j] = at[j] + k[i] * at[i-j];
-
- e *= 1.0f - k[i] * k[i];
- }
-
- if(e < 1.0e-20f) e = 0.0f;
- *g = sqrtf(e);
-}
-
-float tTalkbox_tick(tTalkbox* const v, float synth, float voice)
-{
-
- int32_t p0=v->pos, p1 = (v->pos + v->N/2) % v->N;
- float e=v->emphasis, w, o, x, dr, fx=v->FX;
- float p, q, h0=0.3f, h1=0.77f;
-
- o = voice;
- x = synth;
-
- dr = o;
-
- p = v->d0 + h0 * x; v->d0 = v->d1; v->d1 = x - h0 * p;
- q = v->d2 + h1 * v->d4; v->d2 = v->d3; v->d3 = v->d4 - h1 * q;
- v->d4 = x;
- x = p + q;
-
- if(v->K++)
- {
- v->K = 0;
-
- v->car0[p0] = v->car1[p1] = x; //carrier input
-
- x = o - e; e = o; //6dB/oct pre-emphasis
-
- w = v->window[p0]; fx = v->buf0[p0] * w; v->buf0[p0] = x * w; //50% overlapping hanning windows
- if(++p0 >= v->N) { tTalkbox_lpc(v->buf0, v->car0, v->N, v->O); p0 = 0; }
-
- w = 1.0f - w; fx += v->buf1[p1] * w; v->buf1[p1] = x * w;
- if(++p1 >= v->N) { tTalkbox_lpc(v->buf1, v->car1, v->N, v->O); p1 = 0; }
- }
-
- p = v->u0 + h0 * fx; v->u0 = v->u1; v->u1 = fx - h0 * p;
- q = v->u2 + h1 * v->u4; v->u2 = v->u3; v->u3 = v->u4 - h1 * q;
- v->u4 = fx;
- x = p + q;
-
- o = x;
-
- v->emphasis = e;
- v->pos = p0;
- v->FX = fx;
-
- float den = 1.0e-10f; //(float)pow(10.0f, -10.0f * param[4]);
- if(fabs(v->d0) < den) v->d0 = 0.0f; //anti-denormal (doesn't seem necessary but P4?)
- if(fabs(v->d1) < den) v->d1 = 0.0f;
- if(fabs(v->d2) < den) v->d2 = 0.0f;
- if(fabs(v->d3) < den) v->d3 = 0.0f;
- if(fabs(v->u0) < den) v->u0 = 0.0f;
- if(fabs(v->u1) < den) v->u1 = 0.0f;
- if(fabs(v->u2) < den) v->u2 = 0.0f;
- if(fabs(v->u3) < den) v->u3 = 0.0f;
- return o;
-}
-
-void tTalkbox_setQuality(tTalkbox* const v, float quality)
-{
- v->param[3] = quality;
- v->O = (int32_t)((0.0001f + 0.0004f * v->param[3]) * leaf.sampleRate);
-}
-
-void tVocoder_init (tVocoder* const v)
-{
- v->param[0] = 0.33f; //input select
- v->param[1] = 0.50f; //output dB
- v->param[2] = 0.40f; //hi thru
- v->param[3] = 0.40f; //hi band
- v->param[4] = 0.16f; //envelope
- v->param[5] = 0.55f; //filter q
- v->param[6] = 0.6667f;//freq range
- v->param[7] = 0.33f; //num bands
-
- tVocoder_update(v);
-}
-
-void tVocoder_free (tVocoder* const v)
-{
-
-}
-
-void tVocoder_update (tVocoder* const v)
-{
- float tpofs = 6.2831853f * leaf.invSampleRate;
-
- float rr, th, re;
-
- float sh;
-
- int32_t i;
-
- v->gain = (float)pow(10.0f, 2.0f * v->param[1] - 3.0f * v->param[5] - 2.0f);
-
- v->thru = (float)pow(10.0f, 0.5f + 2.0f * v->param[1]);
- v->high = v->param[3] * v->param[3] * v->param[3] * v->thru;
- v->thru *= v->param[2] * v->param[2] * v->param[2];
-
- if(v->param[7]<0.5f)
- {
- v->nbnd=8;
- re=0.003f;
- v->f[1][2] = 3000.0f;
- v->f[2][2] = 2200.0f;
- v->f[3][2] = 1500.0f;
- v->f[4][2] = 1080.0f;
- v->f[5][2] = 700.0f;
- v->f[6][2] = 390.0f;
- v->f[7][2] = 190.0f;
- }
- else
- {
- v->nbnd=16;
- re=0.0015f;
- v->f[ 1][2] = 5000.0f; //+1000
- v->f[ 2][2] = 4000.0f; //+750
- v->f[ 3][2] = 3250.0f; //+500
- v->f[ 4][2] = 2750.0f; //+450
- v->f[ 5][2] = 2300.0f; //+300
- v->f[ 6][2] = 2000.0f; //+250
- v->f[ 7][2] = 1750.0f; //+250
- v->f[ 8][2] = 1500.0f; //+250
- v->f[ 9][2] = 1250.0f; //+250
- v->f[10][2] = 1000.0f; //+250
- v->f[11][2] = 750.0f; //+210
- v->f[12][2] = 540.0f; //+190
- v->f[13][2] = 350.0f; //+155
- v->f[14][2] = 195.0f; //+100
- v->f[15][2] = 95.0f;
- }
-
- if(v->param[4]<0.05f) //freeze
- {
- for(i=0;i<v->nbnd;i++) v->f[i][12]=0.0f;
- }
- else
- {
- v->f[0][12] = (float)pow(10.0, -1.7 - 2.7f * v->param[4]); //envelope speed
-
- rr = 0.022f / (float)v->nbnd; //minimum proportional to frequency to stop distortion
- for(i=1;i<v->nbnd;i++)
- {
- v->f[i][12] = (float)(0.025 - rr * (double)i);
- if(v->f[0][12] < v->f[i][12]) v->f[i][12] = v->f[0][12];
- }
- v->f[0][12] = 0.5f * v->f[0][12]; //only top band is at full rate
- }
-
- rr = 1.0 - pow(10.0f, -1.0f - 1.2f * v->param[5]);
- sh = (float)pow(2.0f, 3.0f * v->param[6] - 1.0f); //filter bank range shift
-
- for(i=1;i<v->nbnd;i++)
- {
- v->f[i][2] *= sh;
- th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
- v->f[i][0] = (float)(2.0 * rr * cos(th)); //a0
- v->f[i][1] = (float)(-rr * rr); //a1
- //was .98
- v->f[i][2] *= 0.96f; //shift 2nd stage slightly to stop high resonance peaks
- th = acos((2.0 * rr * cos(tpofs * v->f[i][2])) / (1.0 + rr * rr));
- v->f[i][2] = (float)(2.0 * rr * cos(th));
- }
-}
-
-float tVocoder_tick (tVocoder* const v, float synth, float voice)
-{
- float a, b, o=0.0f, aa, bb, oo = v->kout, g = v->gain, ht = v->thru, hh = v->high, tmp;
- uint32_t i, k = v->kval, nb = v->nbnd;
-
- a = voice; //speech
- b = synth; //synth
-
- tmp = a - v->f[0][7]; //integrate modulator for HF band and filter bank pre-emphasis
- v->f[0][7] = a;
- a = tmp;
-
- if(tmp<0.0f) tmp = -tmp;
- v->f[0][11] -= v->f[0][12] * (v->f[0][11] - tmp); //high band envelope
- o = v->f[0][11] * (ht * a + hh * (b - v->f[0][3])); //high band + high thru
-
- v->f[0][3] = b; //integrate carrier for HF band
-
- if(++k & 0x1) //this block runs at half sample rate
- {
- oo = 0.0f;
- aa = a + v->f[0][9] - v->f[0][8] - v->f[0][8]; //apply zeros here instead of in each reson
- v->f[0][9] = v->f[0][8]; v->f[0][8] = a;
- bb = b + v->f[0][5] - v->f[0][4] - v->f[0][4];
- v->f[0][5] = v->f[0][4]; v->f[0][4] = b;
-
- for(i=1; i<nb; i++) //filter bank: 4th-order band pass
- {
- tmp = v->f[i][0] * v->f[i][3] + v->f[i][1] * v->f[i][4] + bb;
- v->f[i][4] = v->f[i][3];
- v->f[i][3] = tmp;
- tmp += v->f[i][2] * v->f[i][5] + v->f[i][1] * v->f[i][6];
- v->f[i][6] = v->f[i][5];
- v->f[i][5] = tmp;
-
- tmp = v->f[i][0] * v->f[i][7] + v->f[i][1] * v->f[i][8] + aa;
- v->f[i][8] = v->f[i][7];
- v->f[i][7] = tmp;
- tmp += v->f[i][2] * v->f[i][9] + v->f[i][1] * v->f[i][10];
- v->f[i][10] = v->f[i][9];
- v->f[i][9] = tmp;
-
- if(tmp<0.0f) tmp = -tmp;
- v->f[i][11] -= v->f[i][12] * (v->f[i][11] - tmp);
- oo += v->f[i][5] * v->f[i][11];
- }
- }
- o += oo * g; //effect of interpolating back up to Fs would be minimal (aliasing >16kHz)
-
- v->kout = oo;
- v->kval = k & 0x1;
- if(fabs(v->f[0][11])<1.0e-10) v->f[0][11] = 0.0f; //catch HF envelope denormal
-
- for(i=1;i<nb;i++)
- if(fabs(v->f[i][3])<1.0e-10 || fabs(v->f[i][7])<1.0e-10)
- for(k=3; k<12; k++) v->f[i][k] = 0.0f; //catch reson & envelope denormals
-
- if(fabs(o)>10.0f) tVocoder_suspend(v); //catch instability
-
- return o;
-
-}
-
-void tVocoder_suspend (tVocoder* const v)
-{
- int32_t i, j;
-
- for(i=0; i<v->nbnd; i++) for(j=3; j<12; j++) v->f[i][j] = 0.0f; //zero band filters and envelopes
- v->kout = 0.0f;
- v->kval = 0;
-}
-
--- a/LEAF/Src/leaf-wavefolder.c
+++ /dev/null
@@ -1,114 +1,0 @@
-/*==============================================================================
-
- leaf-wavefolder.c
- Created: 30 Nov 2018 11:56:49am
- Author: airship
-
-==============================================================================*/
-
-#if _WIN32 || _WIN64
-
-#include "..\Inc\leaf-wavefolder.h"
-
-#else
-
-#include "../Inc/leaf-wavefolder.h"
-
-#endif
-
-void tLockhartWavefolder_init(tLockhartWavefolder* const w)
-{
- w->Ln1 = 0.0;
- w->Fn1 = 0.0;
- w->xn1 = 0.0f;
-}
-
-void tLockhardWavefolder_free(tLockhartWavefolder* const w)
-{
-
-}
-
-double tLockhartWavefolderLambert(double x, double ln)
-{
- double thresh, w, expw, p, r, s, err;
- // Error threshold
- thresh = 10e-6;
- // Initial guess (use previous value)
- w = ln;
-
- // Haley's method (Sec. 4.2 of the paper)
- for(int i=0; i<100; i+=1) {
-
- expw = exp(w);
-
- p = w*expw - x;
- r = (w+1.0)*expw;
- s = (w+2.0)/(2.0*(w+1.0)); err = (p/(r-(p*s)));
-
- if (fabs(err)<thresh) {
- break;
- }
- if (isnan(err))
- {
- break;
- }
-
- w = w - err;
- }
- return w;
-}
-
-float tLockhartWavefolder_tick(tLockhartWavefolder* const w, float samp)
-{
-
- 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 Ln = tLockhartWavefolderLambert(u,w->Ln1);
- double Fn = (0.5*VT/b)*(Ln*(Ln + 2.0)) - 0.5*a*samp*samp;
-
- // Check for ill-conditioning
- if (fabs(samp-w->xn1)<thresh) {
-
- // Compute Averaged Wavefolder Output
- double xn = 0.5*(samp+w->xn1);
- u = d*exp(l*b*xn);
- Ln = tLockhartWavefolderLambert(u,w->Ln1);
- out = (float) (l*VT*Ln - a*xn);
- if (isnan(out))
- {
- ;
- }
-
- }
- else {
-
- // Apply AA Form
- out = (float) ((Fn-w->Fn1)/(samp-w->xn1));
- if (isnan(out))
- {
- ;
- }
- }
-
- // Update States
- w->Ln1 = Ln;
- w->Fn1 = Fn;
- w->xn1 = samp;
-
- return out;
-}
--- a/LEAF/leaf.h
+++ b/LEAF/leaf.h
@@ -22,22 +22,21 @@
#include ".\Inc\leaf-global.h"
#include ".\Inc\leaf-math.h"
#include ".\Inc\leaf-mempool.h"
-#include ".\Inc\leaf-utilities.h"
+#include ".\Inc\leaf-tables.h"
+#include ".\Inc\leaf-tables.h"
+#include ".\Inc\leaf-oscillators.h"
+#include ".\Inc\leaf-filters.h"
#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"
-#include ".\Inc\leaf-string.h"
-#include ".\Inc\leaf-pitch.h"
-#include ".\Inc\leaf-formant.h"
+#include ".\Inc\leaf-effects.h"
+#include ".\Inc\leaf-envelopes.h"
+#include ".\Inc\leaf-dynamics.h"
+#include ".\Inc\leaf-analysis.h"
+#include ".\Inc\leaf-instruments.h"
#include ".\Inc\leaf-midi.h"
-#include ".\Inc\leaf-sample.h"
-#include ".\Inc\leaf-crusher.h"
-#include ".\Inc\leaf-wavefolder.h"
-#include ".\Inc\leaf-tables.h"
+#include ".\Inc\leaf-sampling.h"
+#include ".\Inc\leaf-physical.h"
+#include ".\Inc\leaf-electrical.h"
#else
@@ -44,23 +43,21 @@
#include "./Inc/leaf-global.h"
#include "./Inc/leaf-math.h"
#include "./Inc/leaf-mempool.h"
-#include "./Inc/leaf-utilities.h"
+#include "./Inc/leaf-tables.h"
+#include "./Inc/leaf-tables.h"
+#include "./Inc/leaf-oscillators.h"
+#include "./Inc/leaf-filters.h"
#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"
-#include "./Inc/leaf-string.h"
-#include "./Inc/leaf-pitch.h"
-#include "./Inc/leaf-formant.h"
+#include "./Inc/leaf-effects.h"
+#include "./Inc/leaf-envelopes.h"
+#include "./Inc/leaf-dynamics.h"
+#include "./Inc/leaf-analysis.h"
+#include "./Inc/leaf-instruments.h"
#include "./Inc/leaf-midi.h"
-#include "./Inc/leaf-sample.h"
-#include "./Inc/leaf-crusher.h"
-#include "./Inc/leaf-wavefolder.h"
-#include "./Inc/leaf-tables.h"
-#include "./Inc/leaf-WDF.h"
+#include "./Inc/leaf-sampling.h"
+#include "./Inc/leaf-physical.h"
+#include "./Inc/leaf-electrical.h"
#endif
--- a/LEAF_JUCEPlugin/LEAF.jucer
+++ b/LEAF_JUCEPlugin/LEAF.jucer
@@ -26,53 +26,51 @@
<FILE id="IwBoc4" name="leaf-global.h" compile="0" resource="0" file="../LEAF/Inc/leaf-global.h"/>
<FILE id="cmehFw" name="leaf-math.h" compile="0" resource="0" file="../LEAF/Inc/leaf-math.h"/>
<FILE id="XQTGHV" name="leaf-mempool.h" compile="0" resource="0" file="../LEAF/Inc/leaf-mempool.h"/>
- <FILE id="k0yQ8k" name="leaf-808.h" compile="0" resource="0" file="../LEAF/Inc/leaf-808.h"/>
+ <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/>
+ <FILE id="ZBcTKF" name="leaf-oscillators.h" compile="0" resource="0"
+ file="../LEAF/Inc/leaf-oscillators.h"/>
+ <FILE id="EnRmjE" name="leaf-filters.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filters.h"/>
<FILE id="wn8tAr" name="leaf-delay.h" compile="0" resource="0" file="../LEAF/Inc/leaf-delay.h"/>
- <FILE id="EnRmjE" name="leaf-filter.h" compile="0" resource="0" file="../LEAF/Inc/leaf-filter.h"/>
- <FILE id="dWHebV" name="leaf-formant.h" compile="0" resource="0" file="../LEAF/Inc/leaf-formant.h"/>
- <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/>
- <FILE id="ZBcTKF" name="leaf-oscillator.h" compile="0" resource="0"
- file="../LEAF/Inc/leaf-oscillator.h"/>
- <FILE id="LPMRGU" name="leaf-oversampler.h" compile="0" resource="0"
- file="../LEAF/Inc/leaf-oversampler.h"/>
- <FILE id="NekKkK" name="leaf-pitch.h" compile="0" resource="0" file="../LEAF/Inc/leaf-pitch.h"/>
<FILE id="XmL4ZE" name="leaf-reverb.h" compile="0" resource="0" file="../LEAF/Inc/leaf-reverb.h"/>
- <FILE id="KQca5l" name="leaf-string.h" compile="0" resource="0" file="../LEAF/Inc/leaf-string.h"/>
- <FILE id="OS2D83" name="leaf-utilities.h" compile="0" resource="0"
- file="../LEAF/Inc/leaf-utilities.h"/>
- <FILE id="Szb5LP" name="leaf-vocoder.h" compile="0" resource="0" file="../LEAF/Inc/leaf-vocoder.h"/>
- <FILE id="T6KXi7" name="leaf-sample.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sample.h"/>
- <FILE id="bpUZCA" name="leaf-crusher.h" compile="0" resource="0" file="../LEAF/Inc/leaf-crusher.h"/>
- <FILE id="PRkOp2" name="leaf-wavefolder.h" compile="0" resource="0"
- file="../LEAF/Inc/leaf-wavefolder.h"/>
- <FILE id="lJdTFA" name="leaf-WDF.h" compile="0" resource="0" file="../LEAF/Inc/leaf-WDF.h"/>
- <FILE id="JvZKsP" name="leaf-tables.h" compile="0" resource="0" file="../LEAF/Inc/leaf-tables.h"/>
+ <FILE id="dWHebV" name="leaf-distortion.h" compile="0" resource="0"
+ file="../LEAF/Inc/leaf-distortion.h"/>
+ <FILE id="Szb5LP" name="leaf-effects.h" compile="0" resource="0" file="../LEAF/Inc/leaf-effects.h"/>
+ <FILE id="OS2D83" name="leaf-envelopes.h" compile="0" resource="0"
+ file="../LEAF/Inc/leaf-envelopes.h"/>
+ <FILE id="PRkOp2" name="leaf-dynamics.h" compile="0" resource="0" file="../LEAF/Inc/leaf-dynamics.h"/>
+ <FILE id="LPMRGU" name="leaf-analysis.h" compile="0" resource="0" file="../LEAF/Inc/leaf-analysis.h"/>
+ <FILE id="k0yQ8k" name="leaf-instruments.h" compile="0" resource="0"
+ file="../LEAF/Inc/leaf-instruments.h"/>
+ <FILE id="pXe6b5" name="leaf-midi.h" compile="0" resource="0" file="../LEAF/Inc/leaf-midi.h"/>
+ <FILE id="T6KXi7" name="leaf-sampling.h" compile="0" resource="0" file="../LEAF/Inc/leaf-sampling.h"/>
+ <FILE id="KQca5l" name="leaf-physical.h" compile="0" resource="0" file="../LEAF/Inc/leaf-physical.h"/>
+ <FILE id="lJdTFA" name="leaf-electrical.h" compile="0" resource="0"
+ file="../LEAF/Inc/leaf-electrical.h"/>
</GROUP>
<GROUP id="{A3AE8C8C-29BA-ADB3-DD7D-EEDC2F7B58F3}" name="Src">
- <FILE id="HbG7LO" name="leaf-808.c" compile="1" resource="0" file="../LEAF/Src/leaf-808.c"/>
- <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/>
- <FILE id="nh9xAo" name="leaf-filter.c" compile="1" resource="0" file="../LEAF/Src/leaf-filter.c"/>
- <FILE id="DPGZGc" name="leaf-formant.c" compile="1" resource="0" file="../LEAF/Src/leaf-formant.c"/>
+ <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/>
<FILE id="g41P2E" name="leaf-math.c" compile="1" resource="0" file="../LEAF/Src/leaf-math.c"/>
<FILE id="Uc4jO6" name="leaf-mempool.c" compile="1" resource="0" file="../LEAF/Src/leaf-mempool.c"/>
- <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/>
- <FILE id="q5y59A" name="leaf-oscillator.c" compile="1" resource="0"
- file="../LEAF/Src/leaf-oscillator.c"/>
- <FILE id="E8JjWS" name="leaf-oversampler.c" compile="1" resource="0"
- file="../LEAF/Src/leaf-oversampler.c"/>
- <FILE id="eHUTvP" name="leaf-pitch.c" compile="1" resource="0" file="../LEAF/Src/leaf-pitch.c"/>
- <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/>
- <FILE id="dgAVr5" name="leaf-string.c" compile="1" resource="0" file="../LEAF/Src/leaf-string.c"/>
- <FILE id="uKHzgz" name="leaf-utilities.c" compile="1" resource="0"
- file="../LEAF/Src/leaf-utilities.c"/>
- <FILE id="u1aLLR" name="leaf-vocoder.c" compile="1" resource="0" file="../LEAF/Src/leaf-vocoder.c"/>
- <FILE id="nmtoFJ" name="leaf-sample.c" compile="1" resource="0" file="../LEAF/Src/leaf-sample.c"/>
- <FILE id="Oymcac" name="leaf-crusher.c" compile="1" resource="0" file="../LEAF/Src/leaf-crusher.c"/>
- <FILE id="LVoaGm" name="leaf-wavefolder.c" compile="1" resource="0"
- file="../LEAF/Src/leaf-wavefolder.c"/>
- <FILE id="Oh72PT" name="leaf-WDF.c" compile="1" resource="0" file="../LEAF/Src/leaf-WDF.c"/>
<FILE id="TxA1Gg" name="leaf-tables.c" compile="1" resource="0" file="../LEAF/Src/leaf-tables.c"/>
- <FILE id="BFkVGu" name="leaf.c" compile="1" resource="0" file="../LEAF/Src/leaf.c"/>
+ <FILE id="q5y59A" name="leaf-oscillators.c" compile="1" resource="0"
+ file="../LEAF/Src/leaf-oscillators.c"/>
+ <FILE id="nh9xAo" name="leaf-filters.c" compile="1" resource="0" file="../LEAF/Src/leaf-filters.c"/>
+ <FILE id="lLb7eq" name="leaf-delay.c" compile="1" resource="0" file="../LEAF/Src/leaf-delay.c"/>
+ <FILE id="uyYwEd" name="leaf-reverb.c" compile="1" resource="0" file="../LEAF/Src/leaf-reverb.c"/>
+ <FILE id="E8JjWS" name="leaf-distortion.c" compile="1" resource="0"
+ file="../LEAF/Src/leaf-distortion.c"/>
+ <FILE id="u1aLLR" name="leaf-effects.c" compile="1" resource="0" file="../LEAF/Src/leaf-effects.c"/>
+ <FILE id="uKHzgz" name="leaf-envelopes.c" compile="1" resource="0"
+ file="../LEAF/Src/leaf-envelopes.c"/>
+ <FILE id="Oymcac" name="leaf-dynamics.c" compile="1" resource="0" file="../LEAF/Src/leaf-dynamics.c"/>
+ <FILE id="LVoaGm" name="leaf-analysis.c" compile="1" resource="0" file="../LEAF/Src/leaf-analysis.c"/>
+ <FILE id="HbG7LO" name="leaf-instruments.c" compile="1" resource="0"
+ file="../LEAF/Src/leaf-instruments.c"/>
+ <FILE id="LuoIDh" name="leaf-midi.c" compile="1" resource="0" file="../LEAF/Src/leaf-midi.c"/>
+ <FILE id="nmtoFJ" name="leaf-sampling.c" compile="1" resource="0" file="../LEAF/Src/leaf-sampling.c"/>
+ <FILE id="dgAVr5" name="leaf-physical.c" compile="1" resource="0" file="../LEAF/Src/leaf-physical.c"/>
+ <FILE id="Oh72PT" name="leaf-electrical.c" compile="1" resource="0"
+ file="../LEAF/Src/leaf-electrical.c"/>
</GROUP>
<FILE id="dmljDQ" name="leaf.h" compile="0" resource="0" file="../LEAF/leaf.h"/>
</GROUP>
--- a/LEAF_JUCEPlugin/Source/MyTest.cpp
+++ b/LEAF_JUCEPlugin/Source/MyTest.cpp
@@ -37,6 +37,8 @@
tCycle_init(&sine);
tCycle_setFreq(&sine, 200);
tDelay_init(&delay, 44100, 44100);
+ tDelay_free(&delay); //most basic free test
+ tDelay_init(&delay, 44100, 44100);
}
float LEAFTest_tick (float input)
@@ -98,7 +100,7 @@
void leaf_pool_dump(void)
{
float* buff = (float*)leaf_pool_get_pool();
- int siz = leaf_pool_get_size();
+ unsigned long siz = leaf_pool_get_size();
siz /= sizeof(float);
for (int i = 0; i < siz; i++)
{