[sdiy] help understanding circular buffers for delay line

dan snazelle subjectivity at hotmail.com
Sat Mar 3 02:52:12 CET 2012


matthew


in your code, you wrote:

> mybuffer[i]=read_dac();
> write_dac(mybuffer[j]);



did you mean

mybuffer[i]=read_adc();
write_dac(mybuffer[j];


???


if not, i am not sure at which point in the delay routine to INPUT my audio.


lets say my audio Input is called audio_In()
and my output is called dacOutput


at which point in the delay do I get audio INTO the loop and out of the loop?

also to add feedback, how do I add the output back into itself?


your explanation was actually exceedingly clear, I am just a bit fuzzy on these points as most discussions of delay, do not clearly state where the audio
comes in and how it gets out, etc

thanks!

On Mar 1, 2012, at 10:53 PM, Matthew Smith wrote:

> 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
> _______________________________________________
> Synth-diy mailing list
> Synth-diy at dropmix.xs4all.nl
> http://dropmix.xs4all.nl/mailman/listinfo/synth-diy
> 




More information about the Synth-diy mailing list