shithub: leaf

Download patch

ref: 82851635c27305a84ef549e65cf69567b1d15471
parent: 5ff501a334f9e5f998c23b378977fa331f315cc8
author: Matthew Wang <mjw7@princeton.edu>
date: Fri Jul 23 16:44:12 EDT 2021

Wavetable fixes; minor MB osc optimization?

--- a/leaf/Inc/leaf-oscillators.h
+++ b/leaf/Inc/leaf-oscillators.h
@@ -730,8 +730,8 @@
         float    syncdir;
         int      softsync;
         float   _p, _w, _b, _x, _z;
-        float   _f [FILLEN + STEP_DD_PULSE_LENGTH];
         int     _j, _k;
+        float   _f [FILLEN + STEP_DD_PULSE_LENGTH];
         bool    _init;
         float invSampleRate;
     } _tMBPulse;
@@ -803,8 +803,8 @@
         float    syncdir;
         int      softsync;
         float   _p, _w, _b, _z;
-        float   _f [FILLEN + LONGEST_DD_PULSE_LENGTH];
         int     _j, _k;
+        float   _f [FILLEN + LONGEST_DD_PULSE_LENGTH];
         bool    _init;
         float invSampleRate;
     } _tMBTriangle;
@@ -875,8 +875,8 @@
         float    syncdir;
         int      softsync;
         float   _p, _w, _z;
-        float   _f [FILLEN + STEP_DD_PULSE_LENGTH];
         int     _j;
+        float   _f [FILLEN + STEP_DD_PULSE_LENGTH];
         bool    _init;
         float invSampleRate;
     } _tMBSaw;
@@ -982,6 +982,8 @@
      
      @} */
     
