| @@ -86,15 +86,15 @@ void tTableSampleRateChanged(tTable* const cy) · 85 unmodified lines |
| 86 | c->inc = c->freq * leaf->invSampleRate; | 86 | c->inc = c->freq * leaf->invSampleRate; |
| 87 | } | 87 | } |
| 88 | | 88 | |
| 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) |
| 90 | { | 90 | { |
| 91 | tWavetable_initToPool(cy, table, size, &leaf->mempool); | 91 | tWavetable_initToPool(cy, table, size, maxFreq, &leaf->mempool); |
| 92 | } | 92 | } |
| 93 | | 93 | |
| 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) |
| 95 | { | 95 | { |
| 96 | _tMempool* m = *mp; | 96 | _tMempool* m = *mp; |
| 97 | _tWavetable* c = *cy = (_tWavetable*)mpool_alloc(sizeof(_tTable), m); | 97 | _tWavetable* c = *cy = (_tWavetable*) mpool_alloc(sizeof(_tWavetable), m); |
| 98 | c->mempool = m; | 98 | c->mempool = m; |
| 99 | | 99 | |
| 100 | // Determine base frequency | 100 | // Determine base frequency |
| @@ -102,12 +102,13 @@ void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMem · 1 unmodified line |
| 102 | c->invBaseFreq = 1.0f / c->baseFreq; | 102 | c->invBaseFreq = 1.0f / c->baseFreq; |
| 103 | | 103 | |
| 104 | // Determine how many tables we need | 104 | // 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; |
| 106 | float f = c->baseFreq; | 107 | float f = c->baseFreq; |
| 107 | while (f < 20000.f) | 108 | while (f < maxFreq) |
| 108 | { | 109 | { |
| 109 | c->numTables++; | 110 | 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 |
| 111 | } | 112 | } |
| 112 | | 113 | |
| 113 | c->size = size; | 114 | c->size = size; |
| @@ -125,26 +126,36 @@ void tWavetable_initToPool(tWavetable* const cy, float* table, int size, tMem · 11 unmodified lines |
| 125 | c->tables[0][i] = table[i]; | 126 | c->tables[0][i] = table[i]; |
| 126 | } | 127 | } |
| 127 | | 128 | |
| 128 | // Make bandlimited copies at | 129 | // Make bandlimited copies |
| 129 | f = m->leaf->sampleRate * 0.25f; //start at half nyquist | 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); |
| 130 | for (int t = 1; t < c->numTables; ++t) | 133 | for (int t = 1; t < c->numTables; ++t) |
| 131 | { | 134 | { |
| 132 | tButterworth_initToPool(&c->bl, 4, -1.0f, f, mp); | 135 | tButterworth_setF2(&c->bl, f); |
| 133 | for (int i = 0; i < c->size; ++i) | 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) |
| 134 | { | 140 | { |
| 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 | } |
| 136 | } | 145 | } |
| 137 | tButterworth_free(&c->bl); | 146 | f *= 0.5f; //halve the cutoff for next pass |
| 138 | f *= 0.5f; //half the cutoff for next pass | | |
| 139 | } | 147 | } |
| | 148 | tButterworth_free(&c->bl); |
| | 149 | |
| 140 | | 150 | |
| 141 | c->inc = 0.0f; | 151 | c->inc = 0.0f; |
| 142 | c->phase = 0.0f; | 152 | c->phase = 0.0f; |
| | 153 | c->aa = 0.5f; |
| 143 | | 154 | |
| 144 | tWavetable_setFreq(cy, 220); | 155 | tWavetable_setFreq(cy, 220); |
| 145 | } | 156 | } |
| 146 | | 157 | |
| 147 | void tWavetable_free(tWavetable* const cy) | 158 | void tWavetable_free(tWavetable* const cy) |
| 148 | { | 159 | { |
| 149 | _tWavetable* c = *cy; | 160 | _tWavetable* c = *cy; |
| 150 | | 161 | |
| @@ -153,17 +164,16 @@ void tWavetable_free(tWavetable* const cy) · 2 unmodified lines |
| 153 | mpool_free((char*)c->tables[t], c->mempool); | 164 | mpool_free((char*)c->tables[t], c->mempool); |
| 154 | } | 165 | } |
| 155 | mpool_free((char*)c->tables, c->mempool); | 166 | mpool_free((char*)c->tables, c->mempool); |
| 156 | | | |
| 157 | mpool_free((char*)c, c->mempool); | 167 | mpool_free((char*)c, c->mempool); |
| 158 | } | 168 | } |
| 159 | | 169 | |
| 160 | float tWavetable_tick(tWavetable* const cy) | 170 | float tWavetable_tick(tWavetable* const cy) |
| 161 | { | 171 | { |
| 162 | _tWavetable* c = *cy; | 172 | _tWavetable* c = *cy; |
| 163 | | 173 | |
| 164 | float temp; | 174 | float temp; |
| 165 | int idx; | 175 | int idx; |
| 166 | float fracPart; | 176 | float frac; |
| 167 | float samp0; | 177 | float samp0; |
| 168 | float samp1; | 178 | float samp1; |
| 169 | | 179 | |
| @@ -174,18 +184,26 @@ float tWavetable_tick(tWavetable* const cy) · 4 unmodified lines |
| 174 | | 184 | |
| 175 | // Wavetable synthesis | 185 | // Wavetable synthesis |
| 176 | temp = c->size * c->phase; | 186 | temp = c->size * c->phase; |
| | 187 | |
| 177 | idx = (int)temp; | 188 | idx = (int)temp; |
| 178 | fracPart = temp - (float)idx; | 189 | frac = temp - (float)idx; |
| 179 | samp0 = c->tables[c->oct+1][idx] + | 190 | samp0 = c->tables[c->oct][idx]; |
| 180 | (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w; | | |
| 181 | if (++idx >= c->size) idx = 0; | 191 | if (++idx >= c->size) idx = 0; |
| 182 | samp1 = c->tables[c->oct+1][idx] + | 192 | samp1 = c->tables[c->oct][idx]; |
| 183 | (c->tables[c->oct][idx] - c->tables[c->oct+1][idx]) * c->w; | | |
| 184 | | 193 | |
| 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; |
| 186 | } | 204 | } |
| 187 | | 205 | |
| 188 | void tWavetable_setFreq(tWavetable* const cy, float freq) | 206 | void tWavetable_setFreq(tWavetable* const cy, float freq) |
| 189 | { | 207 | { |
| 190 | _tWavetable* c = *cy; | 208 | _tWavetable* c = *cy; |
| 191 | | 209 | |
| @@ -195,12 +213,173 @@ void tWavetable_setFreq(tWavetable* const cy, float freq) · 3 unmodified lines |
| 195 | | 213 | |
| 196 | c->inc = c->freq * leaf->invSampleRate; | 214 | c->inc = c->freq * leaf->invSampleRate; |
| 197 | | 215 | |
| 198 | c->w = c->freq * c->invBaseFreq; | 216 | // abs for negative frequencies |
| 199 | for (c->oct = 0; c->w > 2.0f; c->oct++) | 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) |
| 200 | { | 257 | { |
| 201 | c->w = 0.5f * c->w; | 258 | c->numTables++; |
| | 259 | f *= 2.0f; // pass this multiplier in to set spacing of tables? |
| 202 | } | 260 | } |
| 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); |
| 204 | } | 383 | } |
| 205 | | 384 | |
| 206 | #if LEAF_INCLUDE_SINE_TABLE | 385 | #if LEAF_INCLUDE_SINE_TABLE |
| @@ -243,9 +422,9 @@ void tCycle_setFreq(tCycle* const cy, float freq) · 36 unmodified lines |
| 243 | float tCycle_tick(tCycle* const cy) | 422 | float tCycle_tick(tCycle* const cy) |
| 244 | { | 423 | { |
| 245 | _tCycle* c = *cy; | 424 | _tCycle* c = *cy; |
| 246 | float temp;; | 425 | float temp; |
| 247 | int intPart;; | 426 | int idx; |
| 248 | float fracPart; | 427 | float frac; |
| 249 | float samp0; | 428 | float samp0; |
| 250 | float samp1; | 429 | float samp1; |
| 251 | | 430 | |
| @@ -257,13 +436,13 @@ float tCycle_tick(tCycle* const cy) · 5 unmodified lines |
| 257 | // Wavetable synthesis | 436 | // Wavetable synthesis |
| 258 | | 437 | |
| 259 | temp = SINE_TABLE_SIZE * c->phase; | 438 | temp = SINE_TABLE_SIZE * c->phase; |
| 260 | intPart = (int)temp; | 439 | idx = (int)temp; |
| 261 | fracPart = temp - (float)intPart; | 440 | frac = temp - (float)idx; |
| 262 | samp0 = __leaf_table_sinewave[intPart]; | 441 | samp0 = __leaf_table_sinewave[idx]; |
| 263 | if (++intPart >= SINE_TABLE_SIZE) intPart = 0; | 442 | if (++idx >= SINE_TABLE_SIZE) idx = 0; |
| 264 | samp1 = __leaf_table_sinewave[intPart]; | 443 | samp1 = __leaf_table_sinewave[idx]; |
| 265 | | 444 | |
| 266 | return (samp0 + (samp1 - samp0) * fracPart); | 445 | return (samp0 + (samp1 - samp0) * frac); |
| 267 | } | 446 | } |
| 268 | | 447 | |
| 269 | void tCycleSampleRateChanged (tCycle* const cy) | 448 | void tCycleSampleRateChanged (tCycle* const cy) |
| @@ -310,12 +489,14 @@ void tTriangle_setFreq(tTriangle* const cy, float freq) · 40 unmodified lines |
| 310 | | 489 | |
| 311 | c->inc = c->freq * leaf->invSampleRate; | 490 | c->inc = c->freq * leaf->invSampleRate; |
| 312 | | 491 | |
| 313 | c->w = c->freq * INV_20; | 492 | // abs for negative frequencies |
| 314 | for (c->oct = 0; c->w > 2.0f; c->oct++) | 493 | c->w = fabsf(c->freq * (TRI_TABLE_SIZE * leaf->invSampleRate)); |
| 315 | { | 494 | |
| 316 | c->w = 0.5f * c->w; | 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 |
| 317 | } | 496 | if (c->w < 0.0f) c->w = 0.0f; |
| 318 | c->w = 2.0f - c->w; | 497 | c->oct = (int)c->w; |
| | 498 | c->w -= c->oct; |
| | 499 | if (c->oct >= 10) c->oct = 9; |
| 319 | } | 500 | } |
| 320 | | 501 | |
| 321 | | 502 | |
| @@ -323,20 +504,36 @@ float tTriangle_tick(tTriangle* const cy) · 1 unmodified line |
| 323 | { | 504 | { |
| 324 | _tTriangle* c = *cy; | 505 | _tTriangle* c = *cy; |
| 325 | | 506 | |
| | 507 | float temp; |
| | 508 | int idx; |
| | 509 | float frac; |
| | 510 | float samp0; |
| | 511 | float samp1; |
| | 512 | |
| 326 | // Phasor increment | 513 | // Phasor increment |
| 327 | c->phase += c->inc; | 514 | c->phase += c->inc; |
| 328 | while (c->phase >= 1.0f) c->phase -= 1.0f; | 515 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 329 | while (c->phase < 0.0f) c->phase += 1.0f; | 516 | 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]; |
| 330 | | 526 | |
| 331 | float out = 0.0f; | 527 | float oct0 = (samp0 + (samp1 - samp0) * frac); |
| 332 | | 528 | |
| 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]; |
| 334 | | 533 | |
| 335 | // Wavetable synthesis | 534 | float oct1 = (samp0 + (samp1 - samp0) * frac); |
| 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; | | |
| 338 | | 535 | |
| 339 | return out; | 536 | return oct0 + (oct1 - oct0) * c->w; |
| 340 | } | 537 | } |
| 341 | | 538 | |
| 342 | void tTriangleSampleRateChanged (tTriangle* const cy) | 539 | void tTriangleSampleRateChanged (tTriangle* const cy) |
| @@ -383,32 +580,50 @@ void tSquare_setFreq(tSquare* const cy, float freq) · 40 unmodified lines |
| 383 | | 580 | |
| 384 | c->inc = c->freq * leaf->invSampleRate; | 581 | c->inc = c->freq * leaf->invSampleRate; |
| 385 | | 582 | |
| 386 | c->w = c->freq * INV_20; | 583 | // abs for negative frequencies |
| 387 | for (c->oct = 0; c->w > 2.0f; c->oct++) | 584 | c->w = fabsf(c->freq * (SQR_TABLE_SIZE * leaf->invSampleRate)); |
| 388 | { | 585 | |
| 389 | c->w = 0.5f * c->w; | 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 |
| 390 | } | 587 | if (c->w < 0.0f) c->w = 0.0f; |
| 391 | c->w = 2.0f - c->w; | 588 | c->oct = (int)c->w; |
| | 589 | c->w -= c->oct; |
| | 590 | if (c->oct >= 10) c->oct = 9; |
| 392 | } | 591 | } |
| 393 | | 592 | |
| 394 | float tSquare_tick(tSquare* const cy) | 593 | float tSquare_tick(tSquare* const cy) |
| 395 | { | 594 | { |
| 396 | _tSquare* c = *cy; | 595 | _tSquare* c = *cy; |
| 397 | | 596 | |
| | 597 | float temp; |
| | 598 | int idx; |
| | 599 | float frac; |
| | 600 | float samp0; |
| | 601 | float samp1; |
| | 602 | |
| 398 | // Phasor increment | 603 | // Phasor increment |
| 399 | c->phase += c->inc; | 604 | c->phase += c->inc; |
| 400 | while (c->phase >= 1.0f) c->phase -= 1.0f; | 605 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 401 | while (c->phase < 0.0f) c->phase += 1.0f; | 606 | while (c->phase < 0.0f) c->phase += 1.0f; |
| | 607 | |
| | 608 | // Wavetable synthesis |
| | 609 | temp = SQR_TABLE_SIZE * c->phase; |
| 402 | | 610 | |
| 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]; |
| 404 | | 616 | |
| 405 | int idx = (int)(c->phase * SQR_TABLE_SIZE); | 617 | float oct0 = (samp0 + (samp1 - samp0) * frac); |
| 406 | | 618 | |
| 407 | // Wavetable synthesis | 619 | idx = (int)temp; |
| 408 | out = __leaf_table_squarewave[c->oct+1][idx] + | 620 | samp0 = __leaf_table_squarewave[c->oct+1][idx]; |
| 409 | (__leaf_table_squarewave[c->oct][idx] - __leaf_table_squarewave[c->oct+1][idx]) * c->w; | 621 | if (++idx >= SQR_TABLE_SIZE) idx = 0; |
| | 622 | samp1 = __leaf_table_squarewave[c->oct+1][idx]; |
| 410 | | 623 | |
| 411 | return out; | 624 | float oct1 = (samp0 + (samp1 - samp0) * frac); |
| | 625 | |
| | 626 | return oct0 + (oct1 - oct0) * c->w; |
| 412 | } | 627 | } |
| 413 | | 628 | |
| 414 | void tSquareSampleRateChanged (tSquare* const cy) | 629 | void tSquareSampleRateChanged (tSquare* const cy) |
| @@ -455,33 +670,50 @@ void tSawtooth_setFreq(tSawtooth* const cy, float freq) · 40 unmodified lines |
| 455 | | 670 | |
| 456 | c->inc = c->freq * leaf->invSampleRate; | 671 | c->inc = c->freq * leaf->invSampleRate; |
| 457 | | 672 | |
| 458 | // base freq 20 | 673 | // abs for negative frequencies |
| 459 | c->w = c->freq * INV_20; | 674 | c->w = fabsf(c->freq * (SAW_TABLE_SIZE * leaf->invSampleRate)); |
| 460 | for (c->oct = 0; c->w > 2.0f; c->oct++) | 675 | |
| 461 | { | 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 |
| 462 | c->w = 0.5f * c->w; | 677 | if (c->w < 0.0f) c->w = 0.0f; // If c->w is < 0.0f, then freq is less than our base freq |
| 463 | } | 678 | c->oct = (int)c->w; |
| 464 | c->w = 2.0f - c->w; | 679 | c->w -= c->oct; |
| | 680 | if (c->oct >= 10) c->oct = 9; |
| 465 | } | 681 | } |
| 466 | | 682 | |
| 467 | float tSawtooth_tick(tSawtooth* const cy) | 683 | float tSawtooth_tick(tSawtooth* const cy) |
| 468 | { | 684 | { |
| 469 | _tSawtooth* c = *cy; | 685 | _tSawtooth* c = *cy; |
| 470 | | 686 | |
| | 687 | float temp; |
| | 688 | int idx; |
| | 689 | float frac; |
| | 690 | float samp0; |
| | 691 | float samp1; |
| | 692 | |
| 471 | // Phasor increment | 693 | // Phasor increment |
| 472 | c->phase += c->inc; | 694 | c->phase += c->inc; |
| 473 | while (c->phase >= 1.0f) c->phase -= 1.0f; | 695 | while (c->phase >= 1.0f) c->phase -= 1.0f; |
| 474 | while (c->phase < 0.0f) c->phase += 1.0f; | 696 | while (c->phase < 0.0f) c->phase += 1.0f; |
| 475 | | 697 | |
| 476 | float out = 0.0f; | 698 | // Wavetable synthesis |
| | 699 | temp = SAW_TABLE_SIZE * c->phase; |
| 477 | | 700 | |
| 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]; |
| 479 | | 706 | |
| 480 | // Wavetable synthesis | 707 | float oct0 = (samp0 + (samp1 - samp0) * frac); |
| 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; | | |
| 483 | | 708 | |
| 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; |
| 485 | } | 717 | } |
| 486 | | 718 | |
| 487 | void tSawtoothSampleRateChanged (tSawtooth* const cy) | 719 | void tSawtoothSampleRateChanged (tSawtooth* const cy) |