//----------------------------| // Jeff Smith, Music 220a // HW #2, Oct 12, 2007 // composition, adapted from Perry & Ge (and other's): // dinky module // Moog module (yummy) // various sample code // // structure: // - a sound file (taken from performance of Handel's Messiah) is run // backwards, while the slice of time between 'samples' is variably reduced // - concurrently, and in random slices, the Dinky instrument is given a // pitch to play // - i use the Echo and NRev unit generators to create a nice reverb // - concurrently, and autonomous of the above loop, the Mooger is sporked // - eventually, we either run out of samples in the messiah, or (more likely) // we've reduced the slice of time between samples to zero // - if any more samples remain, they are played, and the volume is reduced // providing a diminuendo of sorts, with the Mooger getting softer faster // // the result is largely arhythmic because the rate of reduction of time slices // is quasi-random, and the Mooger remains random throughout //--------------------------------------| // you need Dinky to run // this class defines the Dinky instrument // the variables defined at class level are member variables // // to test this: // > chuck dinky.ck try.ck // // NOTE: in a future version of chuck... // this class will be able to extend UGen // the Dinky class class Dinky { // impulse to filter to dac Impulse i => BiQuad f => Envelope e; // set the filter's pole radius .99 => f.prad; // set equal gain zeros 1 => f.eqzs; // set filter gain .2 => f.gain; // set the envelope .004::second => e.duration; public void radius( float rad ) { rad => f.prad; } public void gain( float g ) { g => i.gain; } public void connect( UGen ugen ) { e => ugen; } // t is for trigger public void t( float freq ) { // set the current sample/impulse 1.0 => i.next; // set filter resonant frequency freq => f.pfreq; // open the envelope e.keyOn(); } // t is for trigger (using MIDI notes) public void t( int note ) { t( Std.mtof( note ) ); } // another lazy name: c (for close) public void c() { e.keyOff(); } } Dinky imp; class the_mooger { Moog mog => dac; 0.0 => float mog_time; 0.15 => float vel_min; 0.35 => float vel_max; public void varmod() { while ( true ) { 0.5 + 0.4 * Math.sin ( mog_time * 0.1 ) => mog.modDepth; 0.5 + 0.4 * Math.sin ( mog_time * 0.2 ) => mog.modSpeed; 0.5 + 0.4 * Math.sin ( mog_time * 0.3 ) => mog.filterQ; 0.5 + 0.4 * Math.sin ( mog_time * 0.4 ) => mog.filterSweepRate; 10::ms => now; mog_time + 0.01 => mog_time; } } public void atouch( float impulse) { impulse => float atouch; while ( atouch >= 0.0 && mog.gain() > 0 ) { atouch => mog.afterTouch; atouch - 0.05 => atouch; 10::ms => now; } } public void go_mooging_sir() { // spork varmod shred spork ~varmod(); while ( true ) { 278.43 => mog.freq; Std.rand2f(vel_min, vel_max) => float vel; vel => mog.noteOn; spork ~ atouch(vel); if ( Std.randf() > 0.3 ) { 1::second => now; } else { 0.5::second => now; } } } public void set_velocity_range(float vmin, float vmax) { vmin => vel_min; vmax => vel_max; } } // introducing mr_moog the_mooger mr_moog; // construct the patch SndBuf buf1 => Gain g => NRev r => Echo e => dac; // a section of Handel's Messiah: "I Know" from I know my redeemer lives "data/myredeemer.wav" => buf1.read; .25 => g.gain; .15 => r.mix; e => dac; 1500::ms => e.max => e.delay; .5 => e.gain; .8 => buf1.gain; // connect the Dinky // (in a future version of chuck, Dinky can be defined as an UGen) imp.connect( g ); // set the radius (should never be more than 1) imp.radius( .999 ); //<<< "\n", buf1.samples() >>>; 200 => int base_sample_rate => int cur_sample_rate; // an array (our scale) [ 0, 2, 4, 7, 9, 10 ] @=> int hi[]; // main function -- this loop plays the buf file backwards at chunks of // cur_sample_rate, reducing the amount of time between playbacks in the // process; Dinky will be struck intermittently in the loop fun int buf_plus_dinky() { buf1.samples() => int i; while (cur_sample_rate > 0 && i > 0 ) { false => int imped; i => buf1.pos; if( Std.randf() > 0.2 ) { 45 + Std.rand2(0,3) * 12 + hi[Std.rand2(0,hi.cap()-1)] => imp.t; true => imped; } else { ((cur_sample_rate - 1) + base_sample_rate) % base_sample_rate => cur_sample_rate; } // Std.rand2(100,500)::ms => now; cur_sample_rate::ms => now; if (imped) { imp.c(); false => imped; 10::ms => now; } i - base_sample_rate => i; // <<< i, cur_sample_rate >>>; } return i; } // main() // launch the mooger! spork ~mr_moog.go_mooging_sir(); // invoke our main loop buf_plus_dinky() => int i; // if more samples remain, play more back, reducing gain of mooger faster // than our buffer while (i > 200 && buf1.gain() > .01) { i => buf1.pos; base_sample_rate::ms => now; i - base_sample_rate => i; buf1.gain() - 0.02 => buf1.gain; mr_moog.mog.gain() - 0.03 => mr_moog.mog.gain; // <<< buf1.gain(), i >>>; } // a couple more twangs of the mooger please; buffer play from start (finally) 0.3 => mr_moog.mog.gain; 0.3 => buf1.gain; 0 => buf1.pos; (base_sample_rate * 3)::ms => e.max => e.delay; 4::second => now; // shut down mooger & buffer & echo 0.0 => mr_moog.mog.gain; 0.0 => buf1.gain; 0.0 => e.gain; 2::second => now;