340 lines
9.1 KiB
Text
340 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.
|
||
|
::
|