Other things on this site...

MCLD
music
Evolutionary sound
Listen to Flat Four Internet Radio
Learn about
The Molecules of HIV
MCLD
software
Make Oddmusic!
Make oddmusic!
[Blog archives] [Categories]

SuperCollider inspired web audio coding environments

SuperCollider is an audio environment that gets a lot of things right in terms of hacking around with multichannel sound, live coding and composing the different structures you need for music.

So it's no surprise that in the world of Web Audio currently being born, various people are getting inspired by SuperCollider. I've seen a few people make pure-JavaScript systems which emulate SuperCollider's language style. So here's a list:

I think there's at least one I've forgotten. Please let me know if you spot others, I'd be interested to keep tabs.

So there are obvious questions: is this a duplication of effort? should these people get together and hack on one system? is any one of them better than the others? I don't know if any of them is better, but one thing I know: it's still very early days in the world of Web Audio. (The underlying APIs aren't even implemented fully by all major browsers yet.) I'm sure some cool live coding web systems will emerge, and they may or may not be based on the older generation. But there's still plenty of room for experimentation.

| supercollider |

Notes on how we ran the SuperCollider Symposium 2012

I've just uploaded my notes on how we ran the SuperCollider Symposium 2012 (10-page PDF). sc2012 was a great event and it was a privilege to work with so many great people in putting it together. I hope these notes are useful to future organisers, providing some detailed facts and figures to give you some idea of how we did it.

The document includes details of the timing of things, the budgeting, promotional aspects. I also include some notes about outreach, which I think is important to keep in mind. It's important for community-driven projects to bring existing people together, and to attract new people - and for something like SuperCollider which doesn't have any institution funding it and pushing it forwards, these international gatherings of users are 100% vital both for the existing users angle and the new users angle. Happily, both of these aims can be achieved by putting on diverse shows featuring some of the best SuperCollider artists in the world :)

Shout outs to all the other organisers, who put loads of their own time and enthusiasm in (see the "credits" page), and hi to everyone else I met at the symposium.

(If you weren't there, see also Steve's great photos of sc2012.)

| supercollider |

Cross-correlation signal detection in SuperCollider

If you had to communicate a digital message by playing sound across a noisy room, how would you do it?

That's basically one of the problems signal processing engineers have worked on for decades, and there are many good ways to do it (the same principles allow mobile phones to communicate in a "noisy" radio spectrum too). One thing you can do is spread-spectrum signalling, using a particular signature spread across various different frequency bands. For example, an upwards "chirp" can be more robust than a simple bleep at a single frequency.

I just found this code example I put on the sc-users mailing list. It's quite nice - you use an upwards-chirp and a downwards-chirp, and detect which one has happened, even though we deliberately add loads of noise. (The code uses a technical trick, where we can do cross-correlation signal detection by convolution with the time-reversed signal.)

Server.default = s = Server.internal;
s.boot;
~dursamps = 16384;
~dursecs  = ~dursamps / s.sampleRate;

(
SynthDef(\chirpup, { |dur=0.1|
       var sig = SinOsc.ar(Line.ar(1000, 10000, dur, doneAction: 2));
       Out.ar(0, Pan2.ar(sig * 0.1));
}).add;
SynthDef(\chirpdn, { |dur=0.1|
       var sig = SinOsc.ar(Line.ar(10000, 1000, dur, doneAction: 2));
       Out.ar(0, Pan2.ar(sig * 0.1));
}).add;
SynthDef(\chirprecord, { |dur=0.1, in=0, buf=0|
       var sig = In.ar(in);
       RecordBuf.ar(sig, buf, loop: 0, doneAction: 2)
}).add;
)

~group_chirp    = Group.new(s);
~group_analysis = Group.after(~group_chirp);

////////////////////////////////////
// analysis

// OK now let's create a buffer, then put a frame of data in
~upbuf = Buffer.alloc(s, ~dursamps);
~dnbuf = Buffer.alloc(s, ~dursamps);
(
s.bind{
       Synth(\chirpup , [\dur, ~dursecs], ~group_chirp);
       Synth(\chirprecord, [\dur, ~dursecs, \buf, ~upbuf], ~group_analysis);
}
)
// ...wait for one to finish before doing the next:
(
s.bind{
       Synth(\chirpdn , [\dur, ~dursecs], ~group_chirp);
       Synth(\chirprecord, [\dur, ~dursecs, \buf, ~dnbuf], ~group_analysis);
}
)

