{
   "labels" : [
      "gui",
      "random",
      "pad"
   ],
   "code" : "// A random pad generation thing. Every time you click EXECUTE, a pad with a certain number of melodic lines is generated using the parameters in the GUI.\r\n// Use it -> study the code -> modify it -> ? -> profit!\r\n(\r\n\r\n// This function creates an instance of the Pad Generator\r\n~padGenerator = {\r\n\r\n\tvar res = Environment.make({\r\n\r\n\t\t// Score Parameters\r\n\t\t// See the GUI code for explanations.\r\n\t\t~sp = (\r\n\t\t\tnumMelodicLines:         3,\r\n\t\t\tnumNotesPerMelodLine:  8,\r\n\t\t\tbaseNote:         40,\r\n\t\t\tdegrees:            [0,7,12],\r\n\t\t\tdurs:             [1,2,4,3],\r\n\t\t\tnoteOfs:          [0,12,24],\r\n\t\t);\r\n\t\t~sp.minNoteDur =      { 1/16 }!~sp.numMelodicLines;\r\n\t\t~sp.instrs =          { #[sin1,sin2,sin3,sin1,sin1] }!~sp.numMelodicLines;\r\n\t\t// This Semaphores are used to wait synchronously the ending of all the melodic lines.\r\n\t\t// Every melodic line has a lock associated.\r\n\t\t// When a melodic line stop playing it opens the Semaphore.\r\n\t\t~locks =              List[];\r\n\t\t~executing =          false;\r\n\r\n\t\t// Utility. Translate Symbols arrays to Strings\r\n\t\t~symbolsArrayToString = { |arr|\r\n\r\n\t\t\tvar res;\r\n\r\n\t\t\tif( arr.size == 0 )\r\n\t\t\t{ res = arr.asString; }\r\n\t\t\t{\r\n\t\t\t\tvar strs = arr.collect{|el|\r\n\t\t\t\t\t~symbolsArrayToString.(el);\r\n\t\t\t\t};\r\n\t\t\t\tif( arr[0].size == 0 ){ res = \"#[\" }{ res = \"[ \"; };\r\n\t\t\t\tstrs.do{ |el,i|\r\n\t\t\t\t\tres = res + el + \",\";\r\n\t\t\t\t};\r\n\t\t\t\tres = res + \"]\";\r\n\t\t\t};\r\n\r\n\t\t\tres\r\n\t\t};\r\n\r\n\t\t// Utility. Resize a multidimensional array.\r\n\t\t// Ex:\r\n\t\t// IN   arr = [ [1,2,3], [4,] ]    size = 5\r\n\t\t// OUT  arr = [ [1,2,3], [4,], [1,2,3], [4,], [1,2,3] ]\r\n\t\t~resizeMultiDimArray = { |arr,size|\r\n\r\n\t\t\tvar res = arr;\r\n\r\n\t\t\tif( arr.size > size ){\r\n\r\n\t\t\t\tres = Array.newClear( size );\r\n\t\t\t\tsize.do{ |i| res[i] = arr[i]; };\r\n\r\n\t\t\t};\r\n\r\n\t\t\tif( arr.size < size ){\r\n\r\n\t\t\t\tres = Array.newClear( size );\r\n\t\t\t\tsize.do{ |i| res[i] = arr[ i%(arr.size) ]; };\r\n\r\n\t\t\t};\r\n\r\n\t\t\tres\r\n\t\t};\r\n\r\n\t\t// This function include all the operations to be carried out before the actual playing\r\n\t\t~prepare = {\r\n\r\n\t\t\tSynthDef(\\sin1,{\r\n\r\n\t\t\t\t|out = 0, amp = 0.1, gate = 1, freq = 440|\r\n\r\n\t\t\t\tvar d = ();\r\n\r\n\t\t\t\td.gen    = SinOsc.ar(freq) ** 3;\r\n\t\t\t\td.envAmp = Env.asr(1,1,6).kr(2,Trig1.kr(gate,1,1)) * amp;\r\n\t\t\t\td.res    = Clip.ar( d.gen, -1.01, 1.01 ) * d.envAmp ! 2;\r\n\r\n\t\t\t\tOut.ar(out,d.res);\r\n\r\n\t\t\t}).add;\r\n\r\n\t\t\ts.sync;\r\n\r\n\t\t\tSynthDef(\\sin2,{\r\n\r\n\t\t\t\t|out = 0, amp = 0.1, gate = 1, freq = 440|\r\n\r\n\t\t\t\tvar d = ();\r\n\r\n\t\t\t\td.gen    = SinOsc.ar(freq+[0,1]) ** 2;\r\n\t\t\t\td.envAmp = Env.asr(1,1,6).kr(2,Trig1.kr(gate,1,1)) * amp;\r\n\t\t\t\td.res    = Clip.ar( d.gen, -1.01, 1.01 ) * d.envAmp;\r\n\r\n\t\t\t\tOut.ar(out,d.res);\r\n\r\n\t\t\t}).add;\r\n\r\n\t\t\ts.sync;\r\n\r\n\t\t\tSynthDef(\\sin3,{\r\n\r\n\t\t\t\t|out = 0, amp = 0.1, gate = 1, freq = 440|\r\n\r\n\t\t\t\tvar d = ();\r\n\r\n\t\t\t\td.gen    = SinOsc.ar(freq+[1,0]).abs;\r\n\t\t\t\td.envAmp = Env.asr(1,1,6).kr(2,Trig1.kr(gate,1,1)) * amp;\r\n\t\t\t\td.res    = Clip.ar( d.gen, -1.01, 1.01 ) * d.envAmp ! 2;\r\n\r\n\t\t\t\tOut.ar(out,d.res);\r\n\r\n\t\t\t}).add;\r\n\r\n\t\t\ts.sync;\r\n\t\t};\r\n\r\n\r\n\t\t// Utility\r\n\t\t// Ex: ~playNote.(\\sin1,[\\freq,440],1.5);\r\n\t\t~playNote = { |sdef,args,dur=1|\r\n\r\n\t\t\tvar nt;\r\n\t\t\ts.makeBundle(nil,{ nt = Synth(sdef,args); });\r\n\t\t\tdur.wait;\r\n\t\t\tnt.set(\\gate,0);\r\n\r\n\t\t};\r\n\r\n\t\t// This function generates all the melodic lines and play them.\r\n\t\t// It waits for all of them to finish.\r\n\t\t~score = {\r\n\r\n\t\t\tvar str, strd, stri, strl, numMelodicLines, numNotesPerMelodLine, minNoteDur, degrees,\r\n\t\t\tdurs, noteOfs, instrs;\r\n\r\n\t\t\tnoteOfs    = ~sp.noteOfs.reshape(~sp.numMelodicLines);\r\n\t\t\tminNoteDur = ~sp.minNoteDur.reshape(~sp.numMelodicLines);\r\n\r\n\t\t\t~sp.instrs = ~resizeMultiDimArray.( ~sp.instrs, ~sp.numMelodicLines );\r\n\r\n\t\t\t// The notes of every melodic line are generated here\r\n\t\t\tstr      = (~sp.numMelodicLines).collect{|p|\r\n\t\t\t\t{ ~sp.degrees.choose + noteOfs[p] + ~sp.baseNote }!~sp.numNotesPerMelodLine\r\n\t\t\t};\r\n\t\t\t// The durations of every melodic line are generated here\r\n\t\t\tstrd     = ~sp.numMelodicLines.collect{|p|\r\n\t\t\t\t{ ~sp.durs.choose * minNoteDur[p] }!~sp.numNotesPerMelodLine\r\n\t\t\t};\r\n\t\t\t// The instrument names for every melodic line are generated here\r\n\t\t\tstri     = ~sp.numMelodicLines.collect{|p| { ~sp.instrs[p].choose }!~sp.numNotesPerMelodLine };\r\n\r\n\t\t\t~locks     = { Semaphore(0) }!~sp.numMelodicLines;\r\n\r\n\t\t\t// Code for the acutal playing\r\n\t\t\t~sp.numMelodicLines.do{ |i|\r\n\t\t\t\t{\r\n\t\t\t\t\t// suona, sequenzialmente, le note di una parte\r\n\t\t\t\t\tstr[i].size.do { |j|\r\n\t\t\t\t\t\t~playNote.(\r\n\t\t\t\t\t\t\tstri[i][j],\r\n\t\t\t\t\t\t\t[\\freq,str[i][j].midicps,\\amp,0.01,\\gate,1,],\r\n\t\t\t\t\t\t\tstrd[i][j]\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t};\r\n\t\t\t\t\t// segnala fine parte, rilasciando il Semaphore dedicato\r\n\t\t\t\t\t~locks[i].signal;\r\n\t\t\t\t}.fork;\r\n\t\t\t};\r\n\t\t\t// Wait for all the melodic lines to end\r\n\t\t\tstr.size.do{ |i| ~locks[i].wait; };\r\n\r\n\t\t\t\"Done\".postln;\r\n\r\n\t\t};\r\n\r\n\t\t// Unused\r\n\t\t~finish = {\r\n\r\n\t\t};\r\n\r\n\t\t/* Utility. If this instance of the pad generator is not already generating/playing something,\r\n\t\tthis function executes the input function.*/\r\n\t\t~ifNotAlreadyExecuting = { |func|\r\n\t\t\tif( ~executing, {\r\n\t\t\t\t\"An instance of the patch is already executing\".postln;\r\n\t\t\t},{\r\n\t\t\t\tfunc.();\r\n\t\t\t});\r\n\t\t};\r\n\t\t/* Launch the pad generation/execution. */\r\n\t\t~startScore = { |e|\r\n\t\t\tvar func = {\r\n\t\t\t\ts.waitForBoot{\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\t~ifNotAlreadyExecuting.({\r\n\t\t\t\t\t\t\t~prepare.();\r\n\t\t\t\t\t\t\t~executing = true; ~score.(); ~executing = false;\r\n\t\t\t\t\t\t\t~finish.();\r\n\t\t\t\t\t\t});\r\n\t\t\t\t\t}.fork;\r\n\t\t\t\t};\r\n\t\t\t};\r\n\t\t\tif( e.class == Environment ){\r\n\t\t\t\te.use{ func.(); };\r\n\t\t\t}{\r\n\t\t\t\tfunc.();\r\n\t\t\t};\r\n\t\t};\r\n\r\n\t\t~showUi = { |e,parent,bounds|\r\n\t\t\tvar func = {\r\n\t\t\t\tvar wi, // width\r\n\t\t\t\the=20,  // row height\r\n\t\t\t\trows=8, // rows used for the controls\r\n\t\t\t\thelpRows = 3,\r\n\t\t\t\tdr       = 0, // #rows for the documentation\r\n\t\t\t\thv,     // help view\r\n\t\t\t\tmhb,    // make help button; helper function\r\n\t\t\t\ttr       = rows+1+helpRows+dr, // total number of rows\r\n\t\t\t\tpa;     // panel view\r\n\r\n\t\t\t\tif( bounds.isNil ){\r\n\t\t\t\t\tbounds = Rect(0,0,400,he*(tr));\r\n\t\t\t\t}{\r\n\t\t\t\t\the = bounds / (tr);\r\n\t\t\t\t};\r\n\t\t\t\twi = bounds.width;\r\n\r\n\t\t\t\tif( parent.isNil ){\r\n\t\t\t\t\tparent = Window(\"Pad Generator\",bounds);\r\n\t\t\t\t\tparent.front;\r\n\t\t\t\t};\r\n\r\n\t\t\t\tmhb = { |row=0,msg(\"\")|\r\n\t\t\t\t\tButton(pa,Rect(wi-he,he*(dr+row),he,he)+Rect(2,2,-4,-4))\r\n\t\t\t\t\t.states_([[\"?\",Color.white,Color.blue]])\r\n\t\t\t\t\t.mouseEnterAction_{ hv.string=msg; }\r\n\t\t\t\t\t.mouseLeaveAction_{ hv.string=\"\"; };\r\n\t\t\t\t};\r\n\r\n\t\t\t\tpa = View(parent,bounds);\r\n\r\n\t\t\t\tStaticText(pa,Rect(0,he*0,wi,he*dr)+Rect(2,2,-4,-4))\r\n\t\t\t\t// .background_(Color.blue(0.4))\r\n\t\t\t\t.stringColor_(Color.blue(0.4))\r\n\t\t\t\t.align_(\\left)\r\n\t\t\t\t.string_(\"DOCUMENTATION \\n \");\r\n\r\n\t\t\t\tEZNumber(pa,Rect(0,he*dr,wi-he,he),\"# melodic lines\",[1,100,\\lin,1,1],{ |vv|\r\n\t\t\t\t\te.sp.numMelodicLines = vv.value.asInteger; },e.sp.numMelodicLines,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(0,\"Number of melodic lines played simultaneously.\");\r\n\r\n\t\t\t\tEZNumber(pa,Rect(0,he*(dr+1),wi-he,he),\"# notes per melodic line\",[1,40,\\lin,1,1],{ |vv|\r\n\t\t\t\t\te.sp.numNotesPerMelodLine = vv.value.asInteger; },\r\n\t\t\t\t    e.sp.numNotesPerMelodLine,false,100,gap:2@2,margin:2@2\r\n\t\t\t\t);\r\n\t\t\t\tmhb.(1,\"Length (in number of notes) of every melodic line\");\r\n\r\n\t\t\t\tEZNumber(pa,Rect(0,he*(dr+2),wi-he,he),\"base note\",[20,100,\\lin,1,40],{ |vv|\r\n\t\t\t\t\te.sp.baseNote = vv.value.asInteger; },e.sp.baseNote,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(2,\"A base note the generation algorithm uses as root for the melodic lines\");\r\n\r\n\t\t\t\tEZText(pa,Rect(0,he*(dr+3),wi-he,he),\"degrees set\",{|vv|\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tval = vv.value.interpret;\r\n\t\t\t\t\tif( val.class == Array ){\r\n\t\t\t\t\t\te.sp.degrees = val;\r\n\t\t\t\t\t};\r\n\t\t\t\t},e.sp.degrees.asString,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(3,\"Set of degrees used by the generation algorithm to create the melodic lines\");\r\n\r\n\t\t\t\tEZText(pa,Rect(0,he*(dr+4),wi-he,he),\"relative durs set\",{|vv|\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tval = vv.value.interpret;\r\n\t\t\t\t\tif( val.class == Array ){\r\n\t\t\t\t\t\te.sp.durs = val;\r\n\t\t\t\t\t};\r\n\t\t\t\t},e.sp.durs.asString,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(4,\"Set of relative durations used to calculate the final absolute note durations. \\n\\t\\tabs_note_dur = choose_one('relative durs set') * 'min note dur' \");\r\n\t\t\t\tEZText(pa,Rect(0,he*(dr+5),wi-he,he),\"note offsets\",{|vv|\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tval = vv.value.interpret;\r\n\t\t\t\t\tif( val.class == Array ){\r\n\t\t\t\t\t\te.sp.noteOfs = val;\r\n\t\t\t\t\t};\r\n\t\t\t\t},e.sp.noteOfs.asString,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(5,\"Note offset added to the 'base note' for every melodic line. \\n\\t'note offsets'[i] = note offset for the ith melodic line\");\r\n\r\n\t\t\t\tEZText(pa,Rect(0,he*(dr+6),wi-he,he),\"min note durs\",{|vv|\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tval = vv.value.interpret;\r\n\t\t\t\t\tif( val.class == Array ){\r\n\t\t\t\t\t\te.sp.minNoteDur = val;\r\n\t\t\t\t\t};\r\n\t\t\t\t},e.sp.minNoteDur.asString,false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(6,\"min_note_dur[i] = minimum note duration for the ith melodic line\");\r\n\t\t\t\tEZText(pa,Rect(0,he*(dr+7),wi-he,he),\"instrs\",{|vv|\r\n\t\t\t\t\tvar val;\r\n\t\t\t\t\tval = vv.value.interpret;\r\n\t\t\t\t\tval.class.postln;\r\n\t\t\t\t\tif( val.class == Array ){\r\n\t\t\t\t\t\te.sp.instrs = val;\r\n\t\t\t\t\t};\r\n\t\t\t\t},~symbolsArrayToString.(e.sp.instrs),false,100,gap:2@2,margin:2@2);\r\n\t\t\t\tmhb.(7,\"This array has a sub-array for every melodic line. \\nEvery i-th sub-array contains the instruments that the i-th melodic line can randomly choose for its notes\");\r\n\r\n\t\t\t\tButton(pa,Rect(0,he*(dr+8),wi,he))\r\n\t\t\t\t.states_([[\"EXECUTE\",Color.white,Color.black]])\r\n\t\t\t\t.action_({ e.startScore(); \t});\r\n\r\n\t\t\t\thv = StaticText(pa,Rect(0,he*(dr+9),wi,he*helpRows)+Rect(2,2,-4,-4))\r\n\t\t\t\t.background_(Color.blue(0.4))\r\n\t\t\t\t.stringColor_(Color.white)\r\n\t\t\t\t.align_(\\left)\r\n\t\t\t\t.string_(\"\");\r\n\r\n\t\t\t};\r\n\t\t\tif( e.class == Environment ){ e.use({ func.(parent,bounds); }); }{ func.(e,parent); };\r\n\t\t};\r\n\r\n\t});\r\n\r\n\tres.know = true;\r\n\r\n\tres\r\n};\r\n\r\n~p1 = ~padGenerator.();\r\n~p1.showUi();\r\n\r\n)\r\n\r\n// CODE FOR DEVELOPMENT/DEBUGGING\r\n~p1.executing = false;\r\n~p1.sp\r\n~p1.startScore();\r\n~sp = nil\r\ns.quit",
   "is_private" : null,
   "id" : "1-5e5",
   "name" : "[SIMPLE] Random Pad Generator",
   "author" : "Checco Ruseo",
   "description" : "A random pad generation thing. \r\nEvery time you click EXECUTE, a pad with a certain number of melodic lines is generated using the parameters in the GUI.\r\nUse it -> study the code -> modify it -> ? -> profit!\r\nP.S. sorry for my mediocre english ;)",
   "ancestor_list" : []
}
