Sunday, March 30, 2014

SuperCollider Etude No. 1



I have recently begun to learn SuperCollider, an audio synthesis and music composition programming language/environment.  This is my first complete etude using it.  I cannot by any means claim it to be my most sophisticated composition.  However, it is a lot of fun to have a new outlet for my creativity.  I hope you enjoy.

For those interested, below is the code.  I broke it into two main sections: instruments, and loops.  I built 4 instruments: 

  • a kick drum, 
  • a wind sound which starts like a rushing wind and ends sounding like a nail scraped across a gong.  I called this one woosh (not very creative maybe, but it's descriptive.)
  • a lead synth pad with a built in glissando
  • a woodblock with a random feature on the timbre so the sound randomly changes on a continuum between a woodblock and a crotale.
Here's the instruments code:


//instruments
//kickdrum definition
(
SynthDef(\kickdrum, {
var subosc, subenv, suboutput, clickosc, clickenv, clickoutput, sut;

    subosc = {SinOsc.ar(60)};
    subenv = {Line.ar(1, 0, 0.5, doneAction: 2)};

    clickosc = {LPF.ar(WhiteNoise.ar(1), 1500, mul:0.3)};
clickenv = {Line.ar(1, 0, 0.001)};

    suboutput = (subosc * subenv);
clickoutput = (clickosc * clickenv);
sut = (suboutput + clickoutput)*0.3;
    Out.ar(0, Pan2.ar(sut, 0)
    )

}).add
)
//woosh definition
(
SynthDef(\woosh, {
var out;
out = PinkNoise.ar(EnvGen.kr(Env.sine(3, 0.2), doneAction: 2));
out = (out + FreeVerb2.ar(out, out, 0.5, 1))*0.3;
Out.ar(0, Pan2.ar(out, 0)
)
}).add
)
//lead synth pad
(
SynthDef(\leadSynth, {
arg freq1, freq2, dur = 7;
var out;
out = RHPF.ar(Blip.ar(Line.kr(freq1, freq2, dur, doneAction: 2)));
out = out * 0.05;
out = out * EnvGen.kr(Env.adsr(1, 0.1, 0.7, 1));
out = out + FreeVerb2.ar(out, out, mix: 0.5, room: 1, damp: 0.3);
Out.ar(0, Pan2.ar(out, 0)
)
}).add
)
//woodblock
(
SynthDef(\woodblock, {
arg freq = 1220, rq = 0.02;
var out, rrq;
out = BPF.ar(WhiteNoise.ar * Line.kr(5, 0, 0.02, doneAction: 2), freq, (Rand(0,1)/100));
out = (out + FreeVerb2.ar(out, out, mix: 0.5, room: 0.5, damp: 0.3))*0.3;
Out.ar(0, Pan2.ar(out, 0)
)
}).add
)

Then I built a loop so each instrument is played based on a beat counter.  It is in five sections in a basic bridge form: ABCB'A'

//loop
(
s.record;
a = {
    arg beat;
//A section
//if beat number is divisible by 15 play noise 
if((beat % 15 == 0).and(beat < 64), {Synth(\woosh)});
// B section
    //play kickdrum everybeat from 64 to 284
if((beat >= 64).and(beat<285 div="" kickdrum="" ynth="">

if((beat > 78).and(beat < 88), {Synth(\leadSynth, [\freq1, 220, \freq2, 880])});
if((beat > 100).and(beat < 110), {Synth(\leadSynth, [\freq, 440, \freq2, 1100])});
if((beat > 120).and(beat < 135), {Synth(\leadSynth, [\freq1, 220, \freq2, 880])});
// C section (kickdrum still playing)
if((beat % 6 > 0).and(beat > 150).and(beat < 187), {Synth(\woodblock)});
// B' section (kickdrum still playing)
if((beat > 190).and(beat < 200), {Synth(\leadSynth, [\freq1, 220, \freq2, 880])});
if((beat > 210).and(beat < 220), {Synth(\leadSynth, [\freq, 440, \freq2, 1100])});
if((beat > 230).and(beat < 240), {Synth(\leadSynth, [\freq1, 220, \freq2, 880])});
//A' section
//final four swooshes;
if((beat >= 250).and(beat%10==0).and(beat<290 div="" woosh="" ynth="">
if((beat >= 255).and(beat <=270), {Synth(\leadSynth, [\freq1, 1240, \freq2, 50])});
};

c = TempoClock(1.7);
c.schedAbs(
    0, //evaluate this immediately
    {
        arg ...args;
        args[0].postln;    // arg[0] is the beat number
        a.value(args[0]); // pass the beat number to our function
        1.0               // do it all again on the next beat
    }
);
)

s.prepareForRecord;
s.record;
s.stopRecording;

Don't worry, I haven't totally gone nerd.  I still love beer as the picture above indicates, and I will continue to blog about the beers I try at my waterhole over at my other blog Fermenting the Word.

Looking forward to your comments on the piece and the code.  Like I said, I have a lot to learn.