// reverse them
~upbuf.loadToFloatArray(action: {|data| ~upRbuf = Buffer.loadCollection(s, data.reverse)});
~dnbuf.loadToFloatArray(action: {|data| ~dnRbuf = Buffer.loadCollection(s, data.reverse)});

//////////////////////////////////////
// detection

(
SynthDef(\chirpdetector, { |in=0, upbuf=0, dnbuf=0, framesize=100, out=0|
       var sig = In.ar(in);
       var conv = [upbuf, dnbuf].collect{|buf| Convolution2.ar(sig, buf, 0,
framesize) };
       var smooth = 0.1 * Amplitude.ar(conv, 0, 0.2);
       smooth[0].poll(smooth[0] > 1, "UP");
       smooth[1].poll(smooth[1] > 1, "DN");
       Out.ar(out, smooth);
}).add;
)

~detectbus = Bus.audio(s, 2);
x = Synth(\chirpdetector, [\framesize, ~dursamps, \upbuf, ~upRbuf, \dnbuf, ~dnRbuf, \out, ~detectbus], ~group_analysis);
~detectbus.scope

// Let's add some noise too, to make it a difficult task:
~noise = {WhiteNoise.ar(0.3)}.play(~group_chirp);

// Now we trigger different types of chirp and watch how the output leaps...
// RUN THIS LINE OVER AND OVER, waiting imbetween:
Synth([\chirpdn, \chirpup].choose, [\dur, ~dursecs], ~group_chirp);

The original discussion is here on the sc-users mailing list.

| supercollider |

Dubstep bass in SuperCollider

Dubstep bass in SuperCollider, improveable:

//s.boot

{
    var trig, note, son, sweep;

    trig = CoinGate.kr(0.5, Impulse.kr(2));

    note = Demand.kr(trig, 0, Dseq((22,24..44).midicps.scramble, inf));

    sweep = LFSaw.ar(Demand.kr(trig, 0, Drand([1, 2, 2, 3, 4, 5, 6, 8, 16], inf))).exprange(40, 5000);

    son = LFSaw.ar(note * [0.99, 1, 1.01]).sum;
    son = LPF.ar(son, sweep);   
    son = Normalizer.ar(son);
    son = son + BPF.ar(son, 2000, 2);

    //////// special flavours:
    // hi manster
    son = Select.ar(TRand.kr(trig: trig) < 0.05, [son, HPF.ar(son, 1000) * 4]);
    // sweep manster
    son = Select.ar(TRand.kr(trig: trig) < 0.05, [son, HPF.ar(son, sweep) * 4]);
    // decimate
    son = Select.ar(TRand.kr(trig: trig) < 0.05, [son, son.round(0.1)]);

    son = (son * 5).tanh;
    son = son + GVerb.ar(son, 10, 0.1, 0.7, mul: 0.3);
    son.dup
}.play
| supercollider |

Efficiency in SuperCollider: pausing synths

When I use SuperCollider I often create synths and when they're done I free them, but I don't often pause them. For example, if you've got a synth playing back a recorded audio Buffer, and the Buffer ends, hey ho, no problem, I can leave it running and send a trigger when I want the sound to play again. But since I'm currently working with mobile devices I need to be more careful about that kind of thing.

Here's an example of what I mean. Run this code block to define two synthdefs, a playback one and a "supervisor":

(
s.waitForBoot{
SynthDef(\supervisor, { |targetid=0, trigbus=0, rate=0.25|
    var cycle, pausegate;
    cycle = LFPulse.kr(rate);
    Out.kr(trigbus, Trig1.kr(cycle, 0));
    Pause.kr(cycle, targetid); 
}).send(s);


SynthDef(\player, { |buf=0, trigbus=0|  
    // Some meaningless extra cpu-load so we can see the difference
    var heavycruft = 400.collect{[WhiteNoise, PinkNoise, BrownNoise].choose.ar}.squared.mean;
    Out.ar(0, PlayBuf.ar(1, buf, trigger: In.kr(trigbus)) + (heavycruft * 0.00001))
}).send(s);
}
)

