217 lines
5.5 KiB
Text
217 lines
5.5 KiB
Text
|
#lang scribble/manual
|
||
|
@(require (for-label racket))
|
||
|
|
||
|
@title{jitlib_fading}
|
||
|
Fade envelope generation and crossfading@section{categories}
|
||
|
Libraries>JITLib>Tutorials, Tutorials>JITLib
|
||
|
@section{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
|
||
|
|
||
|
@section{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:
|
||
|
|
||
|
@section{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.
|
||
|
::
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
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{section}
|
||
|
a) automatic fade envelope generation
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// no inner envelope and audio / control rate output
|
||
|
(
|
||
|
~out = { PinkNoise.ar([1,1]*0.1) };
|
||
|
)
|
||
|
|
||
|
(
|
||
|
~kout = { PinkNoise.kr([1,1]*0.1) };
|
||
|
)
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{section}
|
||
|
b) automatic free instead of crossfade
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// 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{section}
|
||
|
c) custom fade envelope
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// 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{section}
|
||
|
d) SynthDef name assignment
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// 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;
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{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)
|
||
|
::
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// 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{section}
|
||
|
e) own free responsibility
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
//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{section}
|
||
|
f) own output responsibility
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// 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))
|
||
|
}
|
||
|
)
|
||
|
::
|
||
|
]
|
||
|
|
||
|
|