PingPong Delay clicking

The PingPong Delay plays ok for like a second and then it starts to click and sound a bit erratic. Not sure if I implemented the delay effect properly or if it has something to do with the bufnum argument.

p=ProxySpace.push(s);

p.makeTempoClock;

p.clock.tempo = 160/60;

(

b = Buffer.alloc(s, s.sampleRate,2);
SynthDef.new(\acid, {|bufnum = 0, out = 1, freq= 100, gate = 0.5, amp= 2, width=0.48, ffreq = 2000, rez=0.8, delayTime = 2, feedback = 0.5 |
	var plfo, fcurve, sig;
	plfo = SinOsc.kr(6, mul:0, add:1);
	freq = Lag.kr(freq, 0.04) * plfo;
	fcurve = EnvGen.kr(Env.adsr(0.0, 0.1, 0.4, 3), gate);
	fcurve = (fcurve - 1).madd(2, 1) * ffreq;
	sig = Pan2.ar( Pulse.ar(freq, width) + Pulse.ar(freq+3, width) );
	sig = RLPFD.ar(sig, fcurve + ffreq, rez) *
	EnvGen.kr(Env.adsr(0, 0.5, 0.8, 0.05), gate, doneAction: Done.freeSelf);
	sig = PingPong.ar(b.bufnum, [sig,sig], delayTime ,feedback, 1 );
	Out.ar(out, sig * amp );

}).add;

) 

(

var seq = Pxrand([0.25, 1, 0.25, 0.50, 0.25, 3, 0.25, 0.50, 1, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 ], inf);
var seq2 = Pxrand([0.25], inf);
~acid = PmonoArtic(
    \acid,
	\legato, seq,
	\degree, Pxrand(
		[ Pxrand([5, 8, 12, 3, 4, -7, 3, 4]-12, 2),
			Pseq([-5, -8, -12, -6, -4, -14, -6, -4]/2, 1)
		], inf),
	\ffreq, Pxrand(
		[ Pxrand([100,500, 800, 1200, 2000, 1200, 2400], 1),
			Pseq([200,800, 900, 1500, 1800, 1200, 1900], 1)
		], inf),
	\dur, seq2,
	\amp, Pxrand([3, 2, 2, 2, 1, 1, 3, 3, 3, 3, 3], inf),
);

~play_acid = ~acid.play();


) 

I believe it’s because you’re calling \dur on both your dry signal and the delayed version. You should probably allocate a separate bus for the signal post delay

Maybe something like this using Pfx instead of packing your delay in the original synthdef:

(
t = TempoClock(160/60);
s.freeAllBuffers;
s.newBusAllocators;
b = Buffer.alloc(s, s.sampleRate, 2);
SynthDef.new(\acid, {|bufnum = 0, out = 0, freq= 100, gate = 0.5, amp= 1, width=0.48, ffreq = 2000, rez=0.8 |
	var plfo, fcurve, sig;
	plfo = SinOsc.kr(6, mul:0, add:1);
	freq = Lag.kr(freq, 0.04) * plfo;
	fcurve = EnvGen.kr(Env.adsr(0.0, 0.1, 0.4, 3), gate);
	fcurve = (fcurve - 1).madd(2, 1) * ffreq;
	sig = Pan2.ar( Pulse.ar(freq, width) + Pulse.ar(freq+3, width) );
	sig = RLPF.ar(sig, fcurve + ffreq, rez);
	EnvGen.kr(Env.adsr(0, 0.5, 0.8, 0.05), gate, doneAction:2);
	Out.ar(out, sig * amp);
}).add;

SynthDef.new(\delay, {
	arg bufnum=0, delayTime = 2.0, feedback = 0.5, out=0, amp=0.5;
	var sig;
	sig = In.ar(out, 2);
	sig = PingPong.ar(b.bufnum, [sig,sig], delayTime ,feedback, 1);
	Out.ar(out, sig);
}).add;
)

(
~acid = PmonoArtic(
    \acid,
	\legato, Pxrand([0.25, 1, 0.25, 0.50, 0.25, 3, 0.25, 0.50, 1, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25 ], inf),
	\degree, Pxrand(
		[ Pxrand([5, 8, 12, 3, 4, -7, 3, 4]-12, 2),
			Pseq([-5, -8, -12, -6, -4, -14, -6, -4]/2, 1)
		], inf),
	\ffreq, Pxrand(
		[ Pxrand([100,500, 800, 1200, 2000, 1200, 2400], 1),
			Pseq([200,800, 900, 1500, 1800, 1200, 1900], 1)
		], inf),
	\dur, Pxrand([0.25], inf),
	\amp, Pxrand([3, 2, 2, 2, 1, 1, 3, 3, 3, 3, 3], inf),
).play(t);
~delay = Pfx(~acid, \delay).play(t);
)
t.free

This worked! I also adjusted the delay in seconds (0.28125) for the tempo since 2.0 didn’t sound right. A few questions though. Why is a new TempoClock needed to play the sequences in the correct tempo? I see that I now have to include the t variable in the play method.

Also why is s.freeAllBuffers and s.newBusAllocators needed?

1 Like

I also adjusted the delay in seconds (0.28125) for the tempo since 2.0 didn’t sound right.

I figured you’d probably end up doing that.

Just remember to separate your effects from things that use an envelope or that you’re calling \dur on (unless you’re after a gated effect). Pfx works great for this.

And as far as TempoClock goes, the default is one second, so \dur is considering the values as fractions of a second. By calling a new tempoclock, you change the length of time that \dur is being multiplied by.

I usually find it very helpful to, toward the top of my code, do something like this:

~bpm = 85;         //85 beats per minute

t = TempoClock(~bpm/60);       //divide by 60 to give TempoClock the BPM value instead of just telling it to play 85 times faster than the length of one second

...

p = Pbind(
\dur, 1/4
);

p.play(t);

Just remember that TempoClock takes the first argument as beats per second essentially. So in most cases:

t = TempoClock(200/60);  ///probably the intent because 200 BPM is a reasonable tempo value
t = TempoClock(200);   ///plays everything 200x faster than the default, or 12000 BPM - well into audio rate and past the thresholds of perception unless you just like writing in extremely long durations
1 Like

The new bus allocator isn’t necessary. I was going to put the effects in a separate bus on the server, but I ended up not doing that because Pfx made more sense.

s.freeAllBuffers is something I highly recommend putting at the beginning of any code you have that uses buffers. This frees the buffers (any that you ay have had left over from other project and most importantly any that were allocated last time) so that you don’t keep piling up the same buffers on the server every time you evaluate.
-You will exceed the number of buffers available if you keep evaluating a code that creates them but doesn’t clean them
-it takes up a bunch of unnecessary space on your computer that should be better dedicated to other purposes and
-I believe will also start to cause timing issues

1 Like

It isn’t.

If you’re only ever using one tempo (a typical case)…

TempoClock.tempo = 85/60;

… and just use the default TempoClock (no need to pass t). (To write the above out fully, it would be TempoClock.default.tempo = 85/60;, but the TempoClock class redirects common messages like scheduling and tempo-setting to the default instance – i.e. it’s intended to be convenient to manipulate the default instance.)

Creating a new clock is valuable to produce polyrhythms at multiple tempi, or to group processes into separate schedulers, but it isn’t required for setting tempo.

hjh