[sdiy] help understanding circular buffers for delay line
Matthew Smith
matt at smiffytech.com
Fri Mar 2 04:53:12 CET 2012
Quoth Dan Snazelle at 02/03/12 12:27...
...
> So, these two indexes....are they both driven by "for" loops?(one with an offset?)
This is one of those concepts I'd generally try to explain using
diagrams. However, let's see what we can do in plain text.
For starters, if you haven't already done so, I'd suggest you have a
look at this Wikipedia article:
http://en.wikipedia.org/wiki/Circular_buffer
...but possibly stopping when you get to the code, as they are using the
dreaded malloc which I have, on more than one occasion, been told to
avoid when dealing with small micros.
Here's a very rough example, without using pointers (which I probably
would in Real Life) where I am sampling at 48ksps, 8 bits.
# define SIZE_OF_BUFFER 4096
unsigned char mybuffer[SIZE_OF_BUFFER];
int i=0; // write index
int j=0; // read index
for (;;)
{
i++;
if (i==SIZE_OF_BUFFER)
{
i=0; // We are indexing from zero, so 4095->0.
}
j=i+1;
if (j==SIZE_OF_BUFFER)
{
j=0;
}
mybuffer[i]=read_dac();
write_dac(mybuffer[j]);
delay(); // wait until it's time for the next sample.
}
In real life, to do make this run in time, I'd make this an ISR, rather
than an infinite for loop, or use an RTOS.
What's happening here is a simple delay. As I haven't initialised
mybuffer[], for the first pass through the loop, write_dac() will be
spitting out indeterminate values - something that should be avoided in
a real implementation.
After that first pass through though, what will be read from the buffer
into the DAC will be the sample that you wrote in there SIZE_OF_BUFFER
iterations ago. (Note that the oldest entry in the buffer is the NEXT
position, or zero if we've reached the end.)
If we are sampling at 48ksps, this means that the value going to the DAC
will be (1/48000) * 4096 = 0.0853 seconds behind what's being read in.
To decrease the delay, we change the relationship between i and j.
To give the effect of an echo, we can scale the value coming out by,
say, shifting it 2 places to the right (divide by 4.) Then we can add it
to the signal being written, shift the result 1 place to the right
(divide by 2, because we could now have a 9 bit number, having added to
the 8 bit number) and then send that to the DAC. So the value coming out
is half of what's gone in, plus a quarter of what was there 85ms ago.
These are very rough examples (probably with errors!) but I hope they
make it a bit more clear.
One thing you may have gathered - any significant delay will need a fair
amount of RAM to achieve which, in a microcontroller context, will
probably involve the use of external RAM. (It's dirt cheap, but does
mean an extra chip.)
Cheers
M
--
Matthew Smith
Business: http://www.smiffytech.com
Blog: http://www.smiffysplace.com
Linkedin: http://www.linkedin.com/in/smiffy
Flickr: http://www.flickr.com/photos/msmiffy
Twitter: http://twitter.com/smiffy
ABN 16 391 203 815
More information about the Synth-diy
mailing list