History

improved wavetable oscs; added tCompactWavetable

Matthew Wang committed 5 years ago

Commit 0400bc11 parent 32f24278 files · +418 −104Browse files

Unified · Split

8 files
  1. TestPlugin/LEAF.jucer +6 −6
  2. TestPlugin/Source/MyTest.cpp +15 −12
  3. leaf/Inc/leaf-global.h +6 −0
  4. leaf/Inc/leaf-math.h +1 −0
  5. leaf/Inc/leaf-oscillators.h +79 −8
  6. leaf/Src/leaf-filters.c +3 −2
  7. leaf/Src/leaf-oscillators.c +307 −75
  8. leaf/leaf-config.h +1 −1
TestPlugin/LEAF.jucer+6−6
@@ -109,8 +109,8 @@ · 108 unmodified lines
109109 <EXPORTFORMATS>
110110 <XCODE_MAC targetFolder="Builds/MacOSX" microphonePermissionNeeded="1">
111111 <CONFIGURATIONS>
112− <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="OOPS" enablePluginBinaryCopyStep="1"/>
113− <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="OOPS"
112+ <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="LEAF" enablePluginBinaryCopyStep="1"/>
113+ <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="LEAF"
114114 enablePluginBinaryCopyStep="1"/>
115115 </CONFIGURATIONS>
116116 <MODULEPATHS>
@@ -136,8 +136,8 @@ · 19 unmodified lines
136136 iosBackgroundAudio="1" iPadScreenOrientation="UIInterfaceOrientationPortrait,UIInterfaceOrientationLandscapeLeft,UIInterfaceOrientationLandscapeRight"
137137 iosDeviceFamily="1,2">
138138 <CONFIGURATIONS>
139− <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="OOPS" enablePluginBinaryCopyStep="1"/>
140− <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="OOPS"
139+ <CONFIGURATION name="Debug" isDebug="1" optimisation="1" targetName="LEAF" enablePluginBinaryCopyStep="1"/>
140+ <CONFIGURATION name="Release" isDebug="0" optimisation="3" targetName="LEAF"
141141 enablePluginBinaryCopyStep="1"/>
142142 </CONFIGURATIONS>
143143 <MODULEPATHS>
@@ -161,10 +161,10 @@ · 17 unmodified lines
161161 <VS2017 targetFolder="Builds/VisualStudio2017">
162162 <CONFIGURATIONS>
163163 <CONFIGURATION name="Debug" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
164− isDebug="1" optimisation="1" targetName="OOPS" debugInformationFormat="ProgramDatabase"
164+ isDebug="1" optimisation="1" targetName="LEAF" debugInformationFormat="ProgramDatabase"
165165 enablePluginBinaryCopyStep="0"/>
166166 <CONFIGURATION name="Release" winWarningLevel="4" generateManifest="1" winArchitecture="x64"
167− isDebug="0" optimisation="3" targetName="OOPS" debugInformationFormat="ProgramDatabase"
167+ isDebug="0" optimisation="3" targetName="LEAF" debugInformationFormat="ProgramDatabase"
168168 enablePluginBinaryCopyStep="0" linkTimeOptimisation="1"/>
169169 </CONFIGURATIONS>
170170 <MODULEPATHS>
TestPlugin/Source/MyTest.cpp+15−12
@@ -9,7 +9,6 @@ · 8 unmodified lines
99 #include "LEAFTest.h"
1010 #include "MyTest.h"
1111
12−
1312 static void leaf_pool_report(void);
1413 static void leaf_pool_dump(void);
1514 static void run_pool_test(void);
@@ -18,11 +17,6 @@ tMBSaw bsaw; · 2 unmodified lines
1817 tMBTriangle btri;
1918 tMBPulse bpulse;
2019
21−tRetune retune;
22−tSimpleRetune sretune;
23−
24−tCompressor compressor;
25−
2620 tSVF lp, hp;
2721
2822 tPeriodDetection pd;
@@ -32,6 +26,12 @@ tEnvelopeFollower ef; · 3 unmodified lines
3226
3327 tTriangle tri;
3428
29+tNoise noise;
30+tButterworth bw;
31+
32+tWavetable wt;
33+tCompactWavetable cwt;
34+
3535 tBuffer samp;
3636 tMBSampler sampler;
3737
@@ -55,9 +55,8 @@ void LEAFTest_init (float sampleRate, int blockSize) · 17 unmodified lines
5555 {
5656 LEAF_init(&leaf, sampleRate, blockSize, memory, MSIZE, &getRandomFloat);
5757
58− tRetune_init(&retune, 1, mtof(48), mtof(72), 2048, &leaf);
59− tSimpleRetune_init(&sretune, 1, mtof(48), mtof(72), 2048, &leaf);
60− tSimpleRetune_setMode(&sretune, 1);
58+ tWavetable_init(&wt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
59+ tCompactWavetable_init(&cwt, __leaf_table_sawtooth[0], 2048, 10000.f, &leaf);
6160 }
6261
6362 inline double getSawFall(double angle) {
@@ -72,7 +71,9 @@ inline double getSawFall(double angle) { · 8 unmodified lines
7271 float LEAFTest_tick (float input)
7372 {
7473 // return tRetune_tick(&retune, input)[0];
75− return tSimpleRetune_tick(&sretune, input);
74+// return tSimpleRetune_tick(&sretune, input);
75+ return tWavetable_tick(&wt);
76+ return tCompactWavetable_tick(&cwt);
7677 }
7778
7879 int firstFrame = 1;
@@ -80,8 +81,10 @@ bool lastState = false, lastPlayState = false; · 1 unmodified line
8081 void LEAFTest_block (void)
8182 {
8283 float val = getSliderValue("slider1");
83− tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
84− tSimpleRetune_tuneVoice(&sretune, 0, 300);
84+ tWavetable_setFreq(&wt, val * 40000.);
85+ tCompactWavetable_setFreq(&cwt, val * 10000.);
86+// tRetune_tuneVoice(&retune, 0, val * 3.0f + 0.5f);
87+// tSimpleRetune_tuneVoice(&sretune, 0, 300);
8588
8689 val = getSliderValue("slider2");
8790 // tRetune_setPitchFactor(&retune, val * 3.0f + 0.5f, 1);
leaf/Inc/leaf-global.h+6−0
@@ -17,6 +17,12 @@ extern "C" { · 16 unmodified lines
1717
1818 #include "leaf-mempool.h"
1919
20+#if _WIN32 || _WIN64
21+#include "..\leaf-config.h"
22+#else
23+#include "../leaf-config.h"
24+#endif
25+
2026 /*!
2127 * @ingroup leaf
2228 * @brief Struct for an instance of LEAF.
leaf/Inc/leaf-math.h+1−0
@@ -35,6 +35,7 @@ extern "C" { · 34 unmodified lines
3535 };
3636
3737 #define SQRT8 2.82842712475f
38+#define LEAF_SQRT2 1.41421356237f
3839 #define WSCALE 1.30612244898f
3940 #define PI (3.14159265358979f)
4041 #define TWO_PI (6.28318530717958f)
leaf/Inc/leaf-oscillators.h+79−8
@@ -17,7 +17,7 @@ extern "C" { · 16 unmodified lines
1717 #include "leaf-mempool.h"
1818 #include "leaf-tables.h"
1919 #include "leaf-filters.h"
20−
20+#include "leaf-distortion.h"
2121
2222 /*!
2323 Header.
@@ -91,30 +91,30 @@ extern "C" { · 67 unmodified lines
9191 @brief Anti-aliased wavetable oscillator.
9292 @{
9393
94− @fn void tWavetable_init (tTable* const osc, float* table, int size, LEAF* const leaf)
94+ @fn void tWavetable_init (tWavetable* const osc, float* table, int size, LEAF* const leaf)
9595 @brief Initialize a tWavetable to the default mempool of a LEAF instance.
9696 @param osc A pointer to the tWavetable to initialize.
9797 @param table A pointer to the wavetable data.
9898 @param size The number of samples in the wavetable.
9999 @param leaf A pointer to the leaf instance.
100100
101− @fn void tWavetable_initToPool (tTable* const osc, float* table, int size, tMempool* const mempool)
101+ @fn void tWavetable_initToPool (tWavetable* const osc, float* table, int size, tMempool* const mempool)
102102 @brief Initialize a tWavetable to a specified mempool.
103103 @param osc A pointer to the tWavetable to initialize.
104104 @param table A pointer to the wavetable data.
105105 @param size The number of samples in the wave table.
106106 @param mempool A pointer to the tMempool to use.
107107
108− @fn void tWavetable_free (tTable* const osc)
108+ @fn void tWavetable_free (tWavetable* const osc)
109109 @brief Free a tWavetable from its mempool.
110110 @param osc A pointer to the tWavetable to free.
111111
112− @fn float tWavetable_tick (tTable* const osc)
112+ @fn float tWavetable_tick (tWavetable* const osc)
113113 @brief Tick a tWavetable oscillator.
114114 @param osc A pointer to the relevant tWavetable.
115115 @return The ticked sample as a float from -1 to 1.
116116
117− @fn void tWavetable_setFreq (tTable* const osc, float freq)
117+ @fn void tWavetable_setFreq (tWavetable* const osc, float freq)
118118 @brief Set the frequency of a tWavetable oscillator.
119119 @param osc A pointer to the relevant tWavetable.
120120 @param freq The frequency to set the oscillator to.
@@ -134,18 +134,89 @@ extern "C" { · 13 unmodified lines
134134
135135 int oct;
136136 float w;
137+ float aa;
137138
138139 tButterworth bl;
139140 } _tWavetable;
140141
141142 typedef _tWavetable* tWavetable;
142143
143− void tWavetable_init(tWavetable* const osc, float* table, int size, LEAF* const leaf);
144− void tWavetable_initToPool(tWavetable* const osc, float* table, int size, tMempool* const mempool);
144+ void tWavetable_init(tWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
145+ void tWavetable_initToPool(tWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
145146 void tWavetable_free(tWavetable* const osc);
146147
147148 float tWavetable_tick(tWavetable* const osc);
148149 void tWavetable_setFreq(tWavetable* const osc, float freq);
150+ void tWavetable_setAntiAliasing(tWavetable* const osc, float aa);
151+
152+ //==============================================================================
153+
154+ /*!
155+ @defgroup tcompactwavetable tCompactWavetable
156+ @ingroup oscillators
157+ @brief A more space-efficient anti-aliased wavetable oscillator than tWavetable but with slightly worse fidelity.
158+ @{
159+
160+ @fn void tCompactWavetable_init (tCompactWavetable* const osc, float* table, int size, LEAF* const leaf)
161+ @brief Initialize a tCompactWavetable to the default mempool of a LEAF instance.
162+ @param osc A pointer to the tCompactWavetable to initialize.
163+ @param table A pointer to the wavetable data.
164+ @param size The number of samples in the wavetable.
165+ @param leaf A pointer to the leaf instance.
166+
167+ @fn void tCompactWavetable_initToPool (tCompactWavetable* const osc, float* table, int size, tMempool* const mempool)
168+ @brief Initialize a tCompactWavetable to a specified mempool.
169+ @param osc A pointer to the tCompactWavetable to initialize.
170+ @param table A pointer to the wavetable data.
171+ @param size The number of samples in the wave table.
172+ @param mempool A pointer to the tMempool to use.
173+
174+ @fn void tCompactWavetable_free (tCompactWavetable* const osc)
175+ @brief Free a tCompactWavetable from its mempool.
176+ @param osc A pointer to the tCompactWavetable to free.
177+
178+ @fn float tCompactWavetable_tick (tCompactWavetable* const osc)
179+ @brief Tick a tCompactWavetable oscillator.
180+ @param osc A pointer to the relevant tCompactWavetable.
181+ @return The ticked sample as a float from -1 to 1.
182+
183+ @fn void tCompactWavetable_setFreq (tCompactWavetable* const osc, float freq)
184+ @brief Set the frequency of a tCompactWavetable oscillator.
185+ @param osc A pointer to the relevant tCompactWavetable.
186+ @param freq The frequency to set the oscillator to.
187+
188+ @} */
189+
190+ typedef struct _tCompactWavetable
191+ {
192+ tMempool mempool;
193+
194+ float** tables;
195+ int numTables;
196+ int* sizes;
197+ float baseFreq, invBaseFreq;
198+ float inc, freq;
199+ float phase;
200+
201+ int oct;
202+ float w;
203+ float aa;
204+
205+ tButterworth bl;
206+
207+ float dsBuffer[2];
208+ tOversampler ds;
209+ } _tCompactWavetable;
210+
211+ typedef _tCompactWavetable* tCompactWavetable;
212+
213+ void tCompactWavetable_init(tCompactWavetable* const osc, const float* table, int size, float maxFreq, LEAF* const leaf);
214+ void tCompactWavetable_initToPool(tCompactWavetable* const osc, const float* table, int size, float maxFreq, tMempool* const mempool);
215+ void tCompactWavetable_free(tCompactWavetable* const osc);
216+
217+ float tCompactWavetable_tick(tCompactWavetable* const osc);
218+ void tCompactWavetable_setFreq(tCompactWavetable* const osc, float freq);
219+ void tCompactWavetable_setAntiAliasing(tCompactWavetable* const osc, float aa);
149220
150221 //==============================================================================
151222
leaf/Src/leaf-filters.c+3−2
@@ -1058,9 +1058,9 @@ void tButterworth_initToPool (tButterworth* const ft, int order, float f1 · 1057 unmodified lines
10581058 for(int i = 0; i < f->order; ++i)
10591059 {
10601060 if (f1 >= 0.0f)
1061− tSVF_initToPool(&f->svf[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*f->order)), mp);
1061+ tSVF_initToPool(&f->svf[i], SVFTypeHighpass, f1, 0.5f/cosf((1.0f+2.0f*i)*PI/(4*f->order)), mp);
10621062 if (f2 >= 0.0f)
1063− tSVF_initToPool(&f->svf[i+o], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(2*f->order)), mp);
1063+ tSVF_initToPool(&f->svf[i+o], SVFTypeLowpass, f2, 0.5f/cosf((1.0f+2.0f*i)*PI/(4*f->order)), mp);
10641064 }
10651065 }
10661066
@@ -1071,6 +1071,7 @@ void tButterworth_free (tButterworth* const ft) · 4 unmodified lines
10711071 for(int i = 0; i < f->numSVF; ++i)
10721072 tSVF_free(&f->svf[i]);
10731073
1074+ mpool_free((char*)f->svf, f->mempool);
10741075 mpool_free((char*)f, f->mempool);
10751076 }
10761077
leaf/Src/leaf-oscillators.c+307−75
@@ -86,15 +86,15 @@ void tTableSampleRateChanged(tTable* const cy) · 85 unmodified lines
8686 c->inc = c->freq * leaf->invSampleRate;
8787 }
8888
89−void tWavetable_init(tWavetable* const cy, float* table, int size, LEAF* const leaf)
89+void tWavetable_init(tWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
9090 {
91− tWavetable_initToPool(cy, table, size, &leaf->mempool);
91+ tWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
9292 }
9393
94−void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMempool* const mp)
94+void tWavetable_initToPool(tWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
9595 {
9696 _tMempool* m = *mp;
97− _tWavetable* c = *cy = (_tWavetable*)mpool_alloc(sizeof(_tTable), m);
97+ _tWavetable* c = *cy = (_tWavetable*) mpool_alloc(sizeof(_tWavetable), m);
9898 c->mempool = m;
9999
100100 // Determine base frequency
@@ -102,12 +102,13 @@ void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMem · 1 unmodified line
102102 c->invBaseFreq = 1.0f / c->baseFreq;
103103
104104 // Determine how many tables we need
105− c->numTables = 1;
105+ // Assume we need at least 2, the fundamental + one to account for setting extra anti aliasing
106+ c->numTables = 2;
106107 float f = c->baseFreq;
107− while (f < 20000.f)
108+ while (f < maxFreq)
108109 {
109110 c->numTables++;
110− f *= 2.0f; // pass this multiplier in to set spacing of tables?
111+ f *= 2.0f; // pass this multiplier in to set spacing of tables? would need to change setFreq too
111112 }
112113
113114 c->size = size;
@@ -125,26 +126,36 @@ void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMem · 11 unmodified lines
125126 c->tables[0][i] = table[i];
126127 }
127128
128− // Make bandlimited copies at
129− f = m->leaf->sampleRate * 0.25f; //start at half nyquist
129+ // Make bandlimited copies
130+ f = m->leaf->sampleRate * 0.25; //start at half nyquist
131+ // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
132+ tButterworth_initToPool(&c->bl, 8, -1.0f, f, mp);
130133 for (int t = 1; t < c->numTables; ++t)
131134 {
132− tButterworth_initToPool(&c->bl, 4, -1.0f, f, mp);
133− for (int i = 0; i < c->size; ++i)
135+ tButterworth_setF2(&c->bl, f);
136+ // Do several passes here to prevent errors at the beginning of the waveform
137+ // Not sure how many passes to do, seem to need more as the filter cutoff goes down
138+ // 12 might be excessive but seems to work for now.
139+ for (int p = 0; p < 12; ++p)
134140 {
135− c->tables[t][i] = tButterworth_tick(&c->bl, table[i]);
141+ for (int i = 0; i < c->size; ++i)
142+ {
143+ c->tables[t][i] = tButterworth_tick(&c->bl, c->tables[t-1][i]);
144+ }
136145 }
137− tButterworth_free(&c->bl);
138− f *= 0.5f; //half the cutoff for next pass
146+ f *= 0.5f; //halve the cutoff for next pass
139147 }
148+ tButterworth_free(&c->bl);
149+
140150
141151 c->inc = 0.0f;
142152 c->phase = 0.0f;
153+ c->aa = 0.5f;
143154
144155 tWavetable_setFreq(cy, 220);
145156 }
146157
147−void tWavetable_free(tWavetable* const cy)
158+void tWavetable_free(tWavetable* const cy)
148159 {
149160 _tWavetable* c = *cy;
150161
@@ -153,17 +164,16 @@ void tWavetable_free(tWavetable* const cy) · 2 unmodified lines
153164 mpool_free((char*)c->tables[t], c->mempool);
154165 }
155166 mpool_free((char*)c->tables, c->mempool);
156−
157167 mpool_free((char*)c, c->mempool);
158168 }
159169
160−float tWavetable_tick(tWavetable* const cy)
170+float tWavetable_tick(tWavetable* const cy)
161171 {
162172 _tWavetable* c = *cy;
163173
164174 float temp;
165175 int idx;
166− float fracPart;
176+ float frac;
167177 float samp0;
168178 float samp1;
169179
@@ -174,18 +184,26 @@ float tWavetable_tick(tWavetable* const cy) · 4 unmodified lines
174184
175185 // Wavetable synthesis
176186 temp = c->size * c->phase;
187+
177188 idx = (int)temp;
178− fracPart = temp - (float)idx;
179− samp0 = c->tables[c->oct+1][idx] +
180− (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w;
189+ frac = temp - (float)idx;
190+ samp0 = c->tables[c->oct][idx];
181191 if (++idx >= c->size) idx = 0;
182− samp1 = c->tables[c->oct+1][idx] +
183− (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w;
192+ samp1 = c->tables[c->oct][idx];
184193
185− return (samp0 + (samp1 - samp0) * fracPart);
194+ float oct0 = (samp0 + (samp1 - samp0) * frac);
195+
196+ idx = (int)temp;
197+ samp0 = c->tables[c->oct+1][idx];
198+ if (++idx >= c->size) idx = 0;
199+ samp1 = c->tables[c->oct+1][idx];
200+
201+ float oct1 = (samp0 + (samp1 - samp0) * frac);
202+
203+ return oct0 + (oct1 - oct0) * c->w;
186204 }
187205
188−void tWavetable_setFreq(tWavetable* const cy, float freq)
206+void tWavetable_setFreq(tWavetable* const cy, float freq)
189207 {
190208 _tWavetable* c = *cy;
191209
@@ -195,12 +213,173 @@ void tWavetable_setFreq(tWavetable* const cy, float freq) · 3 unmodified lines
195213
196214 c->inc = c->freq * leaf->invSampleRate;
197215
198− c->w = c->freq * c->invBaseFreq;
199− for (c->oct = 0; c->w > 2.0f; c->oct++)
216+ // abs for negative frequencies
217+ c->w = fabsf(c->freq * c->invBaseFreq);
218+
219+ // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
220+ c->w = log2f_approx(c->w) + c->aa; // adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
221+ if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
222+ c->oct = (int)c->w;
223+ c->w -= c->oct;
224+
225+ // When out of range of our tables, this will prevent a crash.
226+ // Also causes a blip but fine since we're above maxFreq at this point.
227+ if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
228+}
229+
230+void tWavetable_setAntiAliasing(tWavetable* const cy, float aa)
231+{
232+ _tWavetable* c = *cy;
233+
234+ c->aa = aa;
235+ tWavetable_setFreq(cy, c->freq);
236+}
237+
238+void tCompactWavetable_init(tCompactWavetable* const cy, const float* table, int size, float maxFreq, LEAF* const leaf)
239+{
240+ tCompactWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool);
241+}
242+
243+void tCompactWavetable_initToPool(tCompactWavetable* const cy, const float* table, int size, float maxFreq, tMempool* const mp)
244+{
245+ _tMempool* m = *mp;
246+ _tCompactWavetable* c = *cy = (_tCompactWavetable*) mpool_alloc(sizeof(_tCompactWavetable), m);
247+ c->mempool = m;
248+
249+ // Determine base frequency
250+ c->baseFreq = m->leaf->sampleRate / (float) size;
251+ c->invBaseFreq = 1.0f / c->baseFreq;
252+
253+ // Determine how many tables we need
254+ c->numTables = 2;
255+ float f = c->baseFreq;
256+ while (f < maxFreq)
200257 {
201− c->w = 0.5f * c->w;
258+ c->numTables++;
259+ f *= 2.0f; // pass this multiplier in to set spacing of tables?
202260 }
203− c->w = 2.0f - c->w;
261+
262+ // Allocate memory for the tables
263+ c->tables = (float**) mpool_alloc(sizeof(float*) * c->numTables, c->mempool);
264+ c->sizes = (int*) mpool_alloc(sizeof(int) * c->numTables, c->mempool);
265+ int n = size;
266+ for (int t = 0; t < c->numTables; ++t)
267+ {
268+ c->sizes[t] = n;
269+ c->tables[t] = (float*) mpool_alloc(sizeof(float) * c->sizes[t], m);
270+ n = c->sizes[t] / 2;
271+ }
272+
273+ // Copy table
274+ for (int i = 0; i < c->sizes[0]; ++i)
275+ {
276+ c->tables[0][i] = table[i];
277+ }
278+
279+ // Make bandlimited copies
280+ // Not worth going over order 8 I think, and even 8 is only marginally better than 4.
281+ tButterworth_initToPool(&c->bl, 8, -1.0f, m->leaf->sampleRate * 0.25f, mp);
282+ tOversampler_initToPool(&c->ds, 2, 1, mp);
283+ for (int t = 1; t < c->numTables; ++t)
284+ {
285+ // Similar to tWavetable, doing multiple passes here helps, but not sure what number is optimal
286+ for (int p = 0; p < 12; ++p)
287+ {
288+ for (int i = 0; i < c->sizes[t]; ++i)
289+ {
290+ c->dsBuffer[0] = tButterworth_tick(&c->bl, c->tables[t-1][i*2]);
291+ c->dsBuffer[1] = tButterworth_tick(&c->bl, c->tables[t-1][(i*2)+1]);
292+ c->tables[t][i] = tOversampler_downsample(&c->ds, c->dsBuffer);
293+ }
294+ }
295+ }
296+ tOversampler_free(&c->ds);
297+ tButterworth_free(&c->bl);
298+
299+ c->inc = 0.0f;
300+ c->phase = 0.0f;
301+ c->aa = 0.5f;
302+
303+ tCompactWavetable_setFreq(cy, 220);
304+}
305+
306+void tCompactWavetable_free(tCompactWavetable* const cy)
307+{
308+ _tCompactWavetable* c = *cy;
309+
310+ for (int t = 0; t < c->numTables; ++t)
311+ {
312+ mpool_free((char*)c->tables[t], c->mempool);
313+ }
314+ mpool_free((char*)c->tables, c->mempool);
315+ mpool_free((char*)c->sizes, c->mempool);
316+ mpool_free((char*)c, c->mempool);
317+}
318+
319+float tCompactWavetable_tick(tCompactWavetable* const cy)
320+{
321+ _tCompactWavetable* c = *cy;
322+
323+ float temp;
324+ int idx;
325+ float frac;
326+ float samp0;
327+ float samp1;
328+
329+ // Phasor increment
330+ c->phase += c->inc;
331+ while (c->phase >= 1.0f) c->phase -= 1.0f;
332+ while (c->phase < 0.0f) c->phase += 1.0f;
333+
334+ // Wavetable synthesis
335+ temp = c->sizes[c->oct] * c->phase;
336+ idx = (int)temp;
337+ frac = temp - (float)idx;
338+ samp0 = c->tables[c->oct][idx];
339+ if (++idx >= c->sizes[c->oct]) idx = 0;
340+ samp1 = c->tables[c->oct][idx];
341+
342+ float oct0 = (samp0 + (samp1 - samp0) * frac);
343+
344+ temp = c->sizes[c->oct+1] * c->phase;
345+ idx = (int)temp;
346+ frac = temp - (float)idx;
347+ samp0 = c->tables[c->oct+1][idx];
348+ if (++idx >= c->sizes[c->oct+1]) idx = 0;
349+ samp1 = c->tables[c->oct+1][idx];
350+
351+ float oct1 = (samp0 + (samp1 - samp0) * frac);
352+
353+ return oct0 + (oct1 - oct0) * c->w;
354+}
355+
356+void tCompactWavetable_setFreq(tCompactWavetable* const cy, float freq)
357+{
358+ _tCompactWavetable* c = *cy;
359+
360+ LEAF* leaf = c->mempool->leaf;
361+
362+ c->freq = freq;
363+
364+ c->inc = c->freq * leaf->invSampleRate;
365+
366+ // abs for negative frequencies
367+ c->w = fabsf(c->freq * c->invBaseFreq);
368+
369+ // Probably ok to use a log2 approx here; won't effect tuning at all, just crossfading between octave tables
370+ c->w = log2f_approx(c->w) + c->aa;//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
371+ if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
372+ c->oct = (int)c->w;
373+ c->w -= c->oct;
374+ if (c->oct >= c->numTables - 1) c->oct = c->numTables - 2;
375+}
376+
377+void tCompactWavetable_setAntiAliasing(tCompactWavetable* const cy, float aa)
378+{
379+ _tCompactWavetable* c = *cy;
380+
381+ c->aa = aa;
382+ tCompactWavetable_setFreq(cy, c->freq);
204383 }
205384
206385 #if LEAF_INCLUDE_SINE_TABLE
@@ -243,9 +422,9 @@ void tCycle_setFreq(tCycle* const cy, float freq) · 36 unmodified lines
243422 float tCycle_tick(tCycle* const cy)
244423 {
245424 _tCycle* c = *cy;
246− float temp;;
247− int intPart;;
248− float fracPart;
425+ float temp;
426+ int idx;
427+ float frac;
249428 float samp0;
250429 float samp1;
251430
@@ -257,13 +436,13 @@ float tCycle_tick(tCycle* const cy) · 5 unmodified lines
257436 // Wavetable synthesis
258437
259438 temp = SINE_TABLE_SIZE * c->phase;
260− intPart = (int)temp;
261− fracPart = temp - (float)intPart;
262− samp0 = __leaf_table_sinewave[intPart];
263− if (++intPart >= SINE_TABLE_SIZE) intPart = 0;
264− samp1 = __leaf_table_sinewave[intPart];
439+ idx = (int)temp;
440+ frac = temp - (float)idx;
441+ samp0 = __leaf_table_sinewave[idx];
442+ if (++idx >= SINE_TABLE_SIZE) idx = 0;
443+ samp1 = __leaf_table_sinewave[idx];
265444
266− return (samp0 + (samp1 - samp0) * fracPart);
445+ return (samp0 + (samp1 - samp0) * frac);
267446 }
268447
269448 void tCycleSampleRateChanged (tCycle* const cy)
@@ -310,12 +489,14 @@ void tTriangle_setFreq(tTriangle* const cy, float freq) · 40 unmodified lines
310489
311490 c->inc = c->freq * leaf->invSampleRate;
312491
313− c->w = c->freq * INV_20;
314− for (c->oct = 0; c->w > 2.0f; c->oct++)
315− {
316− c->w = 0.5f * c->w;
317− }
318− c->w = 2.0f - c->w;
492+ // abs for negative frequencies
493+ c->w = fabsf(c->freq * (TRI_TABLE_SIZE * leaf->invSampleRate));
494+
495+ c->w = log2f_approx(c->w);//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
496+ if (c->w < 0.0f) c->w = 0.0f;
497+ c->oct = (int)c->w;
498+ c->w -= c->oct;
499+ if (c->oct >= 10) c->oct = 9;
319500 }
320501
321502
@@ -323,20 +504,36 @@ float tTriangle_tick(tTriangle* const cy) · 1 unmodified line
323504 {
324505 _tTriangle* c = *cy;
325506
507+ float temp;
508+ int idx;
509+ float frac;
510+ float samp0;
511+ float samp1;
512+
326513 // Phasor increment
327514 c->phase += c->inc;
328515 while (c->phase >= 1.0f) c->phase -= 1.0f;
329516 while (c->phase < 0.0f) c->phase += 1.0f;
517+
518+ // Wavetable synthesis
519+ temp = TRI_TABLE_SIZE * c->phase;
520+
521+ idx = (int)temp;
522+ frac = temp - (float)idx;
523+ samp0 = __leaf_table_triangle[c->oct][idx];
524+ if (++idx >= TRI_TABLE_SIZE) idx = 0;
525+ samp1 = __leaf_table_triangle[c->oct][idx];
330526
331− float out = 0.0f;
527+ float oct0 = (samp0 + (samp1 - samp0) * frac);
332528
333− int idx = (int)(c->phase * TRI_TABLE_SIZE);
529+ idx = (int)temp;
530+ samp0 = __leaf_table_triangle[c->oct+1][idx];
531+ if (++idx >= TRI_TABLE_SIZE) idx = 0;
532+ samp1 = __leaf_table_triangle[c->oct+1][idx];
334533
335− // Wavetable synthesis
336− out = __leaf_table_triangle[c->oct+1][idx] +
337− (__leaf_table_triangle[c->oct][idx] - __leaf_table_triangle[c->oct+1][idx]) * c->w;
534+ float oct1 = (samp0 + (samp1 - samp0) * frac);
338535
339− return out;
536+ return oct0 + (oct1 - oct0) * c->w;
340537 }
341538
342539 void tTriangleSampleRateChanged (tTriangle* const cy)
@@ -383,32 +580,50 @@ void tSquare_setFreq(tSquare* const cy, float freq) · 40 unmodified lines
383580
384581 c->inc = c->freq * leaf->invSampleRate;
385582
386− c->w = c->freq * INV_20;
387− for (c->oct = 0; c->w > 2.0f; c->oct++)
388− {
389− c->w = 0.5f * c->w;
390− }
391− c->w = 2.0f - c->w;
583+ // abs for negative frequencies
584+ c->w = fabsf(c->freq * (SQR_TABLE_SIZE * leaf->invSampleRate));
585+
586+ c->w = log2f_approx(c->w);//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
587+ if (c->w < 0.0f) c->w = 0.0f;
588+ c->oct = (int)c->w;
589+ c->w -= c->oct;
590+ if (c->oct >= 10) c->oct = 9;
392591 }
393592
394593 float tSquare_tick(tSquare* const cy)
395594 {
396595 _tSquare* c = *cy;
397596
597+ float temp;
598+ int idx;
599+ float frac;
600+ float samp0;
601+ float samp1;
602+
398603 // Phasor increment
399604 c->phase += c->inc;
400605 while (c->phase >= 1.0f) c->phase -= 1.0f;
401606 while (c->phase < 0.0f) c->phase += 1.0f;
607+
608+ // Wavetable synthesis
609+ temp = SQR_TABLE_SIZE * c->phase;
402610
403− float out = 0.0f;
611+ idx = (int)temp;
612+ frac = temp - (float)idx;
613+ samp0 = __leaf_table_squarewave[c->oct][idx];
614+ if (++idx >= SQR_TABLE_SIZE) idx = 0;
615+ samp1 = __leaf_table_squarewave[c->oct][idx];
404616
405− int idx = (int)(c->phase * SQR_TABLE_SIZE);
617+ float oct0 = (samp0 + (samp1 - samp0) * frac);
406618
407− // Wavetable synthesis
408− out = __leaf_table_squarewave[c->oct+1][idx] +
409− (__leaf_table_squarewave[c->oct][idx] - __leaf_table_squarewave[c->oct+1][idx]) * c->w;
619+ idx = (int)temp;
620+ samp0 = __leaf_table_squarewave[c->oct+1][idx];
621+ if (++idx >= SQR_TABLE_SIZE) idx = 0;
622+ samp1 = __leaf_table_squarewave[c->oct+1][idx];
410623
411− return out;
624+ float oct1 = (samp0 + (samp1 - samp0) * frac);
625+
626+ return oct0 + (oct1 - oct0) * c->w;
412627 }
413628
414629 void tSquareSampleRateChanged (tSquare* const cy)
@@ -455,33 +670,50 @@ void tSawtooth_setFreq(tSawtooth* const cy, float freq) · 40 unmodified lines
455670
456671 c->inc = c->freq * leaf->invSampleRate;
457672
458− // base freq 20
459− c->w = c->freq * INV_20;
460− for (c->oct = 0; c->w > 2.0f; c->oct++)
461− {
462− c->w = 0.5f * c->w;
463− }
464− c->w = 2.0f - c->w;
673+ // abs for negative frequencies
674+ c->w = fabsf(c->freq * (SAW_TABLE_SIZE * leaf->invSampleRate));
675+
676+ c->w = log2f_approx(c->w);//+ LEAF_SQRT2 - 1.0f; adding an offset here will shift our table selection upward, reducing aliasing but lower high freq fidelity. +1.0f should remove all aliasing
677+ if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq
678+ c->oct = (int)c->w;
679+ c->w -= c->oct;
680+ if (c->oct >= 10) c->oct = 9;
465681 }
466682
467683 float tSawtooth_tick(tSawtooth* const cy)
468684 {
469685 _tSawtooth* c = *cy;
470686
687+ float temp;
688+ int idx;
689+ float frac;
690+ float samp0;
691+ float samp1;
692+
471693 // Phasor increment
472694 c->phase += c->inc;
473695 while (c->phase >= 1.0f) c->phase -= 1.0f;
474696 while (c->phase < 0.0f) c->phase += 1.0f;
475697
476− float out = 0.0f;
698+ // Wavetable synthesis
699+ temp = SAW_TABLE_SIZE * c->phase;
477700
478− int idx = (int)(c->phase * SAW_TABLE_SIZE);
701+ idx = (int)temp;
702+ frac = temp - (float)idx;
703+ samp0 = __leaf_table_sawtooth[c->oct][idx];
704+ if (++idx >= SAW_TABLE_SIZE) idx = 0;
705+ samp1 = __leaf_table_sawtooth[c->oct][idx];
479706
480− // Wavetable synthesis
481− out = __leaf_table_sawtooth[c->oct+1][idx] +
482− (__leaf_table_sawtooth[c->oct][idx] - __leaf_table_sawtooth[c->oct+1][idx]) * c->w;
707+ float oct0 = (samp0 + (samp1 - samp0) * frac);
483708
484− return out;
709+ idx = (int)temp;
710+ samp0 = __leaf_table_sawtooth[c->oct+1][idx];
711+ if (++idx >= SAW_TABLE_SIZE) idx = 0;
712+ samp1 = __leaf_table_sawtooth[c->oct+1][idx];
713+
714+ float oct1 = (samp0 + (samp1 - samp0) * frac);
715+
716+ return oct0 + (oct1 - oct0) * c->w;
485717 }
486718
487719 void tSawtoothSampleRateChanged (tSawtooth* const cy)
leaf/leaf-config.h+1−1
@@ -18,7 +18,7 @@ · 17 unmodified lines
1818
1919 //==============================================================================
2020
21−//! Include FIR tables required to use tOversampler.
21+//! Include FIR tables required to use tOversampler and tCompactWavetable which uses tOversampler.
2222 #define LEAF_INCLUDE_OVERSAMPLER_TABLES 1
2323
2424 // Unused

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t