// chesstones.ck, June, 2008, Less Hall (Inventor) // and Dale Parson (Acoustic Interloper). //chess1.ck // Launch as a sound generator for chessgame.py as of // 13 June 2008. This OSC type format is patch specific. // There are 2 banks of ugens with 32 ugens each. // Bank 0 generates sines and bank 1 triangles in the // initial test. Incoming OSC fields are: // bank(i) 0 or 1 for sine or triangle bank respectively // osc(i) oscillator numer 0..31 in that bank // freq(f) frequency or -1.0 to shut it off // phase(f) 0.0 .. 1.0 or -1.0 to shut it off (redundant) // leftampl left channel amplitude 0.0 to 1.0 // rightampl right channel amplitude 0.0 to 1.0 // The amplitudes are 0.0 when freq is -1.0 for shut off. // The output of all ACTIVE oscillators should be summed and // normalized so that running many oscillators does not exceed // some threshold. This entails some scaling. // class to generate sounds for Acoustic Interloper's chess program // by Les Hall (Inventor) // This software is freeware, use as you wish // Modified by Dale E. Parson, June, 2008, to receive input from // Open Sound Control (another kind of OSC), normalize to 1.0. // instantiate the oscillator class oscillators Osc; // hook up the oscillator class Osc.out_left => dac.left; Osc.out_right => dac.right; // call some test functions with time delays between them // Osc.voice (0, 0, 247.5, 0, 0.275, 0.125); // 3::second => now; // Osc.voice (1, 0, 196.0, 0, 0.125, 0.275); // 3::second => now; // Osc.voice (0, 1, 329.0, 0, 0.275, 0.125); // 3::second => now; // Osc.voice (1, 1, 440.0, 0, 0.125, 0.275); // 3::second => now; // Osc.quiet (); // 3::second => now; // The oscillator class class oscillators { // parameters 32 => int num_osc; // number of oscillators // the patch SinOsc sine_wave[num_osc]; Gain sine_left[num_osc]; Gain sine_right[num_osc]; Envelope sine_gainenv_left[num_osc]; Envelope sine_gainenv_right[num_osc]; float sine_left_prenorm[num_osc]; float sine_right_prenorm[num_osc]; TriOsc tri_wave[num_osc]; Gain tri_left[num_osc]; Gain tri_right[num_osc]; Envelope tri_gainenv_left[num_osc]; Envelope tri_gainenv_right[num_osc]; float tri_left_prenorm[num_osc]; float tri_right_prenorm[num_osc]; float last_scale_left ; float last_scale_right ; Gain out_left; Gain out_right; for (0 => int i; i < num_osc; i++) { sine_wave[i] => sine_left[i] => out_left; sine_wave[i] => sine_right[i] => out_right; tri_wave[i] => tri_left[i] => out_left; tri_wave[i] => tri_right[i] => out_right; 0.010 => sine_gainenv_left[i].time ; 0.010 => sine_gainenv_right[i].time ; 0.010 => tri_gainenv_left[i].time ; 0.010 => tri_gainenv_right[i].time ; sine_gainenv_left[i] => sine_left[i] ; sine_gainenv_right[i] => sine_right[i] ; tri_gainenv_left[i] => tri_left[i] ; tri_gainenv_right[i] => tri_right[i] ; } // initialize oscillators as quiet for (0 => int i; i < num_osc; i++) { 1 => sine_wave[i].gain; 1 => tri_wave[i].gain; 0 => sine_left[i].gain; 0 => sine_right[i].gain; 0 => tri_left[i].gain; 0 => tri_right[i].gain; 0 => sine_left_prenorm[i]; 0 => sine_right_prenorm[i]; 0 => tri_left_prenorm[i]; 0 => tri_right_prenorm[i]; } 1 => out_left.gain; 1 => out_right.gain; 1.0 => last_scale_left ; 1.0 => last_scale_right ; // the sine wave function fun void voice (int bank, int osc, float freq, float phase, float left, float right) { float realfreq, realphase, realleft, realright ; if (freq < 0.0) { // This is the kill message. 0.0 => realfreq ; 0.0 => realphase ; 0.0 => realleft ; 0.0 => realright ; } else { freq => realfreq ; phase => realphase ; left => realleft ; right => realright ; } float sum_left, sum_right, left_scale, right_scale ; if (bank == 0) { realleft => sine_left_prenorm[osc]; realright => sine_right_prenorm[osc]; } else { realleft => tri_left_prenorm[osc]; realright => tri_right_prenorm[osc]; } 0.0 => sum_left ; 0.0 => sum_right ; for (0 => int i ; i < num_osc ; i++) { sum_left + sine_left_prenorm[i] + tri_left_prenorm[i] => sum_left ; sum_right + sine_right_prenorm[i] + tri_right_prenorm[i] => sum_right ; } if (sum_left > 1.0) { 1.0 / sum_left => left_scale ; } else { 1.0 => left_scale ; } if (sum_right > 1.0) { 1.0 / sum_right => right_scale ; } else { 1.0 => right_scale ; } // <<< "DEBUG TOP", left_scale, sine_gainenv_left[osc].target(), sine_gainenv_left[osc].value(), sine_left[osc].gain() >>>; if (bank == 0) { // 0.100 => sine_gainenv_left[osc].time ; // 0.0 => sine_gainenv_left[osc].target ; // 0.100 => sine_gainenv_right[osc].time ; // 0.0 => sine_gainenv_right[osc].target ; sine_gainenv_left[osc].value() => sine_left[osc].gain ; sine_gainenv_right[osc].value() => sine_right[osc].gain ; realfreq => sine_wave[osc].freq; realphase => sine_wave[osc].phase; if (left_scale != last_scale_left) { for (0 => int j ; j < num_osc ; j++) { if (j != osc) { // 0.100 => sine_gainenv_left[j].time ; sine_left_prenorm[j] * left_scale => sine_gainenv_left[j].target ; sine_gainenv_left[j].value() => sine_left[j].gain ; } } } if (right_scale != last_scale_right) { for (0 => int j ; j < num_osc ; j++) { if (j != osc) { // 0.100 => sine_gainenv_right[j].time ; sine_right_prenorm[j] * right_scale => sine_gainenv_right[j].target ; sine_gainenv_right[j].value() => sine_right[j].gain ; } } } // 0.100 => sine_gainenv_left[osc].time ; sine_left_prenorm[osc] * left_scale => sine_gainenv_left[osc].target ; sine_gainenv_left[osc].value() => sine_left[osc].gain ; // 0.100 => sine_gainenv_right[osc].time ; sine_right_prenorm[osc] * right_scale => sine_gainenv_right[osc].target ; sine_gainenv_right[osc].value() => sine_right[osc].gain ; 100::ms => now ; now => now ; <<< "DEBUG BOTTOM", osc, left_scale, realfreq, realphase, sine_gainenv_left[osc].target(), sine_gainenv_left[osc].value(), sine_left[osc].gain() >>>; } else { // 0.100 => tri_gainenv_left[osc].time ; 0.0 => tri_gainenv_left[osc].target ; tri_gainenv_left[osc].value() => tri_left[osc].gain ; // 0.100 => tri_gainenv_right[osc].time ; 0.0 => tri_gainenv_right[osc].target ; tri_gainenv_right[osc].value() => tri_right[osc].gain ; realfreq => tri_wave[osc].freq; realphase => tri_wave[osc].phase; if (left_scale != last_scale_left) { for (0 => int j ; j < num_osc ; j++) { if (j != osc) { // 0.100 => tri_gainenv_left[j].time ; tri_left_prenorm[j] * left_scale => tri_gainenv_left[j].target ; tri_gainenv_left[j].value() => tri_left[j].gain ; } } } if (right_scale != last_scale_right) { for (0 => int j ; j < num_osc ; j++) { if (j != osc) { // 0.100 => tri_gainenv_right[j].time ; tri_right_prenorm[j] * right_scale => tri_gainenv_right[j].target ; tri_gainenv_right[j].value() => tri_right[j].gain ; } } } // 0.100 => tri_gainenv_left[osc].time ; tri_left_prenorm[osc] * left_scale => tri_gainenv_left[osc].target ; tri_gainenv_left[osc].value() => tri_left[osc].gain ; // 0.100 => tri_gainenv_right[osc].time ; tri_right_prenorm[osc] * right_scale => tri_gainenv_right[osc].target ; tri_gainenv_right[osc].value() => tri_right[osc].gain ; } left_scale => last_scale_left ; right_scale => last_scale_right ; } // quiet all oscillators fun void quiet () { for (0 => int i; i < num_osc; i++) { 0 => sine_left[i].gain; 0 => sine_right[i].gain; 0 => tri_left[i].gain; 0 => tri_right[i].gain; 0 => sine_left_prenorm[i]; 0 => sine_right_prenorm[i]; 0 => tri_left_prenorm[i]; 0 => tri_right_prenorm[i]; } } } // create our OSC receiver OscRecv recv; // port 7401 used by the chess program 7401 => recv.port; // start listening (launch thread) recv.listen(); // create an address in the receiver, store in new variable recv.event( "list, i i f f f f" ) @=> OscEvent @ oe; // infinite event loop while( true ) { // wait for event to arrive oe => now; // grab the next message from the queue. while( oe.nextMsg() ) { int bank, osc ; float freq, phase, leftampl, rightampl ; // getFloat fetches the expected float (as indicated by "i f") oe.getInt() => bank ; oe.getInt() => osc ; oe.getFloat() => freq ; oe.getFloat() => phase ; oe.getFloat() => leftampl ; oe.getFloat() => rightampl ; Osc.voice(bank, osc, freq, phase, leftampl, rightampl); // print // <<< "got (via OSC):", bank, osc, freq, phase, leftampl, rightampl >>>; } }