ref: 32f24276cd8e22709bacbbbefabb659553c6f1e6
parent: 4317a551587f3712a14078d3701400e2855db3b7
author: Matthew Wang <mjw7@princeton.edu>
date: Tue Jan 5 12:23:21 EST 2021
tWavetable; untested
--- a/Examples/basic-oscillators.c
+++ b/Examples/basic-oscillators.c
@@ -12,9 +12,11 @@
void exampleInit()
{
- LEAF_init(44100, 64, mempool, 1000, &exampleRandom);
+ LEAF leaf;
- tCycle_init(&cycle);
+ LEAF_init(&leaf, 44100, 128, mempool, 1000, &exampleRandom);
+
+ tCycle_init(&cycle, &leaf);
tCycle_setFreq(&cycle, 220);
}
--- a/Examples/basic-oscillators.h
+++ b/Examples/basic-oscillators.h
@@ -8,7 +8,7 @@
==============================================================================
*/
-#include "../LEAF/leaf.h"
+#include "../leaf/leaf.h"
char mempool[1000];
tCycle cycle;
--- a/TestPlugin/LEAF.jucer
+++ b/TestPlugin/LEAF.jucer
@@ -15,7 +15,7 @@
jucerFormatVersion="1">
<MAINGROUP id="F7Bywq" name="LEAF">
<GROUP id="{F7096CF4-1A84-4CC8-A236-06FAE894451E}" name="Examples">
- <FILE id="hMMOsl" name="basic-oscillators.c" compile="0" resource="0"
+ <FILE id="hMMOsl" name="basic-oscillators.c" compile="1" resource="0"
file="../Examples/basic-oscillators.c"/>
<FILE id="mVSe2h" name="basic-oscillators.h" compile="0" resource="0"
file="../Examples/basic-oscillators.h"/>
--- a/leaf/Inc/leaf-analysis.h
+++ b/leaf/Inc/leaf-analysis.h
@@ -963,9 +963,9 @@
//==============================================================================
/*!
- @defgroup tdualpitchdetector tPitchDetector
+ @defgroup tdualpitchdetector tDualPitchDetector
@ingroup analysis
- @brief Combined pitch detection algorithm using boht Joel de Guzman's Q Audio DSP Library and Katya Vetters algorithms
+ @brief Combined pitch detection algorithm using both Joel de Guzman's Q Audio DSP Library and Katya Vetters algorithms
@{
@fn void tDualPitchDetector_init (tDualPitchDetector* const detector, float lowestFreq, float highestFreq, float* inBuffer, int bufSize, LEAF* const leaf)
--- a/leaf/Inc/leaf-filters.h
+++ b/leaf/Inc/leaf-filters.h
@@ -777,11 +777,17 @@
@brief Initialize a tButterworth to the default mempool of a LEAF instance.
@param filter A pointer to the tButterworth to initialize.
@param leaf A pointer to the leaf instance.
+ @param order Order of the filter.
+ @param lowCutoff Lower cutoff frequency.
+ @param upperCutoff Upper cutoff frequency.
@fn void tButterworth_initToPool (tButterworth* const, int N, float f1, float f2, tMempool* const)
@brief Initialize a tButterworth to a specified mempool.
@param filter A pointer to the tButterworth to initialize.
@param mempool A pointer to the tMempool to use.
+ @param order Order of the filter.
+ @param lowCutoff Lower cutoff frequency.
+ @param upperCutoff Upper cutoff frequency.
@fn void tButterworth_free (tButterworth* const)
@brief Free a tButterworth from its mempool.
@@ -808,15 +814,13 @@
#define NUM_SVF_BW 16
typedef struct _tButterworth
{
-
tMempool mempool;
float gain;
+ int order;
+ int numSVF;
- int N;
-
- tSVF low[NUM_SVF_BW];
- tSVF high[NUM_SVF_BW];
+ tSVF* svf;
float f1,f2;
} _tButterworth;
--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -31,20 +31,20 @@
/*!
@defgroup ttable tTable
@ingroup oscillators
- @brief General wavetable oscillator.
+ @brief Simple aliasing wavetable oscillator.
@{
@fn void tTable_init (tTable* const osc, float* table, int size, LEAF* const leaf)
@brief Initialize a tTable to the default mempool of a LEAF instance.
@param osc A pointer to the tTable to initialize.
- @param table A pointer to the wave table data.
- @param size The number of samples in the wave table.
+ @param table A pointer to the wavetable data.
+ @param size The number of samples in the wavetable.
@param leaf A pointer to the leaf instance.
@fn void tTable_initToPool (tTable* const osc, float* table, int size, tMempool* const mempool)
@brief Initialize a tTable to a specified mempool.
@param osc A pointer to the tTable to initialize.
- @param table A pointer to the wave table data.
+ @param table A pointer to the wavetable data.
@param size The number of samples in the wave table.
@param mempool A pointer to the tMempool to use.
@@ -66,7 +66,6 @@
typedef struct _tTable
{
-
tMempool mempool;
float* waveTable;
@@ -83,6 +82,70 @@
float tTable_tick(tTable* const osc);
void tTable_setFreq(tTable* const osc, float freq);
+
+ //==============================================================================
+
+ /*!
+ @defgroup twavetable tWavetable
+ @ingroup oscillators
+ @brief Anti-aliased wavetable oscillator.
+ @{
+
+ @fn void tWavetable_init (tTable* const osc, float* table, int size, LEAF* const leaf)
+ @brief Initialize a tWavetable to the default mempool of a LEAF instance.
+ @param osc A pointer to the tWavetable to initialize.
+ @param table A pointer to the wavetable data.
+ @param size The number of samples in the wavetable.
+ @param leaf A pointer to the leaf instance.
+
+ @fn void tWavetable_initToPool (tTable* const osc, float* table, int size, tMempool* const mempool)
+ @brief Initialize a tWavetable to a specified mempool.
+ @param osc A pointer to the tWavetable to initialize.
+ @param table A pointer to the wavetable data.
+ @param size The number of samples in the wave table.
+ @param mempool A pointer to the tMempool to use.
+
+ @fn void tWavetable_free (tTable* const osc)
+ @brief Free a tWavetable from its mempool.
+ @param osc A pointer to the tWavetable to free.
+
+ @fn float tWavetable_tick (tTable* const osc)
+ @brief Tick a tWavetable oscillator.
+ @param osc A pointer to the relevant tWavetable.
+ @return The ticked sample as a float from -1 to 1.
+
+ @fn void tWavetable_setFreq (tTable* const osc, float freq)
+ @brief Set the frequency of a tWavetable oscillator.
+ @param osc A pointer to the relevant tWavetable.
+ @param freq The frequency to set the oscillator to.
+
+ @} */
+
+ typedef struct _tWavetable
+ {
+ tMempool mempool;
+
+ float** tables;
+ int size;
+ int numTables;
+ float baseFreq, invBaseFreq;
+ float inc, freq;
+ float phase;
+
+ int oct;
+ float w;
+
+ tButterworth bl;
+ } _tWavetable;
+
+ typedef _tWavetable* tWavetable;
+
+ void tWavetable_init(tWavetable* const osc, float* table, int size, LEAF* const leaf);
+ void tWavetable_initToPool(tWavetable* const osc, float* table, int size, tMempool* const mempool);
+ void tWavetable_free(tWavetable* const osc);
+
+ float tWavetable_tick(tWavetable* const osc);
+ void tWavetable_setFreq(tWavetable* const osc, float freq);
//==============================================================================
--- a/leaf/Src/leaf-filters.c
+++ b/leaf/Src/leaf-filters.c
@@ -828,7 +828,6 @@
svf->cL = 0.0f;
}
-
else if (type == SVFTypePeak)
{
svf->cH = 1.0f;
@@ -974,12 +973,12 @@
#endif // LEAF_INCLUDE_FILTERTAN_TABLE
/* Highpass */
-void tHighpass_init(tHighpass* const ft, float freq, LEAF* const leaf)
+void tHighpass_init(tHighpass* const ft, float freq, LEAF* const leaf)
{
tHighpass_initToPool(ft, freq, &leaf->mempool);
}
-void tHighpass_initToPool (tHighpass* const ft, float freq, tMempool* const mp)
+void tHighpass_initToPool (tHighpass* const ft, float freq, tMempool* const mp)
{
_tMempool* m = *mp;
_tHighpass* f = *ft = (_tHighpass*) mpool_calloc(sizeof(_tHighpass), m);
@@ -994,7 +993,7 @@
f->frequency = freq;
}
-void tHighpass_free (tHighpass* const ft)
+void tHighpass_free (tHighpass* const ft)
{
_tHighpass* f = *ft;
@@ -1001,7 +1000,7 @@
mpool_free((char*)f, f->mempool);
}
-void tHighpass_setFreq(tHighpass* const ft, float freq)
+void tHighpass_setFreq(tHighpass* const ft, float freq)
{
_tHighpass* f = *ft;
LEAF* leaf = f->mempool->leaf;
@@ -1011,7 +1010,7 @@
}
-float tHighpass_getFreq(tHighpass* const ft)
+float tHighpass_getFreq(tHighpass* const ft)
{
_tHighpass* f = *ft;
return f->frequency;
@@ -1018,7 +1017,7 @@
}
// From JOS DC Blocker
-float tHighpass_tick(tHighpass* const ft, float x)
+float tHighpass_tick(tHighpass* const ft, float x)
{
_tHighpass* f = *ft;
f->ys = x - f->xs + f->R * f->ys;
@@ -1034,12 +1033,12 @@
f->R = (1.0f-((f->frequency * 2.0f * 3.14f) * leaf->invSampleRate));
}
-void tButterworth_init(tButterworth* const ft, int N, float f1, float f2, LEAF* const leaf)
+void tButterworth_init(tButterworth* const ft, int order, float f1, float f2, LEAF* const leaf)
{
- tButterworth_initToPool(ft, N, f1, f2, &leaf->mempool);
+ tButterworth_initToPool(ft, order, f1, f2, &leaf->mempool);
}
-void tButterworth_initToPool (tButterworth* const ft, int N, float f1, float f2, tMempool* const mp)
+void tButterworth_initToPool (tButterworth* const ft, int order, float f1, float f2, tMempool* const mp)
{
_tMempool* m = *mp;
_tButterworth* f = *ft = (_tButterworth*) mpool_alloc(sizeof(_tButterworth), m);
@@ -1049,14 +1048,19 @@
f->f2 = f2;
f->gain = 1.0f;
- f->N = N;
+ f->numSVF = f->order = order;
+ if (f1 >= 0.0f && f2 >= 0.0f) f->numSVF *= 2;
- if (f->N > NUM_SVF_BW) f->N = NUM_SVF_BW;
+ f->svf = (tSVF*) mpool_alloc(sizeof(tSVF) * f->numSVF, m);
- for(int i = 0; i < N/2; ++i)
+ int o = 0;
+ if (f1 >= 0.0f) o = f->order;
+ for(int i = 0; i < f->order; ++i)
{
- tSVF_initToPool(&f->low[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)), mp);
- tSVF_initToPool(&f->high[i], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*N)), mp);
+ if (f1 >= 0.0f)
+ tSVF_initToPool(&f->svf[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*f->order)), mp);
+ if (f2 >= 0.0f)
+ tSVF_initToPool(&f->svf[i+o], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*f->order)), mp);
}
}
@@ -1064,11 +1068,8 @@
{
_tButterworth* f = *ft;
- for(int i = 0; i < f->N/2; ++i)
- {
- tSVF_free(&f->low[i]);
- tSVF_free(&f->high[i]);
- }
+ for(int i = 0; i < f->numSVF; ++i)
+ tSVF_free(&f->svf[i]);
mpool_free((char*)f, f->mempool);
}
@@ -1077,11 +1078,9 @@
{
_tButterworth* f = *ft;
- for(int i = 0; i < ((f->N)/2); ++i)
- {
- samp = tSVF_tick(&f->low[i],samp);
- samp = tSVF_tick(&f->high[i],samp);
- }
+ for(int i = 0; i < f->numSVF; ++i)
+ samp = tSVF_tick(&f->svf[i], samp);
+
return samp;
}
@@ -1089,8 +1088,10 @@
{
_tButterworth* f = *ft;
+ if (f->f1 < 0.0f || f1 < 0.0f) return;
+
f->f1 = f1;
- for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->low[i], f1);
+ for (int i = 0; i < f->order; ++i) tSVF_setFreq(&f->svf[i], f1);
}
void tButterworth_setF2(tButterworth* const ft, float f2)
@@ -1097,21 +1098,26 @@
{
_tButterworth* f = *ft;
+ if (f->f2 < 0.0f || f2 < 0.0f) return;
+
+ int o = 0;
+ if (f->f1 >= 0.0f) o = f->order;
f->f2 = f2;
- for(int i = 0; i < ((f->N)/2); ++i) tSVF_setFreq(&f->high[i], f2);
+ for (int i = 0; i < f->order; ++i) tSVF_setFreq(&f->svf[i+o], f2);
}
void tButterworth_setFreqs(tButterworth* const ft, float f1, float f2)
{
- _tButterworth* f = *ft;
-
- 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);
- }
+// _tButterworth* f = *ft;
+ tButterworth_setF1(ft, f1);
+ tButterworth_setF1(ft, 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);
+// }
}
void tFIR_init(tFIR* const firf, float* coeffs, int numTaps, LEAF* const leaf)
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -86,6 +86,123 @@
c->inc = c->freq * leaf->invSampleRate;
}
+void tWavetable_init(tWavetable* const cy, float* table, int size, LEAF* const leaf)
+{
+ tWavetable_initToPool(cy, table, size, &leaf->mempool);
+}
+
+void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMempool* const mp)
+{
+ _tMempool* m = *mp;
+ _tWavetable* c = *cy = (_tWavetable*)mpool_alloc(sizeof(_tTable), m);
+ c->mempool = m;
+
+ // Determine base frequency
+ c->baseFreq = m->leaf->sampleRate / (float) size;
+ c->invBaseFreq = 1.0f / c->baseFreq;
+
+ // Determine how many tables we need
+ c->numTables = 1;
+ float f = c->baseFreq;
+ while (f < 20000.f)
+ {
+ c->numTables++;
+ f *= 2.0f; // pass this multiplier in to set spacing of tables?
+ }
+
+ c->size = size;
+
+ // Allocate memory for the tables
+ c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, m);
+ for (int t = 0; t < c->numTables; ++t)
+ {
+ c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->size, m);
+ }
+
+ // Copy table
+ for (int i = 0; i < c->size; ++i)
+ {
+ c->tables[0][i] = table[i];
+ }
+
+ // Make bandlimited copies at
+ f = m->leaf->sampleRate * 0.25f; //start at half nyquist
+ for (int t = 1; t < c->numTables; ++t)
+ {
+ tButterworth_initToPool(&c->bl, 4, -1.0f, f, mp);
+ for (int i = 0; i < c->size; ++i)
+ {
+ c->tables[t][i] = tButterworth_tick(&c->bl, table[i]);
+ }
+ tButterworth_free(&c->bl);
+ f *= 0.5f; //half the cutoff for next pass
+ }
+
+ c->inc = 0.0f;
+ c->phase = 0.0f;
+
+ tWavetable_setFreq(cy, 220);
+}
+
+void tWavetable_free(tWavetable* const cy)
+{
+ _tWavetable* c = *cy;
+
+ for (int t = 0; t < c->numTables; ++t)
+ {
+ mpool_free((char*)c->tables[t], c->mempool);
+ }
+ mpool_free((char*)c->tables, c->mempool);
+
+ mpool_free((char*)c, c->mempool);
+}
+
+float tWavetable_tick(tWavetable* const cy)
+{
+ _tWavetable* c = *cy;
+
+ float temp;
+ int idx;
+ float fracPart;
+ float samp0;
+ float samp1;
+
+ // Phasor increment
+ c->phase += c->inc;
+ while (c->phase >= 1.0f) c->phase -= 1.0f;
+ while (c->phase < 0.0f) c->phase += 1.0f;
+
+ // Wavetable synthesis
+ temp = c->size * c->phase;
+ idx = (int)temp;
+ fracPart = temp - (float)idx;
+ samp0 = c->tables[c->oct+1][idx] +
+ (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w;
+ if (++idx >= c->size) idx = 0;
+ samp1 = c->tables[c->oct+1][idx] +
+ (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w;
+
+ return (samp0 + (samp1 - samp0) * fracPart);
+}
+
+void tWavetable_setFreq(tWavetable* const cy, float freq)
+{
+ _tWavetable* c = *cy;
+
+ LEAF* leaf = c->mempool->leaf;
+
+ c->freq = freq;
+
+ c->inc = c->freq * leaf->invSampleRate;
+
+ c->w = c->freq * c->invBaseFreq;
+ for (c->oct = 0; c->w > 2.0f; c->oct++)
+ {
+ c->w = 0.5f * c->w;
+ }
+ c->w = 2.0f - c->w;
+}
+
#if LEAF_INCLUDE_SINE_TABLE
// Cycle
void tCycle_init(tCycle* const cy, LEAF* const leaf)
@@ -338,6 +455,7 @@
c->inc = c->freq * leaf->invSampleRate;
+ // base freq 20
c->w = c->freq * INV_20;
for (c->oct = 0; c->w > 2.0f; c->oct++)
{
@@ -361,7 +479,7 @@
// Wavetable synthesis
out = __leaf_table_sawtooth[c->oct+1][idx] +
- (__leaf_table_sawtooth[c->oct][idx] - __leaf_table_sawtooth[c->oct+1][idx]) * c->w;
+ (__leaf_table_sawtooth[c->oct][idx] - __leaf_table_sawtooth[c->oct+1][idx]) * c->w;
return out;
}
--- a/leaf/leaf-config.h
+++ b/leaf/leaf-config.h
@@ -54,6 +54,10 @@
//! Include tables for minblep insertion, required for all tMB objects.
#define LEAF_INCLUDE_MINBLEP_TABLES 1
+#define LEAF_NO_DENORMAL_CHECK 0
+
+#define LEAF_USE_CMSIS 0
+
//==============================================================================
#endif // LEAF_CONFIG_H_INCLUDED