| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 
 | class:: Pdef
summary:: stream reference definition
categories:: Libraries>JITLib>Patterns
related:: Classes/Pdefn, Classes/PdefGui
description::
Pdef is a class that provides an interface to its superclass link::Classes/EventPatternProxy::, 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.
code::
Pdef(key)	//returns the instance
Pdef(key, pat)	//stores the pattern and returns the instance, like Tdef and Ndef.
::
It can be used to store event Patterns globally. Changes in this global library have immediate effect.
For strong::non-event patterns:: link::Classes/Pdefn:: is used instead. For another use of Pdef see also link::Tutorials/JITLib/recursive_phrasing::. Graphical overview over all current Pdefs: link::Classes/PdefAllGui::. Overview: link::Overviews/JITLib::.
subsection::First Example
code::
s.boot;
Pdef(\x, Pbind(\note, Pbrown(0, 6, 0.1, inf)));
Pdef(\x).quant = 0; // no waiting.
Pbindf(Pdef(\x), \dur, 0.03).play;
Pbindf(Pdef(\x), \dur, 0.1, \ctranspose, 15).play;
Pbindf(Pdef(\x), \dur, 0.3, \ctranspose, 2).play;
// now change the definition
Pdef(\x, Pbind(\note, Pseq([0, 3, 5, 7, 9, 11], inf)));
Pdef(\x, Pbind(\freq, Pseq([1000, 1923, 245.2, 1718] / 1.2 + 0.1, inf)));
::
ClassMethods::
private::initClass
subsection::Creation
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::, Pdef creates a link::Classes/PlazyEnvir:: internall that dynamically creates the pattern returned from the function, applying the arguments from the inevent.
Using strong::*new(key):: you can access the pattern at that key (if none is given, a default silent event is created)
method::default
Default source, if none is given. The default is an Event.silent of 1.0 beat duration.
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 Pdefs.
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 pattern may have many streams in different places. A change in the pattern definition Pdef propagates through all streams. 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 pattern immediately (stuck conditions can be subverted by this).
method::fadeTime
When the synthdefs that are used contain an code::\amp:: control, the patterns are replaced by crossfading the previous with the new over this time (in beats)
method::envir
Set the event for the Pdef. It is used to filter the incoming stream before it is passed to the source pattern. This is similar to link::Classes/NodeProxy#-nodeMap::. When set for the first time, the pattern is rebuilt.
method::set
Set arguments in the default event. If there is none, it is created and the pattern is rebuilt.
method::map
Map Pdefn to the keys in the event.
method::clear
Set the source to nil
method::endless
Returns a link::Classes/Prout:: that plays the proxy endlessly, replacing strong::nil:: with a strong::default:: value (silent event). This allows to create streams that idle on until a new pattern is inserted.
subsection::Pdef as stream reference
A single Pdef may serve as a definition for multiple streams. These methods show how to fork off separate streams from one instance. Even if they run in different contexts, their definition may still be changed.
method::fork
Play an independent stream in parallel.
argument::quant
can be an array of [quant, phase, offset], or a link::Classes/Quant:: value.
method::embed
Pass a value (typically an link::Classes/Event::) into the pattern inval, and embed the Pdef in the stream.
embedInStream
just like any pattern, embeds itself in stream
subsection::Pdef as EventStreamPlayer
For live coding, each Pdef also may control one instance that plays one stream off it. This is an link::Classes/EventStreamPlayer::, accessible in the instance variable link::#-player::.
method::play
Starts the Pdef and creates a player.
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 Pdef 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 Pdef 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::Pdef as stream reference
code::
(
SynthDef("Pdefhelp", { arg out, freq, sustain=1, amp=1, pan;
	var env, u=1;
	env = EnvGen.kr(Env.perc(0.03, sustain), 1, doneAction:2);
	3.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;
Pdef(\metronom, Pbind(\instrument, \Pdefhelp, \dur, 1, \degree, 16, \legato, 0.1)).play;
x = Pseq([Pdef(\a), Pdef(\b), Pdef(\c)], inf).play;
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.25, \degree, Pseq(#[0, 5, 4, 3])));
Pdef(\b, Pbind(\instrument, \Pdefhelp, \dur, 0.125, \degree, Pseq(#[7, 8, 7, 8])));
Pdef(\c, Pbind(\instrument, \Pdefhelp, \dur, 0.25, \degree, Pseq(#[0, 1, 2], 2)));
Pdef(\c, Pbind(\instrument, \Pdefhelp, \dur, 0.25, \degree, Pseq(#[4, 3, 1, 2]*3)));
// infinite loops are scheduled (to ths clock's next beat by default) and released:
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.753, \degree, Pseq(#[0, 5, 4, 3, 2], inf)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.125, \degree, Pseq(#[0, 5, 4, 3] + 1, 1)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.25, \degree, Pseq(#[0, 5, 4, 3] - 4, 1)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.125, \degree, Pseq(#[0, 5] - 1, 1)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.753, \degree, Pshuf(#[0, 5, 4, 3, 2], inf)));
x.stop;
Pdef(\metronom).stop;
// Pdef can be used in multiple patterns:
(
x = Ppar([
	Pbindf(Pn(Pdef(\a), inf),
		\gtranspose, Pstutter(8, Pseq(#[0, 2, 0, 3],inf))
	),
	Pbindf(Pn(Pdef(\a), inf),
		\gtranspose, Pstutter(8, Pseq(#[7, 4, 0, 3],inf)),
		\dur, 0.6
	),
	Pbindf(Pn(Pdef(\a), inf),
		\degree, Pseq(#[0, 5, 4, 3, 2, 3, 2], 1)
	)
]).play;
)
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.1, \degree, Pseq(#[0, 1, 0, 1, 2], inf)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.2, \degree, Pseq([0, 4], inf)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 1, \degree, Pseq([0, 4], inf)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.2, \degree, Pseq([0, 4, Prand([6, 8b],2)], inf)));
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.1, \degree, Pseq(#[0, 1b, 1, 2b, 2, 3, 4b, 4, 5], inf)));
// using a fade time, the above changes are crossfaded
Pdef(\a).fadeTime = 2;
Pdef(\a, Pbind(\instrument, \Pdefhelp, \dur, 0.2, \degree, Pseq([0, 4, Prand([6, 8b],2)], inf)));
// ...
Pdef(\a).set(\detune, -50); // set environment
Pdef(\a).set(\detune, 0);
x.stop;
::
subsection::Pdef as EventStreamPlayer
code::
(
// load a synthdef
s.boot;
SynthDef("gpdef",
	{ arg out=0, freq=440, sustain=0.05, amp=0.1, pan;
		var env;
		env = EnvGen.kr(Env.perc(0.01, sustain), doneAction:2) * amp;
		Out.ar(out, Pan2.ar(SinOsc.ar(freq, 0, env), pan))
	}).add;
)
Pdef(\x); // creates a Pdef with a default pattern.
Pdef(\x).play; // play it. A silent resting pattern is used.
Pdef(\y).play; // play a second one (automatically instantiated)
// assign various patterns to it:
Pdef(\x, Pbind(\dur, 0.25, \instrument, \gpdef));
Pdef(\x, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5b, 6], inf), \instrument, \gpdef));
Pdef(\x, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5b, 6]+1, inf), \instrument, \gpdef));
Pdef(\y, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5b, 6]-1, inf), \instrument, \gpdef));
Pdef(\y, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5b]-2, inf), \instrument, \gpdef));
// using fadeTime:
Pdef(\y).fadeTime = 8.0;
Pdef(\y, Pbind(\dur, 0.125, \degree, Pseq([3, 4, 5b, 6]+4.rand, inf), \instrument, \gpdef));
Pdef(\y, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5b, 6]-2, inf), \instrument, \gpdef));
(
Pdef(\x, Pbind(
		\dur, 1 / 6,
		\degree, Pseq([3, 4, Prand([8, 2, 3, 9, 10],1) - 5, 6]+1, inf),
		\instrument, \gpdef
		)
	);
)
(
Pdef(\x, Pbind(
		\dur, 0.25,
		\degree, Pseq([3, 4, Prand([8, 2, 3, 9, 10],1), 6], inf),
		\instrument, \gpdef)
	);
)
Pdef(\x).stop;
Pdef(\x).play;
// tempo change
TempoClock.default.tempo = 1.3;
Pdef(\y, Pbind(\dur, 0.25, \degree, Pseq([3, 4, 5, 6]+1, inf), \instrument, \gpdef));
// drop in ending patterns
Pdef(\x, Pbind(\dur, 0.25, \degree, Pseq([3, [7,4], 5, 6]-2), \instrument, \gpdef));
Pdef(\x, Pbind(\dur, 0.125, \degree, Pseq([3, [7,4], 5, 4]-3), \instrument, \gpdef));
Pdef(\x, Pbind(\dur, 0.35, \degree, Pseq([3, [7,4], 5, 4, 3]-3), \instrument, \gpdef));
Pdef(\x, Pbind(\dur, 0.25, \degree, Pshuf([3, [7,4], 5, 6]-2), \instrument, \gpdef));
// clear all.
Pdef(\x).clear;
Pdef(\y).clear;
TempoClock.default.tempo = 1.0;
// GUI example: see also
PdefAllGui(18);
::
subsection::Recursion
Pdefs can be used recursively under the condition that the stream call structure allows it. a structure like the following works:
code::
Pdef(\x, Pseq([Pbind(\instrument, \gpdef), Pdef(\x)], inf));
Pdef(\x).play;
::
but the following would crash, because code::.embedInStream:: is called recursively with no limit:
code::
// Pdef(\y, Pseq([Pdef(\y), Pbind(\instrument, \gpdef)], inf));
::
subsection::Quantizing and outset
When quantizing to a larger number of beats, the changes become very slow if one has to wait for the next beat. Providing an strong::outset:: quant value is a way to make the change so that it appears as if it had been done at the previous grid point already. The stream is fast forwarded to the current position relative to the quant grid. Providing a number larger than zero, the next possible quant point is used as outset.
For example, if quant is 32, and one has just missed the first beat when changing the pattern,
one has to wait for 32 beats until the change happens. Using an outset of 1, it is assumed that you had already
changed the pattern at the first beat, the stream is fast forwarded to the time it would be at now if you had done so. The new pattern is inserted at the next beat (outset=1).
quant can be: strong::[quant, phase, timingOffset, outset]::
note::
This fast forwarding might create a cpu peak if the pattern is very complex/fast or quant is very long. This is hard to avoid, so it simply has to be taken into account.
::
code::
(
Pdef(\x).quant_([8, 0, 0, 1]);
Pdef(\y).quant_([8, 0.5, 0, 1]); // phase: half a beat
Pdef(\x).play;
Pdef(\y).play;
)
Pdef(\x, Pbind(\degree, Pseq((0..7)+2, inf)));
Pdef(\y, Pbind(\degree, Pseq((0..7)-2, inf)));
Pdef(\x, Pbind(\degree, Pseq((0..7)+2, inf), \dur, 0.5));
Pdef(\y, Pbind(\degree, Pseq((0..7).scramble-2, inf), \dur, 0.25, \legato, 0.3));
Pdef(\x, Pbind(\degree, Pseq((0..7), inf)));
Pdef(\x, Pbind(\degree, Pseq([ 1, 5, 6, 7, 0, 3, 2, 4 ], inf), \dur, 1));
Pdef(\x, Pbind(\degree, Pseq([ 0, 2, 2, 4, 0, 4, 0, 4 ], inf), \dur, 1));
Pdef(\x).quant_([8, 1/3, 0, 1]); // phase: 1/6 beat relative to y
Pdef(\x, Pbind(\degree, Pseq([ 1, 1, 1, 7, 0, 2, 2, 4 ], inf), \legato, 0.1));
Pdef(\x, Pbind(\degree, Pseq([ 3, 3, 3, 4b ], inf), \legato, 0.1));
Pdef(\y, Pbind(\degree, Pseq((0..7).scramble-4, inf), \dur, 0.25, \legato, 0.3));
// some testing
(
var quant = #[8, 0, 0, 1]; // quantise to 8 beats, no phase, insert quant to 1 beat
Pdef(\x).quant_(quant);
Pdef(\x).play;
Routine { loop { 8.do { |i| ("uhr:"+i).postln; 1.wait } } }.play(quant:quant);
Pbind(\degree, Pseq((0..7), inf)).play(quant:quant);
)
Pdef(\x, Pbind(\degree, Pseq((0..7)+2, inf)).trace(\degree));
Pdef(\x, Pbind(\degree, Pseq((0..7), inf) + [0, 3]).trace(\degree));
Pdef(\x, Pbind(\degree, Pseq((0..7), inf) + [0, 6], \dur, 0.5).trace(\degree));
Pdef(\x).fadeTime = 8;
Pdef(\x, Pbind(\degree, Pseq((0..7), inf)).trace(\degree));
Pdef(\x, Pbind(\degree, Pseq((0..7).reverse, inf) + [0, 6], \dur, 0.5));
Pdef(\x).fadeTime = nil;
Pdef(\x).quant = 1;
Pdef(\x, Pbind(\degree, Pseq((0..7), inf)).trace(\degree));
Pdef(\x).quant = 8;
Pdef(\x, Pbind(\degree, Pseq((0..7), inf)).trace(\degree));
::
subsection::Update condition
In order to be able to switch to a new pattern under a certain link::#-condition::, the instance variable 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 link::#-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 link::#-count::(n).
code::
Pdef(\x).play;
Pdef(\x).quant = 0; // we don't want quant here.
Pdef(\x, Pbind(\degree, Pseq((0..5), inf), \dur, 0.3)).condition_({ |val, i| i.postln % 6 == 0 });
Pdef(\x, Pbind(\degree, Pseq((0..7) + 5.rand, inf), \dur, 0.3)).condition_({ |val, i| (i % 8).postln == 0 });
// the above is equivalent to:
Pdef(\x, Pbind(\degree, Pseq((0..7) + 5.rand, inf), \dur, 0.3)).count(8);
// the value that is sent in is the event, so decisions can be made dependent on the event's fields
::
subsection::reset
code::
// reset to change immediately:
Pdef(\x).reset;
::
 |