+#define LEAF_NUM_WAVETABLE_FILTER_PASSES 5
+    
     typedef struct _tWaveTable
     {
         tMempool mempool;
@@ -1061,7 +1063,7 @@
            int o2;
            float mix;
            uint32_t phase;
-           int32_t inc;
+           uint32_t inc;
            float freq;
            float invSampleRateTimesTwoTo32;
            int oct;
@@ -1203,7 +1205,7 @@
         int o2;
         float mix;
         uint32_t phase;
-        int32_t inc;
+        uint32_t inc;
         float freq;
         float invSampleRateTimesTwoTo32;
         int oct;
--- a/leaf/Src/leaf-math.c
+++ b/leaf/Src/leaf-math.c
@@ -836,7 +836,7 @@
     int i;
     
     r = MINBLEP_PHASES * phase / w;
-    i = floorf(r); //rintf(r - 0.5f); is there a reason to use rintf here
+    i = r; //rintf(r - 0.5f); is there a reason to use rintf here?
     r -= (float)i;
     i &= MINBLEP_PHASE_MASK;  /* extreme modulation can cause i to be out-of-range */
     /* this would be better than the above, but more expensive:
@@ -860,7 +860,7 @@
     int i;
     
     r = MINBLEP_PHASES * phase / w;
-    i = rintf(r - 0.5f);
+    i = r;
     r -= (float)i;
     i &= MINBLEP_PHASE_MASK;  /* extreme modulation can cause i to be out-of-range */
     
--- a/leaf/Src/leaf-oscillators.c
+++ b/leaf/Src/leaf-oscillators.c
@@ -1843,7 +1843,7 @@
         // Do several passes here to prevent errors at the beginning of the waveform
         // Not sure how many passes to do, seem to need more as the filter cutoff goes down
         // 12 might be excessive but seems to work for now.
-        for (int p = 0; p < 4; ++p)
+        for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
         {
             for (int i = 0; i < c->size; ++i)
             {
@@ -1859,7 +1859,8 @@
 {
     _tWaveTable* c = *cy;
     
-    for (int t = 0; t < c->numTables; ++t)
+    mpool_free((char*)c->baseTable, c->mempool);
+    for (int t = 1; t < c->numTables; ++t)
     {
         mpool_free((char*)c->tables[t], c->mempool);
     }
@@ -1913,7 +1914,7 @@
         // Do several passes here to prevent errors at the beginning of the waveform
         // Not sure how many passes to do, seem to need more as the filter cutoff goes down
         // 12 might be excessive but seems to work for now.
-        for (int p = 0; p < 12; ++p)
+        for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
         {
             for (int i = 0; i < c->size; ++i)
             {
@@ -2090,7 +2091,6 @@
     c->baseFreq = c->sampleRate / (float) c->size;
     c->invBaseFreq = 1.0f / c->baseFreq;
     c->numSubTables = c->tables[0]->numTables;
-
 }
 
 /*//// eventually gotta finish this so you can X/Y control the indices and fade between non-adjacent tables
@@ -2112,12 +2112,15 @@
 void tWaveOsc_setSampleRate(tWaveOsc* const cy, float sr)
 {
     _tWaveOsc* c = *cy;
-    //TODO: need to fix this -JS
-    for (int i = 0; i < c->numTables; ++i)
-    {
-        tWaveTable_setSampleRate(&c->tables[i], sr);
-        //tWaveSubOscS_setSampleRate(&c->oscs[i], sr);
-    }
+    
+    c->sampleRate = sr;
+    // Determine base frequency
+    c->baseFreq = c->sampleRate / (float) c->size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    c->numSubTables = c->tables[0]->numTables;
+    c->invSampleRateTimesTwoTo32 = 1.f/c->sampleRate * TWO_TO_32;
+    
+    tWaveOsc_setFreq(cy, c->freq);
 }
 
 //=======================================================================================
@@ -2184,7 +2187,7 @@
         if (c->sizes[t] < c->sizes[t-1])
         {
             // Similar to tWaveTable, doing multiple passes here helps, but not sure what number is optimal
-            for (int p = 0; p < 12; ++p)
+            for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
             {
                 for (int i = 0; i < c->sizes[t]; ++i)
                 {
@@ -2197,7 +2200,7 @@
         else
         {
             tButterworth_setF2(&c->bl, f);
-            for (int p = 0; p < 12; ++p)
+            for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
             {
                 for (int i = 0; i < c->sizes[t]; ++i)
                 {
@@ -2215,7 +2218,8 @@
 {
     _tWaveTableS* c = *cy;
     
-    for (int t = 0; t < c->numTables; ++t)
+    mpool_free((char*)c->baseTable, c->mempool);
+    for (int t = 1; t < c->numTables; ++t)
     {
         mpool_free((char*)c->tables[t], c->mempool);
     }
@@ -2257,33 +2261,50 @@
     // Allocate memory for the tables
     c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
     c->sizes = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
-    c->tables[0] = c->baseTable;
+    c->sizeMasks = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
     c->sizes[0] = size;
     c->sizeMasks[0] = (c->sizes[0] - 1);
+    c->tables[0] = c->baseTable;
     for (int t = 1; t < c->numTables; ++t)
     {
-        c->sizes[t] = c->sizes[t-1] / 2;
+        c->sizes[t] = c->sizes[t-1] / 2 > 128 ? c->sizes[t-1] / 2 : 128;
         c->sizeMasks[t] = (c->sizes[t] - 1);
         c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->sizes[t], c->mempool);
     }
     
     // Make bandlimited copies
+    f = c->sampleRate * 0.25; //start at half nyquist
     // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
-    tButterworth_initToPool(&c->bl, 8, -1.0f, c->sampleRate * 0.25f, &c->mempool);
-    tButterworth_setSampleRate(&c->bl, c->sampleRate);
+    tButterworth_initToPool(&c->bl, 8, -1.0f, f, &c->mempool);
     tOversampler_initToPool(&c->ds, 2, 1, &c->mempool);
     for (int t = 1; t < c->numTables; ++t)
     {
-        // Similar to tWaveTable, doing multiple passes here helps, but not sure what number is optimal
-        for (int p = 0; p < 12; ++p)
+        // Size is going down; we need to downsample
+        if (c->sizes[t] < c->sizes[t-1])
         {
-            for (int i = 0; i < c->sizes[t]; ++i)
+            // Similar to tWaveTable, doing multiple passes here helps, but not sure what number is optimal
+            for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
             {
-                c->dsBuffer[0] = tButterworth_tick(&c->bl, c->tables[t-1][i*2]);
-                c->dsBuffer[1] = tButterworth_tick(&c->bl, c->tables[t-1][(i*2)+1]);
-                c->tables[t][i] = tOversampler_downsample(&c->ds, c->dsBuffer);
+                for (int i = 0; i < c->sizes[t]; ++i)
+                {
+                    c->dsBuffer[0] = tButterworth_tick(&c->bl, c->tables[t-1][i*2]);
+                    c->dsBuffer[1] = tButterworth_tick(&c->bl, c->tables[t-1][(i*2)+1]);
+                    c->tables[t][i] = tOversampler_downsample(&c->ds, c->dsBuffer);
+                }
             }
         }
+        else
+        {
+            tButterworth_setF2(&c->bl, f);
+            for (int p = 0; p < LEAF_NUM_WAVETABLE_FILTER_PASSES; ++p)
+            {
+                for (int i = 0; i < c->sizes[t]; ++i)
+                {
+                    c->tables[t][i] = tButterworth_tick(&c->bl, c->tables[t-1][i]);
+                }
+            }
+            f *= 0.5f; //halve the cutoff for next pass
+        }
     }
     tOversampler_free(&c->ds);
     tButterworth_free(&c->bl);
@@ -2305,7 +2326,7 @@
     c->mempool = m;
 
     LEAF* leaf = c->mempool->leaf;
-    c->tables =  tables;
+    c->tables = tables;
     c->numTables = numTables;
     
     c->index = 0.0f;
@@ -2352,12 +2373,13 @@
     float samp1;
 
     int oct = c->oct;
-
-    int* sizeMasks = c->tables[c->o1]->sizeMasks;
+    
     float** tables = c->tables[c->o1]->tables;
+    int* sizes = c->tables[c->o1]->sizes;
+    int* sizeMasks = c->tables[c->o1]->sizeMasks;
 
     // Wavetable synthesis
-    temp = sizeMasks[oct] * floatPhase;
+    temp = sizes[oct] * floatPhase;
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[oct][idx];
@@ -2366,7 +2388,7 @@
 
     float oct0 = (samp0 + (samp1 - samp0) * frac);
 
-    temp = sizeMasks[oct+1] * floatPhase;
+    temp = sizes[oct+1] * floatPhase;
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[oct+1][idx];
@@ -2377,11 +2399,12 @@
 
     s1 = oct0 + (oct1 - oct0) * c->w;
 
-    sizeMasks = c->tables[c->o2]->sizeMasks;
     tables = c->tables[c->o2]->tables;
+    sizes = c->tables[c->o2]->sizes;
+    sizeMasks = c->tables[c->o2]->sizeMasks;
 
     // Wavetable synthesis
-    temp = sizeMasks[oct] * floatPhase;
+    temp = sizes[oct] * floatPhase;
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[oct][idx];
@@ -2390,7 +2413,7 @@
 
     oct0 = (samp0 + (samp1 - samp0) * frac);
 
-    temp = sizeMasks[oct+1] * floatPhase;
+    temp = sizes[oct+1] * floatPhase;
     idx = (int)temp;
     frac = temp - (float)idx;
     samp0 = tables[oct+1][idx];
@@ -2462,11 +2485,17 @@
 void tWaveOscS_setSampleRate(tWaveOscS* const cy, float sr)
 {
     _tWaveOscS* c = *cy;
-    //TODO: need to fix this -JS
-    for (int i = 0; i < c->numTables; ++i)
-    {
-        tWaveTableS_setSampleRate(&c->tables[i], sr);
-    }
+    
+    if (c->sampleRate == sr) return;
+    
+    c->sampleRate = sr;
+    // Determine base frequency
+    c->baseFreq = c->sampleRate / (float) c->size;
+    c->invBaseFreq = 1.0f / c->baseFreq;
+    c->numSubTables = c->tables[0]->numTables;
+    c->invSampleRateTimesTwoTo32 = (1.f/c->sampleRate) * TWO_TO_32;
+    
+    tWaveOscS_setFreq(cy, c->freq);
 }
 //
 //void tWaveOscS_setIndexTable(tWaveOscS* const cy, int i, float* table, int size)