LoopBuf, sendBundle & ProxySpace


my problem is to perfectly synchronize the kick proxy with
the guitar loop; I noticed that with the sendMsg I have delays and therefore I tried with the sendBundle which allows me to introduce a latency time for the OSC message; the result is not bad, but I can’t get the precision I’m looking for; can someone help me? thank you;

p.clock = TempoClock.new(2.4);
p.quant = -4;
p.clock.tempo = 150/60;

~k = Pbind(\instrument,\bplay,\buf,d["k"][1],\dur,1,\amp,0.5);

s.sendBundle(0.713,["/s_new", "loopbz", 3713, 1, 0, \bufnum, d["riff"][4].bufnum, \startLoop, 0,\endLoop, 713713713,\gate,0]);

~riff=Pfunc({s.sendBundle(0.713, ["/n_set", 3713, 1, 0, \bufnum, d["riff"][5].bufnum , \rate, p.clock.tempo*60/150, \gate, 1, \amp, amp ]); 713; });

    arg out=0, bufnum=0, rate=1, glide=0, gate=1, loopRel=0, startPos=0, startLoop, endLoop, ipol=2, amp=0.2;
    var env, signal;
    rate = Lag.kr(rate, glide);                                                     
    env = EnvGen.ar(Env.adsr(0.1,0.2,1,2), gate, doneAction: 2);            
    signal = LoopBuf.ar(1,bufnum, BufRateScale.kr(bufnum) * rate, gate+loopRel, startPos, startLoop, endLoop, ipol);
    Out.ar(out, (signal * env * amp).dup);

Just a few general notes, no solution, but maybe they can help you … i haven’t studied the thread history, sorry if these have been pointed out before.

You are probably sidetracking yourself by using a lot of unusual numbers, a 2.4 clock with negative quant, 150/60 tempo (that’s 2.5, right?) … I would recommend getting things to work with the default numbers first. You can always add the wierdness later.

The ~riff thing doesn’t seem to be used – what do you expect it to do? Seems strange to have a lonesome pfunc lying around like that

You are mixing pattern style (pbind) with server-command style (sendbundle). I imagine it will be unnecessarily difficult to sync these two up.



eddi, thanks for the answer; I’m not very experienced;

p.quant = -4; I need it to start the proxy node at the next beat multiple of 16; if I evaluate a proxy node at beat number 21, it will start at beat number 32;

must be p.clock = TempoClock.new (2.5), not 2.4; it’s my mistake, but the result is the same;

when ~riff is evaluated, Pfunc triggers the s.sendBundle, and the message is sent to the next beat multiple of 16;

“You are mixing pattern style (pbind) with server-command style (sendbundle)”; yes, this is clearly the basis of the my problem;

I need a way to sync the LoopBuf with the ProxySpace, but I can’t find a solution,


I tried this:

~riff1 = Pbind(\instrument,\bplay,\buf,d["riff"][5],\dur,8,\amp,0.3,\pan,0.1,\rate,p.clock.tempo*60/150,\rel,8,\legato,0);

	{arg out = 0, buf = 0, rate = 1, amp = 0.5, pan = 0, pos = 0, rel=15;
		var sig,env ;
		sig = Mix.ar(PlayBuf.ar(2,buf,BufRateScale.ir(buf) * rate,1,BufDur.kr(buf)*pos*44100,doneAction:2));
		env = EnvGen.ar(Env.linen(0.0,rel,0),doneAction:2);
		sig = sig * env;
		sig = sig * amp;

bplay is from howto_co34pt_liveCode;

but when I change the sample, and I evaluate ~ riff1, there is an overlap that I don’t want;

~riff1 = Pbind(\instrument,\bplay,\buf,d["riff"][4],\dur,8,\amp,0.3,\pan,0.1,\rate,p.clock.tempo*60/150,\rel,8,\legato,0);

i found!

bplay solution with \rel, 4; and no overlap;


Easy way to write bpm – I usually prefer to write 124/60 rather than 2.0666666666.

But the point about unusual numbers is fair for the 713… no idea of the significance here.

What is the frame index of the downbeat in the buffer you’re looping?


713 is a meaningless number, I use it in different situations, like to get something back from Pfunc and avoid exceptions like “ERROR: Message ‘playAndDelta’ not understood”;

do you mean the total number of buffer frames?

My experience is that Patterns automatically adjust for system latency and so line up with bundled Synths (or stuff with .bind). But nodeProxies seem to add latency especially when they feed each other it can build up. For me it’s either/or patterns+s.bind or nodeProxies. A good way to test whether latency compensation is aligned is to set latency high s.latency= 2

… and MIDI is a whole nother thing…

here’s what the docs have to say

But a numeric return value here is not meaningless!

Let’s take the same code structure and simplify, to illustrate:

p = Pfunc({ thisThread.beats.postln; 1 }).play;



Now, if you write 713 instead of 1, you would get 81.178623736, then 794.178623736… if you wait the 11min 53sec. Probably you aren’t waiting that long, so you might have assumed that it’s going to do the Pfunc only once. It doesn’t. If you return a number here, it will be rescheduled. If that’s not what you wanted, then don’t return a number. (nil is OK for non-repeat.)


s.sendBundle(0.713, ["/s_new", "loopbz", 3713, 1, 0, \bufnum, d["riff"][4].bufnum, \startLoop, 0,\endLoop, 713713713, \gate, 0]);

~riff=Pfunc({ s.sendBundle(0.713, ...) });

If you’re trying to sync two different players, using “meaningless” latency values is guaranteed to de-synchronize!

If you want two things to happen at the same time, the simplest, easiest, most reliable way to do that is:

  • Choose a point on a language-side clock (which you’re already doing by quant).

  • At that time point, send messages with the same latency.

~k will be using s.latency = 0.1 in your example.

To start the riff loop at exactly the same time as ~k, you need to run the ~riff pattern at the same clock time, with the same latency. If ~k’s latency is 0.1 and ~riff’s latency is 0.713, then the riff will be 0.613 seconds late.

This works… (the magic numbers here are taken from an example I wrote once for a help file – the tricky thing was that the rhythm makes sense with a half beat “upbeat” so the synth here offsets the playback start position – if your loop recording starts on the downbeat then you don’t have to do that – the important point is that the synth begins exactly on a downbeat):

b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

~start = 0.404561;
~end = 3.185917;
~beatsInLoop = 4;
~originalTempo = ~beatsInLoop / (~end - ~start);

TempoClock.tempo = ~originalTempo;

SynthDef(\loop, { |out, gate = 1, bufnum, start, startOffset, end, amp = 0.1, rate = 1|
	var eg = EnvGen.kr(Env.asr(0.01, 1, 0.01), gate, doneAction: 2),
	bufsr = BufSampleRate.kr(bufnum),
	// sc3-plugins:
	sig = LoopBuf.ar(1, bufnum, rate * BufRateScale.kr(bufnum), gate,
		startPos: (start + startOffset) * bufsr,
		startLoop: start * bufsr,
		endLoop: end * bufsr
	Out.ar(out, (sig * (amp * eg)).dup);

~loop = Pfunc({
	s.makeBundle(s.latency, {
		~loopsynth = Synth(\loop, [bufnum: b,
			start: ~start, end: ~end, startOffset: 0.5 / ~originalTempo

~notes = Pbind(
	\degree, Pseq([-7, Pwhite(0, 7, 7)], inf),
	\dur, 0.5

p = ~notes.play(quant: -1);

q = ~loop.play(quant: -1);



1 Like