A House Track in SuperCollider
The first several posts on this blog show you how a house beat, its drums, and its riser sound work. Next I’m going to show you how I built a short house track — around two and a half minutes long — entirely in SuperCollider.
First, here’s the track:
This is kind of just a demo, and a real house track would be maybe twice as long, but I think it serves well as a proof of concept. If you’ve been following the previous posts, you recognize these drum sounds, as well as the riser. The previous posts explain those sounds in detail. What’s new are some more melodic sounds — a synth pad and a sound like low bells or perhaps piano strings being scraped — and the fact that this is a track rather than an eight-bar loop.
So there are just three things to explain:
- pattern sequencing in SuperCollider
- the pad synth
- the bells / piano strings synth, which uses Karplus-Strong synthesis
We’ll start at the beginning. As before, there’s a git repo on GitHub, and you’ll need to run a simple installer script if you’re following along in SuperCollider. The git repo has a README which explains how to do that.
Pattern Sequencing in SuperCollider
In
previous
posts,
we saw that
SuperCollider provides a mechanism for sequencing called Pbind
,
for pattern binding.
Pbinds allow us to play musical patterns
like drumbeats and melodies.
The question is how to sequence them, one after the other.
SuperCollider has a mechanism for this called Pspawner
.
You invoke Pspawner
along with a callback which takes a spawner object as an argument.
It’s idiomatic for this object to be named spawner
,
but in this code,
I went with the name salmon
since I was in a goofy mood
and spawning is a thing that salmon do.
Here’s how a typical use of Pspawner
might look:
The spawner’s .par
method stands for “parallel,”
and it sets a pattern playing which can play in parallel (i.e., at the same time) with other patterns.
We’ve seen this Pbind
code in previous posts.
All in all, this code will give you results which are basically identical to calling
.play(~clock)
at the end of the Pbind
.
But because we’re using .par
, we can play other Pbind
objects at the same time.
Also, just like “where there’s smoke, there’s fire,”
where there’s parallel, there’s sequential.
The spawner has a .seq
object which will play a pattern, and then,
when that pattern ends,
the spawner will also stop playing any patterns which it was playing in parallel.
That’s what’s going on in this code,
which plays the first few bars of the track:
This code plays a crash pattern twice, and keeps playing the synth hat pattern and a synth pad until it’s played a kick pattern 6 times, at which point it stops and plays a riser pattern once. That’s how the track begins; more specifically, that’s the first fifteen seconds of it.
But you’ll notice that I’m not just passing patterns to the spawner in most cases here.
Instead I’m calling value()
on these objects and passing those values to the spawner.
That’s because this code is built on the code in the previous posts which played a drum pattern on inifinite repeat.
All the drum patterns in that existing code worked on the assumption that they would run forever.
Rather than rewrite all that code from scratch,
the easiest thing was to write functions which returned Pbind
objects.
Here’s what one of those functions looks like:
Invoking these functions works as shown: functionName.value(argument)
.
This is some of the weirdest syntax in all of SuperCollider to me personally,
because I would have expected functionName(argument)
instead.
However, prior to this, every time I’d used SuperCollider,
it’d been through systems like Overtone and Sonic Pi,
which retain SuperCollider’s power but replace its weird programming language
with more familiar, popular languages.
This is easier in terms of writing code,
but it’s also harder in terms of understanding what SuperCollider is actually doing.
SuperCollider is very powerful,
so it’s totally worth the effort to grapple with the syntax a little.
Anyway, long story short: functions which return Pbinds.
These simple mechanisms are almost all you need in order to do pattern sequencing in SuperCollider.
The code for this track uses only two other methods for its sequencing.
First, there’s salmon.suspendAll;
.
This simply stops all running patterns.
Second, there’s wait()
.
You pass this method a number of beats, and it’ll wait for that many beats before the song moves forward.
And that’s it.
Here’s this code in action:
It might make for cleaner/DRYer code, and/or a track structure which is easier to understand, if I were to wrap these sections up into helper functions. But to get a track going, this is enough. If you’re curious, try reading this code while the track plays. It’s pretty easy to match up the lines of code with the parts of the track.
All that’s left to explain now is the two new sounds: the pad synth and the Karplus-Strong sound.
The Pad Synth
Here’s what the pad synth sounds like:
Both this and the next patch were created by Bruno Ruviaro, one of the two instructors at the CCRMA SuperCollider workshop that I took. This patch was introduced during class. I found the next patch coincidentally, via a Google search, although it’s not really a coincidence per se that a person teaching the workshop had also written popular patches available online.
Anyway, here’s the code:
First we define a function,
and add that function to SuperCollider’s list of synths
under the name “padSynth”.
The function takes a midinote
and a gate
.
In my hardware studio, I usually either send MIDI notes
or gate signals, in my Eurorack modular.
But they’re just data in SuperCollider, and you can use both if you want.
The gate
is passed to an amplitude envelope here:
The gate
signal is very important.
When the gate closes, it does the doneAction
.
In this case (and most cases) the doneAction
is 2, which is equal to the constant Done.freeSelf
,
so when the gate closes, the synth gets freed.
In other words, SuperCollider garbage-collects it,
freeing up memory.
So without gate
, you can bog down your computer
and produce all sorts of unpleasant glitching.
(SuperCollider can also produce pleasant glitching, of course.)
Anyway, an amp envelope is a fairly standard feature in a synthesizer,
but the rest of this code features some interesting quirks.
Although it holds to the same basic model as a
classic subtractive synth,
the freq
in this synth isn’t just determined by converting the MIDI note into a frequency.
It also multiplies that frequency by the output of a noise generator,
to produce a wavering and not quite perfectly tuned sound, reminiscent of classic 1970s/80s analog polysynths:
The !12
means “create twelve copies of this.”
This thickens the sound.
The next few lines control the filter.
With rqmod
, it uses a noise generator to modulate the filter resonance,
and it puts an LFO on the filter frequency with LFCub
,
which I believe stands for “low-frequency cubic,”
because it outputs a waveform similar to a sine wave but made of cubic pieces.
The top frequency is determined by the mouse position,
which I actually forgot when I was recording the audio samples in this blog post,
but if you clone the repo and run the installer,
you can experience this effect by moving your mouse while the pad sound plays.
The function then feeds these generators into RLPF
,
which stands for “resonant low-pass filter.”
As explained in
a previous post,
Out
and Splay
just send the audio to an output bus and pan it across the stereo image, respectively.
So that’s how the pad works. Let’s look at the Karplus-Strong sound.
Karplus-Strong Synthesis
The creators of Karplus-Strong synthesis, Kevin Karplus and Alexander Strong, originally called it “digitar” synthesis, because they felt it produced digital guitar hybrid sounds. It’s easy to understand where they’re coming from. Here’s the Karplus-Strong or digitar sound from the track:
Here’s the code:
I didn’t write this code, but I can tell you roughly how it works.
The Pluck
is a Karplus-Strong unit generator;
you set its delaytime
at the reciprocal of the frequency you want to hear
because Karplus-Strong synthesis works by
looping a short burst of noise through a delay which is also set to a quite short time.
In a situation like that, the pitch of the resulting sound —
which is ultimately just white noise echoing a lot —
is inversely proportional to the delay time.
That’s because the looping of the delay functions like an oscillator,
generating a waveform by looping the initial burst of white noise.
In a sense, Karplus-Strong is a relatively simple form of wavetable synthesis.
Anyway, returning to the code, the WhiteNoise
provides the noise, of course,
and the Impulse
makes it a short burst.
The amp envelope generated by Env.linen
is not staccato,
but that’s applied to the overall sound.
So this is how you construct a complete track in SuperCollider. This is the capstone of the past few blog posts, which are so far the only ones on this blog, so I hope you’ve found this edifying, inspiring, or at least useful. You can make complete tracks entirely within SuperCollider, and hopefully these blog posts have shown you how.