An analogue delay line, definitely not in SuperCollider (photo credit)
Delay...ay....ay....ay......ay patch
For the final blog post of my SoundMakers residency, I’m going to outline some of the technical details of how my SuperCollider patch for Longuement me sui tenus works. The functionality is the same for each of the four singers, with each having his or her own independent “patch” running within SuperCollider. The only difference is that the singers are panned differently across the stereo field.
I’ve provided a diagram that outlines what happens as the vocalists sing: the mic sends the signal to an input “synth,” which then passes it to the delay line and to the end limiter. The delays are created by the spawner independently of the input source, and they pass their signal to the limiter, where it is combined with the original and outputted to the speakers.
In terms of the actual mechanics of the patch, there are a few other things going on—the limiter, for instance, is global to all four singers; it doesn’t process them individually—but this description outlines the core functionality.
Mic Input Synth
Before we get into the nitty gritty, we need to understand some key SuperCollider concepts.
SuperCollider uses Synths and SynthDefs to make sound. A synth in SuperCollider is anything that processes an audio signal, so all patches will have at least one synth. A SynthDef is the set of instructions that determine what the synth does. My simple “Mic Input” SynthDef is shown below:
SynthDef(\mic_in, {
arg in_bus, out_bus;
var signal;
signal = SoundIn.ar(in_bus);
Out.ar(out_bus, signal);
}).send(s);
It has a name (“micin”), two arguments, and a variable. (The variable is not actually necessary, but it makes the SynthDef easier to read, which means I make fewer mistakes.) You’ll see that the two arguments are called “inbus” and “outbus”. Those tell the synth where to look for the microphone signal, and then where to send it. The input bus gets plugged into a _Unit Generator called SoundIn. Unit generators are just predefined snippets of sound processing code. As you might guess, this one listens to microphone inputs. We’ve also got another unit generator called “Out”, which sends the sound out of the synth.
So my mic input synth doesn’t do a whole lot. It basically lets me plug in a microphone and send the signal somewhere else. If I send it out to the speakers, then I will have just made “the world’s most expensive patch cord,” as the tongue-in-cheek help file for SoundIn explains. But I’m not going to send the signal to the speakers, I’m going to send it to the delay line bus and also to the limiter. (A bus is just a container for a signal; it’s like saying, “The canned tomatoes go on the second shelf on the right,” so you can find the tomatoes when you’re looking for them.)
Delay Spawner
You may ask why I sent the mic signal to the delay line bus instead of straight to the delay line synth itself—or for that matter why I didn’t just make a single SynthDef that has the mic input and the delay combined. The reason is that the delay line synths are constantly being created and destroyed. I want the delay effect to vary as the vocalists sing, but I don’t want the artificial effect of an echo suddenly speeding up or slowing down; I want each delay to fade out naturally.
For that reason, I need a never-ending cascade of new delays, each appearing at the right moment in time and going away when it’s no longer needed. Constantly connecting and disconnecting the mic input to these delays would be risky: it could lead to pops and crackles in the audio. It’s much safer to tell the delay synths, “The signal you want is in Bus X, go get it there.” Therefore, the delay synths all listen to the same bus, do their thing for 5-7 seconds, then quietly die without so much as a whimper, replaced by a newer, fresher model (I know, life is brutal for a delay synth).
But how will the patch know when it’s time to make a new delay? I need some kind of process to oversee delay creation, to keep track of timing. That’s where the spawner comes into play. Counterintuitively, the spawner is not a synth, even though it spits out synths. The reason for this is that the spawner doesn’t make any sound: it’s not processing a signal, and synths only process signals, so it can’t be a synth. Instead, it gets controlled through the language-processing side of SuperCollider, and since it needs to be able to keep track of time, I used a clock concept called a Routine. The spawner routine picks some random numbers, uses them to create a new delay synth, then waits until the appropriate time to make another delay synth, on and on forever. Here’s what the code looks like:
Routine.new({
inf.do({ var this_delay, this_decay;
this_delay = rrand(~min_delay,~max_delay);
this_decay = rrand(~min_decay,~max_decay);
Synth.head(~delay_group[0], \delay, [
\in_bus, ~mic_bus[0],
\out_bus, ~delay_bus[0],
\delay_time, this_delay,
\decay_time, this_decay
]);
(this_decay/2).wait;
});
});
I won’t go into all the particulars, but I’ll explain a few key ideas:
- Inf.do – This tells the routine to keep on doing the thing infinitely, forever. You can crash your computer if you use inf.do incorrectly.
- thisdelay and thisdecay – These are the random numbers that the spawner is picking.
- Synth.head – That whole mess of lines starting with “\” are part of the delay synth, basically telling the Synth what to do based on the random numbers.
- (this_decay/2).wait – This is the timing element. I’m telling the routine: Okay, the delay line you just made lasts, say, 5 seconds. So you need to wait before you make another one. How long? Wait half the length of the delay, or 2.5 seconds. That way we get two delay lines overlapping each other.
Limiter
Finally we get to the limiter. I almost always use a limiter in my patches, as a safety mechanism. You never know what kind of loud sound might get produced accidentally, and there’s no point in risking any damage to your equipment. The limiter also gives us a convenient place to collect all the signals that are going out to the speakers.
At first, I just had all the signals marching in series from start to finish, like this: Mic >> Delay >> Limiter. But that introduced problems with balancing the acoustic sound with the delay sound. I wanted them to be the same volume, as explained in my previous post. The simplest way to do that was just to take the sound from the mic and mix it with the sound from the delay in the limiter synth.
Here’s what the SynthDef looks like:
SynthDef(\Limiter, {
arg in1, in2, out_bus, mix=0.5, pan=0, mul=1; var signal;
signal = Limiter.ar(
Mix.new([In.ar(in1) * (1 - mix),In.ar(in2) * mix]),
0.99,
0.002
);
Out.ar(out_bus, Pan2.ar(signal, pan) * mul);
}).send(s);
There are two separate inputs, in1 and in2. There’s a Limiter unit generator, and within it a Mix unit generator that combines the two inputs. There’s also a Pan2 unit generator, which does stereo panning (2 = stereo). All the rest are just settings for each of these. Finally, the Out unit generator sends the sound to the speakers, and we hear the result.
This article originally appeared on the SoundMakers composer-in-residence blog.