Objects and tools for processing MIDI data. Converts from MIDI files to MidiEvent, MidiTrack, and MidiFile objects, and vice-versa.

Further conversion to-and-from MidiEvent/MidiTrack/MidiFile and music21 Stream, Note, etc., objects takes place in music21.midi.translate.

This module uses routines from Will Ware’s public domain library from 2001 see



Convert a char into its binary representation. Useful for debugging.

>>> midi.charToBinary('a')
music21.midi.getNumber(midiStr, length)

Return the value of a string byte or bytes if length > 1 from an 8-bit string or (PY3) bytes object

Then, return the remaining string or bytes object

The length is the number of chars to read. This will sum a length greater than 1 if desired.

Note that MIDI uses big-endian for everything. This is the inverse of Python’s chr() function.

>>> midi.getNumber('test', 0)
(0, 'test')
>>> midi.getNumber('test', 2)
(29797, 'st')
>>> midi.getNumber('test', 4)
(1952805748, '')

Translate each char into a number, return in a list. Used for reading data messages where each byte encodes a different discrete value.

>>> midi.getNumbersAsList('\x00\x00\x00\x03')
[0, 0, 0, 3]

Given a string of data, strip off a the first character, or all high-byte characters terminating with one whose ord() function is < 0x80. Thus a variable number of bytes might be read.

After finding the appropriate termination, return the remaining string.

This is necessary as DeltaTime times are given with variable size, and thus may be if different numbers of characters are used.

(The ellipses below are just to make the doctests work on both Python 2 and Python 3 (where the output is in bytes).)

>>> midi.getVariableLengthNumber('A-u')
(65, ...'-u')
>>> midi.getVariableLengthNumber('-u')
(45, ...'u')
>>> midi.getVariableLengthNumber('u')
(117, ...'')
>>> midi.getVariableLengthNumber('test')
(116, ...'est')
>>> midi.getVariableLengthNumber('E@-E')
(69, ...'@-E')
>>> midi.getVariableLengthNumber('@-E')
(64, ...'-E')
>>> midi.getVariableLengthNumber('-E')
(45, ...'E')
>>> midi.getVariableLengthNumber('E')
(69, ...'')

Test that variable length characters work:

>>> midi.getVariableLengthNumber(b'\xff\x7f')
(16383, ...'')
>>> midi.getVariableLengthNumber('中xy')
(210638584, ...'y')

If no low-byte character is encoded, raises an IndexError

>>> midi.getVariableLengthNumber('中国')
Traceback (most recent call last):
IndexError: ...index out of range

Convert a list of integers into a hex string, suitable for testing MIDI encoding.

>>> # note on, middle c, 120 velocity
>>> midi.intsToHexString([144, 60, 120])
music21.midi.putNumber(num, length)

Put a single number as a hex number at the end of a string length bytes long.

>>> midi.putNumber(3, 4)
>>> midi.putNumber(0, 1)

Translate a list of numbers (0-255) into a bytestring. Used for encoding data messages where each byte encodes a different discrete value.

>>> midi.putNumbersAsList([0, 0, 0, 3])

If a number is < 0 then it wraps around from the top.

>>> midi.putNumbersAsList([0, 0, 0, -3])
>>> midi.putNumbersAsList([0, 0, 0, -1])

A number > 255 is an exception:

>>> midi.putNumbersAsList([256])
Traceback (most recent call last):
music21.midi.MidiException: Cannot place a number > 255 in a list: 256
>>> midi.putVariableLengthNumber(4)
>>> midi.putVariableLengthNumber(127)
>>> midi.putVariableLengthNumber(0)
>>> midi.putVariableLengthNumber(1024)
>>> midi.putVariableLengthNumber(8192)
>>> midi.putVariableLengthNumber(16383)
>>> midi.putVariableLengthNumber(-1)
Traceback (most recent call last):
music21.midi.MidiException: cannot putVariableLengthNumber() when number is negative: -1


class music21.midi.DeltaTime(track, time=None, channel=None)

A MidiEvent subclass that stores the time change (in ticks) since the start or since the last MidiEvent.

Pairs of DeltaTime and MidiEvent objects are the basic presentation of temporal data.

The track argument must be a MidiTrack object.

Time values are in integers, representing ticks.

The channel attribute, inherited from MidiEvent is not used and set to None unless overridden (don’t!).

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.time = 380
>>> dt
<MidiEvent DeltaTime, t=380, track=1, channel=None>

DeltaTime bases

DeltaTime read/write properties

Read/write properties inherited from MidiEvent:

DeltaTime methods


Methods inherited from MidiEvent:


class music21.midi.Enumeration(enumList=None)

Utility object for defining binary MIDI message constants.

Enumeration methods



class music21.midi.MidiEvent(track, type=None, time=None, channel=None)

A model of a MIDI event, including note-on, note-off, program change, controller change, any many others.

MidiEvent objects are paired (preceded) by DeltaTime objects in the list of events in a MidiTrack object.

The track argument must be a MidiTrack object.

The type attribute is a string representation of a Midi event from the channelVoiceMessages or metaEvents definitions.

The channel attribute is an integer channel id, from 1 to 16.

The time attribute is an integer duration of the event in ticks. This value can be zero. This value is not essential, as ultimate time positioning is determined by DeltaTime objects.

The pitch attribute is only defined for note-on and note-off messages. The attribute stores an integer representation (0-127, with 60 = middle C).

