{
   "name" : "Weed, after P. Bourke",
   "author" : "blueprint",
   "ancestor_list" : [],
   "description" : "This is an homage to: http://sccode.org/1-5bp which demonstrates the l-systems composition idea. I've used different synths and some of the l-systems I wrote for https://anvaka.github.io/lsystem/ which lets you play with l-systems in the browser (and 3d).",
   "labels" : [
      "panola",
      "lsystem generative iterative"
   ],
   "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/*\r\n// Weed, P. Bourke\r\naxiom: F\r\nrules:\r\n  F -> FF-[XY]+[XY]\r\n  X -> +cFY\r\n  Y -> -dFX\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:\"F\",\r\n        constants:Set[],\r\n        rules:(\r\n\t\t\t\\F : \"FF-[XY]+[XY]\",\r\n\t\t\t\\X : \"+FY\",\r\n\t\t\t\\Y : \"-FX\",\r\n\r\n\t));\r\n\r\n    var interp = LSystemInterpreter(\r\n        lsystem:lsys,\r\n        globalstate:(\r\n\t\t\t//\\acceptablenotes : Set[\"g3\", \"g3_16\", \"a3\", \"c4\", \"d4_8\", \"f#4_16\", \"g4\", \"g4_16\", \"a4\"],\r\n\t\t\t\\acceptablenotes : Set[\"dis3_16\", \"g3_16\", \"gis3_16\", \"ais3_16\", \"c4_8\", \"c4_16\", \"dis4_16\", \"g4_16\"],\r\n            \\patternnotes : [\"g3\"],\r\n            \\transpose : 0,\r\n            \\tempo : 16,\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                // extend list notes being played (using some randomness :) )\r\n                glob[\\patternnotes] = glob[\\patternnotes].add(glob[\\acceptablenotes].choose.debug(\"add new note\"));\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                glob[\\transpose] = (glob[\\transpose] + [1,2,3,4].choose.debug(\"transpose up\")).clip(-12,12);\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,4].choose.debug(\"transpose down\")).clip(-12, 12);\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            'Y' : [{ | 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                // always return state at the end\r\n                [glob, loc];\r\n            }, nil],\r\n            // whenever you encounter a Y, change tempo (randomly) )\r\n            'X' : [{ | glob, loc |\r\n                glob[\\tempo] = (glob[\\tempo] * [1.6, 0.4, 2.4, 0.8, 3.2, 0.2 ].choose.debug(\"tempo factor\")).clip(8,32);\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 = 0.1, mix = 0.1|\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(3.0, 4.0), 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    SynthDef(\\flute, {\r\n\t\t| out = 0, freq = 440, amp = 1.0, a = 0.1, r = 0.1|\r\n\t\t//var fmod = 1; // clean\r\n\t\t//var fmod = LFCub.kr(freq:1/12).range(1, LFNoise2.kr(freq:12.0).range(1,1.1)); // tone deaf flute\r\n\t\tvar fmod = LFCub.kr(freq:1/12).range(1, LFNoise2.kr(freq:12.0).range(1,1.02)); // flute-like sound\r\n\t\tvar env = EnvGen.ar(Env.perc(a, r), levelScale:0.5, doneAction:2);\r\n\t\tvar snd = SinOsc.ar(freq * fmod)!2;\r\n\t\tOut.ar(bus:out, channelsArray:(env*(amp*snd).tanh));\r\n\t}).add;\r\n\r\n\tSynthDef(\\blips, {arg out = 0, freq = 440, numharm = 11, att = 0.01, rel = 1, amp = 0.2, 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\tSynthDef(\\risset, {|out = 0, pan = 0, freq = 400, amp = 0.05, att = 0.005, rel = 1, gate = 1,vibFreq=7, vibAmp=0,vibAdd=0.5|\r\n\t\tvar amps = #[1, 0.67, 1, 1.8, 2.67, 1.67, 1.46, 1.33, 1.33, 1, 1.33];\r\n\t\tvar durs = #[1, 0.9, 0.65, 0.55, 0.325, 0.35, 0.25, 0.2, 0.15, 0.1, 0.075];\r\n\t\tvar frqs = #[0.56, 0.56, 0.92, 0.92, 1.19, 1.7, 2, 2.74, 3, 3.76, 4.07];\r\n\t\tvar dets = #[0, 1, 0, 1.7, 0, 0, 0, 0, 0, 0, 0];\r\n\t\tvar doneActionEnv = EnvGen.ar(Env.linen(0, att+rel, 0), gate, doneAction: 2);\r\n\t\tvar src = Mix.fill(11, {|i|\r\n\t\t\tvar env = EnvGen.ar(Env.perc(att, rel * durs[i], amps[i], att.explin(0.005, 4, -4.5, 0)), gate);\r\n\t\t\tSinOsc.ar(freq*frqs[i] + dets[i], 0, amp*env);\r\n\t\t});\r\n        src = src * SinOsc.kr(vibFreq*15, mul:vibAmp, add:vibAdd);\r\n\t\tsrc = src * doneActionEnv * 0.5; // make sure it releases node after the end.\r\n\t    Out.ar(out, Pan2.ar(src, pan));\r\n\t}).add;\r\n\tSynthDef(\"waveguideFlute\", { arg scl = 0.2, freq = 440, ipress = 0.9, ibreath = 0.09, ifeedbk1 = 0.4, ifeedbk2 = 0.4, dur = 0.5, gate = 0.5, amp = 1;\r\n\r\n\t\tvar kenv1, kenv2, kenvibr, kvibr, sr, cr, block;\r\n\t\tvar poly, signalOut, ifqc;\r\n\t\tvar aflow1, asum1, asum2, afqc, atemp1, ax, apoly, asum3, avalue, atemp2, aflute1;\r\n\t\tvar fdbckArray;\r\n\r\n\t\tsr = SampleRate.ir;\r\n\t\tcr = ControlRate.ir;\r\n\t\tblock = cr.reciprocal;\r\n\r\n\t\tifqc = freq;\r\n\r\n\t\t// noise envelope\r\n\t\tkenv1 = EnvGen.kr(Env.new(\r\n\t\t\t[ 0.0, 1.1 * ipress, ipress, ipress, 0.0 ], [ 0.06, 0.2, dur - 0.46, 0.2 ], 'linear' )\r\n\t\t);\r\n\t\t// overall envelope\r\n\t\tkenv2 = EnvGen.kr(Env.new(\r\n\t\t\t[ 0.0, amp, amp, 0.0 ], [ 0.1, dur - 0.02, 0.1 ], 'linear' ), doneAction: 2\r\n\t\t);\r\n\t\t// vibrato envelope\r\n\t\tkenvibr = EnvGen.kr(Env.new( [ 0.0, 0.0, 1, 1, 0.0 ], [ 0.5, 0.5, dur - 1.5, 0.5 ], 'linear') );\r\n\r\n\t\t// create air flow and vibrato\r\n\t\taflow1 = LFClipNoise.ar( sr, kenv1 );\r\n\t\tkvibr = SinOsc.ar( 5, 0, 0.1 * kenvibr );\r\n\r\n\t\tasum1 = ( ibreath * aflow1 ) + kenv1 + kvibr;\r\n\t\tafqc = ifqc.reciprocal - ( asum1/20000 ) - ( 9/sr ) + ( ifqc/12000000 ) - block;\r\n\r\n\t\tfdbckArray = LocalIn.ar( 1 );\r\n\r\n\t\taflute1 = fdbckArray;\r\n\t\tasum2 = asum1 + ( aflute1 * ifeedbk1 );\r\n\r\n\t\t//ax = DelayL.ar( asum2, ifqc.reciprocal * 0.5, afqc * 0.5 );\r\n\t\tax = DelayC.ar( asum2, ifqc.reciprocal - block * 0.5, afqc * 0.5 - ( asum1/ifqc/cr ) + 0.001 );\r\n\r\n\t\tapoly = ax - ( ax.cubed );\r\n\t\tasum3 = apoly + ( aflute1 * ifeedbk2 );\r\n\t\tavalue = LPF.ar( asum3, 2000 );\r\n\r\n\t\taflute1 = DelayC.ar( avalue, ifqc.reciprocal - block, afqc );\r\n\r\n\t\tfdbckArray = [ aflute1 ];\r\n\r\n\t\tLocalOut.ar( fdbckArray );\r\n\r\n\t\tsignalOut = avalue;\r\n\r\n\t\tOffsetOut.ar( 0, [ signalOut * kenv2, signalOut * kenv2 ] );\r\n\r\n\t}).add;\r\n    s.sync;\r\n\r\n    fork {\r\n        var skipfirstidx = 4; // increase to skip more steps at the beginning\r\n        var sz = lsys.getCalculatedString.size();\r\n        lsys.getCalculatedString.do({\r\n            | chr, idx |\r\n            var pattern;\r\n            var transposedpattern;\r\n            var transposition;\r\n            var transposition2;\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 = inf;\r\n                if (idx == (sz-1)) { repeats = 3; }; // don't repeat last pattern indefinitely\r\n                transposition = interp.globalState()[\\transpose].debug(\"transpose\");\r\n                transposition2 = interp2.globalState()[\\transpose].debug(\"transpose2\");\r\n                pattern = Pn(\r\n                    Ppar([\r\n                        Padd(\\midinote, Pfunc({transposition}),\r\n                            Panola.new(\r\n                                notation:interp.globalState()[\\patternnotes].join(\" \").debug(\"notes1\"),\r\n                                dur_default:interp.globalState()[\\tempo],\r\n\t\t\t\t\t\t\t\tvol_default:0.1\r\n                            ).asPbind(\\risset)\r\n                        ),\r\n                        Padd(\\midinote, Pfunc({transposition2}),\r\n                            Panola.new(\r\n                                notation:interp2.globalState()[\\patternnotes].join(\" \").debug(\"notes2\"),\r\n                                dur_default:interp2.globalState()[\\tempo]*0.2,\r\n                                playdur_default:1,\r\n                                vol_default:0.1\r\n                            ).asPbind(\\waveguideFlute),\r\n                        )\r\n                    ]),\r\n                    repeats);\r\n                if (player.notNil) { player.stop; };\r\n\t\t\t\tplayer = pattern.play();\r\n                1.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)",
   "is_private" : null,
   "id" : "1-5gV"
}
