linux: shared memory interface - link with librt
[supercollider.git] / HelpSource / Tutorials / Getting-Started / 13-Buffers.schelp
blob116cae63fb9e16590f3cc753a3e8bc235b8854bf
1 title:: 13. Buffers
2 summary:: Getting Started With SuperCollider
3 categories:: Tutorials>Getting-Started
4 related:: Tutorials/Getting-Started/00-Getting-Started-With-SC
6 Buffers represent server buffers, which are ordered arrays of floats on the server. 'float' is short for floating point number, which means a number with a decimal point, like 1.3. This is in contrast to integers, which are positive or negative whole numbers (or zero), and are written without decimal points. So 1 is an integer, but 1.0 is a float.
8 Server buffers can be single or multichannel, and are the usual way of storing data server-side. Their most common use is to hold soundfiles in memory, but any sort of data that can be represented by floats can be stored in a buffer.
10 Like busses, the number of buffers is set before you boot a server (using link::Classes/ServerOptions::), but before buffers can be used, you need to allocate memory to them, which is an asynchronous step. Also like busses, buffers are numbered, starting from 0. Using Buffer takes care of allocating numbers, and avoids conflicts.
12 You can think of buffers as the server-side equivalent of an Array, but without all the elegant OOP functionality. Luckily with Buffer, and the ability to manipulate data in the client app when needed, you can do almost anything you want with buffer data. A server's buffers are global, which is to say that they can be accessed by any synth, and by more than one at a time. They can be written to or even changed in size, emphasis::while:: they are being read from.
14 Many of Buffer's methods have numerous arguments. Needless to say, for full information see the link::Classes/Buffer:: help file.
16 section::Making a Buffer Object and Allocating Memory
18 Making a Buffer object and allocating the necessary memory in the server app is quite easy. You can do it all in one step with Buffer's alloc method:
20 code::
21 s.boot;
22 b = Buffer.alloc(s, 100, 2);    // allocate 2 channels, and 100 frames
23 b.free;                         // free the memory (when you're finished using it)
26 The example above allocates a 2 channel buffer with 100 frames. The actual number of values stored is numChannels * numFrames, so in this case there will be 200 floats. So each frame is in this case a pair of values.
28 If you'd like to allocate in terms of seconds, rather than frames, you can do so like this:
30 code::
31 b = Buffer.alloc(s, s.sampleRate * 8.0, 2); // an 8 second stereo buffer
32 b.free;
35 Buffer's 'free' method frees the memory on the server, and returns the Buffer's number for reallocation. You should not use a Buffer object after doing this.
37 section::Using Buffers with Sound Files
39 Buffer has another class method called 'read', which reads a sound file into memory, and returns a Buffer object. Using the UGen PlayBuf, we can play the file.
41 code::
42 // read a soundfile
43 b = Buffer.read(s, Help.dir +/+ "sounds/a11wlk01.wav");
45 // now play it
47 x = SynthDef("tutorial-PlayBuf",{ arg out = 0, bufnum;
48         Out.ar( out,
49                 PlayBuf.ar(1, bufnum, BufRateScale.kr(bufnum))
50         )
51 }).play(s,[\bufnum, b]);
53 x.free; b.free;
56 PlayBuf.ar has a number of arguments which allow you to control various aspects of how it works. Take a look at the link::Classes/PlayBuf:: helpfile for details of them all, but for now lets just concern ourselves with the first three, used in the example above.
58 code::
59 PlayBuf.ar(
60         1,                              // number of channels
61         bufnum,                         // number of buffer to play
62         BufRateScale.kr(bufnum)         // rate of playback
63         )
66 Number of channels: When working with PlayBuf you must let it know how many channels any buffer it will read in will have. emphasis::You cannot make this an argument in the SynthDef and change it later.:: Why? Remember that SynthDefs must have a fixed number of output channels. So a one channel PlayBuf is always a one channel PlayBuf. If you need versions that can play varying numbers of channels then make multiple SynthDefs or use Function-play.
68 Bufffer Number: As noted above, Buffers are numbered, starting from zero. You can get a Buffer's number using its strong::bufnum:: method, but you will not normally need to do this, since Buffer objects can be passed directly as UGen inputs or Synth args.
70 Rate of Playback: A rate of 1 would be normal speed, 2 twice as fast, etc. But here we see a UGen called BufRateScale. What this does is check the samplerate of the the buffer (this is set to correspond to that of the soundfile when it is loaded) and outputs the rate which would correspond to normal speed. This is useful because the soundfile we loaded (a11wlk01.wav) actually has a samplerate of 11025 Hz. With a rate of 1, PlayBuf would play it back using the sampling rate of the server, which is usually 44100 Hz, or four times as fast! BufRateScale thus brings things back to normal.
72 section::Streaming a File in From Disk
74 In some cases, for instance when working with very large files, you might not want to load a sound completely into memory. Instead, you can stream it in from disk a bit at a time, using the UGen DiskIn, and Buffer's 'cueSoundFile' method:
76 code::
78 SynthDef("tutorial-Buffer-cue",{ arg out=0,bufnum;
79         Out.ar(out,
80                 DiskIn.ar( 1, bufnum )
81         )
82 }).send(s);
85 b = Buffer.cueSoundFile(s,Help.dir +/+ "sounds/a11wlk01-44_1.aiff", 0, 1);
86 y = Synth.new("tutorial-Buffer-cue", [\bufnum,b], s);
88 b.free; y.free;
91 This is not as flexible as PlayBuf (no rate control), but can save memory. footnote::For variable playback rate while streaming from disk, look at the link::Classes/VDiskIn:: UGen.::
93 section::More on Instance Variables and Action Functions
95 Now a little more OOP. Remember that individual Objects store data in emphasis::instance variables::. Some instance variables have what are called getter or setter methods, which allow you to get or set their values. We've already seen this in action with Buffer's 'bufnum' method, which is a getter for its buffer number instance variable.
97 Buffer has a number of other instance variables with getters which can provide helpful information. The ones we're interested in at the moment are numChannels, numFrames, and sampleRate. These can be particularly useful when working with sound files, as we may not have all this information at our fingertips before loading the file.
99 code::
100 // watch the post window
101 b = Buffer.read(s, Help.dir +/+ "sounds/a11wlk01.wav");
102 b.bufnum;
103 b.numFrames;
104 b.numChannels;
105 b.sampleRate;
106 b.free;
109 Now (like with the example using an action function in our Bus-get example; see link::Tutorials/Getting-Started/11-Busses::) because of the small messaging latency between client and server, instance variables will not be immediately updated when you do something like read a file into a buffer. For this reason, many methods in Buffer take action functions as arguments. Remember that an action function is just a Function that will be evaluated after the client has received a reply, and has updated the Buffer's vars. It is passed the Buffer object as an argument.
111 code::
112 // with an action function
113 // note that the vars are not immediately up-to-date
115 b = Buffer.read(s, Help.dir +/+ "sounds/a11wlk01.wav", action: { arg buffer;
116         ("numFrames after update:" + buffer.numFrames).postln;
117         x = { PlayBuf.ar(1, buffer, BufRateScale.kr(buffer)) }.play;
120 // Note that the next line will execute BEFORE the action function
121 ("numFrames before update:" + b.numFrames).postln;
123 x.free; b.free;
126 In the example above, the client sends the read command to the server app, along with a request for the necessary information to update the Buffer's instance variables. It then cues the action function to be executed when it receives the reply, and continues executing the block of code. That's why the 'Before update...' line executes first.
128 section::Recording into Buffers
130 In addition to PlayBuf, there's a UGen called RecordBuf, which lets you record into a buffer.
132 code::
133 b = Buffer.alloc(s, s.sampleRate * 5, 1); // a 5 second 1 channel Buffer
135 // record for four seconds
137 x = SynthDef("tutorial-RecordBuf",{ arg out=0,bufnum=0;
138         var noise;
139         noise = PinkNoise.ar(0.3);      // record some PinkNoise
140         RecordBuf.ar(noise, bufnum);    // by default this loops
141 }).play(s,[\out, 0, \bufnum, b]);
144 // free the record synth after a few seconds
145 x.free;
147 // play it back
149 SynthDef("tutorial-playback",{ arg out=0,bufnum=0;
150         var playbuf;
151         playbuf = PlayBuf.ar(1,bufnum);
152         FreeSelfWhenDone.kr(playbuf); // frees the synth when the PlayBuf has played through once
153         Out.ar(out, playbuf);
154 }).play(s,[\out, 0, \bufnum, b]);
156 b.free;
159 See the link::Classes/RecordBuf:: help file for details on all of its options.
161 section::Accessing Data
163 Buffer has a number of methods to allow you to get or set values in a buffer. Buffer-get and Buffer-set are straightforward to use and take an index as an argument. Multichannel buffers interleave their data, so for a two channel buffer index 0 = frame1-chan1, index 1 = frame1-chan2, index 2 = frame2-chan1, and so on. 'get' takes an action function.
165 code::
166 b = Buffer.alloc(s, 8, 1);
167 b.set(7, 0.5);                  // set the value at 7 to 0.5
168 b.get(7, {|msg| msg.postln});   // get the value at 7 and post it when the reply is received
169 b.free;
172 The methods 'getn' and 'setn' allow you to get and set ranges of adjacent values. 'setn' takes a starting index and an array of values to set, 'getn' takes a starting index, the number of values to get, and an action function.
174 code::
175 b = Buffer.alloc(s,16);
176 b.setn(0, [1, 2, 3]);                           // set the first 3 values
177 b.getn(0, 3, {|msg| msg.postln});               // get them
178 b.setn(0, Array.fill(b.numFrames, {1.0.rand})); // fill the buffer with random values
179 b.getn(0, b.numFrames, {|msg| msg.postln});     // get them
180 b.free;
183 There is an upper limit on the number of values you can get or set at a time (usually 1633 when using UDP, the default). This is because of a limit on network packet size. To overcome this Buffer has two methods, 'loadCollection' and 'loadToFloatArray' which allow you to set or get large amounts of data by writing it to disk and then loading to client or server as appropriate.
185 code::
187 // make some white noise
188 v = FloatArray.fill(44100, {1.0.rand2});
189 b = Buffer.alloc(s, 44100);
192 // load the FloatArray into b, then play it
193 b.loadCollection(v, action: {|buf|
194         x = { PlayBuf.ar(buf.numChannels, buf, BufRateScale.kr(buf), loop: 1)
195                 * 0.2 }.play;
198 x.free;
200 // now get the FloatArray back, and compare it to v; this posts 'true'
201 // the args 0, -1 mean start from the beginning and load the whole buffer
202 b.loadToFloatArray(0, -1, {|floatArray| (floatArray == v).postln });
203 b.free;
206 A FloatArray is just a subclass of Array which can only contain floats.
208 section::Plotting and Playing
210 Buffer has two useful convenience methods: 'plot' and 'play'.
212 code::
213 // see the waveform
214 b = Buffer.read(s, Help.dir +/+ "sounds/a11wlk01.wav");
215 b.plot;
217 // play the contents
218 // this takes one arg: loop. If false (the default) the resulting synth is
219 // freed automatically
220 b.play;                         // frees itself
221 x = b.play(true);               // loops so doesn't free
222 x.free; b.free;
225 section::Other Uses For Buffers
227 In addition to being used for loading in sound files, buffers are also useful for any situation in which you need large and/or globally accessible data sets on the server. One example of another use for them is as a lookup table for waveshaping.
229 code::
230 b = Buffer.alloc(s, 512, 1);
231 b.cheby([1,0,1,1,0,1]);
233 x = play({
234         Shaper.ar(
235                 b,
236                 SinOsc.ar(300, 0, Line.kr(0,1,6)),
237                 0.5
238         )
241 x.free; b.free;
244 The Shaper UGen performs waveshaping on an input source. The method 'cheby' fills the buffer with a series of chebyshev polynomials, which are needed for this. (Don't worry if you don't understand all this.) Buffer has many similar methods for filling a buffer with different waveforms.
246 There are numerous other uses to which buffers can be put. You'll encounter them throughout the documentation.
248 For more information see:
250 link::Classes/Buffer::, link::Classes/PlayBuf::, link::Classes/RecordBuf::, link::Classes/SynthDef::, link::Classes/BufRateScale::, link::Classes/Shaper::
252 ____________________
254 This document is part of the tutorial strong::Getting Started With SuperCollider::.
256 Click here to return to the table of Contents: link::Tutorials/Getting-Started/00-Getting-Started-With-SC::