rsc3/doc-schelp/HelpSource/Classes/Tdef.schelp

339 lines
9.1 KiB
Text

class:: Tdef
summary:: task reference definition
categories:: Libraries>JITLib>Patterns
related:: Classes/TaskProxy, Classes/Task, Classes/Routine
description::
Tdef provides an interface to its superclass TaskProxy. Tdef keeps a reference to a task ( strong::time pattern:: ) that can be replaced while playing. It continues playing when the old stream ended and a new stream is set and schedules the changes to the beat. One Tdef may be used in many tasks in different places. A change in the task definition Tdef propagates through all tasks.
code::
Tdef(key) //returns the instance
Tdef(key, func) //defines the task and returns the instance, like Pdef and Ndef.
::
Graphical overview over all current Tdefs: link::Classes/TdefAllGui::. Overview: link::Overviews/JITLib::
subsection::First Example
code::
Tdef(\x, { loop { 0.5.wait; "aaaaaaaaaaaaaazz".scramble.postln } }).play;
Tdef(\x, { loop { 0.125.wait; "aazz".scramble.postln } });
Tdef(\x, { loop { 0.5.wait; (note: 14.rand).play } });
Tdef(\x, { loop { 0.5.wait; (note: 14.rand + [0, 3, 6, 7].keep(4.rand)).play } });
Tdef(\x).stop;
Tdef(\x).play;
Tdef(\x).clear;
::
ClassMethods::
private::initClass
subsection::Creation
method::new
Store the task in a global dictionary under key, replacing its routine function with the new one.
Using strong::*new(key):: you can access the pattern at that key (if none is given, a default task is created)
method::default
Default source, if none is given. The default task has a function that waits in 1.0 beat steps and does nothing.
method::removeAll
Remove all proxies from the global dictionary ( link::#*all:: )
method::clear
Clear all proxies, setting their source to silence.
method::all
Set or return the environment ( link::Classes/IdentityDictionary:: ) that stores all instances.
method::defaultQuant
Set the default quantisation for new instances (default: 1.0). This can be an array [quant, phase, timingOffset, outset]
InstanceMethods::
subsection::Changing the definition / setting the source
One Tdef may have many tasks in different places. A change in the task definition Tdef propagates through all tasks. The change does not have to be immediate - there is a scheme to schedule when the change becomes effective: a strong::quant:: and strong::clock:: (like elsewhere) and a strong::condition::.
method::quant
Set the quantisation time for beat accurate scheduling.
argument::val
can be an array strong::[quant, phase, timingOffset, outset] ::, or just strong::[quant, phase]:: etc.
method::condition
Provide a condition under which the pattern is switched when a new one is inserted. The stream value and a count value is passed into the function.
method::count
Create and update condition that simply counts up to n and switches the pattern then
method::reset
Switch the task immediately (stuck conditions can be subverted by this).
method::envir
Set the environment (an link::Classes/Event::) for the Tdef. strong::It is passed as first argument into the Task function::.
method::set
Set arguments in the default event. If there is none, it is created and the task routine is rebuilt.
method::clear
Set the source to nil
method::endless
Returns a link::Classes/Prout:: that plays the task endlessly, replacing strong::nil:: with a strong::default:: value 1. This allows to create streams that idle on until a new pattern is inserted.
subsection::Tdef as stream reference
A single Tdef may serve as a definition for multiple tasks. These methods show how to fork off separate routines from one instance. Even if they run in different contexts, their definition may still be changed.
method::fork
Play an independent task in parallel.
argument::clock
the clock on which to play the forked task
argument::quant
can be an array of [quant, phase, offset], or a link::Classes/Quant:: value.
argument::event
an event to pass into the forked task
method::embed
Pass a value (typically an link::Classes/Event::) into the task function, and embed the Tdef in the stream.
method::embedInStream
just like any pattern, embeds itself in stream
subsection::Tdef as EventStreamPlayer
For live coding, each Tdef also may control one instance that plays one task. This is a link::Classes/PauseStream::, accessible in the instance variable link::#-player::.
method::play
Starts the Tdef and creates a player.
argument::argClock
a clock on which to play the Tdef
argument::doReset
a flag whether to reset the task if already playing
argument::quant
can be an array of [quant, phase, offset] or a link::Classes/Quant:: value.
method::stop
Stops the player
method::player
Return the current player (if the Tdef is simply used in other streams this is nil)
method::pause, resume, reset
Perform this method on the player.
method::isPlaying
Returns true if player is running. If a Tdef is playing and its stream ends, it will schedule a stream for playing strong::as soon as a new one is assigned to it::. If it is stopped by strong::stop::, it won't.
Examples::
subsection::Tdef as a Task player
code::
Tdef(\x).play; // create an empty Tdef and play it.
Tdef(\x, { loop({ "ggggggggggggggggg9999ggg999ggg999gg".scramble.postln; 0.5.wait; }) });
Tdef(\x, { loop({ "---------////----------------------".scramble.postln; 0.25.wait; }) });
Tdef(\x, { loop({ thisThread.seconds.postln; 1.wait; }) });
Tdef(\x, { loop({ thisThread.seconds.postln; 1.01.wait; }) });
TempoClock.default.tempo = 2;
Tdef(\x, { "the end".postln });
Tdef(\x, { "one more".postln });
Tdef(\x, { 10.do({ "ten more".scramble.postln; 0.25.wait; }) });
Tdef(\x, { loop({ "lots more".scramble.postln; 0.25.wait; }) });
TempoClock.default.tempo = 1;
Tdef(\x).stop;
Tdef(\x).play;
Tdef(\x).clear;
::
code::
// sound example
(
// load a synthdef
s.boot;
SynthDef(\pdef_grainlet,
{ arg out=0, freq=440, sustain=0.05;
var env;
env = EnvGen.kr(Env.perc(0.01, sustain, 0.3), doneAction: Done.freeSelf);
Out.ar(out, SinOsc.ar(freq, 0, env))
}).add;
)
Tdef(\x).play;
(
Tdef(\x, {
loop({
s.sendMsg("/s_new", "pdef_grainlet", -1,0,0, \freq, rrand(600, 640));
0.1.wait;
})
})
)
(
Tdef(\x, {
var x;
x = Pseries(300, 20, 100).loop.asStream;
loop({
s.sendMsg("/s_new", "pdef_grainlet", -1,0,0, \freq, x.next);
0.05.wait;
})
})
)
(
Tdef(\x, {
var x;
x = Plazy({ Pseries(300 + 300.rand, 10 + 30.rand, 10 + 30.rand) }).loop.asStream;
loop({
s.sendMsg("/s_new", "pdef_grainlet", -1,0,0, \freq, x.next);
0.05.wait;
})
})
)
// metronome
Tdef(\y, { loop({ s.sendMsg("/s_new", "pdef_grainlet", -1,0,0, \freq, 1500); 1.wait; }) }).play;
// play ending stream once
(
Tdef(\x, {
var x, dt;
dt = [0.1, 0.125, 0.05].choose;
x = Plazy({ Pseries(1300 + 300.rand, 110 + 130.rand, 16) }).asStream;
x.do({ arg item;
s.sendMsg("/s_new", "pdef_grainlet", -1,0,0, \freq, item);
dt.wait;
})
})
)
// ... and so on ...
Tdef(\x).stop;
Tdef.removeAll;
::
subsection::Embed and fork: Tdef within other Tasks / Routines
code::
// embed plays tdefs in sequence within a task.
(
Tdef(\a, { "one".postln; 1.wait; "two".postln });
Tdef(\c, { var z; z = Synth(\default); 0.5.wait; z.release });
r = Task({
"counting...".postln;
2.wait;
Tdef(\a).embed;
1.wait;
Tdef(\c).embed;
"done.".postln;
});
)
r.play; // play a stream
Tdef(\c, { var z; z = Synth(\default, [\freq, 300]); 1.5.wait; z.release }); // change the def
r.reset;
r.play;
// of course Tdefs can be used in other Tdefs:
(
Tdef(\a, { 10.do { |i| (" a: " + i).postln; 0.3.wait; } });
Tdef(\b, { 15.do { |i| ("\t\t b: " + i).postln; 0.2.wait; } });
Tdef(\c, { 5.do { |i| ("\t\t\t\t c: " + i).postln; 0.5.wait; } });
Tdef(\d, {
"embed - sequence.".postln;
1.wait;
Tdef(\a).embed;
1.wait;
Tdef(\b).embed;
1.wait;
Tdef(\c).embed;
"done.".postln;
});
)
Tdef(\d).play;
// to start a tdef in its own separate thread, thus branching into parallel threads,
// one can use .fork, or .playOnce
(
Tdef(\a, { 10.do { |i| (" a: " + i).postln; 0.3.wait; } });
Tdef(\b, { 15.do { |i| ("\t\t b: " + i).postln; 0.2.wait; } });
Tdef(\c, { 5.do { |i| ("\t\t\t\t c: " + i).postln; 0.5.wait; } });
Tdef(\d, {
"fork - parallel.".postln;
1.wait;
Tdef(\a).fork;
1.wait;
Tdef(\b).fork;
1.wait;
Tdef(\c).fork;
"done.".postln;
});
)
::
subsection::Tdef as a time pattern
Instead of using a link::Classes/Pdefn:: for time values, it can be useful to use a Tdef. When changing its source, it keeps the stream of values synchronized to its clock.
code::
(
// load a synthdef
s.boot;
SynthDef("pdef_grainlet",
{ arg out=0, freq=440, sustain=0.05;
var env;
env = EnvGen.kr(Env.perc(0.01, sustain, 0.3), doneAction: Done.freeSelf);
Out.ar(out, SinOsc.ar(freq, 0, env))
}).add;
)
Tdef(\z, Pseq([1, 1, 1, 0.5, 0.5], inf));
(
Pset(\instrument, \pdef_grainlet,
Ppar([
Pbind(
\dur, Tdef(\z),
\note, Pseq([1, 3, 2, 1, 0], inf),
\x, Pfunc { TempoClock.default.elapsedBeats.postln } // posts the onset times
),
Pbind(
\dur, 4, // reference beat
\sustain, 0.1,
\note, 8
)
])
).play(quant:1);
)
Tdef(\z, Prand([1, 1, 0.23, 0.5, 0.5], inf)); // exchange time pattern
Tdef(\z, Pseq([1, 1, 1, 1], inf)); // pattern stays in sync.
Tdef(\z, Pseq([1, 1, 1, 0.5, 0.5], inf)); // but might be in different order.
// to avoid this, set quant to an appropriate value.
::