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