// -------------- Overview on doneActions --------------

// a doneAction allows one to free or pause this or other nodes from within a node
// see help file: UGen-doneActions.html

// unit generators that can call a done action:
EnvGen
Line
XLine
Linen
DetectSilence
...

// unit generators that set 'done' flags when finished:

PlayBuf
RecordBuf
BufRd
BufWr
buffer delay ugens ( BufDelayN, BufCombN, BufAllpassN etc.)
Line
XLine
Linen
...

// unit generators that can act on 'done' flags:
Done
FreeSelfWhenDone
PauseSelfWhenDone

// unit generators that can free or pause the enclosing synth or other nodes
FreeSelfWhenDone
PauseSelfWhenDone
FreeSelf
PauseSelf
Free
Pause

// see also:  Synth-Controlling-UGens.html

// using the 'done' flag to release sample player synths:

b = Buffer.loadDialog(s); 

(
SynthDef("sndtest2", { arg buf=0, rate=1, loop=1, amp=1.0; 
	var sig;
	sig = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), loop: loop);  
	FreeSelfWhenDone.kr(sig);		// <-- receives the 'done' flag directly from PlayBuf
	sig = sig * amp;
	Out.ar(0, sig);
	}).play(s, [buf: b.bufnum, loop: 0]);
)

// misplaced FreeSelfWhenDone (because its input is the output of a BinaryOpUgen)
(
SynthDef("sndtest2b", { arg buf=0, rate=1, loop=1, amp=1.0; 
	var sig;
	sig = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), loop: loop);  
	sig = sig * amp;
	FreeSelfWhenDone.kr(sig);		// <-- can't receive the \done flag from PlayBuf anymore!!!
	Out.ar(0, sig);
	}).play(s, [buf: b.bufnum, loop: 0]);
)

// DetectSilence:
(
SynthDef("detect", { arg freq=300;
	var env, trig, sig, thresh;
	thresh = 0.1;
	env = LFNoise2.kr(Rand(1, 2)).range(0, 1);
	DetectSilence.kr(env, thresh, 0, doneAction: 2);
	trig = Impulse.ar(freq * 0.01);
	trig = Decay.ar(trig, (freq * 0.03).reciprocal);
	sig = Resonz.ar(PinkNoise.ar(trig * 20), freq, 0.01) ;
	sig = Pan2.ar(sig * env, Rand(-1.0, 1.0));
	Out.ar(0, sig);
}).store
)

// which one will win the race ?
10.do { arg i;  Synth("detect", [\freq, (i+1).sqrt * 300]) }

// -------------- envelopes --------------

// Linen as a simple and compact fade-in+out envelope generator
(
SynthDef("test1", { arg gate=1;
	var env, sig;
	// a simple envelope:
	env = Linen.kr(gate, 0.1, 1, 1.0, doneAction: 2); 	// doneAction=2  ->  free the synth when done
	sig = BrownNoise.ar(0.1);
	sig = CombN.ar(sig, 0.1, LFTri.kr([0.2, 0.21]).range(0.015, 0.03), 2.0);
	Out.ar(0, sig * env);
}).send(s)
)

y = Synth("test1")
y.set(\gate, 0)		// 1 sec fade out

// the release message sets the release time of the envelope (if any) and sends a \gate message:
y = Synth("test1")
y.release(5.0)		// 5 secs fade out (instead of 1 sec!)

// Env and EnvGen for more flexibility:
(
SynthDef("test2", { arg dur=5;
	var env, sig;
	env = EnvGen.kr(Env([0, 0.5, 0], [ dur*0.8, dur*0.2], \sine), doneAction: 2);
	sig = BrownNoise.ar(0.1);
	sig = CombN.ar(sig, 0.1, LFNoise0.kr([17, 23]).range(0.005, 0.03), 4.0);
	Out.ar(0, sig * env);
}).send(s)
)

y = Synth("test2", [\dur, 10])  // -> the synth kills itself when the envelope ends

// for Env one can set also a release as well as a loop node: 
(
SynthDef("test2b", { arg gate=1, dur=5;
	var env, sig;
	env = EnvGen.kr(Env([0, 0.5, 0], [ dur*0.9, dur*0.1], \sine, releaseNode: 1 ), gate, doneAction: 2);
	sig = BrownNoise.ar(0.1);
	sig = CombN.ar(sig, 0.1, LFNoise0.kr([17, 23]).range(0.005, 0.03), 4.0);
	Out.ar(0, sig * env);
}).send(s)
)

y = Synth("test2b", [\dur, 10])  // -> the envelope is waiting at the releaseNode ...
// ... until the gate is set to 0:
y.set(\gate, 0)		

