1title:: recursive_phrasing 2summary:: Recursive phrases and granular composite sounds 3categories:: JITLib>Tutorials 4related:: Overviews/JITLib, Classes/Pdef, Classes/PlazyEnvirN 5 6Pdef can be used as a global storage for event patterns. Here a way is provided by which these definitions can be used as an instrument that consists of several events (a emphasis::phrase::), such as a cloud of short grains. Furthermore, this scheme can be applied recursively, so that structures like a cloud of clouds can be constructed. 7 8When the event type code::\phrase:: is passed in, the event looks for a pattern in code::Pdef.all:: if it can find a definition. 9list:: 10## if it finds one it plays this pattern in the context of the outer pattern's event. 11## f there is no definition to be found there, it uses a link::Classes/SynthDef:: with this name, if present. 12:: 13 14When passing a emphasis::function:: to Pdef it creates a PlazyEnvirN internally. Its function is evaluated in the context of the input event (see link::Classes/PlazyEnvirN::) which should return a pattern or a stream. Note that this doesn't allow the usual access of the outer environment from within the function. 15 16code:: 17( 18s.boot; 19 20SynthDef(\pgrain, 21 { arg out = 0, freq=800, sustain=0.001, amp=0.5, pan = 0; 22 var window; 23 window = Env.sine(sustain, amp * AmpCompA.kr(freq)); 24 Out.ar(out, 25 Pan2.ar( 26 SinOsc.ar(freq), 27 pan 28 ) * EnvGen.ar(window, doneAction: Done.freeSelf) 29 ) 30 } 31).add; 32 33SynthDef(\noiseGrain, 34 { arg out = 0, freq=800, sustain=0.001, amp=0.5, pan = 0; 35 var window; 36 window = Env.perc(0.002, sustain, amp * AmpCompA.kr(freq)); 37 Out.ar(out, 38 Pan2.ar( 39 Ringz.ar(PinkNoise.ar(0.1), freq, 2.6), 40 pan 41 ) * EnvGen.ar(window, doneAction: Done.freeSelf) 42 ) 43 } 44).add; 45 46 47 48Pdef(\sweep, { arg sustain=1, n=8, freq=440, ratio=0.1; 49 Pbind( 50 \instrument, \pgrain, 51 \dur, sustain.value / n, 52 \freq, Pseq((1..n)) * ratio + 1 * freq.value // freq is a function, has to be evaluated 53 ) 54}); 55Pdef(\sweep2, { arg sustain=1, n=8, freq=440, ratio=0.1; 56 Pbind( 57 \instrument, \noiseGrain, 58 \dur, sustain.value / n, // sustain is also a function, has to be evaluated 59 \freq, Pseq((1..n).scramble) * ratio + 1 * freq.value, 60 \recursionLevel, 2 61 ) 62}); 63Pdef(\sweep3, { arg freq=440; 64 Pbind( 65 \type, \phrase, 66 \instrument, \sweep, 67 \freq, Pfunc({ rrand(0.8, 1.3) }) * freq.value, 68 \dur, 0.3, 69 \legato, 1.3, 70 \n, 5 71 ) 72}); 73) 74 75 76 77 78// the pattern that is found in Pdef.all (or your own defined library) is truncated in time 79// using the sustain provided by the outer pattern. 80( 81Pbind( 82 \type, \phrase, // phrase event from global library 83 \instrument, \sweep, 84 \n, 15, 85 \degree, Pseq([0, 4, 6, 3], inf), 86 \sustain, Pseq([1.3, 0.2, 0.4],inf) 87).play 88) 89 90// multichannel expansion is propagated into the subpatterns 91( 92Pbind( 93 \type, \phrase, // phrase event from global library 94 \instrument, \sweep, 95 \n, 15, 96 \degree, Pseq([0, 0, 6, 3], inf) + Prand([0, [0, 3], [0, 5], [0, 15]], inf), 97 \ratio, Prand([ 0.1, 0.1, [0.1, -0.1] ], inf) 98).play 99) 100 101// various instruments and synthdefs can be used on the same level 102( 103Pbind( 104 \type, \phrase, 105 \instrument, Pseq([\sweep, \default, \sweep2, \sweep3, \pgrain, \pgrain], inf), 106 \degree, Pseq([0, 3, 2], inf), 107 \dur, Pseq([1, 0.5], inf) * 0.7, 108 \n, Pseq([4, 6, 25, 10], inf), 109 \ratio, Prand([0.03, 0.1, 0.4, -0.1],inf) + Pseq([0, 0, [0, 0.02]], inf), 110 \legato, Pseq(#[0.5, 1, 0.5, 0.1, 0.1],inf) 111).play; 112) 113 114 115//////// of course also a patten can be used directly in a Pdef 116 117( 118Pdef(\sweep, 119 Pbind( 120 \instrument, Pseq([\pgrain, \noiseGrain],inf), 121 \dur, Pseq([1, 2, 1, 3, 1, 4, 1, 5]) * 0.05, 122 \legato, Prand([0.5, 0.5, 3],inf) 123 ) 124) 125) 126 127// play directly, embedded in stream (see Pdef.help) 128 129Pn(Pdef(\sweep), 2).play; 130Pdef(\sweep).fork; // play without changing player state (see Pdef.help) 131 132 133// play within a pattern 134( 135Pbind( 136 \type, \phrase, 137 \instrument, \sweep, 138 \degree, Pseq([0, 1b, 4, 2, 3, 1b], inf), 139 \pan, Pfunc(#{ 1.0.rand2 }) 140).play 141) 142 143 144 145//////// recursion examples ////////// 146 147// the given pattern can be recursively applied to itself 148// resulting in selfsimilar sound structures, like lindenmeyer systems (see also Prewrite) 149// special care is taken so that no infinite loops can happen. 150// just like with non recursive phrasing, new values override old values, 151// any values that are not provided within the pattern definition 152// are passed in from the outer event. 153 154 155 156( 157Pdef(\sweep, { arg dur=1, n=4, freq=440, ratio=0.3; 158 Pbind( 159 \instrument, \pgrain, 160 \dur, dur.value / n, // now dur is dependant on outer dur. 161 \freq, Pseries(1, 1, inf) * ratio + 1 * freq.value % 17000 162 ) 163}); 164) 165 166 167// no recursion 168( 169 Pbind( 170 \type, \phrase, 171 \instrument, \sweep, 172 \degree, Pseq((0..5),inf) 173 ).play; 174) 175 176// no recursion, with legato > 1.0 and varying notes 177// note how subpatterns are truncated to note length 178// provided by outer pattern (in this case determined by legato) 179( 180 Pbind( 181 \type, \phrase, 182 \instrument, \sweep, 183 \degree, Pseq((0..5),inf), 184 \legato, Pseq([1.2, 2.8, 0.3], inf) 185 ).play; 186) 187 188// to block the proliferation of \legato into the phrase, set \transparency to 0 189( 190 Pbind( 191 \type, \phrase, 192 \instrument, \sweep, 193 \transparency, 0, 194 \degree, Pseq((0..5),inf), 195 \legato, Pseq([1.2, 2.8, 0.3], inf) 196 ).play; 197) 198 199 200// recursion over one level 201( 202 Pbind( 203 \type, \phrase, 204 \instrument, \sweep, 205 \degree, Pseq([0, 1, 2, 3], inf), 206 \recursionLevel, 1 207 ).play 208) 209 210// recursion over one level: legato is recursively applied 211( 212 Pbind( 213 \type, \phrase, 214 \instrument, \sweep, 215 \degree, Pseq([0, 1, 2, 3], inf), 216 \legato, Pseq([0.5, 1, 1.5, 1.8], inf), 217 \recursionLevel, 1 218 ).play 219) 220 221// to block the proliferation of properties such as \legato and \degree 222// into the phrase, set \transparency to 0. 223( 224 Pbind( 225 \type, \phrase, 226 \instrument, \sweep, 227 \degree, Pseq([0, 1, 2, 3], inf), 228 \legato, Pseq([0.5, 1, 1.5, 1.8], inf), 229 \recursionLevel, 1, 230 \transparency, 0 231 ).play 232) 233 234// recursion over 3 levels: legato is recursively applied 235( 236 Pbind( 237 \type, \phrase, 238 \instrument, \sweep, 239 \degree, 1, 240 \legato, Pseq([0.5, 1, 1.3], inf), 241 \recursionLevel, 3, 242 \n, 3 243 ).play 244) 245 246// to block the proliferation of \legato into the phrase, set \transparency to a level at which 247// to stop passing the value. 248( 249 Pbind( 250 \type, \phrase, 251 \instrument, \sweep, 252 \degree, 1, 253 \legato, Pseq([0.5, 1, 2.3], inf), 254 \recursionLevel, 3, 255 \n, 3, 256 \transparency, Pstutter(8, Prand([0, 1, 2], inf)) 257 ).play 258) 259 260 261 262// to modify this recursion, assign values explicitly: 263( 264Pdef(\sweep, { arg dur=1, n=4, ratio=0.5, freq=440; 265 var legato; 266 freq = freq.value; 267 legato = freq % 200 / 200 * 3 + 0.2; 268 Pbind( 269 \instrument, \pgrain, 270 \dur, dur.value / n, 271 \legato, legato, 272 \freq, Pseq((1..n) * ratio + 1 * freq) 273 ) 274}); 275) 276 277// recursion over one level: degree is assigned to each phrase, 278// because freq is calculated internally and overrides degree on the second level 279( 280 Pbind( 281 \type, \phrase, 282 \instrument, \sweep, 283 \degree, Pseq((0..10),inf), 284 \recursionLevel, 1 285 ).play 286) 287 288 289 290// recursion over two levels 291( 292Pbind( 293 \type, \phrase, 294 \instrument, \sweep, 295 \degree, 0, 296 \recursionLevel, 2 297).play 298) 299 300// recursion over three levels with variable number of grains 301( 302Pbind( 303 \type, \phrase, 304 \instrument, \sweep, 305 \degree, -5, 306 \n, Pseq([1, 2, 3],inf), 307 \recursionLevel, 3 308).play 309) 310 311 312// "zoom" in 313TempoClock.default.tempo = 0.2; 314TempoClock.default.tempo = 1.0; 315 316 317// recursion over variable levels 318( 319Pbind( 320 \type, \phrase, 321 \instrument, \sweep, 322 \n, Prand([2, 7, 3], inf), 323 \degree, -5, 324 \recursionLevel, Prand([0, 1, 2],inf) 325).play 326) 327 328 329 330// replace the frequency based pattern with a degree based pattern 331( 332Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1; 333 Pbind( 334 \instrument, \pgrain, 335 \dur, sustain.value / n, 336 \degree, Pseq((1..n)) * ratio + 1 + degree.value 337 ) 338}); 339) 340 341 342// drunken master 343( 344Pbind( 345 \type, \phrase, 346 \instrument, \sweep, 347 \n, Prand([2, 4, 3, 8], inf), 348 \degree, Pseq([-5, 0, -2], inf), 349 \legato, Pseq([1.4, 0.5, 2], inf), 350 \scale, #[0, 2, 5, 7, 10], 351 \recursionLevel, Prand([0, 1, 2],inf) 352).play 353) 354 355 356( 357Pbind( 358 \type, \phrase, 359 \instrument, \sweep, 360 \synthDef, Prand([\pgrain, \default, \noiseGrain],inf), 361 \n, Prand([2, 4, 3, 8], inf), 362 \degree, Pseq([-5, 0, -2], inf), 363 \recursionLevel, Prand([0, 1],inf) 364).play 365) 366 367 368// use a different parent event in the inner pattern 369( 370e = Event.default; 371e.use { ~sustain = { 2.0.exprand(0.05) } }; 372Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1; 373 Pbind( 374 \parent, e, // replace by some other event 375 \instrument, \pgrain, 376 \dur, sustain.value / n, 377 \degree, Pseq((1..n)) * ratio + 1 + degree.value 378 ) 379}); 380) 381 382 383( 384Pbind( 385 \type, \phrase, 386 \instrument, \sweep, 387 \n, Prand([2, 4, 3, 8], inf), 388 \degree, Pseq([-5, 0, -2], inf), 389 \recursionLevel, Prand([0, 1],inf) 390).play 391) 392 393 394// pass in a pattern from outside 395 396( 397Pdef(\sweep, { arg sustain=1, n=8, degree=0, ratio=1; 398 n = n.value; 399 Pbind( 400 \instrument, \pgrain, 401 \dur, sustain.value / n, 402 \degree, Pseq([ 1, 2, 3, 4, 5 ] * ratio + 1 + degree.value) ) 403}); 404) 405 406 407( 408Pbind( 409 \type, \phrase, 410 \instrument, \sweep, 411 \n, { Pshuf([2, 4, 3, 8, 16, 32], inf) }, // use a function to insulate from embedInStream 412 \degree, Pseq([-5, 0, -2], inf), 413 \recursionLevel, Prand([0, 1],inf) 414).play 415) 416 417 418 419 420// recursion inside the pattern definition 421 422( 423Pdef(\sweep2, { arg sustain=1, n=2, degree=0, ratio=1; 424 Pbind( 425 \type, \phrase, 426 \instrument, \sweep, 427 \dur, sustain.value / n, 428 \degree, Pseq((1..5).scramble * ratio + 1 + degree.value), 429 \recursionLevel, 2 430 ) 431}); 432) 433 434( 435Pbind( 436 \type, \phrase, 437 \instrument, \sweep2, 438 \n, 3, 439 \degree, Pseq([-5, 0, -2], inf) 440).play 441) 442 443 444// instruments do not crossfade while they play (to make phrasing more efficient). 445 446 447( 448Pbind( 449 \type, \phrase, 450 \instrument, \sweep, 451 \n, 3, 452 \degree, Pseq([0, 2b, 3, 4], inf), 453 \dur, 2, 454 \legato, 2 455).play 456) 457 458// change pattern definition while playing: 459( 460Pdef(\sweep, 461 Pbind( 462 \instrument, \pgrain, 463 \dur, exprand(0.01, 0.1), 464 \legato, rrand(0.01, 2.0), 465 \octave, rrand(5, 7) 466 ) 467) 468) 469 470 471// koch "snowflake" 472( 473Pdef(\koch, { arg dur=1, freq=440; 474 Pbind( 475 \dur, dur.value / 3, 476 \freq, freq.value * Pseq([1, 1.2, 1]) 477 ) 478}); 479) 480 481( 482 Pbind( 483 \type, \phrase, 484 \instrument, \koch, 485 \synthDef, \pgrain, 486 \dur, 9, 487 \recursionLevel, 2, 488 \legato, 1.1 489 ).play 490) 491 492( 493 Pbind( 494 \type, \phrase, 495 \instrument, \koch, 496 \synthDef, \pgrain, 497 \dur, 9, 498 \recursionLevel, 4, 499 \legato, 1.1 500 ).play 501) 502 503( 504Pdef(\koch, { arg dur=1, degree=0; 505 Pbind( 506 \dur, dur.value / 3, 507 \degree, degree + Pseq([0, 2, 0]) 508 ) 509}); 510) 511 512 513 514 515 516// soundfile example 517 518 519( 520SynthDef(\play_from_to, { arg out, bufnum, from=0.0, to=1.0, sustain=1.0; 521 var env; 522 env = EnvGen.ar(Env.linen(0.01, sustain, 0.01), 1, doneAction: Done.freeSelf); 523 Out.ar(out, 524 BufRd.ar(1, bufnum, 525 Line.ar(from, to, sustain) * BufFrames.kr(bufnum) 526 ) * env 527 ) 528 529 530}).add; 531) 532 533b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav") 534 535( 536Pdef(\poch, { arg sustain=1.0, from=0.0, to=1.0, n=3; 537 var step; 538 sustain = sustain.value; 539 step = (to - from) / n; 540 Pbind( 541 \instrument, \play_from_to, 542 \from, Pseries(from, step, n), 543 \to, Pseries(from, step, n) + step, 544 \legato, 1.0, 545 \dur, sustain / n 546 ) 547}) 548) 549 550// this plays it straight 551( 552Pbind( 553 \type, \phrase, 554 \instrument, \poch, 555 \recursionLevel, 3, 556 \from, 0, 557 \to, 1, 558 \dur, 3, 559 \bufnum, b 560).play 561) 562 563// now turn round every middle part of every middle part 564( 565Pdef(\poch, { arg sustain=1.0, from=0.0, to=1.0, n=3; 566 var step, f, t, i; 567 sustain = sustain.value; 568 step = (to - from) / n; 569 f = Array.series(n, from, step) +.t [0.0, step]; 570 i = n div: 2; 571 f[i] = f[i].reverse; 572 Pbind( 573 \instrument, \play_from_to, 574 [\from, \to], Pseq(f), 575 \legato, 1.0, 576 \dur, sustain / n 577 ) 578}) 579) 580 581 582// varying recursion 583( 584Pbind( 585 \type, \phrase, 586 \instrument, \poch, 587 \recursionLevel, Prand([0, 1, 2, 3], inf), 588 \from, 0, 589 \to, Prand([-1, 1], inf), 590 \dur, 3, 591 \n, Prand([1, 2, 3], inf), 592 \bufnum, b, 593 \amp, 0.2 594).play 595) 596:: 597