scel: install files to site-lisp/SuperCollider
[supercollider.git] / HelpSource / Tutorials / A-Practical-Guide / PG_06a_Repetition_Contraint_Patterns.schelp
blobad62495d621cf00c841bac677994394cf466e174
1 title:: PG_06a_Repetition_Contraint_Patterns
2 summary:: Patterns that repeat values, or cut other patterns off early
3 related:: Tutorials/A-Practical-Guide/PG_060_Filter_Patterns, Tutorials/A-Practical-Guide/PG_06b_Time_Based_Patterns
4 categories:: Streams-Patterns-Events>A-Practical-Guide
6 section::Repetition and Constraint patterns
8 These are essentially flow of control patterns. Each one takes a source pattern and repeats values from it, or stops the stream early based on a preset constraint.
10 subsection::Repetition patterns
12 These patterns allow you to repeat single values, or (in the case of Pn) entire patterns.
14 definitionList::
15 ## code::Pclutch(pattern, connected):: || If the code::connected:: pattern is true, link::Classes/Pclutch:: returns the next value from code::pattern::. If code::connected:: is false, the previous pattern value is repeated. It's like a clutch in a car: when engaged, the pattern moves forward; when disconnected, it stays where it is.
16 ## code::Pn(pattern, repeats):: || Embeds the source pattern code::repeats:: times: simple repetition. This also works on single values: code::Pn(1, 5):: outputs the number 1 5 times.
17 ## code::Pstutter(n, pattern):: || code::n:: and code::pattern:: are both patterns. Each value from code::pattern:: is repeated code::n:: times. If code::n:: is a pattern, each value can be repeated a different number of times.
18 ## code::PdurStutter(n, pattern):: || Like Pstutter, except the pattern value is divided by the number of repeats (so that the total time for the repeat cycle is the duration value from the source pattern).
20 See also link::Classes/Pstep::, described in link::Tutorials/A-Practical-Guide/PG_06b_Time_Based_Patterns::. Pstep can be used like link::Classes/Pstutter::, but repetition is controlled by time rather than number of repeats per item.
22 code::
23 // play repeated notes with a different rhythmic value per new pitch
24 // using Pstutter
25 p = Pbind(
26                 // making 'n' a separate stream so that degree and dur can share it
27         \n, Pwhite(3, 10, inf),
28         \degree, Pstutter(Pkey(\n), Pwhite(-4, 11, inf)),
29         \dur, Pstutter(Pkey(\n), Pwhite(0.1, 0.4, inf)),
30         \legato, 0.3
31 ).play;
33 p.stop;
36 // using Pfin / Pn
37 // Pn loops the Pbind infinitely
38 // Plazy builds a new Pbind for each iteration
39 // Pfin cuts off the Pbind when it's time for a new value
41 p = Pn(
42         Plazy {
43                 Pbind(
44                         \degree, Pfin(rrand(3, 10), rrand(-4, 11)),
45                         \dur, rrand(0.1, 0.4)
46                 )
47         },
48         inf
49 ).play;
51 p.stop;
54 // using Pclutch
55 // the rule is, when degree changes, dur should change also
56 // if Pdiff returns 0, degree has not changed
57 // so here, nonzero Pdiff values "connect" the clutch and allow a new dur to be generated
58 // otherwise the old one is held
59 p = Pbind(
60         \degree, Pstutter(Pwhite(3, 10, inf), Pwhite(-4, 11, inf)),
61         \dur, Pclutch(Pwhite(0.1, 0.4, inf), Pdiff(Pkey(\degree)).abs > 0),
62         \legato, 0.3
63 ).play;
65 p.stop;
69 subsection::Constraint (or interruption) patterns
71 Instead of prolonging a stream by repetition, these patterns use different methods to stop a stream dynamically. They are especially useful for modularizing pattern construction. One section of your code might be responsible for generating numeric or event patterns. By using constraint patterns, that part of the code doesn't have to know how many events or how long to play. It can just return an infinite pattern, and another part of the code can wrap it in one of these to stop it based on the appropriate condition.
73 definitionList::
74 ## code::Pfin(count, pattern):: || Returns exactly code::count:: values from the source pattern, then stops. (link::Classes/Pfin:: has a cousin, Pfinval, that is deprecated.)
75 ## code::Pconst(sum, pattern, tolerance):: || Output numbers until the sum goes over a predefined limit. The last output value is adjusted so that the sum matches the limit exactly.
76 ## code::Pfindur(dur, pattern, tolerance):: || Like Pconst, but applying the "constrain" behavior to the event's rhythmic values. The source pattern runs up to the specified duration, then stops. This is very useful if you know how long a musical behavior should go on, but the number of events to fill up that time is not known.
78 code::
79 // Two variants on the same thing
80 // Use Pconst or Pfindur to create 4-beat segments with randomized rhythm
81 // Pconst and Pfindur both can ensure the total rhythm doesn't go above 4.0
83 p = Pn(Pbind(
84                 // always a low C on the downbeat
85         \degree, Pseq([-7, Pwhite(0, 11, inf)], 1),
86         \dur, Pconst(4, Pwhite(1, 4, inf) * 0.25)
87 ), inf).play;
89 p.stop;
91 p = Pn(Pfindur(4, Pbind(
92         \degree, Pseq([-7, Pwhite(0, 11, inf)], 1),
93         \dur, Pwhite(1, 4, inf) * 0.25
94 )), inf).play;
96 p.stop;
99 ## code::Psync(pattern, quant, maxdur, tolerance):: || Like Pfindur, but does not have a fixed duration limit. Instead, it plays until either it reaches code::maxdur:: (in which case it behaves like Pfindur, adjusting the last event so the total duration matches code::maxdur::), or the pattern stops early and the last event is rounded up to the next integer multiple of code::quant::. This is hard to explain; a couple of examples might make it clearer.
101 code::
103 // in this case, the pattern stops by reaching maxdur
104 // elapsed time = 4
105 var     startTime;
106 p = (Psync(Pbind(
107         \dur, 0.25,     // total duration = infinite
108         \time, Pfunc { startTime = startTime ? (thisThread.clock.beats.debug("time")) }
109 ), 1, 4) ++ Pfuncn({
110         thisThread.clock.beats.debug("finish time");
111         (thisThread.clock.beats - startTime).debug("elapsed");
112         nil
113 }, 1)).play;
117 // in this case, the pattern stops itself before maxdur (4)
118 // the Pbind's duration (1.25) gets rounded up to 2 (next multiple of 1)
119 var     startTime;
120 p = (Psync(Pbind(
121         \dur, Pn(0.25, 5),      // total duration = 0.25 * 5 = 1.25
122         \time, Pfunc { startTime = startTime ? (thisThread.clock.beats.debug("time")) }
123 ), 1, 4) ++ Pfuncn({
124         thisThread.clock.beats.debug("finish time");
125         (thisThread.clock.beats - startTime).debug("elapsed");
126         nil
127 }, 1)).play;
132 Previous:       link::Tutorials/A-Practical-Guide/PG_060_Filter_Patterns::
134 Next:           link::Tutorials/A-Practical-Guide/PG_06b_Time_Based_Patterns::