Tux

...making Linux just a little more fun!

Dumping MIDI as a series of events

Jimmy ORegan [joregan at gmail.com]


Sat, 26 May 2007 16:21:35 +0100

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.mid
I 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 = tapping
Now to see if I can stomach enough Java to get Tuxguitar to import these things :)


Top    Back