{
   "description" : "Also an homage to: http://sccode.org/1-5bp but using l-systems to drive Pbindefs instead of Panolas. This is slightly easier to modify other factors (env, for instance) and specify freq instead of notes.",
   "ancestor_list" : [],
   "author" : "blueprint",
   "name" : "l-systems Pbindef",
   "id" : "1-5gY",
   "is_private" : null,
   "code" : "/*\r\n// poetasters succulent 1\r\naxiom: A\r\nrules:\r\n A =>[FY]A[FXA]\r\n F => XF\r\n X => FY\r\n Y => [F+F+F][F-F-F]\r\n*/\r\n\r\n(\r\ns.waitForBoot({\r\n    var player;\r\n\r\n    var lsys = LSystem(\r\n        iterations:3,\r\n        axiom:\"A\",\r\n        constants:Set[],\r\n        rules:(\r\n\t\t\t\\A : \"[FY]A[FXA]\",\r\n\t\t\t\\F : \"XF\",\r\n\t\t\t\\X : \"FY\",\r\n\t\t\t\\Y : \"[F+F+F][F-F-F]\"\r\n\t));\r\n    // sitar\r\n\t// 48.midicps * [1, 16/15, 5/4, 4/3, 3/2, 8/5, 15/8, 2, 2*16/15, 2*5/4, 2*4/3, 2*3/2];\r\n    //\r\n    var interp = LSystemInterpreter(\r\n        lsystem:lsys,\r\n        globalstate:(\r\n\t\t\t\\acceptablenotes : 48.midicps * [1, 16/15, 5/4, 4/3, 3/2, 8/5, 15/8, 2, 2*16/15, 2*5/4, 2*4/3, 2*3/2],\r\n\r\n            \\patternnotes : [261,245],\r\n\t\t\t\\customnotes: [\"c3_16@numharm[12]\",\"g-3_8@numharm[10]\"], // not used.\r\n            \\transpose : -3,\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\r\n                // extend list notes being played (using some randomness :) )\r\n                glob[\\patternnotes] = glob[\\patternnotes].add(glob[\\acceptablenotes].choose);\r\n\t\t\t\t// limit pattern to 8 notes.\r\n\t\t\t\tif (glob[\\patternnotes].size > 5) {\r\n                    glob[\\patternnotes].pop;\r\n                };\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\t\t\t\tglob[\\transpose] = (glob[\\transpose] + [1,2,3].choose).clip(-9,9);\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                //\"transpose down\".postln;\r\n                glob[\\transpose] = (glob[\\transpose] - [1,2,3].choose).clip(-9, 9);\r\n\r\n\t\t\t\tglob[\\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 an X, remove first note from the played notes\r\n            'X' : [{ | glob, loc |\r\n                //\"remove first note\".postln;\r\n                if (glob[\\patternnotes].size > 1) {\r\n                    // keep at least one note\r\n                    glob[\\patternnotes] = glob[\\patternnotes].reverse;\r\n                    glob[\\patternnotes].pop;\r\n                    glob[\\patternnotes] = glob[\\patternnotes].reverse;\r\n                };\r\n\t\t\t\tglob[\\lag] = (glob[\\lag] + 0.1).clip(0,2);\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] = (glob[\\lag] - 0.1).clip(0,2);\r\n\t\t\t\t//glob[\\patternnotes] = glob[\\patternnotes].add(glob[\\customnotes].choose.debug(\"add new custom\"));\r\n\t\t\t\tglob[\\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        )\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|\r\n        var snd, click;\r\n        // Basic tone is a SinOsc\r\n        snd = SinOsc.ar(freq) * EnvGen.ar(Env.perc(0.03, Rand(0.7, 1.4), 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))) * 0.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(\"plucking\", { arg amp = 0.1, freq = 440, decay = 2, 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\r\n    s.sync;\r\n\r\n    // up the rate a bit\r\n    TempoClock.default = TempoClock.new(1.5);\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(\\p, \\instrument, \\plucking, \\amp, 0.1);\r\n\t\t//Pbindef(\\p, \\instrument, \\Pdefhelp, \\amp, 0.1);\r\n\t\tPbindef(\\q, \\instrument, \\kalimba, \\amp, 1);\r\n\t\t//q = Pbindef(\\q, \\instrument, \\blips);\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, l, l2, t, t2;\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(interp.globalState()[\\patternnotes].debug(\"notes1\"));\r\n\t\t\t\tn2 = Pseq(interp2.globalState()[\\patternnotes].debug(\"notes2\"));\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\r\n\t\t\t\tpattern =\r\n\t\t\t\t\tPpar([\r\n\t\t\t\t\t\tPbindef(\\p, \\dur, t, \\freq, n1, \\legato, l, \\transpose, trans),\r\n\t\t\t\t\t\tPbindef(\\q, \\dur, t2, \\freq, n2, \\legato, l*0.5, \\transpose, trans2),\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\r\n    }\r\n\r\n});\r\n)",
   "labels" : [
      "lsystem generative iterative"
   ]
}
