As part of a project that has been torturing me with its lack of existence since 2013, I need to learn Supercollider and Overtone. This is what brought me to Clojure in the first place. I’ll be blogging about that project plenty, but enough of that for now.

So I’ve been translating Supercollider code from Eli Fieldsteel‘s very excellent YouTube Supercollider tutorial series into Clojure for use with Overtone. It’s the domain-specific knowledge that gets you. I can’t be productive in Overtone until I understand how Supercollider works. So I’ve got to start with Supercollider, but keep my chops up in Clojure. Hence, this exercise.

Tutorial 3 talks about composing Ugens together to define and control synths in Supercollider. Yesterday and today I translated the final pulseTest synth into Clojure. What I’ve got sounds almost like the example code run from the Supercollider IDE, but something’s off with the ampHz Ugen. It seems to be pulsing at about half the speed, and occasionally I get a very loud low-frequency boom when I kick off the synth. I’d appreciate anyone who can spot my error or help me track down the cause. Here’s what I have:

(defsynth pulsetest "A super awesome synth that almost works the same as it would in SC"
  [ampHz 4
   fund 40
   maxPartial 4
   width 0.5]

  (let [amp1 (* 0.75 (lf-pulse:kr ampHz 0   0.12))
        amp2 (* 0.75 (lf-pulse:kr ampHz 0.5 0.12))

        freq1 (round 
                ; http://doc.sccode.org/Classes/UGen.html#-exprange explains
                ; that it uses a LinExp ugen to do the work. Here, we do the
                ; same manually 
                (lin-exp:kr :in    (lf-noise0:kr 4) 
                            :dstlo fund 
                            :dsthi (* fund maxPartial)) fund)
        freq2 (round 
                ; see above
                (lin-exp:kr :in    (lf-noise0:kr 4) 
                            :dstlo fund 
                            :dsthi (* fund maxPartial)) fund)

        freq1 (* (+ 1 (lf-pulse:kr 8)) freq1)
        freq2 (* (+ 1 (lf-pulse:kr 6)) freq2)

        sig1  (* amp1 (pulse:ar freq1 width))
        sig2  (* amp1 (pulse:ar freq2 width))

        sig1  (free-verb:ar sig1 0.7 0.8 0.25)
        sig2  (free-verb:ar sig2 0.7 0.8 0.25)]
    (do
      (out 0 sig1)
      (out 1 sig2))
    )
  )


Here is the SC version:

 

(
SynthDef.new(\pulseTest, {
        arg ampHz=4, fund=40, maxPartial=4, width=0.5;
        var amp1, amp2, sig1, sig2, freq1, freq2;
        amp1 = LFPulse.kr(ampHz,0,0.12) * 0.75;
        amp2 = LFPulse.kr(ampHz,0.5,0.12) * 0.75;
        freq1 = LFNoise0.kr(4).exprange(fund, fund * maxPartial).round(fund);
        freq2 = LFNoise0.kr(4).exprange(fund, fund * maxPartial).round(fund);
        freq1 = freq1 * (LFPulse.kr(8)+1);
        freq2 = freq2 * (LFPulse.kr(6)+1);
        sig1 = Pulse.ar(freq1, width, amp1);
        sig2 = Pulse.ar(freq2, width, amp2);
        sig1 = FreeVerb.ar(sig1, 0.7, 0.8, 0.25);
        sig2 = FreeVerb.ar(sig2, 0.7, 0.8, 0.25);
        Out.ar(0, sig1);
        Out.ar(1, sig2);
}).add;
)

 

And that’s how far I am. I’m going to proceed to another tutorial for now. I’m also going to find a theme and plugin that makes this code look a little nicer.

You can track my progress at the git repo I have set up for this project.

  • brthrjon

    Your speed problem is because you don’t use amp2. The other sound is coming from the reverb. lower the second parameter (mix) to .5 and you will be good.

    • Holy crap, thanks! I can’t believe I didn’t notice the missing amp2. My output wasn’t panning either, which is an obvious clue in retrospect.

      I’m still having trouble getting rid of the reverb boom, but I’ll chase that another time. I’m gonna get back to translating these, thanks again!