So, I never really got into windows programming much during my youth — by the time I actually knew how to program, I was mostly using Linux — so it's an amusing exercise to mess around with little corners of the Windows API, like for instance MIDI I/O. It's far less scary than I thought.
The following C program just dumps MIDI messages to stdout:
and using some (sigh) perl module that someone wrote years ago, it is disgustingly convenient to transform this into a standard midi file:
The only tricky things were finding out that I needed to link to libwinmm to compile the C program under msys, and understanding the crazy midi "ticks" field and what I needed to set it to in order to make ticks = milliseconds.
Clearly the thing to do is wrap this all in some saner language...
Anyway, here is a quick recording of the head of "Blue Monk".
The following C program just dumps MIDI messages to stdout:
#include <windows.h>
void CALLBACK callback(HMIDIIN handle, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) {
if (uMsg == MIM_DATA) {
printf( "%ld %d %d %d\n", dwParam2, dwParam1 & 0x000000FF, (dwParam1>>8) & 0x000000FF, (dwParam1>>16) & 0x000000FF);
fflush(0);
}
}
int main(void) {
HMIDIIN inHandle;
if (midiInOpen(&inHandle, 0, (DWORD)callback, 0, CALLBACK_FUNCTION)) {
printf("There was an error opening the default MIDI In device!\n");
exit(1);
}
midiInStart(inHandle);
while(1) { Sleep(1000); }
}
and using some (sigh) perl module that someone wrote years ago, it is disgustingly convenient to transform this into a standard midi file:
#!/usr/bin/perl
use MIDI;
use strict;
use warnings;
my $patch = 0;
my $bank = 0;
my $curt = 0;
my @events = (['set_tempo', 0, 500_000],
['control_change', 0, 0, 0, $bank],
['patch_change', 0, 0, $patch],
);
while (<>) {
chomp;
my ($t, $code, $note, $vel) = split;
my $delta = int(($t - $curt) );
if ($code == 144) { # note on
push @events, ['note_on', $delta, 0, $note, $vel];
}
if ($code == 176) { # control change
push @events, ['control_change', $delta, 0, $note, $vel];
}
$curt = $t;
}
my $opus = MIDI::Opus->new({ 'ticks' => 500, 'tracks' => [ MIDI::Track->new({ 'events' => \@events }) ] } );
$opus->write_to_handle( *STDOUT{IO} );
The only tricky things were finding out that I needed to link to libwinmm to compile the C program under msys, and understanding the crazy midi "ticks" field and what I needed to set it to in order to make ticks = milliseconds.
Clearly the thing to do is wrap this all in some saner language...
Anyway, here is a quick recording of the head of "Blue Monk".