// ToneMaze // By Hunter McCurry // 220a Final Project // Fall 2010 /////////// // Global Vars and Things 4 => int difficulty; // Set Difficulty (must be 2, 3 or 4) (Math.pow(2,difficulty) - 1) $ int => int numberOfNodes; Math.rand2( (Math.pow(2,difficulty)/2 - 1) $ int , (Math.pow(2,difficulty) - 2) $ int ) => int endLocation; <<< "endLocation", endLocation >>>; Node myStates[numberOfNodes]; 24 => int fluctuationMax; // for drone tone control 20 => int minMidiNote; // distance between min and max should be greater than 20 100 => int maxMidiNote; 100.0 => float transitionTime; .6 => float defaultVolume; // STK Instruments ModalBar bar => dac; Wurley wurl => dac; Clarinet clair => JCRev r => dac; /////////// // Vars that change a lot [0, 0] @=> int nowPlaying[]; [0, 0] @=> int wasPlaying[]; 60 => int currentNote; 0 => int currentNode; 0 => int currentLevel; 0 => int itsOver; nowPlaying[0] => wasPlaying[0]; nowPlaying[1] => wasPlaying[1]; 2 * currentNode + 1 => nowPlaying[0]; 2 * currentNode + 2 => nowPlaying[1]; ////////// spork ~ listenForKeyboard(); // define class X class Node { int myNote; // patch VoicForm voc=> JCRev r => dac; // voc.freq; 0.0 => voc.gain; .5 => r.gain; .2 => r.mix; 0.5 => voc.loudness; 0.01 => voc.vibratoGain; 1 => int bphonMax; 1 => int bphon; 1 => int up; 60 => int midiPitch; public void setPitch( int noteNum ) { noteNum => midiPitch; Std.mtof( noteNum ) => voc.freq; } } // initialize nodes for( 0 => int i; i < numberOfNodes ; i++ ) { if (i == 0) { .5 => myStates[i].voc.gain; myStates[i].setPitch( 60 ); } else { 0.0 => myStates[i].voc.gain; myStates[ ((i - .001 )/2) $ int ].midiPitch => int parentNote; if ( (i % 2) == 1 ) // lower child { Math.rand2(4,10); // needed for some reason - to randomize seed? (parentNote - minMidiNote)/2 + minMidiNote => int lowParam; parentNote - 1 => int highParam; Math.rand2( lowParam, highParam ) => int lowerHalfNum; myStates[i].setPitch( lowerHalfNum ); <<< i, (parentNote - minMidiNote) / 2 + minMidiNote >>>; <<< "New Low note:", lowerHalfNum, "Position:" , i >>>; } else // higher child { parentNote + 1 => int lowParam; maxMidiNote - (maxMidiNote - parentNote)/2 => int highParam; Math.rand2( lowParam, highParam ) => int upperHalfNum; myStates[i].setPitch( upperHalfNum ); <<< "New High note", upperHalfNum, "Position:", i >>>; } } ( fluctuationMax - 22 * ((i $ float) / numberOfNodes) ) $ int=> myStates[i].bphonMax; } // our main time loop while( !itsOver ) { for( 0 => int i; i < numberOfNodes ; i++ ) { 0.5 => myStates[i].voc.noteOn; myStates[i].bphon => myStates[i].voc.phonemeNum; if (myStates[i].up) { myStates[i].bphon + 1 => myStates[i].bphon; } else { myStates[i].bphon - 1 => myStates[i].bphon; } if ( myStates[i].bphon > myStates[i].bphonMax ) { 0 => myStates[i].up; } else if ( myStates[i].bphon < 1 ) { 1 => myStates[i].up; } } 100::ms => now; //<<< currentLevel >>> ; } fun void transition( ) { for( 0 => int i; i < transitionTime ; i++ ) { // fade out old for ( 0 => int j ; j < 2 ; j++ ) { defaultVolume - defaultVolume * (i / transitionTime) => myStates[wasPlaying[j]].voc.gain; //<<< myStates[wasPlaying[j]].voc.gain >>>; } // fade in new for ( 0 => int j ; j < 2 ; j++ ) { defaultVolume * (i / transitionTime) => myStates[nowPlaying[j]].voc.gain; } 10::ms => now; } // kill any residue 0.0 => myStates[wasPlaying[0]].voc.gain; 0.0 => myStates[wasPlaying[1]].voc.gain; } fun void fadeOut( ) { for( 0 => int i; i < transitionTime ; i++ ) { // fade out old for ( 0 => int j ; j < 2 ; j++ ) { defaultVolume - defaultVolume * (i / transitionTime) => myStates[wasPlaying[j]].voc.gain; } } 0.0 => myStates[wasPlaying[0]].voc.gain; 0.0 => myStates[wasPlaying[1]].voc.gain; } fun void listenForKeyboard() { Hid hi; HidMsg msg; // which keyboard 0 => int device; // get from command line if( me.args() ) me.arg(0) => Std.atoi => device; // open keyboard (get device number from command line) if( !hi.openKeyboard( device ) ) me.exit(); <<< "keyboard '" + hi.name() + "' ready", "" >>>; while( !itsOver ) { // wait on event hi => now; // get one or more messages while( hi.recv( msg ) ) { // whether to make a sound 0 => int playnote; // check for action type if( msg.isButtonDown() ) { if ( msg.key == 44 ) // spacebar { 1 => playnote; } else if (msg.key == 80 && currentNote > 3) // left arrow { currentNote - 1 => currentNote; 1 => playnote; } else if (msg.key == 79 && currentNote < 126) // right arrow { currentNote + 1 => currentNote; 1 => playnote; } else if (msg.key == 82) // up arrow { 1 => playnote; if ( (currentNote == myStates[2 * currentNode + 1].midiPitch) || (currentNote == myStates[2 * currentNode + 2].midiPitch) ) { 0 => int higher; if ( currentNote == myStates[2 * currentNode + 2].midiPitch ) { 1 => higher; } if ((currentLevel + 2) < difficulty ) { currentLevel++; nowPlaying[0] => wasPlaying[0]; nowPlaying[1] => wasPlaying[1]; spork ~ transition(); if ( higher ) { 2 * currentNode + 2 => currentNode; } else { 2 * currentNode + 1 => currentNode; } myStates[currentNode].midiPitch => currentNote; 2 * currentNode + 1 => nowPlaying[0]; 2 * currentNode + 2 => nowPlaying[1]; } else { if (2 * currentNode + 1 + higher == endLocation) { nowPlaying[0] => wasPlaying[0]; nowPlaying[1] => wasPlaying[1]; spork ~ theEnd(currentNote); // // the end! } else { spork ~ deadEnd(); // dead end! } } } else if ( currentLevel == 0 ) { if (currentNote == myStates[currentNode].midiPitch) { spork ~ transition(); } } } else if (msg.key == 81 ) // down arrow { 1 => playnote; if ( currentLevel > 0 ) { currentLevel--; nowPlaying[0] => wasPlaying[0]; nowPlaying[1] => wasPlaying[1]; ((currentNode - .001) / 2) $ int => currentNode; myStates[currentNode].midiPitch => currentNote; 2 * currentNode + 1 => nowPlaying[0]; 2 * currentNode + 2 => nowPlaying[1]; spork ~ transition(); } } <<< msg.key, currentNote >>>; if (playnote) { spork ~ playPosition(); } } } } } fun void playPosition() { // ding! //1 => bar.preset; //.9 => bar.stickHardness; //Std.rand2f( 0, 1 ) => bar.strikePosition; // set freq //currentNote => Std.mtof => bar.freq; currentNote => Std.mtof => wurl.freq; // go //.9 => bar.noteOn; .5 => wurl.noteOn; // advance time .5::second => now; } fun void deadEnd() { // patch Moog moog => dac; // ding! Std.rand2f( 0, .1 ) => moog.filterQ; Std.rand2f( 0, 1 ) => moog.filterSweepRate; Std.rand2f( 0, 1 ) => moog.lfoSpeed; Std.rand2f( 0, 1 ) => moog.lfoDepth; Std.rand2f( 0, 1 ) => moog.volume; // print <<< "---", "" >>>; <<< "filterQ", moog.filterQ() >>>; <<< "filter sweep rate:", moog.filterSweepRate() >>>; <<< "lfo speed:", moog.lfoSpeed() >>>; <<< "lfo depth:", moog.lfoDepth() >>>; <<< "volume:", moog.volume() >>>; // set freq Std.rand2(1,40) => int winner; 10 + Std.rand2(0,2)*12 + winner => Std.mtof => moog.freq; // go .8 => moog.noteOn; // advance time 1::second => now; } fun void theEnd( int note ) { // patch .75 => r.gain; .1 => r.mix; spork ~ fadeOut(); (note % 12) + 48 => int normalizedPitch; spork ~ playClair( normalizedPitch, .6); 200::ms => now; spork ~ playClair( normalizedPitch - 12, .6); 200::ms => now; spork ~ playClair( normalizedPitch, .7); 200::ms => now; spork ~ playClair( normalizedPitch - 12, .6); 200::ms => now; spork ~ playClair( normalizedPitch + 12, .6); 1000::ms => now; clair.noteOff(0); 5000::ms => now; 1 => itsOver; } fun void playClair( float note, float velocity ) { // clear clair.clear( 1.0 ); // set 0.8 => clair.reed; 4 => clair.vibratoFreq; Std.rand2f( .1, .3 ) => clair.noiseGain; Std.rand2f( .1, .3 ) => clair.vibratoGain; Std.mtof( note ) => clair.freq; velocity => clair.noteOn; 1200::ms => now; }