Supercollider 5 – Unit Generators

audio, supercollider

Day Five of 30 Days of Supercollider.

I could write hundreds of pages about UGens. Other people have. I’ll let you read their stuff instead and just give some of the basics.

Unit Generators, or UGens for short, are one of the key building blocks for creating sound in Supercollider. If I understand it correctly, UGens create the signals that are used within Synths to describe sounds that get created in the server. Even if you create a UGen without a Synth, a default Synth is used behind the scenes to wrap that UGen and create the sound. That’s what the function play message does.

A sound could be a single UGen and Synth, or it could be made of multiple UGens hooked up to each other, with envelopes and filters and all kinds of other things in there shaping the final sound. For this post, we’ll just look at a few basic UGens wrapped in functions. Nothing complex.

UGens are defined in classes. And class names start with capital letters. So you’ll see things like SinOsc and LFTri and Saw. UGens have three key methods that can be called, ar, kr, ir. Which one you use is determined by what you’re using it for. Mostly you’ll be using ar, which stands for “audio rate” or kr which is “control rate”. ir is for “initial rate”, but we won’t be getting into that here.

You use audio rate when you are generating actual sound data. By default this creates signals at a default rate of 44,100 samples per second. Control rate generates samples at a much slower rate. It is used for many different things, but one of the more common use cases is to control some aspect of an audio rate UGen. So yeah, you can have one UGen nested inside another UGen. The inner one will usually (but not always) use kr to control some aspect of the outer one, which is actually making sound with ar.

But let’s create a sound. Type in this code and evaluate it:

{ SinOsc.ar(400) }.play;

This creates a sine wave oscillator UGen that generates and audio rate signal at 400 hz – or 400 cps (cycles per second) if you prefer. You should hear a sound, assuming your server is booted and sound is on, etc. Note that the sound will probably only come out of the left speaker / headphone. That’ll be the case for all the sounds in this post. We’ll cover stereo later.

Change the 400 to something between 20 and 20,000 and you can hear other tones.

But there are other arguments. In full, it’s SinOsc.ar(freq, phase, mul, add)

We already saw freq. The phase argument shifts that sine wave one way or the other. This is useful for creating two of the same waves, but getting them to sound separated. Otherwise, not too useful on a sine wave. mul controls the amplitude of the sine wave (multiplies it). It’s default is 1.0. You can think of this as amplitude, or the volume level of the resulting sound. Since you’ll often have multiple sounds playing together, and their volume adds up, you often want to set this down around 0.2 or 0.3 or even some lower amount so that the sum of all your sounds stays at 1 or below. Finally, add adds some amount to the wave, defaulting to 0. This is often more useful in kr than ar, as we’ll see soon.

You can take the defaults for phase and add and just change freq and mul, so you’ll often see something like:

SinOsc.ar(400, mul: 0.5)

Try some of these other UGens:

{ Pulse.ar(400) }.play; // a square wave
{ LFTri.ar(400) }.play; // a triangle wave
{ Saw.ar(400) }.play;   // a sawtooth wave.

Most of the arguments to the ar methods for these UGens are similar to SinOsc, but there will be some differences.

If you ever want to know what your sounds looks like, use plot instead of play:

{ Saw.ar(400) }.plot;   // a sawtooth wave.

We’ll probably get into some other UGens later in this series. But I just want to show a few examples of kr with a UGen within a Ugen.

First, let’s make a SinOsc UGen using kr with a freq of 1 and a mul of 100, and plot it.

{ SinOsc.kr(1, mul: 100)}.plot;

This gives you the following:

Not too useful. Because our frequency is 1, it’s going to take a full second to complete a full sine wave. And the plot is only showing 0.01 seconds. We can fix that by telling plot to plot 1 second:

{ SinOsc.kr(1, mul: 100)}.plot(1);

Note that the amplitude now goes from -100 to +100, every second.

So the cool thing about UGens is that you can do math with them just like they were single values, even though they are in fact objects that produce a stream of values. So we can create a sawtooth wave and just add the above sine wave to its frequency argument.

{ Saw.ar(400 + SinOsc.kr(1, mul: 100)) }.play;

You should now hear a siren type sound. The sawtooth wave has a base frequency of 400 hz, but that’s going to go up and down by 100 (from 300 to 500) once per second. Try playing with those numbers and getting different values. This is known as frequency modulation (yup, just like FM radio), because you are modulating the frequency.

You can do the same thing with amplitude modulation (AM radio) by using the sine wave to change the mul value of the sawtooth wave. But we probably want it to go from 0 to 1 over and over. The math for this is that we want to set mul of sine wave to 0.5 (which makes it go from -0.5 to +0.5) and then add 0.5 to that, to make it go from 0 to 1. That looks like this:

{ SinOsc.kr(1, mul: 0.5, add: 0.5)}.plot(1);

That math can become a pain though. A shortcut is to leave it all out and call range at the end, passing in the min and max values you want the wave to hit.

{ SinOsc.kr(1).range(0, 1) }.plot(1);

Now you use that as the mul argument to the sawtooth wave.

{ Saw.ar(400, mul: SinOsc.kr(1).range(0, 1)) }.play;

Again, try different numbers here, but avoid going much over 1 (or -1) for that final mul value. If you’re not sure what you’re doing, it’s always safe to plot a wave before subjecting your ears to it.

The last thing I’ll show is additive synthesis. This is simply adding two UGens together. Seriously, it’s that simple.

{ SinOsc.ar(400, mul: 0.5) + Saw.ar(770, mul: 0.5) }.play;

Here I’m using a 400 hz sine wave and a 770 hz sawtooth wave. I set both’s mul to 0.5 so it wouldn’t be too loud.

Plotting this at plot(0.05) gives us:

Quite a complex wave, for a complex sound.

One thought on “Supercollider 5 – Unit Generators

  1. This will be an index of the articles I post about Supercollider. Warning: I don’t know a lot about Supercollider yet. This will be a journal of my discoveries as much as anything else. I pro…

Leave a Reply