commit
b2075e5e2d
@ -0,0 +1,289 @@
|
||||
13475 => int monomeIn;
|
||||
16426 => int monomeOut;
|
||||
"/manager" => 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; }
|
Loading…
Reference in New Issue