{
   "name" : "Confetti 3",
   "author" : "henklass",
   "ancestor_list" : [],
   "description" : "Confetti 3 converts random patterns of blocks to more or less structured images. Every block will adapt to the predominant color in its surroundings, taking its upper, lower, left and right neighbour into account. Sound, corresponding to the location on the board, makes for some interesting melodies.\r\nThis program can easily be converted to John Conway's Game of Life: http://sccode.org/1-4YV .",
   "labels" : [
      "random",
      "graphics",
      "1bit music"
   ],
   "id" : "1-4YU",
   "is_private" : null,
   "code" : "s.boot;\r\n(\r\nvar maxWidth=30, maxHeight = 30;\r\nvar z=20, ready = false;\r\nvar newValues=Array2D.new(maxWidth + 2, maxHeight + 2);\r\nvar oldValues=Array2D.new(maxWidth + 2, maxHeight + 2);\r\nvar go;\r\n\r\n\r\n/*There is a decreasing linear connection between log(freq) and location in array: h+(maxWidth*v).\r\nHighest location-value in array = maxWidth*maxHeight\r\nlog(freq)=log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight), so\r\nfreq=exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight)\r\nFurthermore freq depends on value, which is either 0 or 1. \r\nfreq=freq+(freq*value) or freq=(1+value)*freq\r\nCombining those 2:\r\nfreq=(exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight))*(1+value)\r\n\r\n*/\r\n\r\nSynthDef(\\beeper, { arg h, v, p, maxWidth, maxHeight;\r\n\tvar maxfreq=5000, minfreq=50;\r\n\tOut.ar(\r\n\t\t0, \r\n\t\tPan2.ar(\r\n\t\t\tPulse.ar(exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight)))*(1+p), 0.5, 0.3), \r\n\t\t\t2*h/maxWidth-1, //pan depends on column in array\r\n\t\t\t1\r\n\t\t)\r\n\t);\r\n\t\r\n}).add;\r\n\r\nw=Window(\"Confetti3\", Rect(400, 300, z*(maxWidth+2), z*(maxHeight+2))).front;\r\nw.view.background_(Color.white);\r\nw.front;\r\n\r\nw.drawFunc = {\r\n\t\tfor (1, maxHeight, {arg v;\r\n\t\t\tfor (1, maxWidth, {arg h;\r\n\t\t\t\tif (newValues[h,v]==1, \r\n\t\t\t\t\t{Pen.fillColor=Color.white},\r\n\t\t\t\t\t{Pen.fillColor=Color.black}\r\n\t\t\t\t);\r\n\t\t\t\tPen.addRect(Rect(h*z, v*z, z, z));\r\n\t\t\t\tPen.fill;\r\n\t\t\t});\r\n\t\t});\r\n};\r\n\t\t\t\t\t\t\t\t\t\t\t\t\r\n//initialise\r\nfor (0, maxWidth+1,{arg h;\r\n\tfor (0, maxHeight+1, {arg v;\r\n\t\tnewValues[h,v]=0.5;\r\n\t\toldValues[h,v]=0.5;\r\n\t})\r\n});\r\n\r\ngo=Routine({\r\n\t//make random pattern\r\n\tfor (1, maxWidth, {arg h;\r\n\t\tfor (1, maxHeight, {arg v;\r\n\t\t\tnewValues[h,v]=[0, 1].choose;\r\n\t\t\t{w.refresh}.defer;\r\n\t\t\tp=newValues[h,v];\r\n\t\t\tb=Synth(\"beeper\",[p: p, h: h, v: v, maxWidth: maxWidth, maxHeight: maxHeight]);\r\n\t\t\t0.1.wait;\r\n\t\t\tb.free;\r\n\t\t})\r\n\t});\r\n\twhile ({ready==false},{\r\n\t\t//copy newValues to oldValues (ignore the edges)\r\n\t\tfor (1, maxWidth, {arg h;\r\n\t\t\tfor (1, maxHeight, {arg v;\r\n\t\t\t\toldValues[h,v]=newValues[h,v];\r\n\t\t\t})\r\n\t\t});\r\n\t\t//adapt\r\n\t\tfor (1, maxWidth,{arg h;\r\n\t\t\tfor (1, maxHeight, {arg v;\r\n\t\t\t\tif(\r\n\t\t\t\t\toldValues[h, v-1]+oldValues[h+1, v]+oldValues[h-1, v]+oldValues[h, v+1] < 2, \t\t\t\t\t{newValues[h,v]=0}\r\n\t\t\t\t);\r\n\t\t\t\tif(\r\n\t\t\t\t\toldValues[h, v-1]+oldValues[h+1, v]+oldValues[h-1, v]+oldValues[h, v+1] > 2, \r\n\t\t\t\t\t{newValues[h,v]=1}\r\n\t\t\t\t);\r\n\t\t\t\t{w.refresh}.defer;\r\n\t\t\t\tif (newValues[h,v]!=oldValues[h,v],{\r\n\t\t\t\t\tp=newValues[h,v];\r\n\t\t\t\t\tb=Synth(\"beeper\",[p: p, h: h, v: v, maxWidth: maxWidth, maxHeight: maxHeight]);\r\n\t\t\t\t\t0.1.wait;\r\n\t\t\t\t\tb.free;\r\n\t\t\t\t});\r\n\t\t\t})\r\n\t\t});\r\n\t\t//check if ready\r\n\t\tready=true;\r\n\t\tfor (1, maxWidth,{arg h;\r\n\t\t\tfor (1, maxHeight, {arg v;\r\n\t\t\t\tif (oldValues[h,v]!=newValues[h,v], {ready=false});\r\n\t\t\t})\r\n\t\t});\r\n\t});\r\n});\r\n\r\n\r\ngo.play;\r\n)"
}
