317 lines
7 KiB
Text
317 lines
7 KiB
Text
|
#lang scribble/manual
|
||
|
@(require (for-label racket))
|
||
|
|
||
|
@title{Pdefn}
|
||
|
non event stream reference definition@section{categories}
|
||
|
Libraries>JITLib>Patterns, Live Coding
|
||
|
@section{related}
|
||
|
Classes/Pdef
|
||
|
|
||
|
@section{description}
|
||
|
|
||
|
Pdefn provides an interface to its superclass link::Classes/PatternProxy::, keeping a reference to a stream that can be replaced while playing. One pattern may be used in many streams in different places. A change in the pattern definition propagates through all streams.
|
||
|
|
||
|
Pdef and Pdefn use separate global collections.
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
Pdefn(key) //returns the instance
|
||
|
Pdefn(key, pat) //defines the pattern and returns the instance, like Pdef, Tdef and Ndef.
|
||
|
::
|
||
|
|
||
|
It is very similar to link::Classes/PatternProxy::.
|
||
|
|
||
|
Pdefn can be used to store value patterns globally (for strong::event patterns::, see link::Classes/Pdef::). Overview: link::Overviews/JITLib::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
First Example
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
s.boot;
|
||
|
|
||
|
Pdefn(\x, Pbrown(0, 6, 0.1, inf));
|
||
|
Pbind(\note, Pdefn(\x), \dur, 0.3).play;
|
||
|
Pbind(\note, Pdefn(\x), \dur, 0.1, \ctranspose, 15).play;
|
||
|
// now change the definition
|
||
|
Pdefn(\x, Pseq([0, 3, 5, 7, 9, 11], inf));
|
||
|
Pdefn(\x, Pseq([0, 3, 3, 7], inf) + Pseq([0, [0, 3], [0, 5, 7]], inf));
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{ClassMethods}
|
||
|
|
||
|
|
||
|
@section{private}
|
||
|
initClass
|
||
|
|
||
|
@section{subsection}
|
||
|
Creation
|
||
|
|
||
|
@section{method}
|
||
|
new
|
||
|
Store the pattern in a global dictionary under key, replacing its pattern with the new one. If the pattern is a strong::function::, Pdefn creates a link::Classes/Prout:: with this function, passing in the envir, if given(see below).
|
||
|
|
||
|
Using strong::*new(key):: you can access the pattern at that key (if none is given, a default silent event is created)
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
|
||
|
// pattern as an argument
|
||
|
Pdefn(\x, Pseq([1, 2, 5, 6, 7], inf));
|
||
|
Pdefn(\x); // omitting the second argument, we can access the proxy
|
||
|
Pdefn(\x).asStream.nextN(20); // ... play one event stream
|
||
|
Pdefn(\x).source.postcs; // ... and inspect the event pattern itself.
|
||
|
|
||
|
|
||
|
// function as an argument, create a new pattern each time it is called
|
||
|
Pdefn(\x, { Pseq({ 10.rand } ! 8) });
|
||
|
Pn(Pdefn(\x)).asStream.nextN(16);
|
||
|
|
||
|
// the function is called in the incoming event as current environment, so parameters can be passed:
|
||
|
Pdef(\stut, { Pstutter(~stutter ? 1, ~pattern) }); // we use here a Pdef (not a Pdefn!)
|
||
|
Pdefn(\y, Pdef(\stut) <> (pattern: Pdefn(\x), stutter: Pseq([2, 2, 4, 3], inf))).asStream.nextN(16);
|
||
|
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{method}
|
||
|
default
|
||
|
Default source, if none is given. The default is a Pattern that returns 1.0 (This is 1 and not 0 to avoid deadlocks when used as a duration pattern. In a sense, 1 is just as generic as 0).
|
||
|
|
||
|
@section{method}
|
||
|
removeAll
|
||
|
Remove all proxies from the global dictionary ( link::#*all::)
|
||
|
|
||
|
@section{method}
|
||
|
clear
|
||
|
Clear all proxies, setting their source to silence.
|
||
|
|
||
|
@section{method}
|
||
|
all
|
||
|
Set or return the environment ( link::Classes/IdentityDictionary:: ) that stores all Pdefns.
|
||
|
|
||
|
@section{InstanceMethods}
|
||
|
|
||
|
|
||
|
@section{private}
|
||
|
prAdd
|
||
|
|
||
|
@section{Examples}
|
||
|
|
||
|
|
||
|
@section{subsection}
|
||
|
Pdefn in expressions
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
Pdefn(\c, Pdefn(\a) + Pdefn(\b));
|
||
|
|
||
|
t = Pdefn(\c).asStream; // create a stream from Pdefn(\c)
|
||
|
|
||
|
t.value; // default value for a Pdefn is 1, so that it is a good time value default.
|
||
|
|
||
|
Pdefn(\a, 100); // (re)define Pdefn(\a) as 100
|
||
|
|
||
|
t.value;
|
||
|
|
||
|
Pdefn(\b, Pseq([1, 2, 3], inf)); // (re)define Pdefn(\b) as Pseq([1, 2, 3], inf)
|
||
|
|
||
|
3.do { t.value.postln };
|
||
|
|
||
|
Pdefn(\c, Pdefn(\a) * Pdefn(\b) - Pdefn(\a)); // (re)define Pdefn(\c)
|
||
|
|
||
|
8.do { t.value.postln };
|
||
|
|
||
|
Pdefn(\a, Prand([1, 4, 2], inf)); // (re)define Pdefn(\a)
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
Embedding Pdefn in other patterns
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
Pdefn(\x, Pseq([1, 2, 3], inf));
|
||
|
|
||
|
x = Pseq([0, 0, Pdefn(\x)], inf).asStream;
|
||
|
|
||
|
t = Task({ loop({ x.next.postln; 0.3.wait }) }).play;
|
||
|
|
||
|
|
||
|
Pdefn(\x, Pseq([55, 66, 77],inf));
|
||
|
Pdefn(\x, Pseq([55, 66, 77],1));
|
||
|
|
||
|
t.stop;
|
||
|
|
||
|
|
||
|
|
||
|
// Pdefn can be accessed in multiple streams
|
||
|
|
||
|
(
|
||
|
SynthDef("Pdefhelp", { arg out, freq, sustain=1, amp=1, pan;
|
||
|
var env, u=1;
|
||
|
env = EnvGen.kr(Env.perc(0.03, sustain), 1, doneAction: Done.freeSelf);
|
||
|
5.do { var d; d = exprand(0.01, 1); u = SinOsc.ar(d * 300, u, rrand(0.1,1.2) * d, 1) };
|
||
|
Out.ar(out, Pan2.ar(SinOsc.ar(u + 1 * freq, 0, amp * env), pan));
|
||
|
|
||
|
}).add;
|
||
|
s.boot;
|
||
|
)
|
||
|
|
||
|
(
|
||
|
Pdefn(\deg, Pseq([0, 3, 2],inf));
|
||
|
|
||
|
Pset(\instrument, \Pdefhelp,
|
||
|
Ppar([
|
||
|
Pbind(\degree, Pdefn(\deg), \pan, -0.8),
|
||
|
Pbind(\degree, Pdefn(\deg), \dur, 1/3, \pan, 0.8)
|
||
|
])
|
||
|
).play;
|
||
|
)
|
||
|
|
||
|
Pdefn(\deg, Prand([0, 3, [1s, 4]],inf));
|
||
|
|
||
|
Pdefn(\deg, Pn(Pshuf([0, 3, 2, 7, 6],2),inf));
|
||
|
|
||
|
(
|
||
|
Pdefn(\deg, Plazy { var pat;
|
||
|
pat = [Pshuf([0, 3, 2, 7, 6],2), Pseries(0, 1, 11), Pseries(11, -1, 11)].choose;
|
||
|
Pn(pat, inf)
|
||
|
});
|
||
|
)
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
Timing
|
||
|
|
||
|
When does the definition change?
|
||
|
|
||
|
If quant is set, the update is done at the next beat or whatever is specified:
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
Pdefn(\deg).quant = 4;
|
||
|
Pdefn(\deg, Pn(Pseries(0, 1, 8),inf));
|
||
|
|
||
|
Pdefn(\deg).quant = nil; // activate immediately again
|
||
|
|
||
|
(
|
||
|
Pdefn(\deg, {
|
||
|
loop {
|
||
|
5.do { |i|
|
||
|
#[1, 3, 4].choose.yield;
|
||
|
#[5, 0, 12].choose.yield;
|
||
|
#[14, 3, 4].choose.do { |j| (i % j).postln.yield };
|
||
|
}
|
||
|
}
|
||
|
})
|
||
|
)
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
update condition
|
||
|
|
||
|
In order to be able to switch to a new pattern under a certain condition, the instance variable strong::condition:: can be set to a function that returns a boolean. Value and a count index are passed to the function. The condition is always valid for the strong::next pattern:: inserted. For stuck conditions, the strong::reset:: message can be used.
|
||
|
|
||
|
As counting up (such as emphasis::"every nth event, a swap can happen"::) is a common task, there is a method for this, called strong::count(n)::.
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
z = Pbind(\degree, Pdefn(\x, \), \dur, 0.25).play;
|
||
|
Pdefn(\x, Pseq((0..5), inf)).condition_({ |val, i| i.postln % 6 == 0 });
|
||
|
Pdefn(\x, Pseq((7..0), inf)).condition_({ |val, i| i.postln % 8 == 0 });
|
||
|
|
||
|
|
||
|
// the above is equvalent to:
|
||
|
Pdefn(\x, Pseq((7..0), inf)).count(8);
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
Reset
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// reset to change immediately:
|
||
|
Pdefn(\x).reset;
|
||
|
|
||
|
Pdefn(\x).stop;
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
Functions as arguments to Pdefn
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
Pdefn(\deg, { loop { yield(0.1.rand.round(0.01) + [2, 3, 9].choose) } });
|
||
|
|
||
|
// equivalent to:
|
||
|
|
||
|
Pdefn(\deg, Prout { loop { yield(0.1.rand.round(0.01) + [2, 3, 9].choose) } });
|
||
|
|
||
|
// this is not exactly true, see below..
|
||
|
::
|
||
|
|
||
|
]
|
||
|
@section{subsection}
|
||
|
The (inner) environment
|
||
|
|
||
|
|
||
|
@racketblock[
|
||
|
// set() creates a local environment that overrides the outer currentEnvironment
|
||
|
|
||
|
Pdefn(\z).set(\a, 1, \b, 5);
|
||
|
(
|
||
|
Pdefn(\z, { |e|
|
||
|
loop { yield((e.a + e.b) + 0.1.rand.round(0.01)) }
|
||
|
})
|
||
|
); // [1]
|
||
|
|
||
|
t = Pdefn(\z).asStream;
|
||
|
|
||
|
t.nextN(3);
|
||
|
|
||
|
(
|
||
|
Pdefn(\z, { |e|
|
||
|
//(e.a + e.b) + 0.1.rand.round(0.01) 1
|
||
|
Pseq([1, 2, e.a], 1)
|
||
|
})
|
||
|
);
|
||
|
|
||
|
Pdefn(\z, Pseq([1, 2, 3], 1));
|
||
|
|
||
|
e = Pdefn(\z).envir
|
||
|
|
||
|
|
||
|
Pdefn(\z).set(\a, 3);
|
||
|
|
||
|
t.next;
|
||
|
|
||
|
Pdefn(\z).set(\a, Pseq([1, 2, 3], inf));
|
||
|
|
||
|
t.reset;
|
||
|
t.nextN(3);
|
||
|
|
||
|
Pdefn(\z).envir; // post the envir
|
||
|
|
||
|
|
||
|
|
||
|
// if you want to keep using the currentEnvironment at the same time,
|
||
|
// assign the currentEnvironment to the envir's parent (or proto) field
|
||
|
// (this shouldn't be a proxy space of course.)
|
||
|
|
||
|
Pdefn(\z).envir.parent = currentEnvironment;
|
||
|
~a = 9;
|
||
|
~b = 10;
|
||
|
|
||
|
t.nextN(3);
|
||
|
::
|
||
|
]
|
||
|
|
||
|
|