Sculpting Sound with SuperCollider

Super Sound Generator



SuperCollider is not all about particle physics, but it could be. Although described as “… an environment and programming language for real time audio synthesis and algorithmic composition,” it is much more than that, as you will see.


As usual, I chose to use a base Debian “Wheezy” with all updates applied. You can get precompiled SuperCollider packages for several operating systems and Linux flavors, or you can clone the development tree with

$ git clone https://github.com/supercollider/supercollider.git

So I could enjoy the latest features, I went for the clone, but as usual, you will also have to install some dependencies before you can get a clean compile. Installing on Debian, you will need the following:


For certain extensions and plugins, you might find that the following useful as well:

# apt-get install lame alsaplayer-jack

Once all of the above is installed, cd into the supercollider directory and create a build directory before building the packages:

$ mkdir build
$ cd build
$ cmake ..

During the build process, cmake may report the following error

nova-simd submodule is missing: please run 'git submodule init && git submodule update' from the toplevel of your git working tree

and then stop. The solution is quite easy: cd up out of the build directory and run

$ git submodule init && git submodule update



One of the most important SuperCollider dependencies is the Jack sound server. Interestingly, SuperCollider installs just fine without the package that contains the Jack daemon (jackd) proper; it’s only when you try to run the SuperCollider server (more about this below) that it will bomb and inform you that Jack is missing.


# apt-get install jackd1



$ killall jackd


Boot Time





Figure 1: The SuperCollider IDE on startup.

The left pane is the workspace, which is where you write (and often run) your code. Several workspaces can be accessed via tabs across the top of the window. On the top right is the very useful SuperCollider Help system, which you’ll be using a lot. Below that, the Post window displays output, errors, and so on.






If you press Ctrl+Enter while the cursor is on the first line and then do the same on the second line, a 3 should appear in the Post window for each command. Nearly all SuperCollider “commands” are really functions with a return value, and in this case, the only value the interpreter can find is the content of a.

Longer variable names are advisable because some single-character variables are used internally by the interpreter. To do so, use the var keyword. When using var, the variable must belong to a certain scope (i.e., a group of commands executed together).

For example, if you execute

var ab;





var ab;


Also try




and note how the output differs in the Post window. In the first example, you have to press Ctrl+Enter on each line for each word to output. In the second example, you just have to press Ctrl+Enter once while your cursor is on any of the lines to get both words of output.

I could go on, but writing about SuperCollider's programming language deserves a book in itself, and there a plenty of good ones online for free.

From now on, I’ll explain the language through examples. SuperCollider was created to engineer sounds, so I'll proceed to make some noise!

Making a Ruckus













The midi value 60 is middle C.

The second value in SinOsc is the phase offset in radians, which is the position from which the wave starts. If you look at the top left-hand corner of Figure 2 again, you’ll see that the wave starts at 0. If you used






is the same as




(Figure 3). To take a static snapshot, use:


All of these methods – play, scope, and plot – have their own set of parameters. If you try


for example, you'll see a whole second of the wave instead of the default 100th of a second.





which works with different volumes, too:


If you only want the right speaker, you can enter






instead of shutting them all down with the Ctrl+. keystroke.

Piling ’em Up

Up until now, the examples have been pretty boring, but they are the basic building blocks of much more complex and interesting sounds. Because all functions and commands in SuperCollider return a value, you can use the output of one oscillator (e.g., sine) as a parameter for another oscillator. The line

{LFSaw.ar(200, 0, 1 * SinOsc.kr(1, 0, 1))}.scope;

modifies the multiplier (volume) parameter of the sawtooth wave (Figure 2, middle row, far left; a twangy, guitar-like sound), with the sine oscillator. The scope at the end lets you see what’s happening. Note the kr method appended to SinOsc, which is a control function (i.e, it is modulating, not generating, a sound) instead of ar, which is much more CPU intensive. The sine oscillator frequency is set to 1Hz (1 cycle per second), so the saw oscillator's volume varies between 1 and -1 every second, rendering a siren-like sound.

Piling on as many functions as you like allows you to create really sophisticated effects. The following, for example, pans the sound from one speaker to the other:

