Why Mido?¶
Messages as Objects¶
Working with MIDI messages by manipulating the bytes is painful:
NOTE_OFF = 0x80
NOTE_ON = 0x90
...
message = device.read() # Returns [0x92, 0x40, 0x42]
status_byte = message[0]
if status_byte & 0xf0 in [NOTE_ON, NOTE_OFF]:
is_note_on == status_byte & 0x10
if is_note_on:
message_type = 'note_on'
else:
message_type = 'note_off'
channel = message[0] & 0x0f
print('Got {} on channel {}'.format(message_type, channel))
This doesn’t look much like Python! You could make some utility functions on top of this to make it a little bit better, but it won’t get you far.
With Mido, you can instead do:
message = port.receive()
if message.type in ['note_on', 'note_off']:
print('Got {} on channel {}'.format(message.type, message.channel))
Type and Value Checking¶
Working directly with the bytes is also error prone. While MIDI data bytes have a valid range of 0..127, the size of Python integers is only limited by how much memory is available. If you make a mistake in your computation of a data value, it could easily travel around undetected until it blows up some seemingly unrelated part of your system. These kinds of errors are tricky to track down.
Mido messages come with type and value checking built in. This happens when you assign an out of range value to an attribute:
>>> n = mido.Message('note_on')
>>> n.channel = 2092389483249829834
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./mido/messages.py", line 327, in __setattr__
ret = check(value)
File "./mido/messages.py", line 128, in check_channel
raise ValueError('channel must be in range 0..15')
ValueError: channel must be in range 0..15
and when you pass some nonsense as a keyword argument to the constructor or the copy() method:
>>> n.copy(note=['This', 'is', 'wrong'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "./mido/messages.py", line 316, in copy
return Message(self.type, **args)
File "./mido/messages.py", line 290, in __init__
setattr(self, name, value)
File "./mido/messages.py", line 327, in __setattr__
ret = check(value)
File "./mido/messages.py", line 181, in check_databyte
raise TypeError('data byte must be an integer')
TypeError: data byte must be an integer
This means that a Mido message object is always a valid MIDI message.