would you be willing to leak some details of your wavetable/DDS implementation?
Normally I wouldn't release any code early, and honestly this probably isn't useful without the rest of the library, but here's my DDS sine wave implementation.
It's really pretty simple, just a 32 bit phase accumulator (phase and phase_increment are uint32_t, not float, even though it's assigned from a converted float) where the upper 8 bits index into a sine lookup table, and the next lower 16 bit are used to linear interpolate between 2 table entries. The lowest 8 bits aren't used, other than accumulating phase. Those low 8 bit might never have anything useful, since the increment is converted from a float with only 23+1 bit mantissa. Maybe later I'll consider an improved conversion from float to uint32 that properly maps the original mantissa to all 32 bits, but that's a relatively minor issue.
Code:
void AudioSineWave::frequency(float f)
{
if (f > AUDIO_SAMPLE_RATE_EXACT / 2 || f < 0.0) return;
phase_increment = (f / AUDIO_SAMPLE_RATE_EXACT) * 4294967296.0f;
}
void AudioSineWave::update(void)
{
audio_block_t *block;
uint32_t i, ph, inc, index, scale;
int32_t val1, val2;
//Serial.println("AudioSineWave::update");
block = allocate();
if (block) {
ph = phase;
inc = phase_increment;
for (i=0; i < AUDIO_BLOCK_SAMPLES; i++) {
index = ph >> 24;
val1 = sine_table[index];
val2 = sine_table[index+1];
scale = (ph >> 8) & 0xFFFF;
val2 *= scale;
val1 *= 0xFFFF - scale;
block->data[i] = (val1 + val2) >> 16;
//Serial.print(block->data[i]);
//Serial.print(", ");
//if ((i % 12) == 11) Serial.println();
ph += inc;
}
//Serial.println();
phase = ph;
transmit(block);
release(block);
return;
}
phase += phase_increment * AUDIO_BLOCK_SAMPLES;
}
Edit: also, at some point, I'll probably try to optimize this code using the SIMD instructions. That might require doubling the lookup table size, so each pair of values is 32 bit aligned? I have measured this non-optimized code using about 3% of the CPU time, running at the default 44.1 kHz sample rate.
This could pretty easily be turned into any arbitrary waveform by replacing the sine lookup table with whatever waveform you want. I'm planning to do something like that for the library....
but there's probably smarter ways of achieving that, say, preparing the wavetables in advance and just writing them into the flash.
Yes, I've actually thought quite a bit about converting soundfont to an intermediate format. So far, only ideas, not any real code.
I've been focusing on efficient I/O, the library base class that provides all the infrastructure, and a ton of mundane things needed to actually get the hardware released. Currently I'm working on the test strategy and bed-of-nails test system...