{
   "ancestor_list" : [],
   "description" : "again, after building the l-system using https://anvaka.github.io/lsystem/\r\nA composition. https://github.com/poetaster/supercollider-lsystems",
   "name" : "leaf - an lsystem composition",
   "author" : "blueprint",
   "is_private" : null,
   "id" : "1-5hy",
   "code" : "// if you have never done so, run the following code first\r\n(\r\nQuarks.install(\"https://github.com/shimpe/panola\");\r\nQuarks.install(\"https://github.com/shimpe/sc-lsystem\");\r\n)\r\n\r\n/*\r\n// Leaf\r\naxiom: Y---Y\r\nrules:\r\n X => F-FF-F--[--X]F-FF-F--F-FF-F--\r\n Y => f-F+X+F-fY\r\n\r\nnotes from Raga\r\nBilahari\r\nU 1, 9/8, 5/4, 3/2, 27/16, 2\r\nD 2, 15/18, 27/16, 3/2, 4/3, 5/4, 9/8, 1\r\n*/\r\n\r\n(\r\ns.waitForBoot({\r\n    var player;\r\n    var lsys = LSystem(\r\n        iterations:3,\r\n        axiom:\"Y---Y\",\r\n        constants:Set[],\r\n        rules:(\r\n\t\t\t\\X : \"F-FF-F--[--X]F-FF-F--F-FF-F--\",\r\n\t\t\t\\Y : \"-F+X+F-Y\",\r\n\r\n\t));\r\n\r\n    var interp = LSystemInterpreter(\r\n        lsystem:lsys,\r\n        globalstate:(\r\n\t\t\t\\up : 57.midicps * [1, 9/8, 5/4, 3/2, 27/16, 2],\r\n\t\t\t\\down : 57.midicps * [2, 15/18, 27/16, 3/2, 4/3, 5/4, 9/8, 1],\r\n\t\t\t\\pnotes : 57.midicps * [1, 9/8, 5/4],\r\n\t\t\t\\customnotes: [\"c3_16@numharm[12]\",\"g-3_8@numharm[10]\"], // not used.\r\n            \\transpose : 1,\r\n\t\t\t\\counter : 0,\r\n\t\t\t\\lag: 0.0,\r\n            \\tempo : 0.2,\r\n\t\t\t\\dur : 0.2\r\n        ),\r\n        actions:(\r\n            // whenever you encounter an F, extend the list of played notes\r\n            'F' : [{ | glob, loc |\r\n\t\t\t    glob[\\tempo] = [0.8, 0.2, 0.4, 0.2].choose;\r\n                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n            // whenever you encounter a +, transpose up\r\n            '+': [{ | glob, loc |\r\n                // extend list notes being played (using some randomness :) )\r\n\t\t\t\tglob[\\pnotes] = glob[\\pnotes].add(glob[\\up].choose);\r\n\t\t\t\t// limit pattern to 8 notes.\r\n\t\t\t\tif (glob[\\pnotes].size > 9) {\r\n                    glob[\\pnotes].pop;\r\n                };\r\n\r\n                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n            // whenever you encounter a -, transpose down\r\n            '-': [{ | glob, loc |\r\n                //\"remove first note\".postln;\r\n\t\t\t\t// limit pattern to 8 notes.\r\n\t\t\t\tglob[\\pnotes] = glob[\\pnotes].addFirst(glob[\\down].choose);\r\n\t\t\t\tif (glob[\\pnotes].size > 1) {\r\n                    glob[\\pnotes].pop;\r\n                };\r\n\t\t\t\tglob[\\transpose] = [3/4,1/2,1].choose;\r\n                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n            // whenever you encounter an X, remove first note from the played notes\r\n            'X' : [{ | glob, loc |\r\n                //\"transpose down\".postln;\r\n\t\t\t\tglob[\\transpose] = [1,2,3].choose;\r\n\r\n                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n\t\t\t//[0.1, 0.2, 0.3, 0.4, 0.5].choose;\r\n            // whenever you encounter a Y, change tempo (randomly) )\r\n            'Y' : [{ | glob, loc |\r\n\t\t\t\tglob[\\lag] = [0.8, 0.2, 0.4, 0.2].choose;\r\n\t\t\t\t//glob[\\patternnotes] = glob[\\patternnotes].add(glob[\\customnotes].choose.debug(\"add new custom\"));\r\n\r\n\r\n                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n        )\r\n    );\r\n\r\n    var interp2 = interp.deepCopy();\r\n\r\n    SynthDef(\\kalimba, {\r\n        |out = 0, freq = 440, amp = 2, mix = 0.2, rel = 1.4|\r\n        var snd, click;\r\n        // Basic tone is a SinOsc\r\n        snd = SinOsc.ar(freq) * EnvGen.ar(Env.perc(0.03, rel , 1, -7), doneAction: 2);\r\n        snd = HPF.ar( LPF.ar(snd, 380), 120);\r\n        // The \"clicking\" sounds are modeled with a bank of resonators excited by enveloped white noise\r\n        click = DynKlank.ar(`[\r\n            // the resonant frequencies are randomized a little to add variation\r\n            // there are two high resonant freqs and one quiet \"bass\" freq to give it some depth\r\n            [240*ExpRand(0.97, 1.02), 2020*ExpRand(0.97, 1.02), 3151*ExpRand(0.97, 1.02)],\r\n            [-9, 0, -5].dbamp,\r\n            [0.8, 0.07, 0.08]\r\n        ], BPF.ar(PinkNoise.ar, 6500, 0.1) * EnvGen.ar(Env.perc(0.001, 0.01))) * 1;\r\n        snd = (snd*mix) + (click*(1-mix));\r\n        snd = Mix( snd );\r\n        Out.ar(out, Pan2.ar(snd, 0, amp));\r\n    }).add;\r\n\r\n\tSynthDef(\\blips, {arg out = 0, freq = 440, numharm = 11, att = 0.01, rel = 0.7, amp = 1, pan = 0.3;\r\n\t\tvar snd, env;\r\n\t\tenv = Env.perc(att, rel, amp).kr(doneAction: 2);\r\n\t\tsnd = BPF.ar(LeakDC.ar(Mix(Blip.ar([freq, freq*1.01], numharm, env))), 440, 0.4);\r\n\t\tOut.ar(out, Pan2.ar(snd, pan));\r\n\t}).add;\r\n\r\n\r\n\tSynthDef(\"plucking\", { arg amp = 0.1, freq = 440, decay = 1, coef = 0.2;\r\n\t\tvar env, snd;\r\n\t\tenv = EnvGen.kr(Env.linen(0, decay, 0), doneAction: 2);\r\n\t\tsnd = Pluck.ar(\r\n\t\t\tin: WhiteNoise.ar(amp),\r\n\t\t\ttrig: Impulse.kr(0),\r\n\t\t\tmaxdelaytime: 0.1,\r\n\t\t\tdelaytime: freq.reciprocal,\r\n\t\t\tdecaytime: decay,\r\n\t\t\tcoef: coef);\r\n\t\tOut.ar(0, [snd, snd]);\r\n\t}).add;\r\n\tSynthDef(\"bird\", { arg out, freq, sustain=0.7, amp=0.5, pan;\r\n\t\tvar env, u=1;\r\n\t\tenv = EnvGen.kr(Env.perc(0.01, sustain), 1, doneAction: Done.freeSelf);\r\n\t\t5.do { var d; d = exprand(0.01, 1); u = SinOsc.ar(d * 300, u, rrand(0.1,1.2) * d, 1) };\r\n\t\tOut.ar(out, Pan2.ar(SinOsc.ar(u + 1 * freq, 0, amp * env), pan));\r\n\t}).add;\r\n\r\n    s.sync;\r\n\r\n\t// up the rate a bit\r\n\tTempoClock.default = TempoClock.new(1.25);\r\n\r\n\tfork {\r\n        var skipfirstidx = 0; // increase to skip more steps at the beginning\r\n        var sz = lsys.getCalculatedString.size();\r\n\t\tvar p, q, pattern;\r\n\r\n\t\tPbindef(\\r, \\instrument, \\bird, \\amp, 0.04, \\rel, 0.2);\r\n\t\tPbindef(\\p, \\instrument, \\kalimba, \\amp, 0.7);\r\n\t\tPbindef(\\q, \\instrument, \\plucking, \\amp, 0.07, \\decay, 1.5);\r\n\r\n        lsys.getCalculatedString.do({\r\n            | chr, idx |\r\n\r\n            var transposedpattern;\r\n            var trans;\r\n            var trans2;\r\n\t\t\tvar n1, n2, n3, l, l2, t, t2, tadd, wave, ampl;\r\n\r\n            (\"*** PART\" + (idx+1) + \"OF\" + sz + \"***\").postln;\r\n            interp.step(idx);\r\n            interp2.step(idx);\r\n            // start playing from step skipfirstidx\r\n            if (idx > skipfirstidx) {\r\n                var repeats = 1;\r\n                if (idx == (sz-1)) { repeats = 2; }; // don't repeat last pattern indefinitely\r\n                trans = interp.globalState()[\\transpose].debug(\"trans\");\r\n                trans2 = interp2.globalState()[\\transpose].debug(\"trans2\");\r\n\r\n\t\t\t\tn1 = Pseq(trans * interp.globalState()[\\pnotes].debug(\"n1\"));\r\n\t\t\t\tn2 = Pseq(trans2 * interp2.globalState()[\\pnotes].debug(\"n2\"));\r\n\t\t\t\tn3 = Pseq( [n1.first, n2.first ] );\r\n\t\t\t\tl = interp.globalState()[\\lag].debug(\"lag\");\r\n\t\t\t\tl2 = interp2.globalState()[\\lag].debug(\"lag2\");\r\n\t\t\t\tt = interp.globalState()[\\tempo].debug(\"tempo\");\r\n                t2 = interp2.globalState()[\\tempo].debug(\"tempo2\");\r\n\t\t\t\ttadd = t + t2;\r\n\t\t\t\tampl = 0.06;\r\n\t\t\t\tif (trans >1 ) { ampl = 0.05 };\r\n\t\t\t\tif (trans >1.5 ) { ampl = 0.03 };\r\n\t\t\t\tif (trans >2 ) { ampl = 0.02 };\r\n\t\t\t\tpattern = Ppar([\r\n\t\t\t\t\tif (t > 0.2) {\r\n\t\t\t\t\t    Pbind(\\instrument, \\plucking, \\dur, t, \\freq, n1, \\decay, t+1, \\rel, tadd, \\amp, ampl )},\r\n\t\t\t\t\t    Pbind(\\instrument, \\kalimba, \\dur, t2, \\freq, n2, \\rel, tadd , \\amp, 0.6),\r\n\t\t\t\t\t    Pbind(\\instrument, \\bird, \\dur, tadd, \\freq, n1, \\rel, tadd + t2, \\amp, (t/4).clip(0.02, 0.07).postln )\r\n\r\n\t\t\t\t]);\r\n\r\n                if (player.notNil) { player.stop; };\r\n\r\n\t\t\t\tplayer = pattern.play();\r\n\r\n\t\t\t\t1.wait;\r\n                if (idx == (sz-1)) {\r\n                    \"*** ABOUT TO FINISH ***\".postln;\r\n                };\r\n            }\r\n\r\n        });\r\n\t//pattern.play;\r\n    }\r\n\r\n});\r\n)",
   "labels" : [
      "algo lsystem"
   ]
}
