shithub: leaf

Download patch

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