Taking a user-defined action at the end of a XLine

How can I take an arbitrary action (say printing something to the screen) when a doneAction is to be called, i.e. at the end of an XLine I would like to print something, so in code: I would like to have something like

XLine.kr(x, y, z, doneAction: my_function.(arguments_to_change_the_world));

How can I do this?

Generate a trigger that will happen at the same time XLine finishes, then use that to send an OSC message using SendReply.

I would say there might be two more possibilities at least:

  1. According to the Done help document example:
(
SynthDef("Done-help", { arg out, t_trig;
    var line, a, b;

    line= Line.kr(1,0,1);

    a= SinOsc.ar(440,0,0.1*line); //sound fading out
    b= WhiteNoise.ar(Done.kr(line)*0.1); //noise starts at end of line

    Out.ar(out, Pan2.ar(a+b));
}).add;
)

Synth("Done-help"); //note that this synth doesn't have it's own doneAction, so you'll need to manually deallocate it
  1. According to the Node help document example:
{PinkNoise.ar(1) * Line.kr(1,0,2,doneAction: Done.freeSelf)}.play.onFree {"done".postln};
2 Likes

Thanks for teaching me about .onFree - that’s a nice one.

E

1 Like

[Edited]
This is a self-answer to my previous question, which has been moved to the bottom of this edited answer.

Using s.bind { ... } with .onFree for a synth with a duration shorter than the latency time will not give the expected result. It limits the shortest interval to the next execution to the latency time. So, s.bind{ ... } should not be used with .onFree{ ... }

(
SynthDef(\test, { |freq = 440, amp = 0.1, rT = 1, out = 0|
	var sig = SinOsc.ar(freq * [1, 1.01]);
	sig = sig * Env.perc(0.01, rT).ar(Done.freeSelf) * amp;
	OffsetOut.ar(out, sig)
}).add;
)
(
a = { 
		Synth(\test, 
			[
				\freq, (60..72).choose.midicps,
				\amp, (-24, -21 .. -9).choose.dbamp,
				\rT, 0.1,
			]
		).onFree { a.() }
}
)

a.()

Sorry for asking a very stupid question, but I will not remove this. Someone might make the same logical mistake I did.


My question was as follows:

Hm…
*I have here a question. *
Should s.bind be here used as follows?

(
SynthDef(\test, { |freq = 440, amp = 0.1, rT = 1, out = 0|
	var sig = SinOsc.ar(freq * [1, 1.01]) * amp;
	sig = sig * Env.perc(0.01, rT).ar(Done.freeSelf);
	OffsetOut.ar(out, sig)
}).add;
)

(
a = { 
	s.bind { // necessary?
		Synth(\test, 
			[
				\freq, (60..72).choose.midicps,
				\amp, (-24, -21 .. -9).choose.dbamp,
				\rT, 2 ** (-3..1).choose,
			]
		).onFree { a.() }
	}
}
)

a.()

or as follows?

(
a = { 
		Synth(\test, 
			[
				\freq, (60..72).choose.midicps,
				\amp, (-24, -21 .. -9).choose.dbamp,
				\rT, 2 ** (-3..1).choose,
			]
		).onFree { s.bind { a.() } }
}
)

a.()

Thanks in advance!

Interesting question, though… I’m not clear what is “expected” though.

It looks like you’re trying to do a kind of “temporal recursion” but the limiting factor here is that the performance of the outgoing message is delayed by s.latency seconds, but the /n_end message that triggers onFree doesn’t compensate for this by happening early – and it can’t. There’s no way to do that.

But… bind is used for improved timing precision… while onFree introduces network jitter into the timing cycle. So any timing precision you might have gained by bind is lost by waiting for onFree. So in this case, I’d either 1/ accept timing imprecision and drop bind or 2/ calculate precisely the next-note time and schedule it all on the language side (+ bind, - onFree).

hjh

1 Like

Thanks, I feel I’ve got it!

I expected that the rT with a shorter than latency time could produce a repetition as defined. But it does not. So in the following code, the time interval of a is not the same as the time interval of b:

(
s.waitForBoot {
	SynthDef(\test, { |freq = 440, amp = 0.1, rT = 1, pos = 0, out = 0|
		var sig = SinOsc.ar(freq * [1, 1.01]);
		sig = sig * Env.perc(0.01, rT).ar(Done.freeSelf) * amp;
		sig = Balance2.ar(sig[0], sig[1], pos);
		OffsetOut.ar(out, sig)
	}).add;
	
	s.sync;
	
	a = { |rt = 1|
		Synth(\test, 
			[
				\freq, (60..72).choose.midicps,
				\amp, (-18, -15 .. -9).choose.dbamp,
				\rT, 0.1,
				\pos, -0.8
			]
		).onFree { s.bind {a.(rt)} }
	};
	
	b = { |rt = 1|
		Synth(\test, 
			[
				\freq, (60..72).choose.midicps * 2,
				\amp, (-18, -15 .. -9).choose.dbamp,
				\rT, 0.1,
				\pos, 0.8
			]
		).onFree { b.(rt) }
	};
	
	a.(); 
	b.()
}
)

Repetition with .onFree is not a good design!