-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy path05-sampling.html
140 lines (121 loc) · 12.7 KB
/
05-sampling.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
132
133
134
135
136
137
138
139
140
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 2025-02-07 Fri 19:33 -->
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Sampling</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">Sampling</h1>
</header><p>
In addition to its powerful library of oscillators and sound generators, SuperCollider also gives us the ability to use recorded sounds in our synths. In SuperCollider, a recorded sound is stored in a buffer object on the server. A buffer is effectively an array of numbers which can be of any length and can have one or more channels. It's possible to load a sound into a buffer from your hard drive, but it's also possible to record the output of a synth or UGen into a buffer directly on the server. A buffer can be played back normally, or you can control its rate and the playhead position with a UGen.
</p>
<div id="outline-container-org49375c7" class="outline-2">
<h2 id="org49375c7">Loading Sounds</h2>
<div class="outline-text-2" id="text-org49375c7">
<p>
To load a sound from the drive, use the <code>buffer-read</code> function, like so:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>buffer-read<span class="org-whitespace-space"> </span><span class="org-string">"/path/to/your/file.wav"</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
This should be pretty self-explanatory; the only required parameter to <code>buffer-read</code> is the path to the file you want to load. SuperCollider has support for wav and aiff files, of any sample rate and any number of channels.
</p>
</div>
</div>
<div id="outline-container-org40f8687" class="outline-2">
<h2 id="org40f8687">Playing Sounds</h2>
<div class="outline-text-2" id="text-org40f8687">
<p>
Once you've loaded a sound, you'll probably want to play it. Here's an example SynthDef which illustrates the UGens you'd use to do that:
</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><span class="org-builtin">:sample</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span><span class="org-rainbow-delimiters-depth-3">(</span>buffer<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>rate<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>start<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-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>sig<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-5">(</span>play-buf.ar<span class="org-whitespace-space"> </span>2<span class="org-whitespace-space"> </span>buffer<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>*<span class="org-whitespace-space"> </span>rate<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>buf-rate-scale.ir<span class="org-whitespace-space"> </span>buffer<span class="org-rainbow-delimiters-depth-7">)</span><span class="org-rainbow-delimiters-depth-6">)</span>
<span class="org-whitespace-space"> </span><span class="org-builtin">:start-pos</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-6">(</span>*<span class="org-whitespace-space"> </span>start<span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-7">(</span>buf-frames.ir<span class="org-whitespace-space"> </span>buffer<span class="org-rainbow-delimiters-depth-7">)</span><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-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>*<span class="org-whitespace-space"> </span>amp<span class="org-whitespace-space"> </span>sig<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>
Typically, to tell the synth what buffer we want it to play, we would usually add a <code>buffer</code> or <code>bufnum</code> parameter to the synthdef. These are fairly standard names for buffer parameters in synths, and some libraries may expect a buffer to be passed to a synth via a parameter with one of these names. So in general, it's probably a good idea to get in the habit of using one of the two in your buffer-playing synthdefs. For this synth, we've added a <code>buffer</code> parameter.
</p>
<p>
One thing to note is that we don't actually send the buffer object itself to the synth. In SuperCollider, each buffer has a ID number. The server will only understand these IDs, and any other names or objects will likely result in an error. Fortunately, cl-collider (as well as the official SuperCollider client) automatically translates buffer objects to buffer IDs in most functions, so you usually don't have to do it manually. If you do, however, keep in mind that cl-collider's <code>bufnum</code> function is what is used to get a buffer's ID number.
</p>
<p>
After the <code>buffer</code> parameter, we provide another for the playback rate. <code>rate</code> is the number to multiply the buffer's original speed by. So <code>1</code> would play the buffer back at its normal speed, <code>2</code> would play it twice as fast (and one octave higher), and <code>0.5</code> would play it half as fast (one octave lower).
</p>
<p>
In this SynthDef, we also include a <code>start</code> parameter, which lets us pick where in the sample to start playing from. In the SynthDef, a <code>start</code> value of <code>0</code> means start from the beginning, while <code>0.5</code> means start playing halfway through the buffer. Most SuperCollider UGens that use buffers take the playback position as a frame number, but it's often more convenient to be able to specify the relative position in the file regardless of its sample rate, so we multiply <code>start</code> by the number of frames in the sample to make this possible.
</p>
<p>
The body of the SynthDef is fairly simple; the main UGen is <code>play-buf</code> which, as the name suggests, plays the buffer. Its first argument is the number of channels the buffer has. This is required by SuperCollider, and can't be modified while the synth is playing, or used as a parameter. It has to be a static number when the synth is compiled.
</p>
<p>
The second argument to <code>play-buf</code> is the buffer number. After that, the playback rate. Here we multiply our <code>rate</code> parameter by <code>(buf-rate-scale.ir buffer)</code>. <code>buf-rate-scale</code> is a UGen that outputs a number that we can multiply by in order to play a sample at its original speed regardless of the original file's sampling rate. If we just supplied our <code>rate</code> parameter directly, any sample that you load would play at the wrong speed if it doesn't match the sampling rate of the server itself.
</p>
<p>
You might also notice the <code>.ir</code> on the end of <code>buf-rate-scale</code>. <code>.ir</code> specifies that the UGen should "initialization rate": processed only once, when the synth is started. This frees up CPU usage, but it also gives us the disadvantage of not being able to change the buffer that the synth is playing while it's playing. Typically it's not necessary to change the buffer of an already-playing synth, but if you want that ability, you can just change the <code>.ir</code> to a <code>.kr</code>.
</p>
<p>
<code>start-pos</code> is the argument <code>play-buf</code> takes to specify where to start playing the sample from. Since <code>play-buf</code> expects a frame number for that parameter, we multiply our <code>start</code> parameter by the <code>buf-frames</code> UGen, which gives the total number of frames of the buffer. This is another <code>.ir</code> UGen for the same reason as above.
</p>
<p>
Finally, the <code>act</code> parameter specifies what action should be taken when <code>play-buf</code> finishes playing the sound. In our case, we provide <code>:free</code> so that the synth will stop playing and be freed. Without this, the synth would continue running in the background and continue using CPU resources even though it's making no sound.
</p>
<p>
Of course, you may want to have the sound loop instead, in which case <code>act</code> would be left to its default value, so no special action is taken when the sound reaches its end. You would also have to provide <code>play-buf</code>'s <code>loop</code> parameter a value of <code>1</code>.
</p>
<p>
To actually play the <code>sample</code> synth, we'll want to make sure that we've saved the reference to the file we opened with <code>buffer-read</code> to a variable:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span><span class="org-keyword">defvar</span><span class="org-whitespace-space"> </span><span class="org-variable-name">*file*</span><span class="org-whitespace-space"> </span><span class="org-rainbow-delimiters-depth-2">(</span>buffer-read<span class="org-whitespace-space"> </span><span class="org-string">"/path/to/your/file.wav"</span><span class="org-rainbow-delimiters-depth-2">)</span><span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
Then, we can start the <code>sample</code> synth like so:
</p>
<div class="org-src-container">
<pre class="src src-lisp"><span class="org-rainbow-delimiters-depth-1">(</span>synth<span class="org-whitespace-space"> </span>'sample<span class="org-whitespace-space"> </span><span class="org-builtin">:buffer</span><span class="org-whitespace-space"> </span>*file*<span class="org-rainbow-delimiters-depth-1">)</span>
</pre>
</div>
<p>
As mentioned above, since <code>play-buf</code>'s <code>:act</code> argument is set to <code>:free</code>, the synth will automatically be freed when the sample finishes playing. Of course, if we had set the sample to loop, then it would continue looping indefinitely, or until we stop it manually. Because there is no <code>:gate</code> argument, the <code>release</code> function would have no effect, so we would have to call <code>stop</code> instead, to force it to stop.
</p>
<p>
<a href="04-further-soundmaking.html">Previous: Further Soundmaking</a> / <a href="06-sequencing.html">Next: Sequencing</a>
</p>
</div>
</div>
</div>
<div id="postamble" class="status">
<p class="date">Created: 2017-07-25 Tue 03:48. Updated: 2025-02-07 Fri 19:33.</p>
</div>
</body>
</html>