//------------------------------------------------ // name: polyfony.ck // desc: polyfonic mandolin model // // by: Ananya Misra and Ge Wang // send all complaints to prc@cs.princeton.edu //-------------------------------------------- 440 => float defineA; 2.0 => float octaveRatio; 12 => int octaveSize; 0 => int equalFlagStd; 1 => int equalFlagNonStd; 0 => int meanFlag; 0 => int pythagFlag; // device to open (see: chuck --probe) 0 => int device; // get from command line if( me.args() ) me.arg(0) => Std.atoi => device; MidiIn min; MidiMsg msg; ADSR adsr; float register; float oneOctave[octaveSize]; int keyboard[88]; //defineA @=> oneOctave[9]; // try to open MIDI port (see chuck --probe for available devices) if( !min.open( device ) ) me.exit(); // print out device that was opened <<< "MIDI device:", min.num(), " -> ", min.name() >>>; // make our own event class NoteEvent extends Event { int note; int velocity; } // the event NoteEvent on; // array of ugen's handling each note Event @ us[128]; // the base patch Gain g => JCRev r => dac; .1 => g.gain; .1 => r.mix; adsr.set( 10::ms, 8::ms, .5, 250::ms ); fun float findFrequency(int note, float array[]) { float freq; 6 => float defaultOctave; // must be +3 MIDI values to account for octave starting on C, not A (note+3)/octaveSize => float currOctave; if (currOctave >= 6) Math.pow(octaveRatio, currOctave - defaultOctave) => register; else 1/(Math.pow(octaveRatio,(defaultOctave - currOctave))) => register; while(note > 11) { octaveSize -=> note; } register*array[(note+3)%octaveSize] => freq; <<< freq >>>; return freq; } fun void generateScale(int curr) { float x; for (0 => int i; i < oneOctave.cap(); i++) { if (pythagFlag == 1) { // All fifths are exactly in ratio of 3:2 3.0/2.0 => float pythagFifth; defineA*Math.pow(pythagFifth, i) => x; } else if (meanFlag == 1) { // 1/4 comma mean fifth is based off of a third being exactly 5/4 the frequency... //a seventeenth is 2 octaves plus one third, or 4*(5/4), or 5 times the freq. //So, x^4 fifths is 5 and a fifth is 5^(1/4) Math.pow(5, 1.0/4.0) => float meanFifth; defineA*Math.pow(meanFifth,i) => x; } else if (equalFlagStd == 1) { Math.pow(2, 7.0/12.0) => float equalFifth; defineA*Math.pow(equalFifth,i) => x; } else if (equalFlagNonStd == 1) { Math.pow(octaveRatio, 1.0/octaveSize) => float equalTemper; defineA*Math.pow(equalTemper,i) => x; } if (i == 0) x => oneOctave[curr]; // when we're not talking about our defined A... else if (x > 2*defineA) { while (x > 2*defineA ) x/2 => x; } x => oneOctave[curr]; if (equalFlagNonStd == 0) (curr+7)%12 => curr; else curr++; } } // handler for a single voice fun void handler() { // don't connect to dac until we need it TriOsc m; Event off; int note; while( true ) { 0 => int curr; on => now; on.note => note; // dynamically repatch m => g; generateScale(curr); findFrequency(note, oneOctave) => m.freq; // <<< "frequency", findFrequency(note, oneOctave) >>>; //Std.mtof( note ) => m.freq; // Math.random2f( .6, .8 ) => m.pluckPos; // on.velocity / 128.0 => m.pluck; // off @=> us[note]; off => now; null @=> us[note]; m =< g; } while( msg.data3 > 0) { adsr.keyOn(); 10::ms => now; adsr.keyOff(); 10::ms => now; } } // spork handlers, one for each voice for( 0 => int i; i < 20; i++ ) spork ~ handler(); // infinite time-loop while( true ) { // wait on midi event min => now; // get the midimsg while( min.recv( msg ) ) { // catch only noteon if( msg.data1 != 144 ) continue; // print out midi message // <<< msg.data1, msg.data2, msg.data3 >>>; // check velocity if( msg.data3 > 0 ) { // store midi note number msg.data2 => on.note; // store velocity msg.data3 => on.velocity; // signal the event on.signal(); // yield without advancing time to allow shred to run me.yield(); } else { if( us[msg.data2] != null ) us[msg.data2].signal(); } } }