// name: crystalis-go.ck // desc: crystal-in + wind-o-lin combo pack! // author: Ge Wang (gewang@cs.princeton.edu) // date: spring 2007 // whether to map to stereo 0 => int use_stereo; // which mouse 0 => int mouse_dev; // which kb 0 => int kb_dev; // number of channels dac.channels() => int channels; // max is 4 since we have four directions if( channels > 4 ) 4 => channels; // check mono if( use_stereo ) 4 => channels; // base and register 12 => int base; 3 => int register; // filter pole .99999 => float filter_pole_wind; .999975 => float filter_pole_crystal; // uniform volume scaling 35 => float volume; // level control 1 => float level; // filter resonance 1 => float resonance; // print <<< "-----------------", "" >>>; <<< "crystalis - v 1.5", "" >>>; <<< "-----------------", "" >>>; // print channels <<< "* channels:", channels >>>; // hid objects Hid mouse; Hid kb; HidMsg msg; // try if( !mouse.openMouse( mouse_dev ) ) me.exit(); <<< "* mouse ready...", "" >>>; // open keyboard if( !kb.openKeyboard( kb_dev ) ) me.exit(); <<< "* keyboard ready...", "" >>>; // numbers 0 => int L; 1 => int R; 2 => int U; 3 => int D; // key map int key[256]; // key and pitch 0 => key[29]; 1 => key[27]; 2 => key[6]; 3 => key[25]; 4 => key[5]; 5 => key[4]; 6 => key[22]; 7 => key[7]; 8 => key[9]; 9 => key[10]; 10 => key[20]; 11 => key[26]; 12 => key[8]; 13 => key[21]; 14 => key[23]; // which is current -1 => int current; // mode (0 -> wind; 1 -> bow; 2 -> pluck) 0 => int mode; // band map BandedWG @ playing_crystal[256]; // env map ADSR @ playing_wind[256]; // dir map int dir[4]; // find key fun int findNext( int which ) { current++; if( current >= channels ) 0 => current; for( current => int i; i < channels; i++ ) if( dir[i] == 0 ) { which => dir[i]; return i; } for( int i; i < current; i++ ) if( dir[i] == 0 ) { which => dir[i]; return i; } return -1; } // free key fun void freeNext( int which ) { for( int i; i < 4; i++ ) if( dir[i] == which ) 0 => dir[i]; } // 1 BandedWG band[channels]; // 2 Noise noise[channels]; ADSR adsr[channels]; ResonZ reson[channels]; // other Gain gain[channels]; OnePole pole[channels]; LPF lpf[channels]; Impulse imp[4]; NRev reverb[channels]; Gain out[dac.channels() > channels ? dac.channels() : channels]; // normal if( dac.channels() != 6 ) if( use_stereo ) for( int i; i < channels; i++ ) out[i] => dac.chan(i%2); else for( int i; i < channels; i++ ) out[i] => dac.chan(i); else // special: plork 6 channel { <<< "* rerouting audio for 6 channel plork...", "" >>>; for( int i; i < channels; i++ ) { // two per out out[i] => dac.chan(i); out[i] => dac.chan((i+3)%6); } } // connect for( int i; i < channels; i++ ) { // go gain[i] => reverb[i] => out[i]; imp[i] => lpf[i] => pole[i] => gain[i]; 3 => gain[i].op; // preset .9 => band[i].bowRate; .25 => band[i].bowPressure; .12 => band[i].strikePosition; 1 => band[i].preset; adsr[i].set( 2, 1, .75, 3 ); adsr[i].keyOff(); reson[i].freq( 220 ); reson[i].Q( 5 ); // filters // filter_pole => pole[i].pole; volume => gain[i].gain; 10 => lpf[i].freq; // reverb .1 => reverb[i].mix; } // set level fun void setLevel( float val ) { // loop for( int i; i < channels; i++ ) val => out[i].gain; } // wind fun void conn_wind() { // channels for( int i; i < channels; i++ ) { // disconnect crystal band[i] =< gain[i]; // connect wind noise[i] => reson[i] => adsr[i] => gain[i]; // settings filter_pole_wind => pole[i].pole; // reverb 0 => reverb[i].mix; } } // crystal fun void conn_crystal() { // channels for( int i; i < channels; i++ ) { // disconnect wind noise[i] =< reson[i] =< adsr[i] =< gain[i]; // connect crystal band[i] => gain[i]; // settings filter_pole_crystal => pole[i].pole; // reverb .2 => reverb[i].mix; } } // default conn_wind(); // go spork ~ do_kb(); spork ~ network(); // infinite time loop int i; while( true ) { // wait mouse => now; // loop over messages while( mouse.recv( msg ) ) { if( msg.isMouseMotion() ) { // left if( msg.deltaX < 0 ) -msg.deltaX * 4 => imp[L].next; // right else if( msg.deltaX > 0 ) msg.deltaX * 4 => imp[R].next; // up if( msg.deltaY > 0 ) msg.deltaY * 4 => imp[U].next; // down else if( msg.deltaY < 0 ) -msg.deltaY * 4 => imp[D].next; } } } // keyboard fun void do_kb() { // go int i; int shift; while( true ) { // wait kb => now; // inspect while( kb.recv( msg ) ) { // which if( msg.which > 256 ) continue; if( key[msg.which] == 0 && msg.which != 29 ) { // volume if( msg.which == 45 && msg.isButtonDown() ) { .95 *=> level; setLevel( level ); <<< "volume:", level >>>; } else if( msg.which == 46 && msg.isButtonDown() ) { 1.05 *=> level; setLevel( level ); <<< "volume:", level >>>; } // register else if( msg.which == 54 && msg.isButtonDown() ) { if( register > 0 ) register--; <<< "register:", register >>>; } else if( msg.which == 55 && msg.isButtonDown() ) { if( register < 6 ) register++; <<< "register:", register >>>; } // mode else if( msg.which == 16 && shift && msg.isButtonDown() ) { mode++; 3 %=> mode; if( mode == 0 ) { conn_wind(); <<< "-> mode:", "WIND" >>>; } else if( mode == 1 ) { conn_crystal(); <<< "-> mode:", "BOW" >>>; } else { <<< "-> mode:", "PLUCK" >>>; } } else if( msg.which == 225 ) { msg.isButtonDown() => shift; } else if( msg.which >= 30 && msg.which <= 39 ) { // resonance if( msg.isButtonDown() ) { Math.pow( 2.0, msg.which - 34 ) => resonance; <<< "resonance:", resonance >>>; } } } // set else if ( msg.isButtonDown() ) { // the player findNext( msg.which ) => int num; // busy if( num < 0 ) continue; // freq base + register * 12 + key[msg.which] => Std.mtof => band[num].freq => reson[num].freq; register * resonance => reson[num].Q; resonance < 1.0 ? Math.sqrt(resonance) : Math.pow(resonance, .8) => reson[num].gain; // wind if( mode == 0 ) { // bow adsr[num].keyOn(); // remember adsr[num] @=> playing_wind[msg.which]; } else { // bow if( mode == 1 ) 1 => band[num].startBowing; // remember band[num] @=> playing_crystal[msg.which]; } } else if( msg.isButtonUp() ) { 0 => int free; // playing if( playing_crystal[msg.which] != null ) { // stop 1 => playing_crystal[msg.which].stopBowing; // clear null @=> playing_crystal[msg.which]; // free 1 => free; } // playing if( playing_wind[msg.which] != null ) { // stop playing_wind[msg.which].keyOff(); // clear null @=> playing_wind[msg.which]; // free 1 => free; } // dealloc slot if( free ) freeNext( msg.which ); } } } } // receiver fun void network() { // create our OSC receiver OscRecv recv; // use port 6449 6449 => recv.port; // start listening (launch thread) recv.listen(); // create an address in the receiver, store in new variable recv.event( "/plork/synch/crystalis, f" ) @=> OscEvent oe; // count 0 => int count; float gain; // infinite event loop while ( true ) { // wait for event to arrive oe => now; // count if( count < 5 ) count++; if( count < 4 ) <<< ".", "" >>>; else if( count == 4 ) <<< "network ready...", "" >>>; // grab the next message from the queue. while( oe.nextMsg() != 0 ) { // get gain oe.getFloat() => gain; // pluck if( mode == 2 ) for( int i; i < channels; i++ ) gain => band[i].pluck; } } }