{Pan2.ar( LFSaw.ar(200, 0, 1 * SinOsc.kr(1, 0, 1).abs), SinOsc.kr(0.5))}.play;

The Pan2 function is used to pan between two channels – the Pan4 function handles four-channel output – and takes as arguments the audio signal and a number between -1 (left) and +1 (right). The default multiplier of the sine oscillator is 1, so in the second argument of Pan2 (SinOsc.kr(0.5)), you only have to specify the frequency. Now you will hear the siren on the right panning over to the left and back again every half second.

Mix and Match

Now I’ll look closely at the following line from the inside out:

{ Pan2.ar( Mix.fill( 8, { LFSaw.ar(200 + 200.0.rand, 0, 1 / 8) }), SinOsc.kr( 0.5 ) )  }.play;

Among the confusing array of fences, the Pan2.ar function has two parameters: Mix.fill( <n>, { LFSaw.ar(200 + 200.0.rand, 0, 1 / <n>) }) and SinOsc.kr( <n> ).

  • LFSaw.ar(200 + 200.0.rand, 0, 1 / 8), the innermost function of the first parameter, looks similar to an earlier example: the sawtooth wave generator. The rand method affixed to 200.0 (a float number) returns a random number between 0.0 and 200.0, thus generating a sawtooth wave with a frequency between 200 and 400. The pulse starts at 0 with an amplitude (volume) of 1/8.
  • SinOsc.kr( 0.5 ), the second parameter of the Pan2.ar function. is also familiar. This function pans the sound wave between the right and left speaker every half a second.
  • Mix.fill( 8, { … }) is new. The Mix function, as advertised, mixes two (or more) sound waves. In this case, its fill method mixes as many waves as indicated by the first parameter (8). The second parameter to Mix is the wave generator (i.e., the sawtooth oscillator). Here, eight slightly different sawtooth waves (i.e., with frequencies that vary randomly between 200 and 400Hz) are mixed to achieve something that sounds like a truck’s horn in a traffic jam. The volumes of mixed waves are additive, so each wave is assigned a volume of 1/8; with eight waves, the total mixed signal has volume of 1.
  • Pan2.ar( … ), finally, pans the effect from one speaker to the other every half second.

Although piling up functions gives you very sophisticated results, it can also get confusing quickly, which is why grouping is useful. Listing 1 has exactly the same effect as the one-line instruction, but it is much easier to read. Plus, you can use a multicharacter variable to define how many waves (line 2) you want to mix.

Listing 1: Truck Horn

  var waves=8;
      { LFSaw.ar(200 + 200.0.rand, 0, 1 / waves) }


Once you have built your own building blocks, you will want to save them and turn them into a shortcut for creating more sophisticated soundblocks by using SynthDefs. For those familiar with OOP (object-oriented programming), think of SynthDefs as classes that you can then use to generate “objects” by instantiating the Synths.

Listing 2 is an example of building on a simple sine wave oscillator.

