title:: jitlib_fading
summary:: Fade envelope generation and crossfading
categories:: JITLib>Tutorials, Tutorials>JITLib
related:: Overviews/JITLib

link::Classes/NodeProxy:: ( link::Classes/ProxySynthDef:: ) looks for inner envelopes in your definition function to find out whether a fade envelope is needed or not. In case there is no other inner possibility of freeing the synth, either

list::
## link::#a)_automatic_fade_envelope_generation#a):: a fade envelope is created (audio / control rate output)
## link::#b)_automatic_free_instead_of_crossfade#b):: the synth is freed directly with no fading (scalar output or doneAction 1)

## link::#c)_custom_fade_envelope#c):: if you provide a gate arg and a doneAction 2 to your ugenGraph function, this is supposed to be a fade envelope for the synth

## link::#d)_synthdef_name_assignment#d):: if a synthdef name is used, case link::#c)_custom_fade_envelope#c):: is supposed
::

... so in most cases, there is not much to worry about, just these two points ar important, if one wants to use a self releasing synth or a different out ugen:

list::
## link::#e)_own_free_responsibility#e):: own responsibility: if the function creates a ugengraph that can be freed by trigger or other things, it waits for this action instead of the node proxy freeing the synth.

## link::#f)_own_output_responsibility#f):: own out channel with 'out' arg: the control ugen with the name 'out' is set to the output channel number of the proxy.
::

code::
p = ProxySpace.push(s.boot);

~out.play;

// note that you can use this functionality also when using ProxySynthDef directly:

d = ProxySynthDef("test", { arg freq=440; SinOsc.ar(freq) }).send(s);
s.sendMsg("/s_new", "test", 1980, 1, 1, \freq, 340);
s.sendMsg("/n_set", 1980, \freq, 240);
s.sendMsg("/n_set", 1980, \fadeTime, 4);
s.sendMsg("/n_set", 1980, \gate, 0);
::

section::a) automatic fade envelope generation

code::
// no inner envelope and audio / control rate output
(
~out = { PinkNoise.ar([1,1]*0.1) };
)

(
~kout = { PinkNoise.kr([1,1]*0.1) };
)
::

section::b) automatic free instead of crossfade

code::
// inner envelope that cannot free the synth, the synth is freed when a new
// function is assigned.
(
~out = { arg t_trig; EnvGen.kr(Env.asr, t_trig) * PinkNoise.ar([1,1]) };
)
~out.group.set(\t_trig, 1);

(
~out = { arg t_trig; EnvGen.kr(Env.asr, t_trig) * SinOsc.ar([1,1]*400) };
)
~out.group.set(\t_trig, 1);


// for a scalar output also no fade env is created, but the synth is freed (without fading)
(
~out = { Out.ar(0, SinOsc.ar(Rand(440,550),0,0.2)) };
)
::

section::c) custom fade envelope

code::
// when a gate arg is provided, and the env can free the synth, this envelope
// is supposed to be the fade envelope for the synth: no extra fade env is created.
(
~out = { arg gate=1; EnvGen.kr(Env.asr, gate, doneAction: Done.freeSelf) * 0.2 * SinOsc.ar([1,1]*Rand(440,550)) };
)
::

section::d) SynthDef name assignment

code::
// if a symbol is used as input, the defname of a def on the server is supposed
// to represent a SynthDef that has a gate, an out input and can free itself.
(
~out = \default;
)

// this is the minimal requirement arguments for such a use (similar to Pbind)
(
SynthDef("test", { arg gate=1, out;
	Out.ar(out, Formant.ar(300, 200, 10) * EnvGen.kr(Env.asr, gate, doneAction: Done.freeSelf))
}).send(s);
)

// you can also provide a fadeTime arg, whic is set by the proxy:
(
SynthDef("test", { arg gate=1, out, fadeTime=1;
	Out.ar(out,
		Formant.ar(Rand(20,40), 600, 10, 0.2)
		* EnvGen.kr(Env.asr(fadeTime,1,fadeTime), gate, doneAction: Done.freeSelf)
	)
}).send(s);
)

~out = \test;
~out.fadeTime = 3;
::

note::
the strong::number of channels:: is your own responsibility when using symbols, as a symbol carries no channel information! (in all other cases the number of channels is wrapped or expanded to fit the proxy)
::

code::
// if the synthdef has a fixed duration envelope, there is a FAILURE /n_set Node not found message.
// with no further significance
(
SynthDef("test", { arg gate=1, out;
	Out.ar(out,
		Formant.ar(Rand(20,40), 600, 10, 0.6)
		* EnvGen.kr(Env.perc, gate, doneAction: Done.freeSelf)
	)
}).send(s);
)

~out = \test;
::

section::e) own free responsibility

code::
//inner envelope that can free the synth, no extra fade env is created:
(
~out = { arg t_trig; EnvGen.kr(Env.asr, t_trig, doneAction: Done.freeSelf) * PinkNoise.ar([1,1]) };
)
~out.group.set(\t_trig, 1); //end it

~out.send; //start a new synth
~out.group.set(\t_trig, 1); //end it again


// if there is a ugen that can free the synth, no extra fade env is created either,
// but it supposes the synth frees itself, so if a new function is assigned it does
// not get freed.
(
~out = { arg t_trig;
	FreeSelf.kr(t_trig);
	PinkNoise.ar([1,1]*0.3);
};
)
~out.group.set(\t_trig, 1);
::

section::f) own output responsibility

code::
// the arg name 'out' can be used to output through the right channel.
// of course with this one can get problems due to a wrong number of channels
// or deliberate hacks.

//left speaker
(
~out = { arg out;
	OffsetOut.ar(out, Impulse.ar(10,0,0.1))
}
)

//both speakers
(
~out = { arg out;
	OffsetOut.ar(out, Impulse.ar([10, 10],0,0.1))
}
)

//this plays out into another adjacent bus: this is a possible source of confusion.
(
~out = { arg out;
	OffsetOut.ar(out, Impulse.ar([10, 10, 10],0,0.1))
}
)
::
