// @title hw3-sitar.ck // @author Regina Collecchia (colleccr@ccrma) // @desc Homework 3, Music220a-2012 // @version chuck-1.3.1.3 / ma-0.2.2c // @milestone 1 // pick a physical model synth, send to left chan (0) Sitar physmod => PRCRev rev => dac.left; 0.2 => rev.mix; // 2.0 => mod.vibratoRate; // 0.5 => mod.randomGain; // 0.1 => pit.mix; // SinOsc lfo => blackhole; // 1.5 => lfo.freq; // 5 => lfo.gain; // while(samp => now) { // lfo.last() + 5 => pit.shift; // } // bring in a mono .wav file from which to play sample // pass through Envelope to avoid clicks from SndBuf // to right chan (1) SndBuf sampler => Envelope samplerEnv => dac.right; me.sourceDir() + "/morphina_gobi.wav" => string _file; _file => sampler.read; cherr <= "[score] SndBuf: " <= _file <= IO.newline(); 10::ms => samplerEnv.duration; // write signals to files dac.left => WvOut physmodOut => blackhole; dac.right => WvOut samplerOut => blackhole; me.sourceDir() + "/phys.wav" => string _captureP; me.sourceDir() + "/samp.wav" => string _captureS; _captureP => physmodOut.wavFilename; _captureS => samplerOut.wavFilename; // ------------------------------------------------------------ // three algorithms which generate numbers in range -1.0 to 1.0 // see 1) logisticMapNotes.ck 2) logisticMapNotesOSC.ck for // more info fun float logistic(float x, float r) { return r * x * (1.0 - x); } // see 1) psuedoRandomNotes.ck 2) psuedoRandomNotesOSC.ck for // more info fun float random(float r) { if (r > 1.0) { 1.0 => r; } // get a random value return Math.random2f(-r, r); } // see 1) sinNotes.ck 2) sinNotesOSC.ck fun float sinusoid(float r) { // rate in radians at 1 sec period 2 * pi => float sinScale; // convert to desired rate in radians if (r > 0.0) r /=> sinScale; // current time in seconds now / second => float nowInSeconds; // convert to phase angle using rate in radians nowInSeconds * sinScale => float currentPhase; // or could be another trig function return Math.sin(currentPhase); } // ------------------------------------------------------------ // tick the chosen algorithm to get a new value fun float algorithm(float state, string type, float r) { if (type == "logistic") { // choose me to iterate the map and hear logistic map "tune" return logistic(state, r); } else if (type == "random") { // choose me for random "tune" return random(r); } else if (type == "sinusoid") { // choose me for sin function "tune" return sinusoid(r); } else if (type == "constant") { return r; } else { cherr <= "[score] Unknown algorithm type.\n"; } } int phrygian[8]; [60, 61, 64, 65, 67, 68, 70, 72] @=> phrygian; fun int notes(float i) { int j; Math.round( i*7 ) $ int => j; if ( j<0 ) { return -phrygian[-j]; } else { return phrygian[j]; } } // sporkable function that plays physical model notes forever // three algorithms to control frequency and rhythm fun void pLoop(string freqtype, float freqr, string rhytype, float rhyr) { 0.1 => float freqstate; 0.1 => float rhystate; while (true) { // note off in case it's already on physmod.noteOff; // a short rest 50::ms => now; algorithm(freqstate, freqtype, freqr) => freqstate; algorithm(rhystate, rhytype, rhyr) => rhystate; // physmod.pluck(0.7); // use freqstate as a frequency if (freqstate < 0) { -freqstate => freqstate; } Std.mtof(notes(freqstate))+220*freqstate => float f; // to sitar physmod.freq(f); // note on // physmod.noteOn(rhystate*0.9); physmod.noteOn(rhystate*0.5); (rhystate*100+100)::ms => now; } } // sporkable function that plays sampler notes forever fun void sLoop(string type, float r) { 0.1 => float state; float durat; float rates[30]; [-4.0, 1.0, 1.0, 1.0, 1.0, 0.8, 1.2, 0.6, 0.5, 1.0, 1.2, -3.0, 1.0, 1.0, 1.1, -0.3, 1.0, 1.0, 0.9, -0.5, 0.7, -0.3, -0.9, -1.0, 1.0, 2.5, 1.1, 0.3, 1.0] @=> rates; int i; 0 => i; while (true) { // turn off envelope in case it's already on samplerEnv.target(0.0); // a short rest 50::ms => now; algorithm(state, type, r) => state; sampler.length() => dur totalFile; // time in file to start playing sample from ((state + 1.0) * 0.5) * totalFile => dur start; Math.pow(2.7818,rates[i])*700 => durat; // playback rate of sample sampler.rate(rates[i]); // sample duration durat::ms => dur duration; // end time of sample start + duration => dur end; if (end > totalFile) { end - duration => start; } // start position in file in actual samples sampler.pos((start / samp) $ int); // ramp up the envelope samplerEnv.target(1.0); duration => now; if ( i < 28) { i++; } else { 1 => i; } } } // ------------------------------------------------------------ // prepare the show Shred pShred; Shred sShred; // needed to stop both shreds gracefully fun void killShreds() { pShred.exit(); sShred.exit(); me.yield(); // note off physmod.noteOff; // turn off envelope samplerEnv.target(0.0); 10::ms => now; } // ------------------------------------------------------------ // start the show spork ~pLoop("logistic", 1, "sinusoid", 3.1) @=> pShred; 12::second => now; killShreds(); // 3 seconds of silence 3::second => now; spork ~pLoop("random", 0.3, "sinusoid", 1) @=> pShred; spork ~sLoop("sinusoid", 1) @=> sShred; 20::second => now; killShreds(); spork ~pLoop("logistic", 1, "random", 1) @=> pShred; 2::second => now; killShreds(); spork ~pLoop("logistic", 2, "random", 0.4) @=> pShred; spork ~sLoop("logistic", 5) @=> sShred; 10::second => now; killShreds(); spork ~sLoop("logistic", 3) @=> sShred; 5::second => now; killShreds(); spork ~pLoop("random", 0.7, "sinusoid", 1) @=> pShred; spork ~sLoop("logistic", 1) @=> sShred; 20::second => now; killShreds(); spork ~sLoop("sinusoid", 2) @=> sShred; 8::second => now; killShreds(); 3::second => now; //spork ~pLoop("sinusoid", 5.0) @=> pShred; //spork ~sLoop("sinusoid", 5.0) @=> sShred; //5::second => now; // killShreds(); // ------------------------------------------------------------ // finish the show physmodOut.closeFile(); samplerOut.closeFile(); // print message in terminal for sox command cherr <= "[score] Finished. Merge two products with the command below.\n"; cherr <= "sox -M " <= _captureP <= " " <= _captureS <= " "; cherr <= me.sourceDir() + "/Milestone.wav";