Circular Buffer Delay sampling problems

Hank Borders's icon

Anyone know how to get rid of noise made when changing the delay time of a circular buffer(data object).

I've got a "data" object in Gen~ and a "counter" is writing to it and then and an offset counter is reading from it at a delayed time. Essentially a write and read head of a tape loop. When I adjust the delay time I get some weird high frequency noise. I'm assuming that it's because the read counter is moving faster than the sample rate and skipping samples resulting in discontinuity or it.

Max Patch
Copy patch and select New From Clipboard in Max.


The write head in red. The read head in green. You can see the speed of the read counter is faster than the write counter which is counting at sample rate


Roman Thilenius's icon

if it crackles that is because the reading from the buffer isnt interpolated. but if it would be interpolated, it would change the pitch.
the only real solution is to use a windowing function with 3 parallel streams. (easy in MSP, but no idea in gen~ or rnbo.)

Hank Borders's icon

>if it crackles that is because the reading from the buffer isnt interpolated. but if it would be interpolated, it would change the pitch.


I did have the @interp argument of the poke object set to 1 in that patch which should interpolate the output. I tried a few different of the @interp settings but they don't seem to stop the crackle, only change how it sounds. Regardless of the interpolation, the pitch changes which is totally fine. I'm only looking to stop the crackle.

Using the delay object and changing the time doesn't have this crackle, so maybe there is a way to treat the circular buffer in the same way as the delay object's internals?

>the only real solution is to use a windowing function with 3 parallel streams. (easy in MSP, but no idea in gen~ or rnbo.)

What would this look like? I've made other windowing functions in gen before, so I'm willing to take on the task if it helps.

Roman Thilenius's icon

you let them run at some 25-250 hz and track their busy state (>~ 0.5 ?) ; the modulation signal for the readhead is then always routed to the tapping buffer in background, one time per windowing cycle (in MSP you can use sah~ for that)


anything from triangular over hanning to cosine should do, and if you know what you are doing you might come along with 2 windows (i find 3 easier, it seems more safe in case you miscalculate something for 1 sample, and, how should i call it, can allow an actual "overlap" period by making them a bit bigger than 33%)

Graham Wakefield's icon

The delay operator in gen~ doesn't understand "@interp 1", it should be e.g. "@interp linear" or "@interp cubic" etc.

You'll also want to smooth the delay parameter over time. The simplest way is to use a [slide] operator. Bear in mind that the arguments to [slide] are in samples. So e.g. if you want the slide over 10ms, you can say [slide samplerate/100 samplerate/100]. That should eliminate clicks. You'll instead get a pitch shift during that transition.

If you don't want a pitch shift, you'll need a patch with two readers so you can crossfade between one fixed delay time and another -- start the crossfade when you want to change the delay time, and prevent any other delay time changes until the crossfade completes. There's an example of this in the GO book fwiw.

Hank Borders's icon

>The delay operator in gen~ doesn't understand "@interp 1", it should be e.g. "@interp linear" or "@interp cubic" etc.

Aha! This worked! I must have been hallucinating when I thought the numbers were changing the sound of the crackle.

Thank you to both of you for the help!