// // Final 220a Project // Jeff Smith // // Dedicated to the memory of The Skipper, Gilligan, and Mary Anne // // This shred is a proof of concept(s). // // Do everything in Chuck. No preprocessing. No post processing. As a result, everything is // very extensible. // // Multi-channel output in Chuck. I've created a few classes that permit chuck shreds to do // real-time multi-channel panning. The FourChannelPan class supports all types of panning // functions, allowing chuck to place a sound source anywhere w/i a plane (room). The function // is extensible to N channels and N dimensions in theory. The program will output N channel // wave files representing the different channels. // // Metrical precision. I've built a series of drones that 'drone' to a precise meter. In this case, // the meter is defined below as 'bar' and is equivalent to 2.5 seconds, although this variable could // be modified to virtually any value and the program will conform to that new bar and associated // metrical variations of that bar. The result is some fairly sophisticated isorhythms. // // MultiDrone. I've built a complex drone that sits on top of a sound buffer and conforms to the // metrical definitions above. For example, an instances of a lawnmower drone will spork of three // shreds, each playing a slice of the sound buffer. Yet, each of the three sporked drones will // use a different slice (for example bar/15, bar/14, bar/13), the result being that they only come // together and synchronize their 'droning' at the bar, thereby defining a meter. // // Warp. I combine the MultiDrone functions with the MultiChannel panning functions to allow for // linear iterative transformations of the sound placement and the drone. Sporking is used to // allow for panning events to correspond to sound warping. For example, the 'mixer' drone will // circle the room will droning. The xbox360 drone will oscillate between a gain and z-radius on // its two-pole filter from 0.1 - 0.3 over a period, P. // // I also update a couple of the Chuck instruments, specifically TubeBell and StifKarp, to allow // for this same iterative 'warping' function. In the case of the TubeBell, I 'warp' the depth of // the bell to emphasize a different set of overtones. And in the case of the StifKarp, the instru- // ment will 'pluck' a linear series of pitches between two given pitches. // // The score for this composition exists at the bottom of the program. // true => int write_to_file; false => int debug_wav; // constants // A3 220 => float A3; A3 => float fundamental; // fundamental pitch must be >= 22 56 => int fund; 12 => int scale; // scale 0 => int P1; 1 => int m2; 2 => int M2; 3 => int m3; 4 => int M3; 5 => int P4; 6 => int a4; 7 => int P5; 8 => int m6; 9 => int M6; 10 => int m7; 11 => int M7; 12 => int P8; // in ms 2500 => int bar; bar / 2 => int half_note; bar / 4 => int quarter_note; bar / 8 => int eighth_note; // dynamics 0.1 => float ppp; 0.2 => float pp; 0.3 => float p; 0.45 => float mp; 0.55 => float mf; 0.7 => float f; 0.8 => float ff; 0.9 => float fff; // first 31 prime numbers [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113] @=> int primes[]; // multi-channel layout 4 => int num_channels; -1 => int channel_left; 1 => int channel_right; -1 => int channel_front; 1 => int channel_back; // // this class, later a global variable, streams audio to four wave files // representing our different channels class FourChannelWave { WvOut ch[4]; "a_fl.wav" => string ch1_name; "a_fr.wav" => string ch2_name; "a_bl.wav" => string ch3_name; "a_br.wav" => string ch4_name; public void init() { if (!write_to_file) return; ch1_name => ch[0].wavFilename; ch2_name => ch[1].wavFilename; ch3_name => ch[2].wavFilename; ch4_name => ch[3].wavFilename; } public void done() { if (!write_to_file) return; ch1_name => ch[0].closeFile; ch2_name => ch[1].closeFile; ch3_name => ch[2].closeFile; ch4_name => ch[3].closeFile; } public void connect(Gain g[]) { for (0 => int i; i < ch.cap(); i++) { if (write_to_file) { g[i] => ch[i]; if (debug_wav) { if (i % 2 == 0) { ch[i] => dac.left; } else { ch[i] => dac.right; } } else { ch[i] => blackhole; } } else { g[i] => dac.chan(i); } } } } FourChannelWave fcw; // // this class sets up an inheritance framework so sub-classes can write // multi-channel output. Importantly, as the constants above define, the // FourChannelPan operates across a plane defined above as left, front, right, back (-1, -1, 1, 1) // class FourChannelPan { Gain ch_gn[4]; 0 => int fl; 1 => int fr; 2 => int br; 3 => int bl; for (0 => int i; i < ch_gn.cap(); i++) { ch_gn[i].gain(.0); } public void c_connect(float gn, UGen in) { for (0 => int i; i < ch_gn.cap(); i++) { ch_gn[i].gain(gn); in => ch_gn[i]; } fcw.connect(ch_gn); } public void c_connect(UGen in) { c_connect(1.0, in); } public void C_Set(float left_front, float right_front, float left_back, float right_back) { ch_gn[fl].gain(left_front); ch_gn[fr].gain(right_front); ch_gn[bl].gain(left_back); ch_gn[br].gain(right_back); } public void C_SetLR(float left, float right) { ch_gn[fl].gain(left); ch_gn[fr].gain(right); ch_gn[bl].gain(left); ch_gn[br].gain(right); } public void C_SetFB(float front, float back) { ch_gn[fl].gain(front); ch_gn[fr].gain(front); ch_gn[bl].gain(back); ch_gn[br].gain(back); } private float distance(float dx, float dy) { return Math.sqrt((dx * dx) + (dy * dy)); } public void C_PanXY(float dx /* -1 = left, 1 = right */ , float dy /* -1 = front, 1 = back */) { if (dx > 1.0 || dx < -1.0 || dy > 1.0 || dy < -1.0) { <<< "panxy error: ", dx, dy >>>; return; } // hyp (dist) will define the amplitude of the gains. At 2.0, a sound // in the corner yields all others zero, and a sound in the middle would // yield a gain of .28 for all 2.0 => float hyp; (hyp - distance(channel_left - dx, channel_front - dy)) / hyp => float flg; (hyp - distance(channel_right - dx, channel_front - dy)) / hyp => float frg; (hyp - distance(channel_left - dx, channel_back - dy)) / hyp => float blg; (hyp - distance(channel_right - dx, channel_back - dy)) / hyp => float brg; Math.min(1.0, Math.max(0, flg)) => ch_gn[fl].gain; Math.min(1.0, Math.max(0, frg)) => ch_gn[fr].gain; Math.min(1.0, Math.max(0, blg)) => ch_gn[bl].gain; Math.min(1.0, Math.max(0, brg)) => ch_gn[br].gain; // <<< ch_gn[fl].gain(), ch_gn[fr].gain(), ch_gn[bl].gain(), ch_gn[br].gain() >>>; } } // // Variation of the StiffKarp instrument. // // MyStifKarp will generate and place phrases. To play the phrases, it will 'slide' or 'trill'. // A slide will pluck a linear series of pitches between two given pitches. // The instrument's range and scale are defined relative to a fundamental pitch (defined above // in the constants). // class MyStifKarp extends FourChannelPan { StifKarp m; Gain g; .08 => g.gain; Std.mtof(fund) => float last_pitch; private void init_strike() { 0.1 => m.pickupPosition; 0.2 => m.sustain; 0.3 => m.stretch; } public void connect() { m => g; c_connect(g); init_strike(); } private void set_channel(float freq) { // move to new channel when our range changes Std.ftom(freq) $ int => int pitch; if (pitch < fund) { <<< "sk:set_channel: pitch error" >>>; return; } (((pitch - fund) / 12) % num_channels) $ int => int range; if (range > 3 || range < 0) { <<< "sk:set_channel: range error", range >>>; return; } [0.0, 0.0, 0.0, 0.0] @=> float fv[]; 1.0 => fv[range]; C_Set(fv[0], fv[1], fv[2], fv[3]); } public void play(float freq, float velocity, dur length) { freq => m.freq; velocity => m.pluck; length => now; } // do it baby. do a trill public void do_trill(float freq1, float dynamic, float the_time) { freq1 => float cur_freq; // randomly trill on whole or half step Math.ftom(freq1) + Std.rand2(1, 2) => float pitch; Math.mtof(pitch) => float freq2; Math.max(12.0, eighth_note / 12) => float time_chunk; Std.rand2f(time_chunk, the_time / 3) => time_chunk; time_chunk / 2.0 => float half_chunk; while (the_time > time_chunk) { play(freq1, dynamic, half_chunk::ms); play(freq2, dynamic, half_chunk::ms); the_time - time_chunk => the_time; } play(freq1, dynamic, the_time::ms); } // slide baby. do a slide. public void do_slide(float freq1, float freq2, float dynamic, float the_time) { freq1 - freq2 => float delta; freq1 => float cur_freq; the_time / Math.fabs(delta) => float time_chunk; // minimum time chunk of 7.0, max of the_time Math.max(time_chunk, Std.rand2f(7, 10)) => time_chunk; Math.min(Std.rand2f(time_chunk, time_chunk * 6), the_time) => time_chunk; delta / (the_time / time_chunk) => float freq_chunk; // add crescendo/decresendo based on ascent/descent Math.max(Math.min(.3, dynamic), .7) => dynamic; .3 / (the_time / time_chunk) => float dyn_chunk; if (delta < 0) dyn_chunk * -1.0 => dyn_chunk; while (the_time > time_chunk) { play(cur_freq, dynamic, time_chunk::ms); cur_freq - freq_chunk => cur_freq; the_time - time_chunk => the_time; dynamic - dyn_chunk => dynamic; } play(freq2, dynamic, the_time::ms); } public void do_it(float freq1, float dynamic, float the_time) { Std.ftom(freq1) => float pitch1; Std.ftom(last_pitch) => float pitch2; Math.fabs(pitch1 - pitch2) => float delta; set_channel(freq1); // trill or slide? if (delta < M3 || Std.rand2(0, 4) == 2) { do_trill(freq1, dynamic, the_time); } else { do_slide(last_pitch, freq1, dynamic, the_time); } freq1 => last_pitch; } // // convert a pitch (indexed from zero) to a frequency multiple of a // given scale. So, if scale is 12 and pitch is 7, then it returns // the frequency multiple of a perfect fifth. If scale is 10 and pitch // is 7, you get something above a M6th (in diatonic terms) private float scale_pitch_to_freq(float pitch, int scale) { pitch / scale => float f; return Math.pow(2, f); } [P1, m2, M2, a4, P5, m6] @=> int our_scale[]; private float gen_pitch( float tonic, int scale ) { our_scale[Std.rand2(0, our_scale.cap()-1)] => int pitch; scale_pitch_to_freq(pitch, scale) * tonic => float freq; return freq; } // // generate a new musical phrase, return frequencies in array phrase[] // function returns length of this new phrase private int gen_phrase( float tonic, int scale, float phrase[]) { // min phrase length of 5 Std.rand2(5, phrase.cap() - 1) => int length; for (1 => int i; i < length; i++) { // this maps pitches to a range 'scale' gen_pitch(tonic, scale) => phrase[i]; } tonic => phrase[0]; return length; } // play a dynamically generated phrase & return a proposed tonic for the // next phrase (as a function of this phrase) public void play_phrase(int length, float tonic, float new_tonic[]) { for (0 => int i; i < length - 1; i++) { gen_pitch(tonic, scale) => float pitch; do_it(pitch, Std.rand2f(ppp, p), Std.rand2(0, 4) * eighth_note); } do_it(gen_pitch(tonic, scale), Std.rand2f(ppp, mp), half_note); Std.rand2(4, 6) => int range; (fundamental / 2) * Math.pow(2, range) => new_tonic[0]; } public void play_phrase( float tonic, float new_tonic[]) { play_phrase(Std.rand2(5, 25), tonic, new_tonic); } } // // Variation of TubeBell class that 'modulates' speed and depth to emphasize different // overtones. As it modulates, the TubeBell will move a channel from the front to the // back of a room, and vice-versa. The modulation is a function of sin(T) where T is the // bar-length. // class MyTubeBell extends FourChannelPan { TubeBell tb; .5 => float velocity; .1 => tb.afterTouch; 100 => tb.lfoSpeed; .5 => tb.lfoDepth; Gain g; .2 => g.gain; modulate(0.1); public void connect() { tb => g; c_connect(g); } public void set_channel(float index) { // move from back to front w/ index C_PanXY(0, index * 2.0 - 1.0); } public void modulate(float index) { if (index > 1.0 || index < 0.0) { <<< "modulate error", index >>>; return; } 700 * index => tb.lfoSpeed; index / 2 => tb.lfoDepth; index * .55 => velocity; set_channel(index); } public void play(int pitch) { Std.mtof(pitch) => tb.freq; velocity => tb.noteOn; } public void end() { .0 => tb.noteOff; } public void the_bells_THE_BELLS(float bar) { bar / 4 => float quarter; quarter * 3 => float three_quarter; quarter - 10.0 => quarter; three_quarter - 10.0 => three_quarter; while (true) { for (0 => int i; i < 10; i++) { Math.sin((i / 10.0) * pi) => float index; modulate(index); play(fund - 11); quarter::ms => now; end(); 10::ms => now; play(fund - 22); three_quarter::ms => now; end(); 10::ms => now; if (Std.rand2(0, 3)== 1) { play(fund); quarter::ms => now; end(); 10::ms => now; } } // for } // while } // the_bells... } // // this class sits on top of a sound buffer to help facilitate my drone-buffering // defined below // class MySndData { SndBuf my_buf; public void open (string file_name) { file_name => my_buf.read; end(); } public void end() { my_buf.samples() => my_buf.pos; } public int at_end() { return my_buf.pos() >= my_buf.samples(); } public void connect( UGen ugen, float gain ) { my_buf => ugen; gain => my_buf.gain; // 200::ms => e.duration; } public void play( int buf_pos ) { buf_pos => my_buf.pos; } public void play() { play(0); } public void playfromcurrentpos() { play(my_buf.pos()); } } // class PitchData // // this class builds a drone on top of a sound buffer. A drone simply keeps playing // from a given position for 'meter' duration // class DroneData extends MySndData { 0::ms => dur drone_meter; 0 => int buf_pos; Shred @the_drone; public void connect( UGen ugen, float gain ) { my_buf => ugen; gain => my_buf.gain; } public void DronePlay(int buf_pos) { // if play event would go past end of buffer, move to buffer beginning if (drone_meter > 0::ms && buf_pos > 0) { my_buf.samples() => float f; buf_pos / f => f; f * my_buf.length() => dur used_length; my_buf.length() - used_length => dur remaining_length; if (drone_meter > remaining_length) { 0 => buf_pos; } } play(buf_pos); } public void UpdateGain( float gain ) { gain => my_buf.gain; } public void Drone(dur meter_time) { UpdateMeter(meter_time); while (true) { // start on the nth sample DronePlay(10); drone_meter => now; } } public void UpdateMeter(dur meter_time) { if (meter_time < 3::ms ) <<< "meter time too short for envelope" >>> ; meter_time => drone_meter; } } // class DroneData // // this class builds a more complex drone by grouping three buffer drones above, // and playing the three drones together with separate yet congruent meters. The // meters converge at the given 'meter' in the UpdateMeter function. // // MultiDrone also understands how to 'warp' the drone -- an iterative linear transformation // of the sound buffers, in effect moving the gain and z-radius of a two-pole filter. The // class also understands how to 'warp' the location of a sound source. For example, PanRWarp // will 'play' the drone in a circle at origin (x,y) and radius (r) defined w/i the panning // plan of (-1, -1, 1, 1) -> (left, front, right, back) // class MultiDrone extends FourChannelPan { DroneData drones[3]; 1.0 => float d_radius; 0.0 => float d_gain; TwoPole z; 1 => z.norm; 1.0 => z.gain; 1.0 => z.radius; Echo ec; 0.5 => ec.gain; JCRev jcr; .4 => jcr.mix; PitShift ps; 1 => int echo_meter; public void connect(float gain, int e_meter) { z => ps => jcr => ec; c_connect(ec); 0::ms => ec.max => ec.delay; gain => ec.gain; SetEcho(e_meter); UpdateRadius(1.0); UpdateGain(gain); for (0 => int i; i < drones.cap(); i++ ) { drones[i].connect(z, gain); } } public void open(string path) { for (0 => int i; i < drones.cap(); i++) { drones[i].open(path); } } // e-meter is a sub-meter as a function of our drone meter // OR (if > 10), is a separate sub-meter independent of drone meter private int echo_is_constant() { return echo_meter > 10; } public void SetEcho(int e_meter) { e_meter => echo_meter; if (echo_is_constant()) { e_meter::ms => ec.max => ec.delay; } else { // echo meter will be set when we UpdateMeter for drone } } public void UpdateMeter(dur meter, int slice) { // check to see if we update echo meter too (as a function of meter/slice) if (!echo_is_constant()) { (meter / slice) / echo_meter => ec.max => ec.delay; } for (0 => int i; i < drones.cap(); i++) { meter / (slice - i) => dur current; drones[i].UpdateMeter(current); } } public void UpdatePitch(int pitch) { // negative means turn off pitch-shift if (pitch <= 0) { 0.0 => ps.shift; } else { Std.mtof(pitch) => ps.shift; } } public void UpdateRadius( float radius ) { if (radius < 0.0 || radius > 1.0) { <<< "radius error ", radius >>>; return; } radius => d_radius => z.radius; } public void UpdateGain(float gain) { for (0 => int i; i < drones.cap(); i++) { drones[i].UpdateGain(gain); } gain => ec.gain => d_gain; } public void Drone(dur meter, int slice) { UpdateMeter(meter, slice); // spoke the drones, each with a slice-ly reduced meter for (0 => int i; i < drones.cap(); i++) { meter / (slice - i) => dur current; spork ~drones[i].Drone(current) @=> drones[i].the_drone; } } // warp channels from position x1, y1 to x2,y2: -1 <= x,y <= 1 public void PanWarp(float x1, float y1, float x2, float y2, float time_amount) { Math.fabs(x2 - x1) => float dx; Math.fabs(y2 - y1) => float dy; Math.max(dx, dy) => float delta; (delta * 25) $ int => int iterations; if (iterations <= 0) { time_amount::ms => now; return; } (x2 - x1) / iterations => dx; (y2 - y1) / iterations => dy; time_amount / iterations => float time_chunk; for (; iterations > 0; iterations--) { C_PanXY(x1, y1); x1 + dx => x1; y1 + dy => y1; time_chunk::ms => now; time_amount - time_chunk => time_amount; } C_PanXY(x2, y2); time_amount::ms => now; } // pan across radius r w/ origin x,y for time_amount public void PanRWarp(float o_x, float o_y, float r, float p, float time_amount) { (time_amount / 50) $ int => int iterations; if (iterations <= 0) { time_amount::ms => now; return; } time_amount / iterations => float time_chunk; for (0 => int i; i < iterations; i++) { o_x + r * Math.cos(((i * 1.0) / iterations) * 2 * pi + p) => float x; o_y + r * Math.sin(((i * 1.0) / iterations) * 2 * pi + p) => float y; C_PanXY(x, y); time_chunk::ms => now; time_amount - time_chunk => time_amount; } time_amount::ms => now; } // move from start to stop radius over duration time_chunk (in ms) public void RadiusWarp(float stop, float time_amount) { d_radius => float start; stop - start => float delta; // compute number of times to iterate loop (Math.fabs(delta) * 100.0) $ int => int iterations; // test edge case if (iterations <= 0) { UpdateRadius(stop); time_amount::ms => now; return; } time_amount / iterations => float time_chunk; delta / iterations => delta; for (; iterations > 0; iterations--) { UpdateRadius(start); start + delta => start; time_chunk::ms => now; time_amount - time_chunk => time_amount; } UpdateRadius(stop); time_amount::ms => now; } // move gain & radius in parallel to 'stop' value public void Warp(float stop, float time_amount) { d_gain => float gain_start; stop - gain_start => float g_delta; // radius has an inverse relationship to gain d_radius => float radius_start; (1 - stop) - radius_start => float r_delta; // compute number of times to iterate loop (Math.min(Math.fabs(g_delta), Math.fabs(r_delta)) * 100.0) $ int => int iterations; // test edge case if (iterations <= 0) { UpdateRadius(stop); UpdateGain(1 - stop); time_amount::ms => now; return; } time_amount / iterations => float time_chunk; g_delta / iterations => g_delta; r_delta / iterations => r_delta; for (; iterations > 1; iterations--) { UpdateGain(gain_start); gain_start + g_delta => gain_start; UpdateRadius(radius_start); radius_start + r_delta => radius_start; time_chunk::ms => now; time_amount - time_chunk => time_amount; } UpdateRadius(1 - stop); UpdateGain(stop); time_amount::ms => now; } // max-out radius (ring), but iterate across gain for time_amount public void Ring(float stop, float time_amount) { d_gain => float gain_start; stop - gain_start => float g_delta; // compute number of times to iterate loop (Math.fabs(g_delta) * 100.0) $ int => int iterations; // ring the drone UpdateRadius(1.0); // test edge case if (iterations <= 0) { UpdateGain(stop); time_amount::ms => now; return; } time_amount / iterations => float time_chunk; g_delta / iterations => g_delta; for (; iterations > 1; iterations--) { UpdateGain(gain_start); gain_start + g_delta => gain_start; time_chunk::ms => now; time_amount - time_chunk => time_amount; } UpdateGain(stop); time_amount::ms => now; } public void PanOscillate(float x1, float y1, float x2, float y2, float time_amount, float delay, int oscillations) { while (oscillations > 0) { PanWarp(x1, y1, x2, y2, time_amount / 2); PanWarp(x2, y2, x1, y1, time_amount / 2); delay::ms => now; --oscillations; } } public void Oscillate(float start, float stop, float time_amount, float delay, int oscillations) { while (oscillations > 0) { Warp(start, time_amount / 2); Warp(stop, time_amount / 2); delay::ms => now; --oscillations; } } public void KillDrone() { for (0 => int i; i < drones.cap(); i++) { drones[i].end(); Machine.remove(drones[i].the_drone.id()); } } } // MultiDrone // main body of shred -- The Score if (write_to_file) { fcw.init(); <<< "writing to file" >>>; } bar::ms => dur dronemeter; bar => float cur_bar; MultiDrone mower, trimmer; mower.open("data/lawnmowerz.wav"); mower.connect(0.00, 5); mower.Drone(dronemeter, primes[6]); trimmer.open("data/hedgetrimmerz.wav"); trimmer.connect(0.00, 100); trimmer.Drone(dronemeter, primes[4]); // bring a drone into focus <<< "A" >>>; // bring in drone from back, left to middle spork ~mower.PanWarp(channel_left, channel_back, 0, 0, cur_bar * 5); // in parallel, bring up radius of two-pole and gain of the drone mower.Warp(.3, cur_bar * 5); // send mower back to the back,left corner spork ~mower.PanWarp(0, 0, channel_left, channel_back, cur_bar * 3); // in parallel, bring down radius of two-pole and gain of the drone spork ~mower.Warp(.01, cur_bar * 3); (cur_bar / 3)::ms => now; // bring trimmer in from back right to front right spork ~trimmer.PanWarp(channel_right, channel_front, 0, 0, cur_bar / 3); trimmer.Warp(.4, cur_bar / 3); // etc. spork ~trimmer.PanWarp(0, 0, channel_right, channel_front, cur_bar / 2); spork ~trimmer.Warp(.05, cur_bar / 2); (cur_bar * 2)::ms => now; <<< "B" >>>; spork ~mower.PanWarp(channel_left, channel_back, 0, 0, cur_bar * 3); mower.Warp(.3, cur_bar * 3); spork ~mower.PanWarp(0, 0, channel_left, channel_back, cur_bar); spork ~mower.Warp(.2, cur_bar); (cur_bar / 2)::ms => now; spork ~trimmer.PanWarp(channel_right, channel_front, 0, 0, cur_bar / 4); trimmer.Warp(.6, cur_bar / 4); spork ~trimmer.PanWarp(0, 0, channel_right, channel_front, cur_bar / 3); spork ~trimmer.Warp(.1, cur_bar / 3); MultiDrone xbox; xbox.open("data/xbox360z.wav"); xbox.connect(0.00, 60); xbox.Drone(dronemeter, primes[4]); spork ~xbox.PanOscillate(channel_left / 2, channel_front / 2, channel_right / 2, channel_front / 2, cur_bar / 3, 0.0, 3); spork ~xbox.Oscillate(.1, .25, cur_bar / 3, 0.0, 3); (cur_bar * 2)::ms => now; <<< "C" >>>; spork ~mower.PanWarp(channel_left, channel_back, 0, 0, cur_bar * 3); spork ~mower.Warp(.45, cur_bar * 3); spork ~trimmer.PanWarp(channel_right, channel_front, 0, 0, cur_bar / 9); trimmer.Warp(.5, cur_bar / 9); spork ~trimmer.PanWarp(0, 0, channel_right, channel_front, cur_bar / 4); trimmer.Warp(.1, cur_bar / 4); (cur_bar / 2)::ms => now; spork ~xbox.Warp(0.01, cur_bar); spork ~trimmer.PanWarp(channel_right, channel_front, channel_right, channel_back, cur_bar * 3); trimmer.Warp(.6, cur_bar * 3); cur_bar::ms => now; trimmer.UpdatePitch(a4); cur_bar::ms => now; MultiDrone mixer; mixer.open("data/mixmaster2z.wav"); mixer.connect(0.00, 100); mixer.Drone(dronemeter / 5, primes[3]); spork ~mixer.PanRWarp(0, 0, 1, pi, cur_bar * 11); spork ~mixer.Warp(.45, cur_bar * 4); spork ~trimmer.PanWarp(channel_right, channel_back, channel_right, channel_front, cur_bar); trimmer.UpdatePitch(0); trimmer.Warp(.1, cur_bar); spork ~mower.PanWarp(0, 0, channel_left, channel_back, cur_bar * 3); mower.Warp(.01, cur_bar * 3); (cur_bar / 3)::ms => now; mower.KillDrone(); <<< "D" >>>; trimmer.Warp(0.01, cur_bar / 4); spork ~xbox.PanOscillate(channel_left / 2, channel_front / 2, channel_right / 2, channel_back / 2, cur_bar / 3, 0.0, 7); spork ~xbox.Oscillate(.1, .3, cur_bar / 3, 0.0, 7); cur_bar::ms => now; <<< "E" >>>; mixer.UpdatePitch(m6); spork ~trimmer.PanWarp(channel_right, channel_front, 0, 0, cur_bar / 5); trimmer.Warp(.7, cur_bar / 5); spork ~trimmer.PanWarp(0, 0, channel_right, channel_front, cur_bar / 7); trimmer.Warp(.1, cur_bar / 7); cur_bar::ms => now; spork ~mixer.Warp(.01, cur_bar * 3); trimmer.KillDrone(); <<< "F" >>>; MultiDrone blowdryer; blowdryer.open("data/blowdryerz.wav"); blowdryer.connect(0.00, 50); blowdryer.Drone(dronemeter, primes[5]); blowdryer.C_PanXY(channel_left, channel_back); blowdryer.Warp(.40, cur_bar); spork ~xbox.Warp(0.0, cur_bar); <<< "f1" >>>; blowdryer.Ring(.3, cur_bar / 2); cur_bar::ms => now; spork ~blowdryer.Warp(.1, cur_bar * 3); cur_bar::ms => now; mixer.UpdatePitch(P8); spork ~xbox.PanOscillate(channel_left, channel_front / 2, channel_right, channel_front / 2, cur_bar / 3, 0.0, 5); spork ~xbox.Oscillate(.2, .5, cur_bar / 3, 0.0, 5); <<< "f2" >>>; mixer.Warp(0.04, cur_bar); mixer.KillDrone(); <<< "G" >>>; MultiDrone leafblower; leafblower.open("data/leafblowerz.wav"); leafblower.connect(0.00, 5); leafblower.Drone(dronemeter, primes[7]); spork ~leafblower.PanOscillate(0, 0, channel_right, channel_back, cur_bar, cur_bar * 2.5, 10); spork ~leafblower.Oscillate(.55, .1, cur_bar, cur_bar * 2.5, 10); cur_bar::ms => now; (cur_bar / 2)::ms => now; xbox.Warp(0.01, cur_bar); xbox.KillDrone(); cur_bar::ms => now; blowdryer.Warp(0.01, cur_bar * 2); blowdryer.KillDrone(); mower.Drone(dronemeter, primes[7]); spork ~mower.PanOscillate(0, 0, channel_left, channel_back, cur_bar, cur_bar * 3, 8); spork ~mower.Oscillate(.55, .1, cur_bar, cur_bar * 3, 8); <<< "H" >>>; MyTubeBell mtb; mtb.connect(); spork ~mtb.the_bells_THE_BELLS(cur_bar * 2) @=> Shred @the_bells; (3 * cur_bar)::ms => now; trimmer.Drone(dronemeter, primes[4]); cur_bar * Std.rand2f(1, 3) => float delay; spork ~trimmer.PanOscillate(channel_right, channel_front, 0, 0, cur_bar / 2, delay, 4); spork ~trimmer.Oscillate(.65, .0, cur_bar / 2, delay, 4); MyStifKarp sk; sk.connect(); [fundamental * 6] @=> float tonic[]; <<< "h1" >>>; sk.play_phrase(tonic[0], tonic); cur_bar * 3 * Std.rand2f(.85,1.25)::ms => now; <<< "h2" >>>; sk.play_phrase(tonic[0], tonic); cur_bar * 4 * Std.rand2f(.85,1.25)::ms => now; <<< "h3" >>>; sk.play_phrase(tonic[0], tonic); cur_bar * 3 * Std.rand2f(.85,1.25)::ms => now; spork ~mower.Warp(0.00, cur_bar); (cur_bar / 2)::ms => now; mower.KillDrone(); spork ~leafblower.Warp(0.00, cur_bar); (cur_bar / 2)::ms => now; leafblower.KillDrone(); trimmer.KillDrone(); Machine.remove(the_bells.id()); bar::ms => now; if (write_to_file) { fcw.done(); } <<< "done" >>>;