// // // Hunter McCurry // CCRMA 2011 // array of instruments 32 => int polyphony; // set up array Shakers insts[polyphony]; // step through and instantiate for ( 0 => int i; i insts[i] => JCRev r; r => dac.chan(0); r => dac.chan(1); .03 => r.mix; } // counter var 0 => int instCtr; // Mutable Global Params 10 => int g_growRate; .02 => float g_growProbability; 10 => int g_splitToSize; // split *to size*, so that cell will split when it is twice this number 0.7 => float g_repeatProbability; 200 => int g_ageLim; .4 => float g_duration; .6 => float g_mutation; //.95 => float g_likelihoodOfInstChange; // define class SoundNode class SoundNode { // data Std.rand2( 0, 22 ) => int randVal; //<<< randVal >>>; while( randVal == 3 || randVal == 4 || randVal == 5 || randVal == 9 || randVal == 10 || randVal == 22 ) { Std.rand2( 0, 22 ) => randVal; } //<<< "randVal: ----------", randVal >>>; randVal => int which; // 3 sucks, 4 not great, 5 eh..., 9 hmmm..., 22 nope, 23 nah Std.mtof( Std.rand2f( 0.0, 128.0 ) ) =>float freq; /*Std.rand2f( 0, 128 )*/ 1 => float objects; // 0 to 128 1.0 => float velocity; // scaled to 1.0 g_duration => float duration; // in seconds g_repeatProbability => float repeatProbability; g_growProbability => float growProbability; g_splitToSize => int splitToSize; //g_likelihoodOfInstChange => float likelihoodOfInstChange; // pointer to next SoundNode @ next; // functions fun SoundNode getNext() { return next; } fun void setNext( SoundNode newNext ) { newNext @=> next; } // get duration fun float getDuration() { return duration; } } fun void incrementInstCounter() { instCtr++; if ( instCtr == polyphony ) { 0 => instCtr; } } fun void LifeManager( SoundNode head, int numberOfNodes, int age, int ageLim, int spawnNum ) { SoundNode currentNode; head @=> currentNode; for ( age; age < ageLim; age++ ) { // "age" velocity values (older is quieter) currentNode.velocity * (.8 + (.2 * (1 - ((age + 0.0)/ageLim)))) => currentNode.velocity; //<<< currentNode.velocity >>>; // mutate duration parameter (currentNode.duration * g_mutation) => float maxChange; Std.rand2f(0.0, maxChange) - (maxChange/2) => float mutationDurationChange; currentNode.duration + mutationDurationChange => currentNode.duration; // decrease likelyhood of offspring with age 1 / (spawnNum + 1) => float spawnChance; spawnChance * (1-((age+0.0)/ageLim)) => float offspringChance; // "visit" and play node/note //<<< "originator: ", head, "current node: ", currentNode, "spawnNum: ", spawnNum, " age: ", age, " size: ", numberOfNodes >>>; //<<< "splitToSize: ", currentNode.splitToSize >>>; spork ~ VisitNode( currentNode ); //<<>>; currentNode.getDuration()::second => now; // grow one node bigger if ( Std.rand2f( 0.0, 1.0 ) < currentNode.growProbability ) { SoundNode insertion; insertion.setNext( currentNode.getNext() ); currentNode.setNext( insertion ); Std.rand2( 0, 22 ) => int randVal; while( randVal == 3 || randVal == 4 || randVal == 5 || randVal == 9 || randVal == 10 || randVal == 22 ) { Std.rand2( 0, 22 ) => randVal; } randVal => insertion.which; numberOfNodes++; } currentNode.getNext() @=> currentNode; // split in two! if ( (numberOfNodes == (2*currentNode.splitToSize)) && (Std.rand2f( 0.0, 1.0 ) < offspringChance) ) { //<<< "splitting!" >>>; AdvanceNTimes( currentNode, currentNode.splitToSize ) @=> SoundNode oppositeNode; currentNode.getNext() @=> SoundNode tmpNode; currentNode.setNext( oppositeNode.getNext() ); oppositeNode.setNext( tmpNode.getNext() ); // spawn "offspring" spork ~ LifeManager( oppositeNode, currentNode.splitToSize, age+(ageLim*.05) $ int, ageLim, spawnNum+1 ); // reset numberOfNodes //<<< "currentNode: ", currentNode, "oppositeNode: ", oppositeNode >>>; currentNode.splitToSize => numberOfNodes; //<<< "numberOfNodes: ", numberOfNodes >>>; //(currentNode.getDuration()/2)::second => now; } } 5::second => now; } fun SoundNode AdvanceNTimes( SoundNode curNode, int n ) { SoundNode nextNode; for ( n; n > 0; n-- ) { curNode.getNext() @=> nextNode; nextNode @=> curNode; } return curNode; } fun void VisitNode( SoundNode curNode ) { playNote( curNode.which, curNode.freq, curNode.objects, curNode.velocity ); incrementInstCounter(); } fun void playNote( int which, float freq, float objects, float velocity ) { //<<< "instCtr: ", instCtr >>>; which => insts[instCtr].which; freq => insts[instCtr].freq; objects => insts[instCtr].objects; velocity => insts[instCtr].noteOn; } // main starts here spork ~ listenForKeyboard(); // main loop while ( true ) { 10::second => now; } // only keyboard junk from here on out ////////////////////////////////////// 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( true ) { // wait on event hi => now; // get one or more messages while( hi.recv( msg ) ) { // check for action type if( msg.isButtonDown() ) { <<< msg.key >>>; if ( msg.key == 44 ) // spacebar { <<< "space!" >>>; SoundNode head; head.setNext( head ); <<< ((1 - g_duration) * 170 + 10) >>>; spork ~ LifeManager( head, 1, 0, ((1 - g_duration) * 170 + 10) $ int, 0 ); } // 1, q, a, z set duration else if (msg.key == 30 ) // 1 { 1.0 => g_duration; <<< "new duration is: ", g_duration >>>; } else if (msg.key == 20 ) // q { if (g_duration < .99) { g_duration + .02 => g_duration; } <<< "new duration is: ", g_duration >>>; } else if (msg.key == 4 ) // a { if (g_duration > .03) { g_duration - .02 => g_duration; } <<< "new duration is: ", g_duration >>>; } else if (msg.key == 29 ) // z { .02 => g_duration; <<< "new duration is: ", g_duration >>>; } // 2, w, s, x set mutation else if (msg.key == 31 ) // 2 { .6 => g_mutation; <<< "new mutation is: ", g_mutation >>>; } else if (msg.key == 26 ) // w { if (g_mutation < .97) { g_mutation + .02 => g_mutation; } <<< "new mutation is: ", g_mutation >>>; } else if (msg.key == 22 ) // s { if (g_mutation > .03) { g_mutation - .02 => g_mutation; } <<< "new mutation is: ", g_mutation >>>; } else if (msg.key == 27 ) // x { .02 => g_mutation; <<< "new mutation is: ", g_mutation >>>; } // 3, e, d, c set grow Probability else if (msg.key == 32 ) // 3 { .7 => g_growProbability; <<< "new growProbability is: ", g_growProbability >>>; } else if (msg.key == 8 ) // e { if (g_growProbability < .97) { g_growProbability + .02 => g_growProbability; } <<< "new growProbability is: ", g_growProbability >>>; } else if (msg.key == 7 ) // d { if (g_growProbability > .03) { g_growProbability - .02 => g_growProbability; } <<< "new growProbability is: ", g_growProbability >>>; } else if (msg.key == 6 ) // c { .02 => g_growProbability; <<< "new growProbability is: ", g_growProbability >>>; } // 4, r, f, v set Split to Size (only takes effect on new creatures) else if (msg.key == 33 ) // 4 { 20 => g_splitToSize; <<< "new splitToSize is: ", g_splitToSize >>>; } else if (msg.key == 21 ) // r { g_splitToSize++; <<< "new splitToSize is: ", g_splitToSize >>>; } else if (msg.key == 9 ) // f { if (g_splitToSize > 5) { g_splitToSize--; } <<< "new splitToSize is: ", g_splitToSize >>>; } else if (msg.key == 25 ) // v { 5 => g_splitToSize; <<< "new splitToSize is: ", g_splitToSize >>>; } // doesn't do anything actually else if (msg.key == 80 ) // left arrow { <<< "left!" >>>; } else if (msg.key == 79 ) // right arrow { <<< "right!" >>>; } else if (msg.key == 82) // up arrow { <<< "up!" >>>; } else if (msg.key == 81 ) // down arrow { <<< "down!" >>>; } } } } }