-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy path04-further-soundmaking.html
131 lines (114 loc) · 14.1 KB
/
04-further-soundmaking.html
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
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 2025-02-07 Fri 19:32 -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Further Soundmaking</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">Further Soundmaking</h1>
</header><div id="outline-container-org7cee043" class="outline-2">
<h2 id="org7cee043"><code>defsynth</code></h2>
<div class="outline-text-2" id="text-org7cee043">
<p>
We've been using the <code>proxy</code> macro to define and redefine sounds, but this limits us to sounds that play continuously. Most music is made from sounds that are temporal and periodic, so we need a way to define a sound that can be re-triggered.
</p>
<p>
<code>proxy</code> is good for testing out sounds, but once we've made something that we want to use, we define it with <code>defsynth</code>. Here's a basic example:
</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>drum<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span>freq<span class="org-whitespace-space"> </span>3000<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.ar<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>perc<span class="org-whitespace-space"> </span>0.001<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">: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>lpf.ar<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>white-noise.ar<span class="org-rainbow-delimiters-depth-6">)</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>*<span class="org-whitespace-space"> </span>freq<span class="org-whitespace-space"> </span>env<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>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>0<span class="org-whitespace-space"> </span>0.2<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>
It's not the most exciting drum sound of all time, but now at least you can re-trigger it. To do so, just evaluate <code>(synth 'drum :freq 3000)</code>.
</p>
<p>
Notice that <code>defsynth</code> is very similar to <code>defun</code>. With <code>defsynth</code> you provide the name of the synth (<code>drum</code>), its parameters (<code>(freq 3000)</code>), and the body, which describes how it generates its sound.
</p>
<p>
In the case of this synth, we create two variables, <code>env</code> and <code>sig</code>. <code>env</code> is bound to an envelope generator UGen, <code>env-gen.ar</code>, which takes an envelope specification and generates an audio signal from that specification. <code>(perc 0.001 0.1)</code> is the function generating the specification; its first parameter is the time in seconds to rise from <code>0</code> to <code>1</code>, and the second parameter is the time to fall back to <code>0</code>. The <code>:act :free</code> keywords for <code>env-gen</code> specify that once the envelope has reached its end, the synth will be removed from the server, freeing up CPU resources.
</p>
<p>
The signal (<code>sig</code>) being generated is white noise (<code>white-noise.ar</code>) with its high frequencies dampened by the <code>lpf</code> low pass filter. The filter's frequency (<code>lpf</code>'s second argument) is the envelope generator multiplied by the synth's <code>freq</code> argument. Since the <code>perc</code> function generates an envelope that goes from <code>0</code> to <code>1</code> and then to <code>0</code> again, multiplying it by frequency is a simple way to change the brightness of the sound. Try the <code>synth</code> function with different values for its <code>:freq</code> key, from <code>20</code> to <code>10000</code> to get a feel for how it affects the sound.
</p>
<p>
The last line of the synth definition contains the <code>out.ar</code> UGen. When we use the <code>proxy</code> function, this UGen is automatically inserted for us for convenience, but when we define a synth manually, we have to specify it. <code>out</code>'s first argument is the index of the bus that you want to write to–in this case we just use <code>0</code> since we want the sound to go to our speakers. <code>out</code>'s second argument is a UGen or list of UGens that are generating the sound. Up to this point, we've only been generating mono (single channel) sounds. The <code>pan2</code> UGen accepts a mono signal as input (<code>sig</code> in our case) and converts it into a stereo signal based on its second argument, which specifies the panning position (here we use <code>0</code> to position it centrally). Finally, <code>pan2</code>'s third argument is an amplitude input, so we multiply the overall volume of the synth by <code>0.2</code>.
</p>
</div>
</div>
<div id="outline-container-orgaff985f" class="outline-2">
<h2 id="orgaff985f">Best Practices</h2>
<div class="outline-text-2" id="text-orgaff985f">
<p>
If you're going to make music with cl-collider, you're likely to end up writing a lot of ~defsynth~s. Because of this, it may be a good idea to use a template system for your editor. For example, Emacs users can use skeleton or yasnippet. Both of these allow you to create a template and easily insert it into a file so you don't have to do as much manual typing.
</p>
<p>
You may want to use something like the following as your basic template synth:
</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>newsynth<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>amp<span class="org-whitespace-space"> </span>0.5<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>out<span class="org-whitespace-space"> </span>0<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>adsr<span class="org-whitespace-space"> </span>0.001<span class="org-whitespace-space"> </span>0.1<span class="org-whitespace-space"> </span>0.5<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>saw.ar<span class="org-whitespace-space"> </span>freq<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>out<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>amp<span class="org-whitespace-space"> </span>env<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>
This is a good synthdef to start from because it includes most of what you'll need to get started: standard arguments, an envelope that frees the synth when complete, and of course, UGens to generate and output sound.
</p>
<p>
<code>gate</code>, <code>freq</code>, <code>amp</code>, <code>pan</code>, and <code>out</code> are all fairly common and standard arguments for synthdefs. <code>gate</code> is used to tell the synth whether it should play or release. If you were playing on a piano, <code>gate</code> would be <code>1</code> when you press a key, and would become <code>0</code> when you release the key. Because we provide <code>gate</code> to the <code>env-gen</code>, the envelope will start when the gate is 1 and will proceed to the release section when the gate becomes 0. Then, when the release section ends, the envelope will free itself.
</p>
<p>
<code>freq</code> is the standard argument name for sending pitch information to a synthdef. If you want to control the pitch of a synth using a midi note number instead, you can use the <code>midicps</code> function to convert the midi note number to a frequency. Like so:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defparameter</span><span class="org-whitespace-space"> </span><span class="org-variable-name">*ns*</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>synth<span class="org-whitespace-space"> </span>'newsynth<span class="org-whitespace-space"> </span><span class="org-builtin">:freq</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-3">(</span>midicps<span class="org-whitespace-space"> </span>40<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>
We don't have to specify all of the arguments to <code>newsynth</code> since they all have default values.
</p>
<p>
Since the synth will sustain until we specifically tell it to release, we save the result of calling the <code>synth</code> function to the <code>*ns*</code> variable. When we want to release it, we can just call <code>release</code> on <code>*ns*</code>, like so:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>release<span class="org-whitespace-space"> </span>*ns*<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
<a href="03-make-a-sound.html">Previous: Make a Sound</a> / <a href="05-sampling.html">Next: Sampling</a>
</p>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="date">Created: 2017-06-30 Fri 01:18. Updated: 2025-02-07 Fri 19:32.</p>
</div>
</body>
</html>