[sdiy] Wavetables
Olivier Gillet
ol.gillet at gmail.com
Mon Jan 24 22:43:01 CET 2011
> Which reveals a flaw in my current code - I'm checking to see if my pointer
> value has reached maximum (and duly resetting if it has) *before* copying
> the value to the port. Need to shift that down to the end of the function,
> after the pointer increment. That way, the copy from the table to the port
> is executed FIRST in the ISR. (Current code is looking for an external
> interrupt, but same would apply if I had the code space to do this with an
> on-board counter.)
I don't adhere to the "generate one sample per ISR call" philosophy,
but if you ever do so, the right workflow is:
static sample_t sample;
ISR() {
OUTPUT = sample;
// Code to recompute sample
}
but not:
ISR() {
sample_t sample;
// Code to compute sample
OUTPUT = sample;
}
Because in the second case, if the code has a variable runtime (due to
conditional branches) you'll see jitter. I think this is the problem
you describe.
Personally, in absence of DMA, I favor:
ISR() {
OUTPUT = ring_buffer_read(buffer);
}
+
while(1) {
if (ring_buffer_readable(buffer) < N) {
for (i = 0; i < N; ++i) {
// Compute sample.
ring_buffer_write(buffer, sample);
}
}
}
The benefit is the following: if the synthesis code is very
complicated, you don't have to push/pull from the stack the entire set
of registers everytime there's a sample to render. A ringbuffer
read/write per sample is way cheaper than pushing/popping 20 registers
per sample. And this allows the computational time to be "smoothed",
so you can use algorithms that do very fancy things once in a while
(eg: sync).
Olivier
More information about the Synth-diy
mailing list