// Permutations for Laptop Orchestra (2009) // ~ Jacob Quinn Shenker 1 => int kbd_spacebar; // tone row //[[0, 2, 4, 7, 9, 13, 15, 16, 17, 19], [3,10,11], [2,8], [1]] @=> int rows[][]; [[0, 2, 3, 7, 8, 13], [0,1,2,3],[0,-12,0,12]] @=> int rows[][]; //[[0, 2, 3, 7, 8, 13], [0,4,7,12,13], [5,5,4,6], [2,3], [0]] @=> int rows[][]; //[[0, 2, 3, 7, 8, 13]] @=> int rows[][]; // tempo for autoplay 100::ms => dur T; int positions[rows.cap()]; 0 => int deviceNum_kbd; 0 => int deviceNum_mouse; Hid hid_kbd; HidMsg msg_kbd; Hid hid_mouse; HidMsg msg_mouse; if( !hid_kbd.openKeyboard( deviceNum_kbd ) ) me.exit(); <<< "keyboard '", hid_kbd.name(), "' ready" >>>; if( !hid_mouse.openMouse( deviceNum_mouse ) ) me.exit(); <<< "mouse '", hid_mouse.name(), "' ready" >>>; MAUI_View control_view; MAUI_LED led_rows[rows.cap()][0];//[rows[0].cap()]; MAUI_Button button_rows[rows.cap()][0];//[rows[0].cap()]; control_view.size(rows[0].cap()*100, rows.cap()*100+50+50+50); MAUI_Button dummy_button; dummy_button.size(1,1); dummy_button.position(0,0); control_view.addElement(dummy_button); 0 => int play; MAUI_Button play_button; play_button.toggleType(); play_button.name("play (;)"); play_button.size(control_view.width()/3., 100); play_button.position(0, control_view.height()-100); control_view.addElement(play_button); fun void controlPlayButton() { while (true) { play_button => now; <<< "play button:", play_button.state() >>>; togglePlay(play_button.state()); } } spork ~ controlPlayButton(); MAUI_Button spacebar_button; spacebar_button.pushType(); spacebar_button.name("next (spacebar)"); spacebar_button.size(control_view.width()/3., 100); spacebar_button.position(control_view.width()/3., control_view.height()-100); control_view.addElement(spacebar_button); fun void controlSpacebarButton() { while (true) { spacebar_button => now; advanceTime(); displayPositions(); playNow(); spacebar_button => now; // not needed for key-based "clicks" } } spork ~ controlSpacebarButton(); 0 => int mouse; MAUI_Button mouse_button; mouse_button.toggleType(); mouse_button.name("mouse (q)"); mouse_button.size(control_view.width()/3., 100); mouse_button.position(control_view.width()*2/3., control_view.height()-100); control_view.addElement(mouse_button); fun void controlMouseButton() { while (true) { mouse_button => now; <<< "mouse button:", mouse_button.state() >>>; toggleMouse(mouse_button.state()); } } spork ~ controlMouseButton(); 0 => int button_action; fun void keyboardLoop() { while( true ) { // wait on event hid_kbd => now; // get one or more messages <<< "msg_kbd:", msg_kbd.which >>>; while( hid_kbd.recv( msg_kbd ) ) { if (msg_kbd.which == 29 && msg_kbd.isButtonDown()) { <<< "semicolon down" >>>; play_button.state(!play_button.state()); togglePlay(play_button.state()); } if (msg_kbd.which == 27 && msg_kbd.isButtonDown()) { <<< "q down" >>>; mouse_button.state(!mouse_button.state()); toggleMouse(mouse_button.state()); } else if (msg_kbd.which == 44 && msg_kbd.isButtonDown()) { <<< "space down" >>>; if (kbd_spacebar == 1) { advanceTime(); displayPositions(); playNow(); } } else if (msg_kbd.which == 44 && !msg_kbd.isButtonDown()) { <<< "space up" >>>; // do stuff } else if (msg_kbd.which == 224 && msg_kbd.isButtonDown()) { <<< "ctl down" >>>; change_action(1); } else if (msg_kbd.which == 224 && !msg_kbd.isButtonDown()) { <<< "ctl up" >>>; change_action(-1); } else if (msg_kbd.which == 226 && msg_kbd.isButtonDown()) { <<< "opt down" >>>; change_action(2); } else if (msg_kbd.which == 226 && !msg_kbd.isButtonDown()) { <<< "opt up" >>>; change_action(-2); } else if (msg_kbd.which == 225 && msg_kbd.isButtonDown()) { <<< "shift down" >>>; change_action(4); } else if (msg_kbd.which == 225 && !msg_kbd.isButtonDown()) { <<< "shift up" >>>; change_action(-4); } else if (msg_kbd.which == 227 && msg_kbd.isButtonDown()) { <<< "apple down" >>>; change_action(8); } else if (msg_kbd.which == 227 && !msg_kbd.isButtonDown()) { <<< "apple up" >>>; change_action(-8); } } } } fun void mouseLoop() { while (mouse == 1) { // wait on HidIn as event hid_mouse => now; // messages received while( hid_mouse.recv( msg_mouse ) ) { // mouse motion if( msg_mouse.isMouseMotion() ) { // axis of motion if( msg_mouse.deltaX ) { <<< "mouse motion:", msg_mouse.deltaX, "on x-axis" >>>; } else if( msg_mouse.deltaY ) { <<< "mouse motion:", msg_mouse.deltaY, "on y-axis" >>>; } } // mouse button down else if( msg_mouse.isButtonDown() ) { <<< "mouse button", msg_mouse.which, "down" >>>; } // mouse button up else if( msg_mouse.isButtonUp() ) { <<< "mouse button", msg_mouse.which, "up" >>>; } // mouse wheel motion (requires chuck 1.2.0.8 or higher) else if( msg_mouse.isWheelMotion() ) { // axis of motion if( msg_mouse.deltaX ) { <<< "mouse wheel:", msg_mouse.deltaX, "on x-axis" >>>; } else if( msg_mouse.deltaY ) { <<< "mouse wheel:", msg_mouse.deltaY, "on y-axis" >>>; } } } } } fun void change_action(int increment) { increment +=> button_action; if (button_action < 0) { 0 => button_action; } } spork ~ keyboardLoop(); fun void toggleMouse(int state) { state => mouse; if (mouse == 1) { spork ~ mouseLoop(); } } fun void togglePlay(int state) { state => play; if (play == 1) { spork ~ timeLoop(); } //advanceTime(); //displayPositions(); } fun void timeLoop() { T => now; while (play == 1) { advanceTime(); displayPositions(); playNow(); T => now; } } for (0 => int i; i < rows.cap(); i++) { MAUI_LED leds[rows[i].cap()] @=> led_rows[i]; MAUI_Button buttons[rows[i].cap()] @=> button_rows[i]; for (0 => int k; k < rows[i].cap(); k++) { leds[k] @=> MAUI_LED led; led.color(MAUI_LED.blue); led.size(30,30); led.position(k*100+20,i*100+35); control_view.addElement(led); buttons[k] @=> MAUI_Button button; button.pushType(); button.size(100,100); button.position(k*100,i*100+50); nameButton(i, k); control_view.addElement(button); } } displayPositions(); control_view.display(); fun void nameButton(int i, int k) { button_rows[i][k] @=> MAUI_Button button; button.name(rows[i][k] + ""); } fun void controlButton(int i, int k) { button_rows[i][k] @=> MAUI_Button button; while( true ) { // wait for the button to be pushed down button => now; // button down <<< "button pushed:", button.name(), button_action >>>; if (button_action == 0) // click: swap k-th and (k+1)-th (modulo length of tone row) { (k+1) % rows[i].cap() => int k1; rows[i][k] @=> int temp; rows[i][k1] @=> rows[i][k]; temp @=> rows[i][k1]; nameButton(i, k1); } else if (button_action == 4) // click+shift: increment { 1 +=> rows[i][k]; } else if (button_action == 8) // click+apple: decrement { 1 -=> rows[i][k]; } else if (button_action == 6) // click+opt+shift: increment by an octave { 12 +=> rows[i][k]; } else if (button_action == 10) // click+opt+apple: decrement by an octave { 12 -=> rows[i][k]; } nameButton(i, k); button => now; // button up } } for (0 => int i; i < rows.cap(); i++) { for (0 => int k; k < rows[i].cap(); k++) { spork ~ controlButton(i, k); } } //fun void displayRows(MAUI_Button button_rows[][], int rows[][]) //{ // for (0 => int i; i < rows.cap(); i++) // { // for (0 => int k; k < rows.cap(); k++) // { // nameButton(i, k); // } // } //} fun void displayPosition(MAUI_LED leds[], int position) { for (0 => int i; i < leds.cap(); i++) { if (position == i) { leds[i].light(); } else { leds[i].unlight(); } } } fun void displayPositions() { for (0 => int i; i < rows.cap(); i++) { displayPosition(led_rows[i], positions[i]); } } fun void advanceTime() { 1 => int advance; for (0 => int i; i < rows.cap(); i++) { if (advance) { (1 + positions[i]) % rows[i].cap() => positions[i]; } if (positions[i] == 0 && advance) { 1 => advance; } else { 0 => advance; } } } fun void playNow() { 0 => int note; for (0 => int i; i < rows.cap(); i++) { rows[i][positions[i]] +=> note; } <<< "note:", note >>>; } while(true) 1::day => now;