// @title playPulses.ck // @desc play genomic sequences as pulse trains // @author Brent Townshend (b@tc.com) //=== TODO: modify this path and name for your system ===// "/Users/bst/Dropbox/Music220a/HW1/" => string dataDir; // Configuration settings // string dataFile; // dataFile: File containing folds // By convention, folds-NN.dat has NN lines for each sequence in the NGS data; each of these is a stochastic folding of the same structure // That way, if you use folds-10.dat and have 10 voices, then all the voices are playing alternative foldings of the same sequence string saveFile; // Filename for saving recording 20.0 => float update; // update rate in ms 1 => int nvoices; // number of voices 1 => int useSine; // 1 to use sine oscillator 0.0 => float skew; [ 0,1, 2,3, 4, 5,6, 7,8, 9, 10, 11 ] @=> int scale[]; // Intervals to use 6=>int example; // Example number to configure <<<"Running example ",example>>>; if (example==1) { "ex1.wav" => saveFile; "folds-1.dat" => dataFile; 500.0 => update; } else if (example==2) { "ex2.wav" => saveFile; "folds-1.dat" => dataFile; } else if (example==3) { "ex3.wav" => saveFile; "folds-1.dat" => dataFile; 2=>update; } else if (example==4) { "ex4.wav" => saveFile; "folds-1.dat" => dataFile; 2=>update; 10=>nvoices; } else if (example==5) { "ex5.wav" => saveFile; "folds-10.dat" => dataFile; 2=>update; 10=>nvoices; 1=>skew; } else if (example==6) { "ex6.wav" => saveFile; "folds-10.dat" => dataFile; 100 => update; 10=>nvoices; 0=>useSine; 1.1456=>skew; [ 0, 2, 4, 5, 7, 9, 11 ] @=> int scale[]; } // Number of notes played per line of input to keep a regular rhythm to start each new sequence // Make it larger to leave a silent gap between sequences 60=>int blocksize; // Base note (MIDI) 48=>int basenote; // new class to manage envelopes class Env { Step s => Envelope e => blackhole; // feed constant into env update::ms => e.duration; // set ramp time fun void target (float val) { e.target(val); } fun void value(float val) {e.value(val); } } class Player { SinOsc sine; Wurley inst; NRev rev; if (useSine) sine => rev => dac; else inst => rev => dac; rev.mix(0.05); Env amp, freq; fun void noteOn(float vel) { inst.noteOn(vel); } fun void noteOff(float vel) { inst.noteOff(vel); } fun void run() { // sample loop to smoothly update gain, freq <<<"Starting player ",me.id()>>>; amp.value(0.0); freq.value(Std.mtof(basenote)); while (true) { 1::samp => now; // Update before setting so that envelopes have a value before using them the first time sine.gain(amp.e.last()/10.0); inst.gain(amp.e.last()/10.0); sine.freq(freq.e.last()); inst.freq(freq.e.last()); } } spork ~ run() @=> Shred @ child; } FoldReader sr; if (!sr.open(dataDir+dataFile)) me.exit(); 0=>int nchildren; fun void run() { 1+=>nchildren; Player p; while (true) { sr.next() => string line; 0 => int note; 1.0 => float amp; if (line.length()==0) break; // for (0=>int i;iint i;iw; if (w ==')' ) { note-1 => note; // Decrease pitch on way back out of a helix 1.0 => amp; } else if (w=='(' ) { note+1 => note; // Increase pitch as we go up a helix 1.0 =>amp; } else 1.4/=>amp; // Fade out during unpaired bases (scale[note%scale.cap()]+Math.floor(note/scale.cap())*12) $ int + basenote => int mnote; // <<>>; p.freq.target(Std.mtof(mnote)); p.amp.target(amp); } else { p.amp.target(0.0); } p.noteOn(1.0); update::ms*0.95 => now; p.noteOff(1.0); update::ms*0.05 => now; } } 1-=>nchildren; <<<"Player ",p.child.id()," done, ",nchildren," left.">>>; p.amp.target(0.0); // Avoid click at end update::ms=>now; p.child.exit(); me.exit(); } for (0=>int j;j now; // Skew them spork ~ run(); } // Recording to a file: // pull samples from the dac dac => WvOut w => blackhole; // this is the output file name saveFile => w.wavFilename; <<<"writing to file:", "'" + w.filename() + "'">>>; // temporary workaround to automatically close file on remove-shred null @=> w; // infinite time loop... do { // Wait until all the children are done 1::second=>now; } while ( nchildren>0 );