Now when I use the player synth like normal...

b = Buffer.read(s, "sounds/a11wlk01.wav")   
t = Bus.control(s);
x = Synth(\player, [\buf, b, \trigbus, t])

...I can see the CPU load on my machine shoots up to 40% (because of the pointless extra load I deliberately added into that second SynthDef), and it stays there even when the Buffer ends.

(Often you'd tell your synth to free itself when the Buffer ends using doneAction:2 - that works fine, but in this case I want the synth to keep running so I can retrigger it.)

Having run the above code, now start the supervisor running:

y = Synth(\supervisor, [\targetid, x.nodeID, \trigbus, t], x, addAction: \addBefore)

This should repeatedly pause-and-restart the playback. When the sound is silent, the CPU load drops from 40% down to 0.1%. So, clearly it makes a saving!

So in order to do this I had to use Pause.kr() in the supervisor, and also to tell the supervisor which node to pause/unpause (using x.nodeID). The supervisor is also sending triggers to a control bus, and the player is grabbing those triggers to reset playback to the start.

| supercollider |

sc140: squeezing entire pieces of music into tweet-sized snippets

The New Scientist has a nice article about my sc140 project to highlight the amazing music that some people have been creating using the medium of Twitter.

This is all made possible by a rather lovely piece of software called SuperCollider, which is a programming language specialised for sound and music. The really nice thing about that is that it has the benefits of "traditional" music software on the one hand (for example, standard effects like echo and reverb are easily at hand), and also the benefits of a modern programming language on the other: it's much more flexible than traditional music software, you can tell the computer abstract things like "play these 7 notes, then a random burst of noise, then 12 random notes of your own choosing, then repeat the whole thing 4 or 5 times". (That description doesn't sound like it'd make a great piece of music does it? :) Well let's just call it an illustrative example.)

Programming languages can be a bit scary to learn at first, and I think it's perfectly reasonable that more traditional music software is still used for a lot of things. Often, music producers have a standard way of working and a standard set of effects that they pick off the shelf, twiddle some knobs, and there you go, no problem.

But as a fairly experimental musician I long ago got fed up of those restrictions and searched for something that would give me a lot more freedom. The flip-side of that freedom is that sometimes you have to spend more time building the tools you want before you use them. But I've been able to do a lot with SuperCollider, to the extent that it's now my main tool in my PhD work where I'm processing beatboxing sounds in real-time and transforming them for interactive music purposes.

The SuperCollider tweets thing is interesting and fun - 140 characters is a very strong limitation so to try and create even a decent sound, let alone a whole piece of music, is quite an achievement. On the other hand, SuperCollider tweeters often resort to clever little programming tricks in order to squeeze as much as possible into that tiny space.

So I do worry that the sc140 project makes SuperCollider look almost completely impenetrable, these 140 characters of obscure alien code! To demonstrate that SuperCollider's not actually too scary to learn, watch this SuperCollider in 60 seconds video.

| supercollider |

Reverse-engineering the rave hoover

One of the classic rave synth sounds is the "hoover", a sort of slurry chorussy synth line like the classic Dominator by Human Resource. I decided to recreate that sound from scratch, by reverse engineering the sound and recreating it in SuperCollider. Here's how to do it:

Step 1: Listening …

| supercollider |

SuperCollider Symposium 2009

Just back from the SuperCollider Symposium at Wesleyan. It felt like I was nonstop (did 2 talks, 2 workshops, 2 gigs! Hopefully no-one got sick of me) but there was lots of fascinating stuff to hear about and discuss. Some things:

Sciencey: Chris Kiefer's neural network classes were interesting …

| supercollider |

YMCA (NYC) and whether it's fun to stay at the

For budget accommodation in New York, I got a tip to try the YMCA. It was $90/night for a single room, which is not cheap although it is cheap for Manhattan. But did it live up to the claims? Let's examine the evidence:

  • "You can get yourself clean" - hmm …
| supercollider |

SuperCollider mobile device prototype interface

A demo of my prototype interface for mobile touchscreen devices to play a SuperCollider synth. The interface is made using GTK.

| supercollider |

social