{
   "ancestor_list" : [
      "1-Eo"
   ],
   "description" : "bulging version of [simple rand-n-step](http://sccode.org/1-Eo) but with comments, which maybe helpful to reuse this stuff\r\n\r\nit seems, someday, it should be rewritten as Quark )",
   "author" : "vividsnow",
   "name" : "rand-n-step+",
   "code" : "( \r\nvar w, status, limit, buttons, controls = [], one_button, data, synths, one_synth, synths_generator, \r\ndensity_one = 1/4, density_many = 1/10, type_distribution = [0.85, 0.15], // tweak it to get more or less dense pattern grid\r\ntask, resolution, direction, pos = 0, step = 1, border = 1, dims = [16,16]; // tweak dims to change size of grid\r\nw = Window(\"rand-n-step+\", Rect(50,250,dims[0]*22+10+250,dims[1]*22+60)).acceptsMouseOver_(true); // window init\r\nstatus = StaticText(w, Rect(5, w.bounds.height - 20, w.bounds.width, 20));\r\nlimit = { ReplaceOut.ar(0, Limiter.ar(In.ar(0,2))) }.play( addAction:\\addToTail ); // limiter\r\ndata = Array2D(dims[1],dims[0]); // prepare data\r\n// and buttons\r\none_button = { | b, density = 0.1 |\r\n\tb.valueAction = 0; // reset\r\n\tdensity.coin.if({ b.valueAction = [1,2].wchoose(type_distribution) }); // tweak it\r\n};\r\nsynths = Array.fill(dims[1], { () });\r\nbuttons = Array.fill(dims[1], { |l|\r\n\tcontrols = controls.add([ // control buttons\r\n\t\tButton( w, Rect( 10 + (22*dims[0]), 35 + (22*l), 20, 20) ).states_([['m'],['u']]).action_({ |b| // mute / unmute\r\n\t\t\tsynths[l].gate = b.value.booleanValue.not.binaryValue;\r\n\t\t}).mouseOverAction_({ status.string = 'mute/unmute' }),\r\n\t\tButton( w, Rect( 10 + (22*(dims[0]+1)), 35 + (22*l), 20, 20) ).states_([['p']]).action_({ // dice pattern line\r\n\t\t\tbuttons[l].do({ |b| one_button.(b, density_one) }); // tweak it\r\n\t\t}).mouseOverAction_({ status.string = 'randomize pattern' }),\r\n\t\tButton( w, Rect( 10 + (22*(dims[0]+2)), 35 + (22*l), 20, 20) ).states_([['s']]).action_({ // dice one synth\r\n\t\t\tsynths[l] = one_synth.(l);\r\n\t\t}).mouseOverAction_({ status.string = 'randomize synth' }),\r\n\t\tSlider( w, Rect( 10 + (22*(dims[0]+3)), 35 + (22*l), 60, 20) ).action_({ |b| // synth amp\r\n\t\t\tsynths[l].amp = b.value.linexp(0,1,1/16,16);\r\n\t\t}).mouseOverAction_({ status.string = 'tweak synth amp' }),\r\n\t\tSlider( w, Rect( 10 + (22*(dims[0]+3)+60), 35 + (22*l), 60, 20) ).action_({ |b| // synth stretch\r\n\t\t\tsynths[l].stretch = b.value.linexp(0,1,1/8,8);\r\n\t\t}).mouseOverAction_({ status.string = 'tweak synth stretch' }),\r\n\t\tSlider( w, Rect( 10 + (22*(dims[0]+3)+120), 35 + (22*l), 60, 20) ).action_({ |b| // synth pan\r\n\t\t\tsynths[l].pan = b.value.linlin(0,1,-1,1);\r\n\t\t}).mouseOverAction_({ |b| status.string = 'tweak synth pan ' })\r\n\t]);\r\n\tArray.fill(dims[0], { |i| // grid\r\n\t\tButton( w, Rect( 5 + (22*i), 35 + (22*l), 20, 20) ).states_([ ['-'], ['+'], ['%'] ]).action_({ \r\n\t\t\t|b| data[l,i] = b.value \r\n\t\t}).mouseOverAction_({ status.string = '\"%\" makes sound with 0.5 probability' }); \r\n\t});\r\n});\r\n// synth gen functions and initialization\r\none_synth = { |i| // tweak this function to (generate and) return other synthdef names\r\n\tvar name = 'rstp'++i, pan = -1.0.rand2;\r\n\tSynthDef(name, { |index = 0, amp = 1, stretch = 1, pan = 0| // args: horizontal position in grid, amplitude and stretch correction, pan\r\n\t\tvar sig = Pan2.ar( // tweak sig to get different sound texture\r\n\t\t\tPMOsc.ar(80.exprand(10000), 1.exprand(200), 1.exprand(20)),\r\n\t\t\tpan,\r\n\t\t\tEnvGen.kr(Env(Array.rand(4, 0, 0.05.rrand(0.4)).add(0), Array.rand(3, 0.1, 1.2).add(0.1), 5.rand2), levelScale: amp, timeScale: stretch, doneAction: 2)\r\n\t\t);\r\n\t\tOut.ar(0, sig);\r\n\t}).add;\r\n\tcontrols[i][3].valueAction_(1.explin(1/16,16,0,1));\r\n\tcontrols[i][4].valueAction_(1.explin(1/8,8,0,1));\r\n\tcontrols[i][0].valueAction_(0);\r\n\tcontrols[i][5].valueAction_(pan.linlin(-1,1,0,1));\r\n\t(name: name, gate: 1, amp: 1, stretch: 1, pan: pan);\r\n};\r\nsynths_generator = { Array.fill(dims[1], { |i| synths[i] = one_synth.(i) } ) };\r\nsynths_generator.();\r\n// step task\r\ntask = Task({\r\n\tinf.do({\r\n\t\tpos = (pos + step).mod(dims[0]);\r\n\t\tdims[1].do({ |l|\r\n\t\t\t(buttons[l] @@ pos).font_(Font(\"sans\", 20));\r\n\t\t\t(buttons[l] @@ (pos-step)).font_(Font(\"sans\", 14));\r\n\t\t\tsynths[l].gate.booleanValue.if({\r\n\t\t\t\tvar args = [index: pos, amp: synths[l].amp, stretch: synths[l].stretch * TempoClock.tempo.reciprocal * resolution.reciprocal, pan: synths[l].pan ];\r\n\t\t\t\tswitch( data[l,pos],\r\n\t\t\t\t\t1, { Synth(synths[l].name, args) },\r\n\t\t\t\t\t2, { 0.5.coin.if({ Synth(synths[l].name, args) }) }\r\n\t\t\t\t);  \r\n\t\t\t});\r\n\t\t});\r\n\t\tswitch( pos,\r\n\t\t\t0,             { (border == -1 && step == -1).if({ direction.valueAction = 0 }) },\r\n\t\t\t(dims[0] - 1), { (border == -1 && step ==  1).if({ direction.valueAction = 1 }) }\r\n\t\t);\t\r\n\t\t(TempoClock.default.tempo.reciprocal / resolution).yield;\r\n\t});\r\n}, AppClock).play(quant:[0]);\r\n// app buttons\r\nButton(w, Rect(5,5, w.bounds.width - 10 / 7, 20)).states_([['reset']]).action_({ |b|\r\n\tsynths_generator.();\r\n\tbuttons.flat.do({ |b| one_button.(b, 0) }); // tweak it\r\n}).mouseOverAction_({ status.string = 'reset everything' });\r\nButton(w, Rect(w.bounds.width - 10 / 7 * 1 + 5, 5, w.bounds.width - 10 / 6, 20)).states_([['lucky?']]).action_({ |b| // lazy patterns\r\n\tbuttons.flat.do({ |b| one_button.(b, density_many) }); // tweak it\r\n}).mouseOverAction_({ status.string = 'create random pattern grid' });\r\nButton(w, Rect(w.bounds.width - 10 / 7 * 2 + 5, 5, w.bounds.width - 10 / 7, 20)).states_([['noisy?']]).action_({ |b|\r\n\tsynths_generator.();\r\n}).mouseOverAction_({ status.string = 'randomize all synths' });\r\nButton(w, Rect(w.bounds.width - 10 / 7 * 3 + 5, 5, w.bounds.width - 10 / 7, 20)).states_([['pause'],['play']]).action_({ |b|\r\n\tb.value.booleanValue.if({ task.pause }, { task.resume(quant:[0]) });\r\n}).mouseOverAction_({ status.string = 'play/pause' });\r\ndirection = Button(w, Rect(w.bounds.width - 10 / 7 * 4 + 5, 5, w.bounds.width - 10 / 7, 20)).states_([['r-t-l'],['l-t-r']]).action_({ |b|\r\n\tb.value.booleanValue.if({ step = -1 }, { step = 1 });\r\n}).mouseOverAction_({ status.string = 'change playing direction' });\r\nButton(w, Rect(w.bounds.width - 10 / 7 * 5 + 5, 5, w.bounds.width - 10 / 7, 20)).states_([['fold'],['wrap']]).action_({ |b|\r\n\tb.value.booleanValue.if({ border = -1 }, { border = 1 });\r\n}).mouseOverAction_({ status.string = 'behavior on the grid border' });\r\nSlider(w, Rect(w.bounds.width - 10 / 7 * 6 + 5, 5, w.bounds.width - 10 / 7, 20)).action_({ |b|\r\n\tresolution = b.value.linlin(0, 1, 1, 8).quantize(1, 1);\r\n\tstatus.string = 'resolution: ' ++ resolution;\r\n}).valueAction_(4.linlin(1,8,0,1)).mouseOverAction_({ status.string = 'change grid resulution' });\r\n// show\r\nw.front.onClose = { task.stop; limit.free };\r\nstatus.string_('hello, point something to get hint, hopefully..');\r\n)",
   "is_private" : null,
   "id" : "1-KH",
   "labels" : [
      "gui",
      "code fork",
      "sequencer",
      "random",
      "step"
   ]
}
