The Living Thing / Notebooks : Supercollider

Supercollider (downloads link) is the collective noun describing two coupled programming languages oriented toward live interactive music. I use ‘em a lot, e.g. for pattern machine. The default user-facing language is called sclang, an aging smalltalk derivative with nice scheduling facilities. The DSP backend is called scsynth. The two talk to one another over opensoundcontrol. scsynth is wonderful. sclang has wonderful advanced features, but is a locked-in underdeveloped ghetto, kind of a District 9 of software.

Perhaps you’d like to use javascript to control supercollider instead? Or something else? There is a whole ecosystem of alternative sequencing languages that interface with the DSP core.

That’s what I’m mostly doing, these days. Vanilla supercollider will be dealt with later.

Supercollider alternative: Clojure+overtone+scsynth

Clojure replaces scsynth, using overtone.

Supercollider alternative: javascript+scsynth

Javascript, using supercollider.js. (Browsers are synthesizers these days in a more general sense too. See javascript audio.)

Supercollider alternative: python+scsynth

FoxDot runs supercollider scripts from python. It comes with an IDE, which is a waste of time IMO, but a nice scheduler (see the docs)

Supercollider alternative: haskell+scsynth

TidalCycles aka Tidal, runs supercollider scripts from Haskell. It has a beautiful although opinionated syntax

Vanilla Supercollider notes

In a classic failure of academic publishing, the de facto manual for SC was released as a closed-source, heavily-delayed, pre-obsoleted, very expensive book. There is an effort underway to transate Valle’s alternative manual.

There are lots of bad bits mentioned. Don’t interpret these as complaints; think of them as little public encouragements for me to learn C++ coding and start fixing them. NB: this won’t actually ever happen.

OTOH, why the hell does there exist yet another poorly-maintained programming language, when we have many, many very good ones? Why not choose your battles by adapting a mainstream langauge to be better at programming audio? If that sounds too complicated (and it is somewhat complicated) here are some things that you should not expect to sneak up and pounce on you doing it the old school way.

debugging

No step debugger, so you have to debug your complex nests of client and server-side code with print statements. No, really, that’s the recommended way, and precisely what the debug method does.

Not-really-interactive scope

USed to defining variables in a REPL and then using them later?

Try running these two lines, both at once:

var foo="bar";
foo;

You should get back, as you’d expect, bar. Now, run them one at a time. Result:

• ERROR: Variable 'foo' not defined.
   in file 'selected text'
   line 1 char 3:
  foo•;

You can work around this by using “environments”, and other hacks, that is, creating variable as entries in a hash-table with reasonably compact syntax: give them names prepended with a tilde, as, e.g. ~foo. However, this means that you have completely different syntax and scoping rules in live and library coding. There are two different languages you now have to work with, and neither helps to debug the other particularly much. If, say, you wanted to copy a troublesome method from a class into the interactive document window to step through it and work out where it’s gone wrong (since, as mentioned above, there is no step debugger, this is as good as it gets)… and so the pain develops from a nagging irritation to a skull-grinding cluster headache.

Concurrency hell

While supercollider stil has the best sequencer, other concurrency problems have been solved by the rest of the world while sclang stagnated.

Server-client concurrency hell. If you code the way that the help files do things, i.e. small numbers of lines of code, each executed manually, you will end up writing code that looks like it works but explodes the moment you try to up the speed or parallelism with which it is executed. TTo do anything at all you need to execute it inside a Routine and use server synchronisation to make sure that nothing arrives out of order. However, in my experience this is not 100% reliable; the entire thing relies on UDP packets which have no particularly useful guarantees about order or arrival. However, it’s better than nothing; If you don’t do this, sometimes you will get nice, plain errors. More perniciously, sometimes, though, with with patches involving complicated wiring such as Instr and FFTs and such, you put yourself at risk of having things wired together entirely incorrectly, and having hard-to-trace examples of Bus objects full of crosstalk and garbage.

IO

OSC and MIDI are handled by a, to my mind, elegant evented asynchronous callback system after the latest modern trend. Could be a little better but feels fairly natural, and you can subclass away the rough edges. However for all other IO (file, socket, other network protocols, serial, whatever), it’s blocking access. So if you wish to talk other, more modern protocols, you are reasonably fucked, and for that matter, your elegant OSC/MIDI system is caught in the crossfire. In practice you end up running another instance to relay pipe contents over OSC.