// EnvGen can also be used for other parameters:
(
SynthDef("test2c", { arg dur=5;
	var env, freq, sig;
	env = EnvGen.kr(Env([0, 0.5, 0], [ dur*0.8, dur*0.2], \sine), doneAction: 2);
	freq = EnvGen.kr(Env([1, 60], [dur], 4));
	sig = BrownNoise.ar(0.1);
	sig = CombN.ar(sig, 0.1, LFNoise0.kr(freq * [1.0, 1.1]).range(0.005, 0.03), 4.0);
	Out.ar(0, sig * env);
}).send(s)
)

y = Synth("test2c", [\dur, 20])  // -> the synth kills itself when the envelope ends

// every envelope or curve generator - not only amp controlling envelopes - can call doneActions: 
(
y = SynthDef("test3", { 
	var freq, sig;
	freq = XLine.kr(10, 5000, 10, doneAction: 2); 	
	sig = Dust.ar(freq * [1, 1.1]);
	Out.ar(0, sig * 0.3);
}).play(s)
)

// -------------- envelope follower --------------

b = Buffer.loadDialog(s); // speech or drum loop

// the Amplitude UGen is an envelope follower:
(
SynthDef("sndtest2", { arg buf=0, rate=1, loop=1, amp=1.0; 
	var sig, env, mod;
	mod = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), loop: loop);  
	env = Amplitude.ar(mod, 0.005, 0.05);
	sig = Pulse.ar([100, 101.7]) * env;
	Out.ar(0, sig);
	}).play(s, [buf: b.bufnum, loop: 1]);
)

// using the envelope follower for the cutoff freq:
(
SynthDef("autowah", { arg buf=0, rate=1, loop=1, amp=1.0; 
	var sig, env;
	sig = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), loop: loop);  
	env = Amplitude.ar(sig, 0.002, 0.02);
	sig = RLPF.ar(sig, env.exprange(100, 1000) * [1, 1.5], 0.01, 0.3);
	sig = Limiter.ar(sig, 0.95);
	Out.ar(0, sig);
	}).play(s, [buf: b.bufnum, loop: 1]);
)

// -------------- triggers --------------

// a trigger is a signal transition from the nonpositive (<=0) to the positive (> 0) domain

// some ugens that act on trigger signals:

Trig
Trig1
SendTrig
TDelay
Latch
PulseCount
Stepper
SetResetFF
ToggleFF
Timer
CoinGate
TRand
TExpRand
FreeSelf
PauseSelf
Free
Pause
Decay
Decay2
PlayBuf
RecordBuf
TGrains
all Demand UGens
...

// some examples:

{ Trig.ar(Dust.ar(1), 0.2) * FSinOsc.ar(800, 0, 0.5) }.play

{ SinOsc.ar( TRand.kr(2000, 3000, Dust.kr(3)), 0, 0.1) }.play

{ SinOsc.ar( TRand.kr(2000, 3000, Dust.kr(3)), 0, 0.2 * ToggleFF.kr(Dust.kr(4))) }.play

// every crossing of the zero line might be used as a trigger signal:

// i.e. also a sine:
{ SinOsc.ar( TRand.kr(2000, 3000, SinOsc.kr(3)), 0, 0.1) }.play

// or an envelope:
(
SynthDef("testtrig", { arg thresh=0.05; 
	var sig, trig, amp;
	trig = SoundIn.ar(0); // reading from the first audio input of the interface  
	trig = Amplitude.ar(trig, 0.002, 0.02) > thresh;
	amp = Decay.ar(trig, 0.1);
	sig = RLPF.ar(Crackle.ar * amp, LFNoise0.kr(11).exprange(50, 500), 0.1) ;
	sig = Limiter.ar(sig, 0.5);
	Out.ar(0, sig);
	}).play;
)

// re-triggering a soundfile:

b = Buffer.loadDialog(s); 

(
SynthDef("sndtest2", { arg buf=0, rate=1, loop=1, amp=1.0; 
	var sig, trig;
	trig = Dust.kr(3);
	sig = PlayBuf.ar(1, buf, rate * BufRateScale.ir(buf), trig, loop: loop);  
	sig = sig * amp;
	Out.ar(0, sig);
	}).play(s, [buf: b.bufnum]);
)

	
// -------------- SendTrig --------------	
	
(
// calling the language when receiving a trigger:	
SynthDef("detector", { arg thresh=0.05;
	var trig;
	trig = SoundIn.ar(0); // reading from the first audio input of the interface  
	trig = Amplitude.ar(trig, 0.002, 0.02) > thresh;
	SendTrig.ar(trig,0,trig);
}).send(s);
)

(
// register to receive this message
OSCresponder(s.addr,'/tr',{ arg time,responder,msg;
	"something happened!\n".postln;
}).add;
)

y = Synth("detector");

y.free;

(
// a responder which generates and plays a new SynthDef on every 'tr' message
OSCresponder(s.addr,'/tr',{ arg time,responder,msg;
	{ SinOsc.ar(rrand(300, 500), 0, XLine.kr(0.5, 0.01, 0.1, doneAction: 2)) }.play;
}).add;
)

y = Synth("detector");

y.free;