The velocity attribute is only defined for note-on and note-off messages. The attribute stores an integer representation (0-127). A note-on message with velocity 0 is generally assumed to be the same as a note-off message.

The data attribute is used for storing other messages, such as SEQUENCE_TRACK_NAME string values.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = "NOTE_ON"
>>> = 3
>>> me1.time = 200
>>> me1.pitch = 60
>>> me1.velocity = 120
>>> me1
<MidiEvent NOTE_ON, t=200, track=1, channel=3, pitch=60, velocity=120>
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = "SEQUENCE_TRACK_NAME"
>>> me2.time = 0
>>> = 'guitar'
>>> me2
<MidiEvent SEQUENCE_TRACK_NAME, t=0, track=1, channel=None, data=b'guitar'>

MidiEvent read/write properties

MidiEvent methods


Return a set of bytes for this MIDI event.


Return a boolean if this is a DeltaTime subclass.

>>> mt = midi.MidiTrack(1)
>>> dt = midi.DeltaTime(mt)
>>> dt.isDeltaTime()

Return a boolean if this is should be interpreted as a note-off message, either as a real note-off or as a note-on with zero velocity.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = "NOTE_OFF"
>>> me1.isNoteOn()
>>> me1.isNoteOff()
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = "NOTE_ON"
>>> me2.velocity = 0
>>> me2.isNoteOn()
>>> me2.isNoteOff()

Return a boolean if this is a note-on message and velocity is not zero.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = "NOTE_ON"
>>> me1.velocity = 120
>>> me1.isNoteOn()
>>> me1.isNoteOff()

Returns True if other is a MIDI event that specifies a note-off message for this message. That is, this event is a NOTE_ON message, and the other is a NOTE_OFF message for this pitch on this channel. Otherwise returns False

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = "NOTE_ON"
>>> me1.velocity = 120
>>> me1.pitch = 60
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = "NOTE_ON"
>>> me2.velocity = 0
>>> me2.pitch = 60
>>> me1.matchedNoteOff(me2)
>>> me2.pitch = 61
>>> me1.matchedNoteOff(me2)
>>> me2.type = "NOTE_OFF"
>>> me1.matchedNoteOff(me2)
>>> me2.pitch = 60
>>> me1.matchedNoteOff(me2)
>>> = 12
>>> me1.matchedNoteOff(me2)
False, midiStr)

Parse the string that is given and take the beginning section and convert it into data for this event and return the now truncated string.

The time value is the number of ticks into the Track at which this event happens. This is derived from reading data the level of the track.

TODO: These instructions are inadequate.

>>> # all note-on messages (144-159) can be found
>>> 145 & 0xF0 # testing message type extraction
>>> 146 & 0xF0 # testing message type extraction
>>> (144 & 0x0F) + 1 # getting the channel
>>> (159 & 0x0F) + 1 # getting the channel
MidiEvent.setPitchBend(cents, bendRange=2)
Treat this event as a pitch bend value, and set the ._parameter1 and
._parameter2 fields appropriately given a specified bend value in cents.

The bendRange parameter gives the number of half steps in the bend range.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.setPitchBend(50)
>>> me1._parameter1, me1._parameter2
(0, 80)
>>> me1.setPitchBend(100)
>>> me1._parameter1, me1._parameter2
(0, 96)
>>> me1.setPitchBend(200)
>>> me1._parameter1, me1._parameter2
(127, 127)
>>> me1.setPitchBend(-50)
>>> me1._parameter1, me1._parameter2
(0, 48)
>>> me1.setPitchBend(-100)
>>> me1._parameter1, me1._parameter2
(0, 32)


class music21.midi.MidiFile

Low-level MIDI file writing, emulating methods from normal Python files.

The ticksPerQuarterNote attribute must be set before writing. 1024 is a common value.

This object is returned by some properties for directly writing files of midi representations.

MidiFile methods


Close the file., attrib=’rb’)

Open a MIDI file path for reading or writing.

For writing to a MIDI file, attrib should be “wb”.


Assign a file-like object, such as those provided by StringIO, as an open file object.

>>> from music21.ext.six import StringIO
>>> fileLikeOpen = StringIO()
>>> mf = midi.MidiFile()
>>> mf.openFileLike(fileLikeOpen)
>>> mf.close()

Read and parse MIDI data stored in a file.


Read and parse MIDI data as a string, putting the data in .ticksPerQuarterNote and a list of MidiTrack objects in the attribute .tracks.


Write MIDI data as a file to the file opened with .open().


Convert the information in self.ticksPerQuarterNote into MIDI data header and return it as a string.


Generate the MIDI data header and convert the list of MidiTrack objects in self.tracks into MIDI data and return it as a string.


class music21.midi.MidiTrack(index)

A MIDI Track. Each track contains a list of MidiChannel objects, one for each channel.

All events are stored in the events list, in order.

An index is an integer identifier for this object.

TODO: Better Docs

>>> mt = midi.MidiTrack(0)

MidiTrack methods


returns a string of midi-data from the .events in the object.


Get all channels used in this Track.


Get all unique program changes used in this Track, sorted.


Return True/False if this track has any note-on/note-off pairs defined.

Read as much of the string (representing midi data) as necessary; return the remaining string for reassignment and further processing.

The string should begin with MTrk, specifying a Midi Track

Creates and stores DeltaTime and MidiEvent objects.


Set the channel of all events in this Track.


We may attach events to this track before setting their track parameter. This method will move through all events and set their track to this track.