// This code is based off of "twilight-redux-kb.ck" by Ge Wang. //-------------------------------------------------------------------- //Write to file dac => WvOut2 writer => blackhole; writer.wavFilename("/Users/catrian/Desktop/hw3.wav"); // default filename (can be overwritten via input argument) "beeps.wav" => string FILENAME; // get file name, if one specified as input x0argument if( me.args() > 0 ) me.arg(0) => FILENAME; // overall volume 1 => float MAIN_VOLUME; // grain duration base 50::ms => dur GRAIN_LENGTH; // factor relating grain duration to ramp up/down time .5 => float GRAIN_RAMP_FACTOR; // playback rate 1 => float GRAIN_PLAY_RATE; // grain position (0 start; 1 end) 0.05 => float GRAIN_POSITION; // grain position randomization .001 => float GRAIN_POSITION_RANDOM; // grain jitter (0 == periodic fire rate) 1 => float GRAIN_FIRE_RANDOM; // max lisa voices 30 => int LISA_MAX_VOICES; // load file into a LiSa (use one LiSa per sound) load( FILENAME ) @=> LiSa @ lisa; // patch it PoleZero blocker => NRev reverb => dac; // connect lisa.chan(0) => blocker; // reverb mix .05 => reverb.mix; // pole location to block DC and ultra low frequencies .99 => blocker.blockZero; Event expo; fun void exposition (Event e) { e => now; while(true) { for (1 => int i; i < 4; i++) { (.005 * i) +=> GRAIN_POSITION; 100::ms => now; (.005 * i) -=> GRAIN_POSITION; 500::ms => now; } 500::ms => now; } } Event r; fun void rise (Event e) { e => now; 0 => int i; <<>>; 0.01 => GRAIN_POSITION; while(true) { while (i < 25) { .005 +=> GRAIN_PLAY_RATE; 100::ms => now; i++; <<>>; } while (i > 0) { .005 -=> GRAIN_PLAY_RATE; 100::ms => now; i--; <<>>; } } } Event c; fun void climax (Event e) { 0 => int i; e => now; while (i < 50) { 1.05 *=> GRAIN_LENGTH; 100::ms => now; i++; } } Event e; fun void end (Event e) { e=>now; 0::ms => dur end; while (GRAIN_PLAY_RATE > .825) { .005 -=> GRAIN_PLAY_RATE; 100::ms => now; } while (GRAIN_POSITION > 0) { .005 -=> GRAIN_POSITION; 100::ms => now; } while (GRAIN_LENGTH > end) { 1.05 /=> GRAIN_LENGTH; 100::ms => now; } } // spork it spork ~ print(); spork ~ exposition(expo); spork ~ climax(c); //spork ~ end(e); // main loop while( true ) { // fire a grain fireGrain(); // amount here naturally controls amount of overlap between grains GRAIN_LENGTH / 8 + Math.random2f(0,GRAIN_FIRE_RANDOM)::ms => now; expo.signal(); r.signal(); c.signal(); e.signal(); } // fire! fun void fireGrain() { // grain length GRAIN_LENGTH => dur grainLen; // ramp time GRAIN_LENGTH * GRAIN_RAMP_FACTOR => dur rampTime; // play pos GRAIN_POSITION + Math.random2f(0,GRAIN_POSITION_RANDOM) => float pos; // a grain if( lisa != null && pos >= 0 ) spork ~ grain( lisa, pos * lisa.duration(), grainLen, rampTime, rampTime, GRAIN_PLAY_RATE ); } // grain sporkee fun void grain( LiSa @ lisa, dur pos, dur grainLen, dur rampUp, dur rampDown, float rate ) { // get a voice to use lisa.getVoice() => int voice; // if available if( voice > -1 ) { // set rate lisa.rate( voice, rate ); // set playhead lisa.playPos( voice, pos ); // ramp up lisa.rampUp( voice, rampUp ); // wait (grainLen - rampUp) => now; // ramp down lisa.rampDown( voice, rampDown ); // wait rampDown => now; } } // print fun void print() { // time loop while( true ) { // values <<< "pos:", GRAIN_POSITION, "random:", GRAIN_POSITION_RANDOM, "rate:", GRAIN_PLAY_RATE, "size:", GRAIN_LENGTH/second >>>; // advance time 100::ms => now; } } // load file into a LiSa fun LiSa load( string filename ) { // sound buffer SndBuf buffy; // load it "/Users/catrian/Desktop/" => string dataDir; dataDir + filename => buffy.read; // new LiSa LiSa lisa; // set duration buffy.samples()::samp => lisa.duration; // transfer values from SndBuf to LiSa for( 0 => int i; i < buffy.samples(); i++ ) { // args are sample value and sample index // (dur must be integral in samples) lisa.valueAt( buffy.valueAt(i), i::samp ); } // set LiSa parameters lisa.play( false ); lisa.loop( false ); lisa.maxVoices( LISA_MAX_VOICES ); return lisa; }