SuperCollider sound generator

Super Sound

© Lead Image © Pinnacle-Animates, 123RF.com

© Lead Image © Pinnacle-Animates, 123RF.com

Article from Issue 161/2014
Author(s):

SuperCollider is a versatile and powerful sound generator that can be used to create, filter, and modulate sound. In this article, we tackle the basics.

SuperCollider [1] is not all about particle physics, but it could be. Although it's 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.

Installation

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 [2], or you can clone the development tree with

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

So that 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:

# apt-get install cmake libsndfile1-dev libx11-dev libxt-dev libjack-dev libasound2-dev libqt4-dev emacs

For certain extensions and plugins, the following items might be useful as well:

# apt-get install lame alsaplayer-jack

After these things are all 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 and then stop:

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

The solution is quite easy: cd out of the build directory and run

$ git submodule init && git submodule update

Then, you can re-enter build and run cmake again.

Once cmake has finished successfully, run make and, when done, run make install as root to copy all the bits and pieces into place.

One of the most important SuperCollider dependencies is the Jack [3] 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.

Most Linux distros contain precompiled packages of Jack in their repos, so you can usually just install it using your software manager. In Debian, for example, you would do

# apt-get install jackd1

You also don't have to worry about running the jackd server by hand because SuperCollider (SC) will do that for you when you start the SC server.

What you will have to do is kill the Jack daemon when you exit SuperCollider:

$ killall jackd

If you don't, most of your audio programs (including Firefox when playing videos and so on) will freeze while they try to access PulseAudio or Alsa.

Boot Time

With the installation out of the way, you'll find most of the important files under /usr/local and in your own home directory under .local/share/SuperCollider. The SuperCollider executables will be in /usr/local/bin, and some configuration files and documentation will be in /usr/local/share/SuperCollider.

As for the executables, SuperCollider installs scide, sclang, sclangpipe_app, scsynth, scvim, and supernova. The most interesting two are scide and sclang, but just for the record, sclangpipe_app is used by scvim, which in turn is a Vim-like front end for sclang, and scsynth is the server proper, which I'll address shortly. Finally, supernova is an implementation of the SuperCollider server for parallel processing, although you won't need it for the purposes of this article.

On the other hand, sclang, short for SuperCollider language, is a command-line interpreter similar to Bash or the Python terminal that works well if you just want to try things out but is not so useful for complex coding. You can run it by entering sclang in a terminal window. Much more useful is scide, the SuperCollider IDE (Figure 1), which is also run in a terminal window.

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.

To run SuperCollider commands, type them into the workspace and press Ctrl+Enter while the cursor is on the same line. The SuperCollider language is an object-oriented functional language similar to Smalltalk, with syntactical characteristics borrowed from LISP and C++. You can declare a single-character variable (which are all objects) just by setting it to a value:

a=3;

Note the semicolon that ends a command. Now you can access the value of a by calling the value method:

a.value;

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 this, 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 the lines

var ab;
ab=3;

the Post window will print an error stating that the variable ab is not defined.

To create a scope so you can use ab, you have to group the commands between brackets:

(
var ab;
ab=3;
)

Now, when you place your cursor anywhere within the brackets and hit Ctrl+Enter, the value is assigned to ab correctly. Also try

"Hello".postln;
"World".postln;

and

(
"Hello".postln;
"World".postln;
)

and note how the outputs differ 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 to output. I could go on, but writing about SuperCollider's programming language deserves a book in itself, and there a plenty of good ones [4] 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

Before you can begin, you have to run the SuperCollider server by entering

s.boot

in the IDE window (and hitting Ctrl+Enter). The s object is one of those internal single-character variables I mentioned earlier, and it represents the local server and has its own methods and attributes. (You can also use a remote server, if you like.) To stop the server, you would use s.quit.

From the menubar, you can run the server with Language | Boot Server, or using the keyboard, you press Ctrl+B. Check for any errors in the Post window and make sure the volume of your headphones is up, but not too high: Mistakes in SC code tend to make SuperCollider's output very noisy, indeed, and you don't want to damage your headphones, speakers, or, worse, your eardrums.

The simplest sound you can generate with SuperCollider is an unfiltered and unmodulated wave, and the shortest way to do that is with an unnamed function (curly brackets enclose functions in SuperCollider):

{SinOsc.ar(261.26, 0, 0.7)}.play;

The SinOsc object calls a sine wave oscillator, similar to the image in the top left corner of Figure 2.

Figure 2: Different types of sound waves. Top row, left to right: simple sine wave, parabolic sine wave, and cubic sine wave. Middle row: sawtooth wave, triangle wave, and pulse wave. Bottom: white noise wave.

The ar method tells the interpreter to generate an audio signal. As you will see later, you can also generate control signals (kr), but for a smooth, high-quality sound, you need to call ar.

Parameters appear within brackets. The first value, 261.26, is the frequency or pitch, measured in hertz (i.e., phases per second). The higher the number, the higher the pitch (261.26, by the way, is middle C). In this case, the oscillator runs through 261.26 cycles per second.

If you are familiar with midi notation, you can give the value using the .midicps attribute:

{SinOsc.ar(60.midicps, 0, 0.7)}.play;

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

{SinOsc.ar(261.26, pi, 0.7)}.play;

the wave would start halfway though (i.e, cutting the 0 axis), but on the way down.

The third parameter is the multiplier and affects the volume of the wave. It varies from 0 (silence) to very loud. You probably don't want to go past 1. Another way to pass parameters to a function is by naming them. In this case, you can place them in any order. For example,

{SinOsc.ar(261.26, pi, 0.7)}.play;

is the same as

{SinOsc.ar(mul:0.7, freq:261.26, phase:pi)}.play;

To silence the sound, press Ctrl+. (period). If you want to see what the wave looks like as it plays, try

{SinOsc.ar(261.26, pi, 0.7)}.scope;

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

Figure 3: The scope method shows the wave as it plays.
{SinOsc.ar(261.26, pi, 0.7)}.plot;

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

{SinOsc.ar(261.26, pi, 0.7)}.plot(1);

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

When using headphones, you can hear sound only through the left speaker because each channel is assigned independently through an array and channel 0 corresponds to the left speaker. If you enter

{[SinOsc.ar(261.26, pi, 0.7), SinOsc.ar(300, pi, 0.7)]}.play;

you will hear a sine wave at 261.26Hz through your left speaker and a sine wave at 300Hz through your right speaker. This command can be shortened to

{SinOsc.ar([261.26, 300], pi, 0.7)}.play;

and it also works with different volumes:

{SinOsc.ar([261.26, 300], pi, [0.7, 0.5])}.play;

If you only want the right speaker, enter

{SinOsc.ar([0, 300], pi, 0.7)}.play;

or:

{[nil, SinOsc.ar(300, pi, 0.7)]}.play;

To assign a function to a variable and then free one channel at a time, use

x = {SinOsc.ar(261.26, pi, 0.7)}.play;
y = {[nil, SinOsc.ar(300, pi, 0.5)]}.play;
x.free;
y.free;

instead of shutting them all down with the Ctrl+. key combination.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters

Support Our Work

Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.

Learn More

News