SuperColliderで竹内関数音楽

先日SuperColliderのワークショップに行ってきました。SuperColliderとは音楽・音響をプログラミングするための言語でアーティストや研究者の人が使っているらしいです。
 
たとえばこんな感じでプログラミングできます。

{MoogFF.ar(
    Pulse.ar([55, 110], 0.5, Pulse.kr(8).range(0, 1)),
    MouseX.kr(100, 5000),
    MouseY.kr(4, 0)
)}.play; 

これは55Hzと110Hzの矩形波を鳴らした音を8Hzでリズムを刻んでさらにMoog風のフィルターをかけるというプログラムです。マウスを横に動かすとフィルターのカットオフ周波数が変化したり縦に動かすとレゾナンスの深さが変化したりします。
 
ちょっとクセはありますが、RubySmalltalkのようなオブジェクト指向の記述方法で音がプログラムできるのはなかなか面白いです。
 
そんなわけでSuperColliderのプログラムがちょっと書けるようになったので、例によって竹内関数で音楽を生成するやつを書いてみました。ほっとくと343,073小節演奏します。たぶん。
 

(
    var scale, arpeggiator, tarai;
    var bar = 0;

    SynthDef("tone", {|freq=440|
        var out;
        out = SinOsc.ar(freq);
        out = out * Line.kr(0.5, 0, 0.5, doneAction:2);
        out = Pan2.ar(out);
        Out.ar(0, out);
    }).send(s);

    scale = Array.new(20);
    20.do{|i|
        scale.add(Scale.dorian.degreeToFreq(i, 62.midicps, 1));
    };

    arpeggiator = {|x, y, z|
        var w = 0.11;
        var a = [x, y, z].sort;
        2.do {
            Synth("tone", [freq: a[0]]);
            w.wait;
            Synth("tone", [freq: a[0] * 2]);
            w.wait;
            Synth("tone", [freq: a[1]]);
            w.wait;
            Synth("tone", [freq: a[1] * 2]);
            w.wait;
            Synth("tone", [freq: a[2]]);
            w.wait;
            Synth("tone", [freq: a[2] * 2]);
            w.wait;
            Synth("tone", [freq: a[1]]);
            w.wait;
            Synth("tone", [freq: a[1] * 2]);
            w.wait;
        };
    };

    tarai = {|x, y, z|
        bar = bar + 1;
        postln(' ' ++ bar ++ ': ['++ x ++ ', ' ++ y ++ ', ' ++ z ++ ']');
        arpeggiator.value(scale[x + 1], scale[y + 1], scale[z + 1]);
        if ( x <= y, {
            y;
        },{
            tarai.value(
                tarai.value(x - 1, y, z),
                tarai.value(y - 1, z, x),
                tarai.value(z - 1, x, y)
            );
        });
    };

    Task({
        tarai.value(10, 5, 0);
    }).play;
)

 
Mac版のSueprCollider3.5.3で動作確認していますがバージョンによっては動かないみたいです。
幸運にも動いたときはこんな音が鳴ります。