...making Linux just a little more fun!
Jimmy ORegan [joregan at gmail.com]
I was looking at some tablature programs today, and found that there's an extension to MIDI called "Rich MIDI Tablature Format" to represent some guitar specific things. A few Windows programs support it, but none of the open source programs do.
I was wondering how to even go about finding out the differences between this format and regular MIDI (without having to find out too much about MIDI), when Perl (or, more specifically, Perl's MIDI module) came to the rescue: it has an option to dump everything as a series of events.
Take this short piece of Lilypond:
\header { title = "Flowers" dedication = "Ona wie" subtitle = "1 January 2005" } \new TabStaff { \repeat volta 2 { d'4\4 b'8\3 d'\4 a'4.\3 e'8\4 e'\4 fis'\4 g'\4 e'\4 fis'\4 g'\4 a'4\3 d'4\4 b'8\3 d'\4 a'4.\3 e'8\4 a'\3 g'\4 fis'\4 e'\4 d'2\4 } \repeat volta 2 { a4\5 e'8\4 fis'\4 g'4.\4 e'8\4 e'\4 fis'\4 g'\4 e'\4 fis'\4 g'\4 a'4\3 a4\5 e'8\4 fis'\4 g'4.\4 e'8\4 g'\4 fis'\4 e'\4 b'\3 a'2\3 } \repeat volta 2 { a8\4 d\4 fis\4 g\4 e\5 a,\5 cis\5 d\5 d\5 cis\5 b,\6 a,\6 a,\6 cis\5 e\5 g\4 a8\4 d\4 fis\4 g\4 e\5 a,\5 cis\5 d\5 d\5 cis\5 b,\6 a,\6 a,2\6 } }I recreated the first 4 bars in one of the Windows tablature programs, and with this command:
$ perl -MMIDI -e 'my $o=MIDI::Opus->new({"from_file"=>$ARGV[0]});$o->dump({"dump_tracks"=>1});' flowers-rtmf.midI got this output:
MIDI::Opus->new({ 'format' => 1, 'ticks' => 240, 'tracks' => [ # 3 tracks... # Track #0 ... MIDI::Track->new({ 'type' => 'MTrk', 'events' => [ # 5 events. ['copyright_text_event', 0, 'TablEdited by Jimmy O\'Regan'], ['track_name', 0, 'Flowers - Jimmy O\'Regan'], ['set_tempo', 0, 500000], ['time_signature', 0, 4, 2, 36, 8], ['key_signature', 0, 0, 0], ] }), # Track #1 ... MIDI::Track->new({ 'type' => 'MTrk', 'events' => [ # 88 events. ['track_name', 0, 'Guitar Standard'], ['raw_meta_event', 0, 16, "\x00\x00\x40;72-("], ['patch_change', 0, 0, 25], ['patch_change', 0, 1, 25], ['control_change', 0, 0, 101, 0], ['control_change', 0, 0, 100, 0], ['control_change', 0, 0, 6, 2], ['control_change', 0, 0, 101, 127], ['control_change', 0, 0, 100, 127], ['pitch_wheel_change', 0, 0, 0], ['control_change', 0, 1, 101, 0], ['control_change', 0, 1, 100, 0], ['control_change', 0, 1, 6, 2], ['control_change', 0, 1, 101, 127], ['control_change', 0, 1, 100, 127], ['pitch_wheel_change', 0, 1, 0], ['control_change', 0, 0, 10, 63], ['control_change', 0, 1, 10, 63], ['control_change', 0, 0, 93, 0], ['control_change', 0, 0, 91, 0], ['control_change', 0, 1, 93, 0], ['control_change', 0, 1, 91, 0], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 62, 95], ['note_off', 240, 0, 62, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 71, 95], ['raw_meta_event', 120, 17, "\x03"], ['note_on', 0, 0, 62, 95], ['note_off', 120, 0, 71, 100], ['note_off', 0, 0, 62, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 69, 95], ['note_off', 360, 0, 69, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 64, 95], ['note_off', 120, 0, 64, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 64, 95], ['note_off', 120, 0, 64, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 66, 95], ['note_off', 120, 0, 66, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 67, 95], ['note_off', 120, 0, 67, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 64, 95], ['note_off', 120, 0, 64, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 66, 95], ['note_off', 120, 0, 66, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 67, 95], ['note_off', 120, 0, 67, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 69, 95], ['note_off', 240, 0, 69, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 62, 95], ['note_off', 240, 0, 62, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 71, 95], ['raw_meta_event', 120, 17, "\x03"], ['note_on', 0, 0, 62, 95], ['note_off', 120, 0, 71, 100], ['note_off', 0, 0, 62, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 69, 95], ['note_off', 360, 0, 69, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 64, 95], ['note_off', 120, 0, 64, 100], ['raw_meta_event', 0, 17, "\x02"], ['note_on', 0, 0, 69, 95], ['note_off', 120, 0, 69, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 67, 95], ['note_off', 120, 0, 67, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 66, 95], ['note_off', 120, 0, 66, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 64, 95], ['note_off', 120, 0, 64, 100], ['raw_meta_event', 0, 17, "\x03"], ['note_on', 0, 0, 62, 95], ['note_off', 480, 0, 62, 100], ] }), # Track #2 ... MIDI::Track->new({ 'type' => 'MTrk', 'events' => [ # 1 events. ['track_name', 0, 'Flowers - Jimmy O\'Regan'], ] }), ] });The interesting parts - those that are absent in the standard MIDI export - are the "raw_meta_event" lines. "['raw_meta_event', 0, 16, "\x00\x00\x40;72-("]" sets up the tuning (two nulls, then the MIDI numbers of the notes from the highest string to the lowest), and "['raw_meta_event', 0, 17, "\x03"]", where "\x03" is the number of the string starting at 0 for the highest.
The second line can also have a second digit: "['raw_meta_event', 0, 17, "\x02\x01"]", where
0x01 = hammer on 0x02 = pulloff 0x03 = slide 0x05 = brush 0x06 = roll 0x07 = natural harmonic 0x08 = artificial harmonic 0x09 = vibrato 0x0a = tremolo 0x0c = bend (followed by 0x02) 0x0d = muted 0x0e = dead note 0x0f = tappingNow to see if I can stomach enough Java to get Tuxguitar to import these things