This python library is intended to open midi files as python objects. Midi file is binary files, list in form of tracks. Every track contains a sequence of events. Each event is associated delta time, which refers to time from perivous event, current event should occur.
In same structure rmidi has MIDI as base class, MIDI.Track for track representation and MIDI.Track.Event to represent each event.
rmidi is available on python pip. You can install library through below command.
$ pip install rmidirmidi has two classes for handling the midi files MIDI and AbsoluteMidi, further documentation reveals out their differences.
You can open **.mid** files with MIDI class only, which can transform to AbsoluteMidi class object
>>> from rmidi.midi import MIDI
>>> mid = MIDI.parse_midi(<midi-file-path>)
>>> # do any manupulation it
>>> mid.create_file(<midi-file-name>, <dir-path> = current-dir) # if dir is not specified file is store in current directory >>> from rmidi.midi import MIDI
>>> mid = MIDI(empty = True) # creates file with, format_type = 0, track_count = 0, time_div = 0x1e0
>>> mid.create_file("empyty.mid")Below shows how to add any note to midi object, thing to note specifically here is every note_on event, there should always be note_off event. You can also disable velocity, to have note_off event
>>> from rmidi.midi import MIDI
>>> mid = MIDI(empty = True, track_count = 0) # creates file with, format_type = 0, time_div = 0x1e0
>>> mid.track(0).add_event(0, 'note_on', note_number = 60, velocity = 90, channel_no = 0) # add note with midi number 60 to track 0
>>> mid.track(0).add_event(4, 'note_off' note_number = 60, velocity = 90, channel_no = 0) # there should be coressponding note-off event assosiated with note-onHere note_on and note_off event has same parameter structure, and everything in specified above.
param structure (time, event, note_number, velocity, channel_no).
time := delta time in traditional way of note presenting, as whole = 1, half = 2, quater = 4, and so on>>> from rmidi import MIDI
>>> y = MIDI.parse_midi(<midi_file_path>)Output
_____________________________________________________________________________________________________________________________ . . . | Absolute Time | Duration | Delta Time | ETYPE | Event ID | META | LENGTH | DATA |______________________________________________________________________________________________________________________________ . . . | 0.000000 | 0.000000 | 0x0 | META | 0xff | 0x58 | 0x4 | 0x04 0x02 0x18 0x0 | 0.000000 | 0.000000 | 0x0 | META | 0xff | 0x59 | 0x2 | 0x00 0x0 | 0.000000 | 0.000000 | 0x0 | META | 0xff | 0x51 | 0x3 | 0x07 0xa1 0x2 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x79 0x0 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xc0 | 0 | 0x1 | 0x0 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x07 0x6 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x0a 0x4 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x5b 0x0 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x5d 0x0 | 0.000000 | 0.000000 | 0x0 | META | 0xff | 0x21 | 0x1 | 0x0 | 0.000000 | 0.000000 | 0x0 | CHANNEL | 0x90 | 0 | 0x2 | 0x48 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x48 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4a 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x4a 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4c 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x4c 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4d 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x4d 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4f 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x4f 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x51 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x51 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x53 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x53 0x0 | 0.000000 | 0.000000 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x54 0x5 | 0.000000 | 0.000000 | 0x71f | CHANNEL | 0x90 | 0 | 0x2 | 0x54 0x0 | 0.000000 | 0.000000 | 0x1 | META | 0xff | 0x2f | 0x0 |
Absolute Midi is defined as its time from start, in seconds.
>>> from rmidi import MIDI, AbosluteMidi
>>> y = MIDI.parse_midi(<midi-file-path>)
>>> yabs = AbsoluteMidi.to_abs_midi(y)
>>> print(yabs)Output
| Absolute Time | Duration | Note Time | Delta Time | ETYPE | Event ID | META | LENGTH | DATA |______________________________________________________________________________________________________________________________ . . . | 0.000000 | 0.000000 | 0 | 0x0 | META | 0xff | 0x58 | 0x4 | 0x04 0x02 0x18 0x08 | 0.000000 | 0.000000 | 0 | 0x0 | META | 0xff | 0x59 | 0x2 | 0x00 0x00 | 0.000000 | 0.000000 | 0 | 0x0 | META | 0xff | 0x51 | 0x3 | 0x07 0xa1 0x20 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x79 0x00 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xc0 | 0 | 0x1 | 0x00 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x07 0x64 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x0a 0x40 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x5b 0x00 | 0.000000 | 0.000000 | 0 | 0x0 | CHANNEL | 0xb0 | 0 | 0x2 | 0x5d 0x00 | 0.000000 | 0.000000 | 0 | 0x0 | META | 0xff | 0x21 | 0x1 | 0x00 | 0.000000 | 31.649306 | 1.0666666666666667 | 0x0 | CHANNEL | 0x90 | 0 | 0x2 | 0x48 0x50 | 33.333333 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4a 0x50 | 66.666667 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4c 0x50 | 100.000000 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4d 0x50 | 133.333333 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x4f 0x50 | 166.666667 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x51 0x50 | 200.000000 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x53 0x50 | 233.333333 | 31.649306 | 1.0666666666666667 | 0x61 | CHANNEL | 0x90 | 0 | 0x2 | 0x54 0x50 | 0.000000 | 0.000000 | 0 | 0x1 | META | 0xff | 0x2f | 0x0 | *******************************************************************************************************************
rmidi.dataset.NoteSequence is similar object to that of Magenta.NoteSequence, It holds everthing in dict, whole midi file is express as python nested dictionary
>>> from rmidi.dataset import notesequence
>>> ns = NoteSequence(<midi-file-path>)
>>> print(ns)Output
[
{
"track-0": [
[
"type : meta",
"deltatime : 0",
"time : 0",
"duration : 0",
"subtype : time_sig",
"length : 4",
"data : 0x04 0x02 0x18 0x08 \n"
],
[
"type : meta",
"deltatime : 0",
"time : 0",
"duration : 0",
"subtype : key_sig",
"length : 2",
"data : 0x00 0x00 \n"
],
[
"type : meta",
"deltatime : 0",
"time : 0",
"duration : 0",
"subtype : set_tempo",
"length : 3",
"data : 0x07 0xa1 0x20 \n"
],
[
"type : cntroller",
"deltatime : 0",
"event_id : 176",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False",
"subtype : mode_messages_0"
],
[
"type : program_change",
"deltatime : 0",
"event_id : 192",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False"
],
[
"type : cntroller",
"deltatime : 0",
"event_id : 176",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False",
"subtype : main_volume"
],
[
"type : cntroller",
"deltatime : 0",
"event_id : 176",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False",
"subtype : pan"
],
[
"type : cntroller",
"deltatime : 0",
"event_id : 176",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False",
"subtype : effects_depth_0"
],
[
"type : cntroller",
"deltatime : 0",
"event_id : 176",
"time : 0",
"duaration : 0",
"pitch : None",
"velocity : None",
"is_drum : False",
"subtype : effects_depth_2"
],
[
"type : meta",
"deltatime : 0",
"time : 0",
"duration : 0",
"subtype : midi_port",
"length : 1",
"data : 0x00 \n"
],
[
"type : note_on",
"deltatime : 0",
"event_id : 144",
"time : 0.0",
"duaration : 31.649305555555554",
"pitch : 72",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 33.33333333333333",
"duaration : 31.649305555555557",
"pitch : 74",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 66.66666666666666",
"duaration : 31.649305555555557",
"pitch : 76",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 99.99999999999999",
"duaration : 31.649305555555557",
"pitch : 77",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 133.33333333333331",
"duaration : 31.649305555555543",
"pitch : 79",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 166.66666666666663",
"duaration : 31.649305555555543",
"pitch : 81",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 199.99999999999994",
"duaration : 31.649305555555543",
"pitch : 83",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 233.33333333333326",
"duaration : 31.649305555555543",
"pitch : 84",
"velocity : 80",
"is_drum : False"
],
[
"type : meta",
"deltatime : 1",
"time : 0",
"duration : 0",
"subtype : end_of_track",
"length : 0",
"data : \n"
]
]
}
]
NoteSequence object is subscriptable, you can access, any note from praticular track easily.
>>> event = ns[0][11] # this will give you the 11th event occured from 0th track
>>> event = ns[0, 11] # this to is valid in numpy styleConverts the dict to pretty string
Input
from rmidi.dataset import NoteSequence
dict_ = {0: OrderedDict([(17, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 233.33333333333326, 'duaration': 31.649305555555543, 'pitch': 84, 'velocity': 80, 'is_drum': False}), (16, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 199.99999999999994, 'duaration': 31.649305555555543, 'pitch': 83, 'velocity': 80, 'is_drum': False}), (15, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 166.66666666666663, 'duaration': 31.649305555555543, 'pitch': 81, 'velocity': 80, 'is_drum': False}), (14, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 133.33333333333331, 'duaration': 31.649305555555543, 'pitch': 79, 'velocity': 80, 'is_drum': False}), (13, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 99.99999999999999, 'duaration': 31.649305555555557, 'pitch': 77, 'velocity': 80, 'is_drum': False}), (12, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 66.66666666666666, 'duaration': 31.649305555555557, 'pitch': 76, 'velocity': 80, 'is_drum': False}), (11, {'type': 'note_on', 'deltatime': 97, 'event_id': 144, 'time': 33.33333333333333, 'duaration': 31.649305555555557, 'pitch': 74, 'velocity': 80, 'is_drum': False}), (10, {'type': 'note_on', 'deltatime': 0, 'event_id': 144, 'time': 0.0, 'duaration': 31.649305555555554, 'pitch': 72, 'velocity': 80, 'is_drum': False})])}
print(NoteSequence.tostring(dict_))
Output
[
{
"track-0": [
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 233.33333333333326",
"duaration : 31.649305555555543",
"pitch : 84",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 199.99999999999994",
"duaration : 31.649305555555543",
"pitch : 83",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 166.66666666666663",
"duaration : 31.649305555555543",
"pitch : 81",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 133.33333333333331",
"duaration : 31.649305555555543",
"pitch : 79",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 99.99999999999999",
"duaration : 31.649305555555557",
"pitch : 77",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 66.66666666666666",
"duaration : 31.649305555555557",
"pitch : 76",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 33.33333333333333",
"duaration : 31.649305555555557",
"pitch : 74",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 0",
"event_id : 144",
"time : 0.0",
"duaration : 31.649305555555554",
"pitch : 72",
"velocity : 80",
"is_drum : False"
]
]
}
]
To get just notes, i.e. just note_on and note_off event, you can call NoteSequence object as ns.notes
>>> from rmidi.dataset import NoteSequence
>>> ns = NoteSequence(<midi-file-path>)
>>> notes = ns.notes
>>> print(notes)
>>> print(ns.tostring(notes)) # to pretty printOutput
[
{
"track-0": [
[
"type : note_on",
"deltatime : 0",
"event_id : 144",
"time : 0.0",
"duaration : 31.649305555555554",
"pitch : 72",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 33.33333333333333",
"duaration : 31.649305555555557",
"pitch : 74",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 66.66666666666666",
"duaration : 31.649305555555557",
"pitch : 76",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 99.99999999999999",
"duaration : 31.649305555555557",
"pitch : 77",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 133.33333333333331",
"duaration : 31.649305555555543",
"pitch : 79",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 166.66666666666663",
"duaration : 31.649305555555543",
"pitch : 81",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 199.99999999999994",
"duaration : 31.649305555555543",
"pitch : 83",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 233.33333333333326",
"duaration : 31.649305555555543",
"pitch : 84",
"velocity : 80",
"is_drum : False"
]
]
}
]
It orders the events within track base on event attribute, order by is intended to work for attributes 'time', 'duration', 'pitch', deltatime
>>> from rmidi.dataset import NoteSequence
>>> ns = NoteSequence(filepath)
>>> ordered = ns.order_by(<attribute_name>, reverse=True)
>>> print(ordered) # Output for pitch sorted in reverseOutput
[
{
"track-0": [
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 233.33333333333326",
"duaration : 31.649305555555543",
"pitch : 84",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 199.99999999999994",
"duaration : 31.649305555555543",
"pitch : 83",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 166.66666666666663",
"duaration : 31.649305555555543",
"pitch : 81",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 133.33333333333331",
"duaration : 31.649305555555543",
"pitch : 79",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 99.99999999999999",
"duaration : 31.649305555555557",
"pitch : 77",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 66.66666666666666",
"duaration : 31.649305555555557",
"pitch : 76",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 97",
"event_id : 144",
"time : 33.33333333333333",
"duaration : 31.649305555555557",
"pitch : 74",
"velocity : 80",
"is_drum : False"
],
[
"type : note_on",
"deltatime : 0",
"event_id : 144",
"time : 0.0",
"duaration : 31.649305555555554",
"pitch : 72",
"velocity : 80",
"is_drum : False"
]
]
}
]
Convert NoteSequece to AbsoluteMidi object.
>>> from rmidi.dataset import NoteSequence
>>> ns = NoteSequence(filepath)
>>> absmidi = ns.to_abs_midi()
>>> print(type(absmidi))Output
<class 'rmidi.absolutemidi.AbsoluteMidi'>
Basic class able to generate midi from sequence, with fixed or random time associated with each event.