Imagine you have a buffer that is continuously being writting to and read from. In my example i read the buffer in a loop backwards. For visual aid i made a beautiful image in paint.
Imagine a buffer that is circular with a playinghead moving counterclockwise and the recordinghead moving clockwise. If they have the same speed and both start on top, then they would meet twice every cycle, once on top and once on the bottom.

When the heads meet id like to have some kind of crossfade. My attempt is as follows:
Once the heads are at a distance d from eachother, i try to crossfade from the playheads current position to one frame behind the recordinghead. Once the heads are closer then distance d there is a trigger, to trigger this crossfade. I thought that this way you crossfade over the collision and there would be no clicks. However there are still clicks.

``````({

//with a modulating frequency of 1 there are no clicks
//because the buffer contents effectively dont change
sig = SinOsc.ar(440 + SinOsc.ar(1.5, mul: 100))*0.1;

buffer = Buffer.alloc(s, 44100);

recHead = Phasor.ar(0, 1, 0, 44100);
//we pretend PlayBufCF uses this playHead
playHead = Phasor.ar(0, -1, 44100 - 1, -1);

//second part of if statement is when
//the playHead and recHead are on opposite sides of the 0 frame

//bufwr for reference
//with a modulating frequency of 1 there are also no clicks with BufRd

//trying out different lagtimes, but it doesnt change much
PlayBufCF.ar(1, buffer, -1, trigger, recHead - 1, loop:1, lag:MouseX.kr(0.1,1).poll);

}.play)
``````

I know that in my example the “real” playhead jumps a few frames ahead every trigger, so the trigger gets more and more behind. So i’d need to update the playhead and then update the trigger retroactively with this new playhead, however i have no idea how i should do that.

Has anyone solved this problem before and if so how did you implement a smooth transition when recordinghead and playhead cross?

This will only work when |readingrate| == |writingrate|. Maybe i can find a solution to more general cases with different reading rates later.

``````(
{
var playBackLength = 1.5;
var buf1, buf2, buf3, in, out, phase, currentBuf, nextBuf, fade = 0.1, trigger = Impulse.ar(playBackLength.reciprocal), extraDelay = 0.1;

//random input
in = SinOsc.ar(LFNoise1.kr(1).range(500,800) + LFNoise1.kr(0.5).range(-100, 100)) * EnvGen.kr(Env.perc(0.05,0.2), Impulse.kr(3.5));

//make 3 buffers
buf1 = Buffer.alloc(s, 44100*playBackLength);
buf2 = Buffer.alloc(s, 44100*playBackLength);
buf3 = Buffer.alloc(s, 44100*playBackLength);

//nextbuf is the buf being written to and currentbuf is the buf being read
nextBuf = Demand.ar(trigger, 0, Dseq([buf1, buf2, buf3], inf));

//recordbuf seems to work more reliable than bufwr with a phasor
RecordBuf.ar(in, nextBuf, loop:1);

//reverse playback
phase = Phasor.ar(0, -1, 44100*playBackLength - 1, -1);
//delay until the first buffer filled

out = BufRd.ar(1, currentBuf, phase);

}.play;
)
``````
``````	//make 3 buffers
buf1 = Buffer.alloc(s, 44100*playBackLength);
buf2 = Buffer.alloc(s, 44100*playBackLength);
buf3 = Buffer.alloc(s, 44100*playBackLength);
``````

Btw, you shouldn’t allocate buffers inside of a synthdef - calling play on a function wraps it in a synthdef.

Yeah i know, it was just convenient for testing. This is just a rough sketch for a possible solution.