// name: playmidi.ck
// desc: example to render a MIDI file using ChucK
// path
NRev reverb => dac;
// just a bit of reverb
0.025 => reverb.mix;
// the MIDI file in object
MidiFileIn min;
// the MIDI message shuttle
MidiMsg msg;
// the filename
string filename;
// if no command line arguments provided
if( me.args() == 0 ) me.dir() + "bwv772.mid" => filename;
// else use that filename
else me.arg(0) => filename;
// open the file; exit on error
if( !min.open(filename) ) me.exit();
// print out
cherr <= "----------" <= IO.newline();
cherr <= "MIDI file: " <= IO.newline()
<= " |- " <= filename <= IO.newline()
<= " |- contains " <= min.numTracks() <= " tracks" <= IO.newline();
// print
cherr <= "----------" <= IO.newline();
cherr <= "playing..." <= IO.newline();
cherr <= "----------" <= IO.newline();
// flag
int done;
// for each track, spork a separate shred with the track number
for( int t; t < min.numTracks(); t++ )
spork ~ doTrack( t, 1 );
// keeping track of how many tracks are done
while( done < min.numTracks() )
1::second => now;
// done
cherr <= "done; cleaning up..." <= IO.newline();
// close the file
min.close();
// entry point for each shred assigned to a track
fun void doTrack( int track, float speed )
{
// hack polyphony
Wurley s[4];
// for each voice
for( int i; i < s.size(); i++ )
{
// set gain
.5 => s[i].gain;
// connect to output
s[i] => reverb;
}
// voice number for quick polyphony
int v;
// read through all MIDI messages on track
while( min.read( msg, track ) )
{
// this means no more MIDI events at current time; advance time
if( msg.when > 0::second )
msg.when * speed => now; // speed of 1 is nominal
// catch NOTEON messages (lower nibble == 0x90)
if( (msg.data1 & 0xF0) == 0x90 && msg.data2 > 0 && msg.data3 > 0 )
{
// get the pitch and convert to frequencey; set
msg.data2 => Std.mtof => s[v].freq;
// velocity data; note on
msg.data3/127.0 => s[v].noteOn;
// cycle the voices
(v+1)%s.size() => v;
// log
cherr <= "NOTE ON track:" <= track <= " pitch:" <= msg.data2 <=" velocity:" <= msg.data3 <= IO.newline();
}
// other messages
else
{
// log
// cherr <= "----EVENT (unhandled) track:" <= track <= " type:" <= (msg.data1&0xF0)
// <= " data2:" <= msg.data2 <= " data3:" <= msg.data3 <= IO.newline();
}
}
// done with track
done++;
}