// title: Confetti3aX, John Conway's Game of Life; fast, Xenakis-inspired version // author: henklass // description: // John Conway's Game of Life, Xenakis-inspired version with lots of synths switched on by live cells. // The slow, 1-bit-music version can be found at http://sccode.org/1-4YV . // code: s.boot; ( /*There is a decreasing linear connection between log(freq) and location in array: h+(maxWidth*v). Highest location-value in array = maxWidth*maxHeight log(freq)=log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight), so freq=exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight) Furthermore freq depends on value, which is either 0 or 1. freq=freq+(freq*value) or freq=(1+value)*freq Combining those 2: freq=(exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight))*(1+value) */ SynthDef(\beeper, { arg h, v, maxWidth, maxHeight; var maxfreq=5000, minfreq=50; Out.ar( 0, Pan2.ar( Pulse.ar(exp(log(maxfreq)-((log(maxfreq)-log(minfreq))*(h+(maxWidth*v))/(maxWidth*maxHeight))), 0.5, 0.02), 2*h/maxWidth-1, //pan depends on column in array 1 ) ); }).add; ) ( var maxWidth=45, maxHeight = 45; var z=15, ready = false; var newValues=Array2D.new(maxWidth + 2, maxHeight + 2); var oldValues=Array2D.new(maxWidth + 2, maxHeight + 2); var beepers=Array2D.new(maxWidth + 1, maxHeight + 1); var go, total; w=Window("Confetti3", Rect(400, 300, z*(maxWidth+2), z*(maxHeight+2))).front; w.view.background_(Color.white); w.front; w.drawFunc = { for (1, maxHeight, {arg v; for (1, maxWidth, {arg h; if (newValues[h,v]==0, {Pen.fillColor=Color.white}, {Pen.fillColor=Color.black} ); Pen.addRect(Rect(h*z, v*z, z, z)); Pen.fill; }); }); }; go=Routine({ //make random pattern for (1, maxWidth, {arg h; for (1, maxHeight, {arg v; newValues[h,v]=[0, 1].choose; if (newValues[h,v]==1, { beepers[h,v]=Synth("beeper",[h: h, v: v, maxWidth: maxWidth, maxHeight: maxHeight]) }); }) }); {w.refresh}.defer; 0.03.wait; while ({ready==false},{ //copy edges of board to edges of array for(1, maxWidth, {arg h; newValues[h,0]=newValues[h, maxHeight]; newValues[h, maxHeight+1]=newValues[h, 1]; }); for(1, maxHeight, {arg v; newValues[ 0, v]=newValues[maxWidth, v]; newValues[maxWidth+1, v]=newValues[1, v]; }); newValues[0,0]=newValues[maxWidth, maxHeight]; newValues[0, maxHeight+1]=newValues[maxWidth, 1]; newValues[maxWidth+1, 0]=newValues[1, maxHeight]; newValues[maxWidth+1, maxHeight+1]=newValues[1,1]; //copy newValues to oldValues (including edges) for (0, maxWidth+1, {arg h; for (0, maxHeight+1, {arg v; oldValues[h,v]=newValues[h,v]; }) }); //adapt for (1, maxWidth,{arg h; for (1, maxHeight, {arg v; total=oldValues[h-1,v-1] + oldValues[h,v-1] + oldValues[h+1,v-1] + oldValues[h-1,v]+ oldValues[h+1,v] + oldValues[h-1,v+1] + oldValues[h,v+1] + oldValues[h+1,v+1]; if( (total<=1 )|| (total > 3), {newValues[h,v]=0} ); if( total==3, {newValues[h,v]=1} ); if (newValues[h,v]!=oldValues[h,v],{ if (newValues[h,v]==1, { beepers[h,v]=Synth("beeper",[h: h, v: v, maxWidth: maxWidth, maxHeight: maxHeight]); }, { beepers[h,v].free; }); }); }); }); //check if ready ready=true; for (1, maxWidth,{arg h; for (1, maxHeight, {arg v; if (oldValues[h,v]!=newValues[h,v], {ready=false}); }) }); {w.refresh}.defer; 0.1.wait; }); }); go.play; )