supernova: fix for small audio vector sizes
[supercollider.git] / HelpSource / Tutorials / Streams-Patterns-Events3.schelp
blob3d6a6a0089942f336b5901e1682ad8c0a9384c06
1 title:: Understanding Streams, Patterns and Events - Part 3
2 summary:: ListPatterns
3 related:: Tutorials/Streams-Patterns-Events1, Tutorials/Streams-Patterns-Events2, Tutorials/Streams-Patterns-Events4, Tutorials/Streams-Patterns-Events5, Tutorials/Streams-Patterns-Events6, Tutorials/Streams-Patterns-Events7
4 categories:: Streams-Patterns-Events>Understanding-Streams-Patterns-and-Events
6 section::ListPatterns
8 ListPatterns are link::Classes/Pattern::s that iterate over arrays of objects in some fashion. All ListPatterns have in common the instance variables list and repeats. The list variable is some link::Classes/Array:: to be iterated over. The repeats variable is some measure of the number of times to do something, whose meaning varies from subclass to subclass. The default value for repeats is 1.
10 A link::Classes/Pseq:: is a Pattern that cycles over a list of values. The repeats variable gives the number of times to repeat the entire list.
12 code::
13 //////////////////////////////////////////////////////////////
14 // Note: This SynthDef used throughout this document
16 s = Server.local;
17 SynthDef( \help_SPE3_SimpleSine, {
18         arg freq, sustain=1.0;
19         var osc;
20         osc = SinOsc.ar( [freq,freq+0.05.rand] ) * EnvGen.ar(
21                 Env.perc, doneAction: 2, levelScale: 0.3, timeScale: sustain
22         );
23         Out.ar(0,osc);
24 }).add;
26 //////////////////////////////////////////////////////////////
29 var a, b;
30 a = Pseq.new(#[1, 2, 3], 2);    // repeat twice
31 b = a.asStream;
32 7.do({ b.next.postln; });
36 Pseq also has an offset argument which gives a starting offset into the list.
38 code::
40 var a, b;
41 a = Pseq.new(#[1, 2, 3, 4], 3, 2);      // repeat 3, offset 2
42 b = a.asStream;
43 13.do({ b.next.postln; });
47 You can pass a function for the repeats variable that gets evaluated when the stream is created.
49 code::
51 var a, b;
52 a = Pseq.new(#[1, 2], { rrand(1, 3) }); // repeat 1,2, or 3 times
53 b = a.asStream;
54 7.do({ b.next.postln; });
58 If you specify the value code::inf:: for the repeats variable, then it will repeat indefinitely.
60 code::
62 var a, b;
63 a = Pseq.new(#[1, 2, 3], inf);  // infinite repeat
64 b = a.asStream;
65 10.do({ b.next.postln; });
69 Pseq used as a sequence of pitches:
71 Remember that math operations like code::midicps:: can be used on streams.
73 The alternative code::Pseq(...).midicps.asStream:: is also possible because both pattern and stream inherit from link::Classes/AbstractFunction:: for which midicps is a method. ( midicps converts a midi value to cycles per second or Hz )
75 code::
77 var a, d;
78 a = Pseq(#[60, 61, 63, 65, 67, 63], inf ).asStream.midicps;
79 d = 0.3;
80 Task({
81         12.do({
82                 Synth(\help_SPE3_SimpleSine, [ \freq, a.next, \sustain, d ]);
83                 d.wait;
84         });
85 }).play
89 link::Classes/Pser:: is like Pseq, however the repeats variable gives the number of items returned instead of the number of complete cycles.
91 code::
93 var a, b;
94 a = Pser.new(#[1, 2, 3], 5);    // return 5 items
95 b = a.asStream;
96 6.do({ b.next.postln; });
100 link::Classes/Prand:: returns one item from the list at random for each repeat.
102 code::
104 var a, b;
105 a = Prand.new(#[1, 2, 3, 4, 5], 6);     // return 6 items
106 b = a.asStream;
107 7.do({ b.next.postln; });
111 Prand used as a sequence of pitches:
113 code::
115 var a, d;
116 a = Prand(#[60, 61, 63, 65], inf).midicps.asStream;
117 d = 0.3;
118 Task({
119         12.do({
120                 Synth(\help_SPE3_SimpleSine,[\freq, a.next]);
121                 d.wait;
122         });
123 }).play;
127 link::Classes/Pxrand::, like Prand, returns one item from the list at random for each repeat, but Pxrand never repeats the same element twice in a row.
129 code::
131 var a, b;
132 a = Pxrand.new(#[1, 2, 3], 10); // return 10 items
133 b = a.asStream;
134 11.do({ b.next.postln; });
138 Pxrand used as a sequence of pitches:
140 code::
142 var a;
143 a = Pxrand(#[60, 61, 63, 65], inf).midicps.asStream;
144 Task({
145         12.do({
146                 Synth(\help_SPE3_SimpleSine, [\freq, a.next]);
147                 0.8.wait;
148         });
149 }).play;
153 link::Classes/Pshuf:: iterates over the list in scrambled order. The entire scrambled list is repeated in the same order the number of times given by the repeats variable.
155 code::
157 var a, b;
158 a = Pshuf.new(#[1, 2, 3, 4], 3);
159 b = a.asStream;
160 13.do({ b.next.postln; });
164 Pshuf used as a sequence of pitches:
166 code::
168 var a, b;
169 a = Pshuf(#[60, 61, 65, 67], inf).midicps.asStream;
170 Task({
171         12.do({
172                 Synth(\help_SPE3_SimpleSine,[\freq, a.next]);
173                 0.5.wait;
174         });
175 }).play;
179 section::Nesting Patterns
181 If a link::Classes/Pattern:: encounters another Pattern in its list, it embeds that pattern in its output. That is, it creates a stream on that pattern and iterates that pattern until it ends before moving on.
183 For example here is one pattern nested in another.
185 code::
187 var a, b;
188 a = Pseq.new([1, Pseq.new([100,200], 2), 3], 3);
189 b = a.asStream;
190 19.do({ b.next.postln; });
194 Pseqs nested in a Prand:
196 code::
198 var a, b;
199 a = Prand.new([
200                 Pseq.new([1, 2], 2),
201                 Pseq.new([3, 4], 2),
202                 Pseq.new([5, 6], 2)
203         ], 3);
204 b = a.asStream;
205 13.do({ b.next.postln; });
209 Nested sequences of pitches:
211 code::
213 var a;
214 a = Prand([
215                 Pseq(#[60, 61, 63, 65, 67, 63]),
216                 Prand(#[72, 73, 75, 77, 79], 6),
217                 Pshuf(#[48, 53, 55, 58], 2)
218         ], inf
219 ).midicps.asStream;
220 Task({
221         loop({
222                 Synth( \help_SPE3_SimpleSine, [\freq, a.next] );
223                 0.3.wait;
224         });
225 }).play;
229 section::Math operations on ListPatterns
231 Pattern code::b:: plays pattern a once normally, once transposed up a fifth and once transposed up a fourth.
233 code::
235 var a, b;
236 a = Pseq(#[60, 62, 63, 65, 67, 63]);
237 b = Pseq([ a, a + 7, a + 5], inf).asStream;
238 Task({
239         24.do({
240                 Synth(\help_SPE3_SimpleSine, [ \freq, b.next.midicps ]);
241                 0.3.wait;
242         });
243 }).play;
247 Adding two patterns together. The second pattern transposes each fifth note of the first pattern down an octave.
249 code::
251 var a;
252 a = Pseq(#[60, 62, 63, 65, 67, 63], inf) + Pseq(#[0, 0, 0, 0, -12], inf);
253 a = a.asStream.midicps;
254 Task({
255         25.do({
256                 Synth(\help_SPE3_SimpleSine,[\freq, a.next]);
257                 0.3.wait;
258         });
259 }).play;
263 section::Making Music with ListPatterns
265 Here is the same example given in part 2 rewritten to use ListPatterns. It uses nested patterns and results in much more concise code. SuperCollider allows you to write code::SomeClass.new(params):: as code::SomeClass(params):: eliminating the ".new". This can make code like the pattern examples below, which create a lot of objects, more readable.
267 code::
269 SynthDef( \help_SPE3_Allpass6, { arg freq;
270         var out, env;
271         out = RLPF.ar(
272                 LFSaw.ar( freq, mul: EnvGen.kr( Env.perc, levelScale: 0.3, doneAction: 2 ) ),
273                 LFNoise1.kr(1, 36, 110).midicps,
274                 0.1
275         );
276         6.do({ out = AllpassN.ar(out, 0.05, [0.05.rand, 0.05.rand], 4) });
277         Out.ar( 0, out );
278 }).add
282 var freqStream;
284 freqStream = Pseq([
285         Prand([
286                 nil,    // a nil item reached in a pattern causes it to end
287                 Pseq(#[24, 31, 36, 43, 48, 55]);
288         ]),
289         Pseq([ 60, Prand(#[63, 65]), 67, Prand(#[70, 72, 74]) ], { rrand(2, 5) }),
290         Prand(#[74, 75, 77, 79, 81], { rrand(3, 9) })
291 ], inf).asStream.midicps;
293 Task({
294         loop({
295                 Synth( \help_SPE3_Allpass6, [\freq, freqStream.next ]);
296                 0.13.wait;
297         });
298 }).play;
302 Here is an example that uses a Pattern to create a rhythmic solo. The values in the pattern specify the amplitudes of impulses fed to the link::Classes/Decay2:: generator.
304 code::
306 SynthDef( \help_SPE3_Mridangam, { arg t_amp;
307         var out;
309         out = Resonz.ar(
310                 WhiteNoise.ar(70) * Decay2.kr( t_amp, 0.002, 0.1 ),
311                 60.midicps,
312                 0.02,
313                 4
314         ).distort * 0.4;
316         Out.ar( 0, out );
317         DetectSilence.ar( out, doneAction: 2 );
318 }).add;
320 SynthDef( \help_SPE3_Drone, {
321         var out;
322         out = LPF.ar(
323                 Saw.ar([60, 60.04].midicps)
324                 +
325                 Saw.ar([67, 67.04].midicps),
326                 108.midicps,
327                 0.007
328         );
329         Out.ar( 0, out );
330 }).add;
334 // percussion solo in 10/8
336 var stream, pat, amp;
338 pat = Pseq([
339         Pseq(#[0.0], 10),
341         // intro
342         Pseq(#[0.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 2),
343         Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0], 2),
344         Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.2, 0.0, 0.2, 0.0, 0.0], 2),
345         Pseq(#[0.9, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.2, 0.0, 0.2], 2),
347         // solo
348         Prand([
349                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
350                 Pseq(#[0.9, 0.2, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
351                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.2]),
352                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.2, 0.2, 0.0, 0.7, 0.0, 0.0]),
353                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.2, 0.2, 0.7, 0.2, 0.0]),
354                 Pseq(#[0.9, 0.2, 0.2, 0.7, 0.2, 0.2, 0.2, 0.7, 0.2, 0.2]),
355                 Pseq(#[0.9, 0.2, 0.2, 0.7, 0.2, 0.2, 0.2, 0.7, 0.0, 0.0]),
356                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.2, 0.2, 0.2, 0.7, 0.0, 0.0]),
357                 Pseq(#[0.9, 0.0, 0.4, 0.0, 0.4, 0.0, 0.4, 0.0, 0.4, 0.0]),
358                 Pseq(#[0.9, 0.0, 0.0, 0.4, 0.0, 0.0, 0.4, 0.2, 0.4, 0.2]),
359                 Pseq(#[0.9, 0.0, 0.2, 0.7, 0.0, 0.2, 0.0, 0.7, 0.0, 0.0]),
360                 Pseq(#[0.9, 0.0, 0.0, 0.7, 0.0, 0.0, 0.0, 0.7, 0.0, 0.0]),
361                 Pseq(#[0.9, 0.7, 0.7, 0.0, 0.0, 0.2, 0.2, 0.2, 0.0, 0.0]),
362                 Pseq(#[0.9, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0])
363         ], 30),
365         // tehai : 7 beat motif 3 times sharing 1st beat with next 7x3
366         // and again the third time:
367         //   123456712345671234567                   123456712345671234567
368         //                       123456712345671234567
369         //   !                   !                   !                   !
370         //   1234567890123456789012345678901234567890123456789012345678901
371         Pseq(#[2.0, 0.0, 0.2, 0.5, 0.0, 0.2, 0.9,
372                 1.5, 0.0, 0.2, 0.5, 0.0, 0.2, 0.9,
373                 1.5, 0.0, 0.2, 0.5, 0.0, 0.2], 3),
374         Pseq(#[5], 1),  // sam
376         Pseq(#[0.0], inf)
379 stream = pat.asStream;
381 Task({
382         Synth(\help_SPE3_Drone);
383         loop({
384                 if( ( amp = stream.next ) > 0,
385                         { Synth(\help_SPE3_Mridangam, [ \t_amp, amp ]) }
386                 );
387                 (1/8).wait;
388         })
389 }).play
393 To go to the next file:
394 link::Tutorials/Streams-Patterns-Events4::