Created
February 9, 2013 22:57
-
-
Save jordanorelli/4747484 to your computer and use it in GitHub Desktop.
conway's game of life for the monome, written in chuck
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24787 => int monomeIn; | |
17102 => int monomeOut; | |
"/example" => string monomePrefix; | |
"127.0.0.1" => string monomeHost; | |
OscRecv recv; | |
monomeIn => recv.port; | |
recv.listen(); | |
fun float[][] toneGrid(int width, int height, int columnStep, int rowStep, float baseFreq, float octaveSteps) { | |
float tones[width][height]; | |
Math.pow(2, 1.0/ octaveSteps $ float) => float toneStep; | |
for(0 => int row; row < height; row++) { | |
baseFreq * Math.pow(toneStep, row * rowStep) => float rowBase; | |
for(0 => int col; col < width; col++) { | |
rowBase * Math.pow(toneStep, col * columnStep) | |
=> tones[col][row]; | |
} | |
} | |
return tones; | |
} | |
class Monome { | |
string prefix; | |
string hostname; | |
OscRecv recv; | |
OscSend snd; | |
// PROTECTED FINAL | |
// | |
// Initialization: sets up the monome and listens for incoming messages. | |
fun void init(string _prefix, string _hostname, int in, int out) { | |
preInit(); | |
_prefix => prefix; | |
_hostname => hostname; | |
OscSend m; | |
m.setHost(hostname, out); | |
m @=> snd; | |
in => recv.port; | |
recv.listen(); | |
spork ~ keyListener(); | |
spork ~ tiltListener(); | |
all(0); | |
postInit(); | |
} | |
// PUBLIC | |
// | |
// preInit is called before the init cycle finishes. | |
// | |
fun void preInit() {} | |
// PUBLIC | |
// | |
// postInit is called after the init cycle finishes. | |
// | |
fun void postInit() {} | |
// PUBLIC | |
// | |
// key is called once for every time a key is pressed on the Monome. | |
// Override this method in a child class to define how to handle key | |
// presses from the monome. | |
fun void key(int x, int y, int z) { | |
<<< prefix, "key", x, y, z >>>; | |
} | |
// PUBLIC | |
// | |
// position change on tilt sensor n, integer (8-bit) values (x, y, z). | |
// This method is called once for each OSC message received from the monome | |
// with regards to its tilt. | |
fun void tilt(int n, int x, int y, int z) { | |
<<< prefix, "tilt", n, x, y, z >>>; | |
} | |
// PRIVATE | |
// | |
// key press handler. This is invoked automatically by the Monome | |
// constructor, and should not be called. This method starts an infinite | |
// loop and listens for incoming osc messages from the monome. When | |
// messages are received, the monome object's "key" method is called. | |
// | |
fun void keyListener() { | |
recv.event(prefix+"/grid/key", "iii") @=> OscEvent e; | |
while(true) { | |
e => now; | |
while(e.nextMsg() != 0) { | |
e.getInt() => int x; | |
e.getInt() => int y; | |
e.getInt() => int z; | |
key(x, y, z); | |
} | |
} | |
} | |
// PRIVATE | |
// | |
// tilt sensor handler. This is invoked automatically by the Monome | |
// constructor, and should not be called. This method starts an infinite | |
// loop and listens for incoming osc messages from the monome. When | |
// messages are received, the monome object's "tilt" method is called. | |
// | |
fun void tiltListener() { | |
recv.event(prefix+"/tilt", "iiii") @=> OscEvent e; | |
while(true) { | |
e => now; | |
while(e.nextMsg() != 0) { | |
e.getInt() => int n; | |
e.getInt() => int x; | |
e.getInt() => int y; | |
e.getInt() => int z; | |
tilt(n, x, y, z); | |
} | |
} | |
} | |
// PROTECTED FINAL | |
// | |
// set led at (x,y) to state s (0 or 1). | |
// | |
fun void set(int x, int y, int s) { | |
snd.startMsg(prefix+"/grid/led/set", "iii"); | |
snd.addInt(x); | |
snd.addInt(y); | |
snd.addInt(s); | |
me.yield(); | |
} | |
// PROTECTED FINAL | |
// | |
// set all leds to state s (0 or 1). | |
// | |
fun void all(int i) { | |
snd.startMsg(prefix+"/grid/led/all", "i"); | |
snd.addInt(i); | |
me.yield(); | |
} | |
} | |
class Life extends Monome { | |
float tones[8][8]; | |
int lifeState[8][8]; | |
int nextLifeState[8][8]; | |
100::ms => dur genStep; | |
false => int running; | |
fun void preInit() { | |
toneGrid(8, 8, 1, 6, 220, 12) @=> tones; | |
} | |
fun void postInit() { | |
all(0); | |
spork ~ live(); | |
} | |
fun void live() { | |
true => running; | |
while(running) { | |
step(); | |
genStep => now; | |
} | |
} | |
fun void pause() { | |
<<< "pause!" >>>; | |
if(running) { | |
false => running; | |
} else { | |
spork ~ live(); | |
} | |
} | |
fun void step() { | |
for(0 => int i; i < 8; i++) { | |
for(0 => int j; j < 8; j++) { | |
step(i, j); | |
} | |
} | |
for(0 => int i; i < 8; i++) { | |
for(0 => int j; j < 8; j++) { | |
if(nextLifeState[i][j] != lifeState[i][j]) { | |
set(i, j, nextLifeState[i][j]); | |
spork ~ play(i, j); | |
} | |
nextLifeState[i][j] => lifeState[i][j]; | |
} | |
} | |
} | |
fun void play(int x, int y) { | |
SinOsc s => ADSR env => dac; | |
tones[x][y] => s.freq; | |
env.set(20::ms, 100::ms, 0.7, 20::ms); | |
env.keyOn(); | |
40::ms => now; | |
env.keyOff(); | |
40::ms => now; | |
} | |
fun void step(int x, int y) { | |
countNeighbors(x, y) => int neighborcount; | |
if(lifeState[x][y] == 1) { | |
if(neighborcount == 2 || neighborcount == 3) { | |
1 => nextLifeState[x][y]; | |
} else { | |
0 => nextLifeState[x][y]; | |
} | |
} else { | |
if(neighborcount == 3) { | |
1 => nextLifeState[x][y]; | |
} else { | |
0 => nextLifeState[x][y]; | |
} | |
} | |
} | |
fun int wrap(int x) { | |
if(x > 7) return 0; | |
if(x < 0) return 7; | |
return x; | |
} | |
fun int countNeighbors(int x, int y) { | |
0 => int count; | |
wrap(x - 1) => int left_x; | |
wrap(x + 1) => int right_x; | |
wrap(y - 1) => int up_y; | |
wrap(y + 1) => int down_y; | |
lifeState[left_x][up_y] +=> count; | |
lifeState[x][up_y] +=> count; | |
lifeState[right_x][up_y] +=> count; | |
lifeState[left_x][y] +=> count; | |
lifeState[right_x][y] +=> count; | |
lifeState[left_x][down_y] +=> count; | |
lifeState[x][down_y] +=> count; | |
lifeState[right_x][down_y] +=> count; | |
return count; | |
} | |
fun void key(int x, int y, int z) { | |
if(z == 0) { | |
return; | |
} | |
toggle(x, y); | |
} | |
fun void toggle(int x, int y) { | |
if(lifeState[x][y] == 0) { | |
1 => lifeState[x][y]; | |
} else { | |
0 => lifeState[x][y]; | |
} | |
set(x, y, lifeState[x][y]); | |
} | |
} | |
new Life @=> Life m; | |
m.init(monomePrefix, monomeHost, monomeIn, monomeOut); | |
fun void keyboardHandler() { | |
Hid hi; | |
HidMsg msg; | |
if(!hi.openKeyboard(0)) { | |
<<< "can't open keyboard" >>>; | |
return; | |
} | |
while(true) { | |
hi => now; | |
while(hi.recv(msg)) { | |
if(msg.isButtonDown()) { | |
if(msg.which == 44) { | |
m.pause(); | |
} | |
} | |
} | |
} | |
} | |
spork ~ keyboardHandler(); | |
while(true) { 1::second => now; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment