-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy path06-sequencing.html
More file actions
216 lines (189 loc) · 30.7 KB
/
06-sequencing.html
File metadata and controls
216 lines (189 loc) · 30.7 KB
1
2
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
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 2025-02-07 Fri 19:34 -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sequencing</title>
<meta name="author" content="modula t. worm" />
<meta name="generator" content="Org Mode" />
<link type='text/css' rel='stylesheet' href='css.css' />
</head>
<body>
<div id="preamble" class="status">
<nav>
<ol class="bar">
<li value="0"><a href="index.html">Contents</a></li>
<li><a href="01-introduction.html">Introduction</a></li>
<li><a href="02-getting-started.html">Getting Started</a></li>
<li><a href="03-make-a-sound.html">Make a Sound</a></li>
<li><a href="04-further-soundmaking.html">Further Soundmaking</a></li>
<li><a href="05-sampling.html">Sampling</a></li>
<li><a href="06-sequencing.html">Sequencing</a></li>
<li><a href="07-effects.html">Effects</a></li>
<li><a href="08-architecture.html">Architecture</a></li>
<li><a href="09-other-libraries.html">Other Libraries</a></li>
</ol>
</nav>
</div>
<div id="content" class="content">
<header>
<h1 class="title">Sequencing</h1>
</header><p>
Up to this point, we've been testing sounds by playing them manually using their functions defined by <code>defsynth</code>, or by using <code>proxy</code>. However, it would be very difficult to play interesting music just by typing every sound we want to hear on the keyboard. Most synthesizers have methods of triggering notes automatically, either by connecting external hardware or software, or by using functionality built in to the synthesizer. Typically, we'd refer to the hardware or software controlling the synthesizer as a "sequencer".
</p>
<div id="outline-container-org3963672" class="outline-2">
<h2 id="org3963672"><code>callback</code></h2>
<div class="outline-text-2" id="text-org3963672">
<p>
cl-collider comes with a built in method of sequencing sounds. It's fairly simple and easy to learn, as it is basically just a few functions and macros that allow sounds (or other functions) to be triggered automatically at some point in the future. Let's take a look. First, we'll define a basic synth that we can play around with:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>defsynth<span class="org-whitespace-space"> </span>simple<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span>gate<span class="org-whitespace-space"> </span>1<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>freq<span class="org-whitespace-space"> </span>440<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>pan<span class="org-whitespace-space"> </span>0<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>amp<span class="org-whitespace-space"> </span>0.5<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let*</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>env<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>env-gen.kr<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>asr<span class="org-whitespace-space"> </span>0.01<span class="org-whitespace-space"> </span>1<span class="org-whitespace-space"> </span>0.1<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-whitespace-space"> </span><span class="org-builtin">:gate</span><span class="org-whitespace-space"> </span>gate<span class="org-whitespace-space"> </span><span class="org-builtin">:act</span><span class="org-whitespace-space"> </span><span class="org-builtin">:free</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>sig<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>sin-osc.ar<span class="org-whitespace-space"> </span>freq<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span>0.2<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>out.ar<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>pan2.ar<span class="org-whitespace-space"> </span>sig<span class="org-whitespace-space"> </span>pan<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>*<span class="org-whitespace-space"> </span>env<span class="org-whitespace-space"> </span>amp<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
Then, we can define a function to start playing this synth:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span><span class="org-whitespace-space"> </span><span class="org-function-name">testing</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">()</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>syn<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>synth<span class="org-whitespace-space"> </span>'simple<span class="org-whitespace-space"> </span><span class="org-builtin">:freq</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>midicps<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>+<span class="org-whitespace-space"> </span>30<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-8">(</span>random<span class="org-whitespace-space"> </span>40<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>now<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-whitespace-space"> </span>#'release<span class="org-whitespace-space"> </span>syn<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>now<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-whitespace-space"> </span>1<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span>#'testing<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
The first thing the <code>testing</code> function does is start a new <code>simple</code> synth. Calling <code>(synth 'simple)</code> returns a <code>node</code> object representing the synth playing on the server. Here we provide the frequency to the synth by generating a random MIDI note number and converting it to a frequency with the <code>midicps</code> function.
</p>
<p>
Below that, we use the <code>callback</code> function to schedule the release of the synth 0.7 seconds in the future. The <code>now</code> function returns the current time, so adding 0.7 to it means "0.7 seconds from now". <code>callback</code> effectively causes a function to run at a specified time using cl-collider's scheduler. Respectively, its arguments are: when to run the function, the function to run (in this case <code>release</code>), and (optionally) the arguments to that function. Here we provide the node returned by <code>synth</code> so it will be released.
</p>
<p>
After that, we use <code>callback</code> again to re-schedule the <code>testing</code> function. That way, we continue to hear notes playing. To give some space between notes, we schedule it to trigger again after one second.
</p>
<p>
Once you define that function, you can call it using <code>(testing)</code> and you should hear random notes being played. Since this is a standard Common Lisp function, you can re-define it on the fly and the next time it's called it will automatically use the new definition. So if we wanted the function to stop playing, we could simply evaluate the following:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span><span class="org-whitespace-space"> </span><span class="org-function-name">testing</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">()</span>
<span class="org-whitespace-space"> </span>nil<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
Another example; if we want multiple notes simultaneously:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defun</span><span class="org-whitespace-space"> </span><span class="org-function-name">testing-2</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">()</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">let*</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-rainbow-delimiters-depth-4">(</span>note<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>+<span class="org-whitespace-space"> </span>30<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>random<span class="org-whitespace-space"> </span>40<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>syns<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span><span class="org-keyword">loop</span><span class="org-whitespace-space"> </span><span class="org-builtin">:for</span><span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span><span class="org-builtin">:in</span><span class="org-whitespace-space"> </span>'<span class="org-rainbow-delimiters-depth-6">(</span>0<span class="org-whitespace-space"> </span>12<span class="org-whitespace-space"> </span>24<span class="org-rainbow-delimiters-depth-6">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:collect</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>synth<span class="org-whitespace-space"> </span>'simple<span class="org-whitespace-space"> </span><span class="org-builtin">:freq</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>midicps<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-8">(</span>+<span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span>note<span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">loop</span><span class="org-whitespace-space"> </span><span class="org-builtin">:for</span><span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span><span class="org-builtin">:in</span><span class="org-whitespace-space"> </span>syns
<span class="org-whitespace-space"> </span><span class="org-builtin">:do</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>now<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-whitespace-space"> </span>#'release<span class="org-whitespace-space"> </span>i<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>now<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-whitespace-space"> </span>1<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span>#'testing-2<span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
This function generates a random MIDI note, then creates two more synths that play at the same time as the first, but one and two octaves higher. This gives a chord or organ-like sound. Of course, you could just put more UGens in the synthdef itself and get the same effect if you so choose. It would certainly be easier, since you can just rely on cl-collider's multi-channel expansion in synthdefs.
</p>
</div>
</div>
<div id="outline-container-org377fcc7" class="outline-2">
<h2 id="org377fcc7">Closures</h2>
<div class="outline-text-2" id="text-org377fcc7">
<p>
Using closures, we can write functions that perform different actions each time they're called:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">let</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span>index<span class="org-whitespace-space"> </span>0<span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>list<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>list<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span>2<span class="org-whitespace-space"> </span>4<span class="org-whitespace-space"> </span>6<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-keyword">defun</span><span class="org-whitespace-space"> </span><span class="org-function-name">testing-3</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">()</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span><span class="org-keyword">let*</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span><span class="org-rainbow-delimiters-depth-5">(</span>note<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>+<span class="org-whitespace-space"> </span>30<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>nth<span class="org-whitespace-space"> </span>index<span class="org-whitespace-space"> </span>list<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>syns<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span><span class="org-keyword">loop</span><span class="org-whitespace-space"> </span><span class="org-builtin">:for</span><span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span><span class="org-builtin">:in</span><span class="org-whitespace-space"> </span>'<span class="org-rainbow-delimiters-depth-7">(</span>0<span class="org-whitespace-space"> </span>12<span class="org-whitespace-space"> </span>24<span class="org-rainbow-delimiters-depth-7">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:collect</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>synth<span class="org-whitespace-space"> </span>'simple<span class="org-whitespace-space"> </span><span class="org-builtin">:freq</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-8">(</span>midicps<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-9">(</span>+<span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span>note<span class="org-rainbow-delimiters-depth-9">)</span><span class="org-rainbow-delimiters-depth-8">)</span><span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span><span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span><span class="org-keyword">loop</span><span class="org-whitespace-space"> </span><span class="org-builtin">:for</span><span class="org-whitespace-space"> </span>i<span class="org-whitespace-space"> </span><span class="org-builtin">:in</span><span class="org-whitespace-space"> </span>syns
<span class="org-whitespace-space"> </span><span class="org-builtin">:do</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>now<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-whitespace-space"> </span>#'release<span class="org-whitespace-space"> </span>i<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>setf<span class="org-whitespace-space"> </span>index<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>mod<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>1+<span class="org-whitespace-space"> </span>index<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>length<span class="org-whitespace-space"> </span>list<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span>
<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>callback<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>now<span class="org-rainbow-delimiters-depth-5">)</span><span class="org-whitespace-space"> </span>1<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-whitespace-space"> </span>#'testing-3<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
Since closures let us keep track of state, we can make arpeggios instead of just playing random midi notes.
</p>
</div>
</div>
<div id="outline-container-orgef0302d" class="outline-2">
<h2 id="orgef0302d">Patterns</h2>
<div class="outline-text-2" id="text-orgef0302d">
<p>
Though you can of course implement any behaviors you want using functions and cl-collider's scheduler as shown above, it does require a lot of bookkeeping. Calculating the frequency for each note, saving each synth in a variable, releasing it later, etcetera–and that's just for simple behavior like the above. You could, of course, define some functions and macros to make it easier, but there is another way.
</p>
<p>
If you're using SuperCollider's built-in programming language, it comes with a library of sequencing functionality called "patterns". These can be used to create musical sequences much more easily than manually writing functions like we've done above. SuperCollider's patterns language is designed to make it simple to express musical behaviors and specify synth parameters for each musical event. There are many kinds of patterns that can be used to generate everything from static sequences that sound the same every time, to totally algorithmic or random patterns that result in constantly-changing outputs. Patterns can even be combined to easily create more complex behaviors.
</p>
<p>
cl-collider doesn't have a patterns system built in, but there is a library called <a href="https://github.com/defaultxr/cl-patterns">cl-patterns</a> which re-creates much of its functionality in Lisp. It's beyond the scope of this tutorial to describe cl-patterns in-depth, but here are a few examples to show what can be done with it:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>pbind<span class="org-whitespace-space"> </span><span class="org-builtin">:pdef</span><span class="org-whitespace-space"> </span><span class="org-builtin">:testing</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:instrument</span><span class="org-whitespace-space"> </span><span class="org-builtin">:simple</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>pwhite<span class="org-whitespace-space"> </span>30<span class="org-whitespace-space"> </span>70<span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:dur</span><span class="org-whitespace-space"> </span>1
<span class="org-whitespace-space"> </span><span class="org-builtin">:legato</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
This pattern produces the same output as our original <code>testing</code> function above. The most obvious advantage is that it's much more obvious what the code is supposed to do; each key specifies its value directly rather than being entangled in the definition of the behavior. Instead of having to write <code>(+ 30 (random 40))</code> to get values from <code>30</code> to <code>70</code>, we can just use the <code>pwhite</code> pattern as <code>(pwhite 30 70)</code> to get values within that range.
</p>
<p>
Another advantage of using cl-patterns is that all patterns are automatically synchronized to a tempo. If the tempo is changed, all patterns will automatically use the new tempo value and will stay in sync, without us needing to update their code or remember to multiply the duration and release time by the tempo.
</p>
<p>
Here's an example of how <code>testing-2</code> would be rewritten as a pattern:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>pbind<span class="org-whitespace-space"> </span><span class="org-builtin">:pdef</span><span class="org-whitespace-space"> </span><span class="org-builtin">:testing-2</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:instrument</span><span class="org-whitespace-space"> </span><span class="org-builtin">:simple</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>pwhite<span class="org-whitespace-space"> </span>30<span class="org-whitespace-space"> </span>70<span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>p+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>pk<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>list<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span>12<span class="org-whitespace-space"> </span>24<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:dur</span><span class="org-whitespace-space"> </span>1
<span class="org-whitespace-space"> </span><span class="org-builtin">:legato</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
As you can see, it's nearly the same as our first pattern; we only had to add one additional line to produce two additional notes per event. The additional notes are automatically handled and released when necessary just as expected.
</p>
<p>
And finally, here's how our last function, <code>testing-3</code>, would look as a pattern:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>pbind<span class="org-whitespace-space"> </span><span class="org-builtin">:pdef</span><span class="org-whitespace-space"> </span><span class="org-builtin">:testing-3</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:instrument</span><span class="org-whitespace-space"> </span><span class="org-builtin">:simple</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>p+<span class="org-whitespace-space"> </span>40<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>pseq<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-4">(</span>list<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span>2<span class="org-whitespace-space"> </span>4<span class="org-whitespace-space"> </span>6<span class="org-rainbow-delimiters-depth-4">)</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>p+<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>pk<span class="org-whitespace-space"> </span><span class="org-builtin">:midinote</span><span class="org-rainbow-delimiters-depth-3">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>list<span class="org-whitespace-space"> </span>0<span class="org-whitespace-space"> </span>12<span class="org-whitespace-space"> </span>24<span class="org-rainbow-delimiters-depth-3">)</span><span class="org-rainbow-delimiters-depth-2">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:dur</span><span class="org-whitespace-space"> </span>1
<span class="org-whitespace-space"> </span><span class="org-builtin">:legato</span><span class="org-whitespace-space"> </span>0.7<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
(Note again that this example will not work in the current verison of cl-patterns, for the same reason as the previous.)
</p>
<p>
As you can see, we don't need to create a closure to keep track of state; the <code>pseq</code> pattern does that for us, allowing us to focus more on the behavior we want and less on how to implement it.
</p>
<p>
As mentioned before, a full explanation of how cl-patterns works is beyond the scope of this document, but the project's <a href="https://github.com/defaultxr/cl-patterns">repo</a> includes plenty of documentation that should help to get you started.
</p>
<p>
<a href="05-sampling.html">Previous: Sampling</a> / <a href="07-effects.html">Next: Effects</a>
</p>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="date">Created: 2017-10-10 Tue 03:51. Updated: 2025-02-07 Fri 19:34.</p>
</div>
</body>
</html>