I recently had a student talk to me about all the different uses of various types of oscillators. At the end of this conversation he asked how come you didn’t mention the super saw. To be honest I had no clue what he was taking about, so I did some research. All a super saw is, is multiple sawtooth oscillators out of tune with one another. Something I have done a million times but never knew there was a name for it. After this conversation I programmed a basic example with a GUI in Supercollider to demonstrate to the class. Super Saws are fun for many reasons. Personally I like them because the phasing creates interesting polyrhythms. In the code below I made the frequencies detunable by +/- 10Hz so the maximum difference between oscillators is 20Hz.
SynthDef(“supersaw”, { arg freq, d1, d2, d3, d4, d5, d6, d7, d8, vol = 0, rl = 5, gate = 1;
var mix, env;
env = Env.cutoff(rl);
mix = Mix.new([Saw.ar(freq, 0.4), Saw.ar(freq + d1, 0.4), Saw.ar(freq – d2, 0.4), Saw.ar(freq + d3, 0.4), Saw.ar(freq – d4, 0.4), Saw.ar(freq + d5, 0.4), Saw.ar(freq + d6, 0.4), Saw.ar(freq + d7, 0.4), Saw.ar(freq – d8, 0.4),]);
Out.ar([0, 1], (mix * vol) * EnvGen.kr(env, gate, doneAction: Done.freeSefl));
}).send(s);
To break down this code: I am using the freq argument to set the main frequency and the dn arguments to control the amount of detune in Hz. The Mix.new is very important for this. The mix sums all of the saws together which virtually allows the phases to do fun things. I am also using a generator to produce a fade out for demonstration purposes for class. The little SynthDef is nothing fancy but it is fun. I am copying the GUI code below. it create sliders to control the amount of detuning for each oscillator. The GUI isn’t super pretty, but gets the job done for quick demonstration purposes.
(
var sl1, sl2, sl3, sl4, sl5, sl6, sl7, sl8, nb, nb2, bu, reset;
w = Window.new(“Super Saw”, Rect(128, 64, 360, 360));
y = FreqScopeView(w,Rect(240, 10, 100, 50) );
y.active_(true);
y.freqMode_(1);
w.onClose_({ y.kill });
t = ControlSpec(0.0, 1, \lin, 0.01);
b = ControlSpec(-10, 10, \lin, 0.01);
c = ControlSpec(-10, 10, \lin, 0.01);
d = ControlSpec(-10, 10, \lin, 0.01);
e = ControlSpec(-10, 10, \lin, 0.01);
f = ControlSpec(-10, 10, \lin, 0.01);
g = ControlSpec(-10, 10, \lin, 0.01);
h = ControlSpec(-10, 10, \lin, 0.01);
nb = NumberBox(w, Rect(20, 20, 150, 20))
.action_({ z.set(\freq, nb.value);
});
nb2 = NumberBox(w, Rect(180, 20, 50, 30))
.value_(0)
.action_({
u = (t.map(nb2.value));
z.set(\vol, u);
});
nb2.scroll_step = 0.01;
bu = Button(w, Rect(180, 50, 50, 30))
.states_([
[“Off”, Color.black, Color.red],
[“On”, Color.white, Color.black]])
.action_({
if (bu.value == 1 , {z = Synth(“supersaw”);}, {z.free})
});
sl1 = Slider(w, Rect(20, 50, 150, 20))
.value_(0.5)
.action_({
a = (b.map(sl1.value));
[“Slider1”,a.value].postln;
z.set(\d1, a);
});
sl2 = Slider(w, Rect(20, 80, 150, 20))
.value_(0.5)
.action_({
i = (c.map(sl2.value));
[“Slider2”,i.value].postln;
z.set(\d2, i);
});
sl3 = Slider(w, Rect(20, 110, 150, 20))
.value_(0.5)
.action_({
j = (d.map(sl3.value));
[“Slider3”,j.value].postln;
z.set(\d3, j);
});
sl4 = Slider(w, Rect(20, 140, 150, 20))
.value_(0.5)
.action_({
k= (e.map(sl4.value));
[“Slider4”,k.value].postln;
z.set(\d4, k);
});
sl5 = Slider(w, Rect(20, 170, 150, 20))
.value_(0.5)
.action_({
l= (f.map(sl5.value));
[“Slider5”,l.value].postln;
z.set(\d5, l);
});
sl6 = Slider(w, Rect(20, 200, 150, 20))
.value_(0.5)
.action_({
m= (g.map(sl6.value));
[“Slider6”,m.value].postln;
z.set(\d6, m);
});
sl7 = Slider(w, Rect(20, 230, 150, 20))
.value_(0.5)
.action_({
n= (h.map(sl7.value));
[“Slider7”,n.value].postln;
z.set(\d7, n);
});
sl8 = Slider(w, Rect(20, 260, 150, 20))
.value_(0.5)
.action_({
o= (b.map(sl8.value));
[“Slider8”,o.value].postln;
z.set(\d7, o);
});
ServerMeterView.new(s, w, 170@130, 2, 4);
CmdPeriod.doOnce({w.close});
reset = Button.new(w, Rect(240, 90, 100, 40) )
.states_([
[“Reset”, Color.white, Color.black]])
.action_({
reset.value.postln;
if( reset.value == 0) {sl1.valueAction = 0.5; sl2.valueAction = 0.5; sl3.valueAction = 0.5; sl4.valueAction = 0.5; sl5.valueAction = 0.5;sl6.valueAction = 0.5; sl7.valueAction = 0.5; sl8.valueAction = 0.5};
});
w.front
)