Listing 2: Sine SynthDef

  {arg myfreq=261.626, myvol=0.5;
  Out.ar([0, 1], SinOsc.ar(myfreq, 0, myvol))

Line 2 defines a SynthDef named ("sinewave") and declares some arguments that can be used later as parameters when called.

The new function in line 4, Out, writes a signal to a bus (channel). In this case, the first parameter is an array ([0, 1]) that indicates it will be writing to channel 0 (left) and 1 (right). The second parameter is the function that will be generating the wave (i.e., a simple audio (ar) sine wave).

Finally, on line 5, the SynthDef gets added to the server with add so it can be called from anywhere. If your SynthDef is really useful, you can save it for future sessions by changing add to writeDefFile and executing the block. Your SynthDef will then be loaded into the server every time it boots.

Now call the SynthDef (line 1) and pass it some parameters (line 2), or change the tone and volume as it plays:

x=Synth("sinewave", [myfreq:400]);
x.set("myfreq", 200);

Although the SynthDef structures are very useful, they have certain limitations compared with functions. For starters, a SynthDef is compiled, then the server runs the compiled, static version every time it is called. Therefore, if the SynthDef contains a random number generator, the random number will be calculated at run time, and the result is stored statically within the Synth, so it will not change any of the times the Synth is called.

You also can’t define dynamically the number of channels (buses) or waves you are going to use, again because this has to be compiled into the Synth.

Beyond the IDE

As mentioned elsewhere, SuperoCollider is a means to and end. Apart from an extensive vocabulary for sound, sclang offers a complete toolset that allows you to create your own interfaces. Listing 3, for example, creates the interface shown in Figure 4.

Figure 4: A simple graphic interface to change pitch and volume of a sine wave.

Listing 3: guiexample.scd

SynthDef("sinewave", {arg myfreq=261.626, myvol=0.5;
  Out.ar(0, SinOsc.ar(myfreq,0,myvol))
var awindow, myslider, myknob, mybutton;
myslider=EZSlider(awindow, label:"Volume",controlSpec:[0,1], action:{|mv| x.set("myvol",mv.value)}, initVal:0.5);
myknob=EZKnob(awindow, label:"Pitch",controlSpec:\freq, action:{|mn| x.set("myfreq",mn.value)}, initVal:261.626);
mybutton=Button(awindow, Rect(20,20, 50, 25))
  .states_([["Off", Color.black, Color.grey],
  .action_({ arg vbutton;

This program recycles the sinewave SynthDef seen earlier and, from lines 9 to 31, creates a simple window with three elements – a slider, a knob, and a button – to control the wave. Line 12 creates the window with FlowView, setting the title to Example.

EZSlider in line 13 creates the volume slider, and its parameters set the parent window (i.e., the window that contains it), the values it can take (between 0 and 1), the action it controls (a volume change of x, which is an “object” of the sinwave SynthDef, set in line 22), and the initial value (0.5).

The EZKnob widget in line 14 is virtually the same as EZSlider, except it controls the frequency of x.

The Button widget in line 16 creates a multistate button (with the values "Off" and "On") and starts and stops the sound depending on whether it transitions from one state to the other or vice versa.

Finally, line 30 sets the button’s initial state; otherwise, the button will not show up in the window.

To run this program, first execute the sinewave SynthDef (take your cursor to somewhere within the brackets and press Ctrl+Enter) then the program proper (move down to line 10, for example, and repeat Ctrl+Enter), and the window will pop up. Press the On/Off button to start and stop the sound, and drag the slider to change its volume or twist the knob to change the pitch.

Quarks and Plugins

Extensions are called Quarks in the SuperCollider lingo. These comprise anything from musical games (e.g., Chordtris, a musical Tetris played with a midi keyboard; Figure 5) to graphical interfaces for live performances.

Figure 5: Chordtris is a Quark (extension) that allows you to play a musical version of Tetris.

SuperCollider comes with its own package manager, also named Quarks (Figure 6). To get a list of Quarks, type Quarks.gui in the SC IDE, press Ctrl+Enter, and click the Update Quarks Listing button in the window. If nothing happens in a reasonable stretch of time, check the SC IDE Post window for errors. It may instruct you to erase a directory, such as /home/[user]/.local/share/SuperCollider/quarks and run Quarks.gui again.

Figure 6: SuperCollider comes with its own package manager for extensions (Quarks).

After installing or deleting Quarks, you might have to update the libraries and help systems by clicking Language | Recompile Class Library.

Plugins enhance the environment and add functionality to the language. To download the latest set of plugins from GitHub, use

$ git clone https://github.com/supercollider/sc3-plugins.git

and then compile as you would any source code program.


SuperCollider is not for the faint of heart. As with particle physics, sound creation and manipulation is difficult. That said, SuperCollider is immense, and I have only covered the very bare basics in this article. SuperCollider broaches literally everything you will ever need for sound engineering, allowing you to use it at nearly any level of competence.

SuperCollider is useful for educational purposes (plot and scope are great to show students what happens when a sound is being produced), composing, and live performances. If you want to experiment, check out the MouseX and MouseY functions to create a two-dimensional virtual theremin on your screen with a couple of lines of code. Also see how easy it is to create a Vocoder or to develop your own tools for your personal recording studio.

Related content

  • SuperCollider


comments powered by Disqus

Issue 231/2020

Buy this issue as a PDF

Digital Issue: Price $12.99
(incl. VAT)