music21.midi.translate

Module to translate MIDI data to music21 Streams and vice versa. Note that quantization of notes takes place in the quantize() method not here.

Functions

music21.midi.translate.streamToMidiFile(inputM21: music21.stream.Stream, addStartDelay: bool = False)music21.midi.MidiFile

Converts a Stream hierarchy into a MidiFile object.

>>> s = stream.Stream()
>>> n = note.Note('g#')
>>> n.quarterLength = 0.5
>>> s.repeatAppend(n, 4)
>>> mf = midi.translate.streamToMidiFile(s)
>>> mf.tracks[0].index  # Track 0: conductor track
0
>>> len(mf.tracks[1].events)  # Track 1: music track
22

From here, you can call mf.writestr() to get the actual file info.

>>> sc = scale.PhrygianScale('g')
>>> s = stream.Stream()
>>> x=[s.append(note.Note(sc.pitchFromDegree(i % 11), quarterLength=0.25)) for i in range(60)]
>>> mf = midi.translate.streamToMidiFile(s)
>>> mf.open('/Volumes/disc/_scratch/midi.mid', 'wb')
>>> mf.write()
>>> mf.close()
music21.midi.translate.midiFileToStream(mf: music21.midi.MidiFile, inputM21=None, quantizePost=True, **keywords)

Note: this is NOT the normal way to read a MIDI file. The best way is generally:

score = converter.parse(‘path/to/file.mid’)

Convert a MidiFile object to a Stream object.

The inputM21 object can specify an existing Stream (or Stream subclass) to fill.

Keywords to control quantization: quantizePost controls whether to quantize the output. (Default: True) quarterLengthDivisors allows for overriding the default quantization units in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

>>> import os
>>> fp = common.getSourceFilePath() / 'midi' / 'testPrimitive' / 'test05.mid'
>>> mf = midi.MidiFile()
>>> mf.open(fp)
>>> mf.read()
>>> mf.close()
>>> len(mf.tracks)
1
>>> s = midi.translate.midiFileToStream(mf)
>>> s
<music21.stream.Score ...>
>>> len(s.flat.notesAndRests)
11
music21.midi.translate.assignPacketsToChannels(packets, channelByInstrument=None, channelsDynamic=None, initTrackIdToChannelMap=None)

Given a list of packets, assign each to a channel.

Do each track one at time, based on the track id.

Shift to different channels if a pitch bend is necessary.

Keep track of which channels are available. Need to insert a program change in the empty channel too, based on last instrument.

Insert pitch bend messages as well, one for start of event, one for end of event.

packets is a list of packets. channelByInstrument should be a dictionary. channelsDynamic should be a list. initTrackIdToChannelMap should be a dictionary.

music21.midi.translate.channelInstrumentData(s: music21.stream.Stream, acceptableChannelList: Optional[List[int]] = None) → Tuple[Dict[Optional[int], int], List[int]]

Read through Stream s and finding instruments in it, return a 2-tuple, the first a dictionary mapping MIDI program numbers to channel numbers, and the second, a list of unassigned channels that can be used for dynamic allocation.

Substreams without notes or rests (e.g. representing a conductor track) will not consume a channel.

Only necessarily works if prepareStreamForMidi() has been run before calling this routine.

music21.midi.translate.chordToMidiEvents(inputM21, includeDeltaTime=True)

Translates a Chord object to a list of base.DeltaTime and base.MidiEvents objects.

See noteToMidiEvents above for more details.

>>> c = chord.Chord(['c3', 'g#4', 'b5'])
>>> c.volume = volume.Volume(velocity=90)
>>> c.volume.velocityIsRelative = False
>>> eventList = midi.translate.chordToMidiEvents(c)
>>> eventList
[<MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=48, velocity=90>,
 <MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=68, velocity=90>,
 <MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=83, velocity=90>,
 <MidiEvent DeltaTime, t=1024, track=None, channel=None>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=48, velocity=0>,
 <MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=68, velocity=0>,
 <MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=83, velocity=0>]
music21.midi.translate.conductorStream(s: music21.stream.Stream)music21.stream.Part

Strip the given stream of any events that belong in a conductor track rather than in a music track, and returns a Part containing just those events, without duplicates, suitable for being a Part to turn into a conductor track.

Sets a default MetronomeMark of 120 if no MetronomeMarks are present and a TimeSignature of 4/4 if not present.

Ensures that the conductor track always sorts before other parts.

Here we purposely use nested generic streams instead of Scores, Parts, etc. to show that this still works. But you should use Score, Part, Measure instead.

>>> s = stream.Stream(id='scoreLike')
>>> p = stream.Stream(id='partLike')
>>> p.priority = -2
>>> m = stream.Stream(id='measureLike')
>>> m.append(tempo.MetronomeMark(100))
>>> m.append(note.Note('C4'))
>>> p.append(m)
>>> s.insert(0, p)
>>> conductor = midi.translate.conductorStream(s)
>>> conductor.priority
-3

The MetronomeMark is moved and a default TimeSignature is added:

>>> conductor.show('text')
{0.0} <music21.tempo.MetronomeMark Quarter=100>
{0.0} <music21.meter.TimeSignature 4/4>

The original stream still has the note:

>>> s.show('text')
{0.0} <music21.stream.Stream partLike>
    {0.0} <music21.stream.Stream measureLike>
        {0.0} <music21.note.Note C>
music21.midi.translate.durationToMidiTicks(d)

Converts a Duration object to midi ticks.

Depends on defaults.ticksPerQuarter, Returns an int. Does not use defaults.ticksAtStart

>>> n = note.Note()
>>> n.duration.type = 'half'
>>> midi.translate.durationToMidiTicks(n.duration)
2048
>>> d = duration.Duration('quarter')
>>> dReference = midi.translate.ticksToDuration(1024, inputM21DurationObject=d)
>>> dReference is d
True
>>> d.type
'quarter'
>>> d.type = '16th'
>>> d.quarterLength
0.25
>>> midi.translate.durationToMidiTicks(d)
256
music21.midi.translate.elementToMidiEventList(el: music21.base.Music21Object) → Optional[List[music21.midi.MidiEvent]]

Return a list of MidiEvents (or None) from a Music21Object, assuming that dynamics have already been applied, etc. Does not include DeltaTime objects.

Channel is set to the default, 1. Track is not set.

>>> n = note.Note('C4')
>>> midiEvents = midi.translate.elementToMidiEventList(n)
>>> midiEvents
[<MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=60, velocity=90>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=60, velocity=0>]
music21.midi.translate.filterPacketsByTrackId(packetsSrc: List[Dict[str, Any]], trackIdFilter: Optional[int] = None) → List[Dict[str, Any]]

Given a list of Packet dictionaries, return a list of only those whose trackId matches the filter.

>>> packets = [
...     {'trackId': 1, 'name': 'hello'},
...     {'trackId': 2, 'name': 'bye'},
...     {'trackId': 1, 'name': 'hi'},
... ]
>>> midi.translate.filterPacketsByTrackId(packets, 1)
[{'trackId': 1, 'name': 'hello'},
 {'trackId': 1, 'name': 'hi'}]
>>> midi.translate.filterPacketsByTrackId(packets, 2)
[{'trackId': 2, 'name': 'bye'}]

If no trackIdFilter is passed, the original list is returned:

>>> midi.translate.filterPacketsByTrackId(packets) is packets
True
music21.midi.translate.getEndEvents(mt=None, channel=1)

Returns a list of midi.MidiEvent objects found at the end of a track.

>>> midi.translate.getEndEvents(channel=2)
[<MidiEvent DeltaTime, t=1024, track=None, channel=2>,
 <MidiEvent END_OF_TRACK, t=0, track=None, channel=2, data=b''>]
music21.midi.translate.getMetaEvents(events)
music21.midi.translate.getNotesFromEvents(events: List[Tuple[int, music21.midi.MidiEvent]]) → List[Tuple[Tuple[int, music21.midi.MidiEvent], Tuple[int, music21.midi.MidiEvent]]]

Returns a list of Tuples of MIDI events that are pairs of note-on and note-off events.

music21.midi.translate.getPacketFromMidiEvent(trackId: int, offset: int, midiEvent: music21.midi.MidiEvent, obj: Optional[music21.base.Music21Object] = None, lastInstrument: Optional[music21.instrument.Instrument] = None) → Dict[str, Any]

Pack a dictionary of parameters for each event. Packets are used for sorting and configuring all note events. Includes offset, any cent shift, the midi event, and the source object.

Offset and duration values stored here are MIDI ticks, not quarter lengths.

>>> n = note.Note('C4')
>>> midiEvents = midi.translate.elementToMidiEventList(n)
>>> getPacket = midi.translate.getPacketFromMidiEvent
>>> getPacket(trackId=1, offset=0, midiEvent=midiEvents[0], obj=n)
{'trackId': 1,
 'offset': 0,
 'midiEvent': <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=60, velocity=90>,
 'obj': <music21.note.Note C>,
 'centShift': None,
 'duration': 1024,
 'lastInstrument': None}
>>> inst = instrument.Harpsichord()
>>> getPacket(trackId=1, offset=0, midiEvent=midiEvents[1], obj=n, lastInstrument=inst)
{'trackId': 1,
 'offset': 0,
 'midiEvent': <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=60, velocity=0>,
 'obj': <music21.note.Note C>,
 'centShift': None,
 'duration': 0,
 'lastInstrument': <music21.instrument.Harpsichord 'Harpsichord'>}
music21.midi.translate.getStartEvents(mt=None, channel=1, instrumentObj=None)

Returns a list of midi.MidiEvent objects found at the beginning of a track.

A MidiTrack reference can be provided via the mt parameter.

>>> midi.translate.getStartEvents()
[<MidiEvent DeltaTime, t=0, track=None, channel=1>,
 <MidiEvent SEQUENCE_TRACK_NAME, t=0, track=None, channel=1, data=b''>]
>>> midi.translate.getStartEvents(channel=2, instrumentObj=instrument.Harpsichord())
[<MidiEvent DeltaTime, t=0, track=None, channel=2>,
 <MidiEvent SEQUENCE_TRACK_NAME, t=0, track=None, channel=2, data=b'Harpsichord'>,
 <MidiEvent DeltaTime, t=0, track=None, channel=2>,
 <MidiEvent PROGRAM_CHANGE, t=0, track=None, channel=2, data=6>]
music21.midi.translate.getTimeForEvents(mt: music21.midi.MidiTrack) → List[Tuple[int, music21.midi.MidiEvent]]

Get a list of tuples of (tickTime, MidiEvent) from the events with time deltas.

music21.midi.translate.instrumentToMidiEvents(inputM21, includeDeltaTime=True, midiTrack=None, channel=1)

Converts a Instrument object to a list of MidiEvents

TODO: DOCS and TESTS

music21.midi.translate.keySignatureToMidiEvents(ks: music21.key.KeySignature, includeDeltaTime=True)

Convert a single Key or KeySignature object to a two-element list of midi events, where the first is an empty DeltaTime (unless includeDeltaTime is False) and the second is a KEY_SIGNATURE MidiEvent

>>> ks = key.KeySignature(2)
>>> ks
<music21.key.KeySignature of 2 sharps>
>>> eventList = midi.translate.keySignatureToMidiEvents(ks)
>>> eventList
[<MidiEvent DeltaTime, t=0, track=None, channel=None>,
 <MidiEvent KEY_SIGNATURE, t=0, track=None, channel=1, data=b'\x02\x00'>]
>>> k = key.Key('b-')
>>> k
<music21.key.Key of b- minor>
>>> eventList = midi.translate.keySignatureToMidiEvents(k, includeDeltaTime=False)
>>> eventList
[<MidiEvent KEY_SIGNATURE, t=0, track=None, channel=1, data=b'\xfb\x01'>]
music21.midi.translate.midiAsciiStringToBinaryString(midiFormat=1, ticksPerQuarterNote=960, tracksEventsList=None) → bytes

Convert Ascii midi data to a bytes object (formerly binary midi string).

tracksEventsList contains a list of tracks which contain also a list of events.

asciiMidiEventList = [‘0 90 27 66’, ‘0 90 3e 60’, ‘3840 80 27 00’, ‘0 80 3e 00’]

The format of one event is : ‘aa bb cc dd’:

aa = delta time to last event (integer)
bb = Midi event type
cc = Note number (hex)
dd = Velocity (integer)

Example:

>>> asciiMidiEventList = []
>>> asciiMidiEventList.append('0 90 31 15')
>>> midiTrack = []
>>> midiTrack.append(asciiMidiEventList)
>>> midiBinaryBytes = midi.translate.midiAsciiStringToBinaryString(tracksEventsList=midiTrack)
>>> midiBinaryBytes
b'MThd\x00\x00\x00\x06\x00\x01\x00\x01\x03\xc0MTrk\x00\x00\x00\x04\x00\x901\x0f'

Note that the name is from pre-Python 3. There is now in fact nothing called a “binary string” it is in fact a bytes object.

music21.midi.translate.midiEventsToChord(eventList, ticksPerQuarter=None, inputM21=None)

Creates a Chord from a list of DeltaTime and MidiEvent objects. See midiEventsToNote for details.

All DeltaTime objects except the first are ignored.

>>> mt = midi.MidiTrack(1)
>>> dt1 = midi.DeltaTime(mt)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me1.pitch = 45
>>> me1.velocity = 94
>>> dt2 = midi.DeltaTime(mt)
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me2.pitch = 46
>>> me2.velocity = 94
>>> dt3 = midi.DeltaTime(mt)
>>> dt3.time = 2048
>>> me3 = midi.MidiEvent(mt)
>>> me3.type = midi.ChannelVoiceMessages.NOTE_OFF
>>> me3.pitch = 45
>>> me3.velocity = 0
>>> dt4 = midi.DeltaTime(mt)
>>> me4 = midi.MidiEvent(mt)
>>> me4.type = midi.ChannelVoiceMessages.NOTE_OFF
>>> me4.pitch = 46
>>> me4.velocity = 0
>>> c = midi.translate.midiEventsToChord([dt1, me1, dt2, me2, dt3, me3, dt4, me4])
>>> c
<music21.chord.Chord A2 B-2>
>>> c.duration.quarterLength
2.0
music21.midi.translate.midiEventsToInstrument(eventList)

Convert a single MIDI event into a music21 Instrument object.

music21.midi.translate.midiEventsToKey(eventList)music21.key.Key

Convert a single MIDI event into a KeySignature object.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.MetaEvents.KEY_SIGNATURE
>>> me1.data = midi.putNumbersAsList([2, 0])  # d major
>>> ks = midi.translate.midiEventsToKey(me1)
>>> ks
<music21.key.Key of D major>
>>> ks.mode
'major'
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.MetaEvents.KEY_SIGNATURE
>>> me2.data = midi.putNumbersAsList([-2, 1])  # g minor
>>> me2.data
b'\xfe\x01'
>>> midi.getNumbersAsList(me2.data)
[254, 1]
>>> ks = midi.translate.midiEventsToKey(me2)
>>> ks
<music21.key.Key of g minor>
>>> ks.sharps
-2
>>> ks.mode
'minor'
music21.midi.translate.midiEventsToNote(eventList, ticksPerQuarter=None, inputM21=None)

Convert from a list of midi.DeltaTime and midi.MidiEvent objects to a music21 Note.

The list can be presented in one of two forms:

[deltaTime1, midiEvent1, deltaTime2, midiEvent2]

or

[(deltaTime1, midiEvent1), (deltaTime2, midiEvent2)]

It is assumed, but not checked, that midiEvent2 is an appropriate Note_Off command. Thus, only three elements are really needed.

The inputM21 parameter can be a Note or None; in the case of None, a Note object is created. In either case it returns a Note (N.B.: this will change soon so that None will be returned if inputM21 is given. This will match the behavior of other translate objects).

N.B. this takes in a list of music21 MidiEvent objects so see […] on how to convert raw MIDI data to MidiEvent objects

In this example, we start a NOTE_ON event at offset 1.0 that lasts for 2.0 quarter notes until we send a zero-velocity NOTE_ON (=NOTE_OFF) event for the same pitch.

>>> mt = midi.MidiTrack(1)
>>> dt1 = midi.DeltaTime(mt)
>>> dt1.time = 1024
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me1.pitch = 45
>>> me1.velocity = 94
>>> dt2 = midi.DeltaTime(mt)
>>> dt2.time = 2048
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.ChannelVoiceMessages.NOTE_ON
>>> me2.pitch = 45
>>> me2.velocity = 0
>>> n = midi.translate.midiEventsToNote([dt1, me1, dt2, me2])
>>> n.pitch
<music21.pitch.Pitch A2>
>>> n.duration.quarterLength
1.0
>>> n.volume.velocity
94

An inputM21 object can be given in which case it’s set.

>>> m = note.Note()
>>> dummy = midi.translate.midiEventsToNote([dt1, me1, dt2, me2], inputM21=m)
>>> m.pitch
<music21.pitch.Pitch A2>
>>> m.duration.quarterLength
1.0
>>> m.volume.velocity
94
music21.midi.translate.midiEventsToTempo(eventList)

Convert a single MIDI event into a music21 Tempo object.

TODO: Need Tests

music21.midi.translate.midiEventsToTimeSignature(eventList)

Convert a single MIDI event into a music21 TimeSignature object.

>>> mt = midi.MidiTrack(1)
>>> me1 = midi.MidiEvent(mt)
>>> me1.type = midi.MetaEvents.TIME_SIGNATURE
>>> me1.data = midi.putNumbersAsList([3, 1, 24, 8])  # 3/2 time
>>> ts = midi.translate.midiEventsToTimeSignature(me1)
>>> ts
<music21.meter.TimeSignature 3/2>
>>> me2 = midi.MidiEvent(mt)
>>> me2.type = midi.MetaEvents.TIME_SIGNATURE
>>> me2.data = midi.putNumbersAsList([3, 4])  # 3/16 time
>>> ts = midi.translate.midiEventsToTimeSignature(me2)
>>> ts
<music21.meter.TimeSignature 3/16>
music21.midi.translate.midiFilePathToStream(filePath, inputM21=None, **keywords)

Used by music21.converter:

Take in a file path (name of a file on disk) and using midiFileToStream,

return a Score object (or if inputM21 is passed in, use that object instead).

Keywords to control quantization: quantizePost controls whether to quantize the output. (Default: True) quarterLengthDivisors allows for overriding the default quantization units in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

>>> fp = '/Users/test/music21/midi/testPrimitive/test05.mid'
>>> streamScore = midi.translate.midiFilePathToStream(fp)
>>> streamScore
<music21.stream.Score ...>
music21.midi.translate.midiStringToStream(strData, **keywords)

Convert a string of binary midi data to a Music21 stream.Score object.

Keywords to control quantization: quantizePost controls whether to quantize the output. (Default: True) quarterLengthDivisors allows for overriding the default quantization units in defaults.quantizationQuarterLengthDivisors. (Default: (4, 3)).

N.B. – this has been somewhat problematic, so use at your own risk.

>>> midiBinStr = (b'MThd\x00\x00\x00\x06\x00\x01\x00\x01\x04\x00'
...               + b'MTrk\x00\x00\x00\x16\x00\xff\x03\x00\x00\xe0\x00@\x00'
...               + b'\x90CZ\x88\x00\x80C\x00\x88\x00\xff/\x00')
>>> s = midi.translate.midiStringToStream(midiBinStr)
>>> s.show('text')
{0.0} <music21.stream.Part ...>
    {0.0} <music21.note.Note G>
music21.midi.translate.midiTrackToStream(mt, ticksPerQuarter=None, quantizePost=True, inputM21=None, **keywords)music21.stream.Part

Note that quantization takes place in stream.py since it’s useful not just for MIDI.

>>> fp = common.getSourceFilePath() / 'midi' / 'testPrimitive' / 'test05.mid'
>>> mf = midi.MidiFile()
>>> mf.open(fp)
>>> mf.read()
>>> mf.close()
>>> mf
<music21.midi.MidiFile 1 track>
>>> len(mf.tracks)
1
>>> mt = mf.tracks[0]
>>> mt
<music21.midi.MidiTrack 0 -- 56 events>
>>> mt.events
[<MidiEvent DeltaTime...>,
 <MidiEvent SEQUENCE_TRACK_NAME...>,
 <MidiEvent DeltaTime...>,
 <MidiEvent NOTE_ON, t=0, track=0, channel=1, pitch=36, velocity=90>,
 ...]
>>> p = midi.translate.midiTrackToStream(mt)
>>> p
<music21.stream.Part ...>
>>> len(p.notesAndRests)
11
>>> p.notes[0].pitch.midi
36
>>> p.notes[0].volume.velocity
90

Note that the output Part has not yet had measures made, nor does it have a TimeSignature yet.

>>> p.show('text')
{0.0} <music21.instrument.Instrument ''>
{0.0} <music21.note.Note C>
{1.0} <music21.note.Rest rest>
{2.0} <music21.chord.Chord F3 G#4 C5>
{3.0} <music21.note.Rest rest>
{4.5} <music21.note.Note B->
...
music21.midi.translate.midiTracksToStreams(midiTracks: List[music21.midi.MidiTrack], ticksPerQuarter=None, quantizePost=True, inputM21: music21.stream.Score = None, **keywords) → <music21.stream.Stream 0x10a5b4580>

Given a list of midiTracks, populate either a new stream.Score or inputM21 with a Part for each track.

music21.midi.translate.music21ObjectToMidiFile(music21Object, *, addStartDelay=False)music21.midi.MidiFile

Either calls streamToMidiFile on the music21Object or puts a copy of that object into a Stream (so as not to change activeSites, etc.) and calls streamToMidiFile on that object.

music21.midi.translate.noteToMidiEvents(inputM21, includeDeltaTime=True, channel=1)

Translate a music21 Note to a list of four MIDI events – the DeltaTime for the start of the note (0), the NOTE_ON event, the DeltaTime to the end of the note, and the NOTE_OFF event.

If includeDeltaTime is not True then the DeltaTime events aren’t returned, thus only two events are returned.

The initial deltaTime object is always 0. It will be changed when processing Notes from a Stream.

The channel can be specified, otherwise channel 1 is assumed.

>>> n1 = note.Note('C#4')
>>> eventList = midi.translate.noteToMidiEvents(n1)
>>> eventList
[<MidiEvent DeltaTime, t=0, track=None, channel=1>,
 <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=61, velocity=90>,
 <MidiEvent DeltaTime, t=1024, track=None, channel=1>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=61, velocity=0>]
>>> n1.duration.quarterLength = 2.5
>>> eventList = midi.translate.noteToMidiEvents(n1)
>>> eventList
[<MidiEvent DeltaTime, t=0, track=None, channel=1>,
 <MidiEvent NOTE_ON, t=0, track=None, channel=1, pitch=61, velocity=90>,
 <MidiEvent DeltaTime, t=2560, track=None, channel=1>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=1, pitch=61, velocity=0>]

Omitting DeltaTimes:

>>> eventList2 = midi.translate.noteToMidiEvents(n1, includeDeltaTime=False, channel=9)
>>> eventList2
[<MidiEvent NOTE_ON, t=0, track=None, channel=9, pitch=61, velocity=90>,
 <MidiEvent NOTE_OFF, t=0, track=None, channel=9, pitch=61, velocity=0>]
music21.midi.translate.offsetToMidiTicks(o, addStartDelay=False)

Helper function to convert a music21 offset value to MIDI ticks, depends on defaults.ticksPerQuarter and defaults.ticksAtStart.

Returns an int.

>>> defaults.ticksPerQuarter
1024
>>> defaults.ticksAtStart
1024
>>> midi.translate.offsetToMidiTicks(0)
0
>>> midi.translate.offsetToMidiTicks(0, addStartDelay=True)
1024
>>> midi.translate.offsetToMidiTicks(1)
1024
>>> midi.translate.offsetToMidiTicks(20.5)
20992
music21.midi.translate.packetStorageFromSubstreamList(substreamList: List[music21.stream.Part], *, addStartDelay=False) → Dict[int, Dict[str, Any]]

Make a dictionary of raw packets and the initial instrument for each subStream.

If the first Part in the list of parts is empty then a new Conductor object will be given as the instrument.

>>> s = stream.Score()
>>> p = stream.Part()
>>> m = stream.Measure(number=1)
>>> m.append(tempo.MetronomeMark(100))
>>> m.append(instrument.Oboe())
>>> m.append(note.Note('C4', type='whole'))  # MIDI 60
>>> p.append(m)
>>> s.append(p)
>>> sOut = midi.translate.prepareStreamForMidi(s)
>>> partList = list(sOut.parts)
>>> packetStorage = midi.translate.packetStorageFromSubstreamList(partList)
>>> list(sorted(packetStorage.keys()))
[0, 1]
>>> list(sorted(packetStorage[0].keys()))
['initInstrument', 'rawPackets']
>>> from pprint import pprint
>>> pprint(packetStorage)
{0: {'initInstrument': <music21.instrument.Conductor 'Conductor'>,
     'rawPackets': [{'centShift': None,
                     'duration': 0,
                     'lastInstrument': None,
                     'midiEvent': <MidiEvent SET_TEMPO, t=0, track=None, channel=1, ...>,
                     'obj': <music21.tempo.MetronomeMark Quarter=100>,
                     'offset': 0,
                     'trackId': 0},
                    {'centShift': None,
                     'duration': 0,
                     'lastInstrument': None,
                     'midiEvent': <MidiEvent TIME_SIGNATURE, t=0, ...>,
                     'obj': <music21.meter.TimeSignature 4/4>,
                     'offset': 0,
                     'trackId': 0}]},
 1: {'initInstrument': <music21.instrument.Oboe 'Oboe'>,
     'rawPackets': [{'centShift': None,
                     'duration': 0,
                     'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                     'midiEvent': <MidiEvent PROGRAM_CHANGE,
                                      t=0, track=None, channel=1, data=68>,
                     'obj': <music21.instrument.Oboe 'Oboe'>,
                     'offset': 0,
                     'trackId': 1},
                    {'centShift': None,
                     'duration': 4096,
                     'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                     'midiEvent': <MidiEvent NOTE_ON, t=0,
                                      track=None, channel=1, pitch=60, velocity=90>,
                     'obj': <music21.note.Note C>,
                     'offset': 0,
                     'trackId': 1},
                    {'centShift': None,
                     'duration': 0,
                     'lastInstrument': <music21.instrument.Oboe 'Oboe'>,
                     'midiEvent': <MidiEvent NOTE_OFF, t=0,
                                       track=None, channel=1, pitch=60, velocity=0>,
                     'obj': <music21.note.Note C>,
                     'offset': 4096,
                     'trackId': 1}]}}
music21.midi.translate.packetsToDeltaSeparatedEvents(packets: List[Dict[str, Any]], midiTrack: music21.midi.MidiTrack) → List[music21.midi.MidiEvent]

Given a list of packets (which already contain MidiEvent objects) return a list of those Events with proper delta times between them.

At this stage MIDI event objects have been created. The key process here is finding the adjacent time between events and adding DeltaTime events before each MIDI event.

Delta time channel values are derived from the previous midi event.

music21.midi.translate.packetsToMidiTrack(packets, trackId=1, channel=1, instrumentObj=None)

Given packets already allocated with channel and/or instrument assignments, place these in a MidiTrack.

Note that all packets can be sent; only those with matching trackIds will be collected into the resulting track

The channel defines the channel that startEvents and endEvents will be assigned to

Use streamToPackets to convert the Stream to the packets

music21.midi.translate.prepareStreamForMidi(s)music21.stream.Stream

Given a score, prepare it for MIDI processing, and return a new Stream:

  1. Expand repeats.

2. Make changes that will let us later create a conductor (tempo) track by placing MetronomeMark, TimeSignature, and KeySignature objects into a new Part, and remove them from other parts.

  1. Ensure that the resulting Stream always has part-like substreams.

Note: will make a deepcopy() of the stream.

>>> s = stream.Score()
>>> p = stream.Part()
>>> m = stream.Measure(number=1)
>>> m.append(tempo.MetronomeMark(100))
>>> m.append(note.Note('C4', type='whole'))  # MIDI 60
>>> p.append(m)
>>> s.append(p)
>>> sOut = midi.translate.prepareStreamForMidi(s)
>>> sOut.show('text')
{0.0} <music21.stream.Part 0x10b0439a0>
    {0.0} <music21.tempo.MetronomeMark Quarter=100>
    {0.0} <music21.meter.TimeSignature 4/4>
{0.0} <music21.stream.Part 0x10b043c10>
    {0.0} <music21.stream.Measure 1 offset=0.0>
        {0.0} <music21.note.Note C>
music21.midi.translate.streamHierarchyToMidiTracks(inputM21, *, acceptableChannelList=None, addStartDelay=False)

Given a Stream, Score, Part, etc., that may have substreams (i.e., a hierarchy), return a list of MidiTrack objects.

acceptableChannelList is a list of MIDI Channel numbers that can be used or None. If None, then 1-9, 11-16 are used (10 being reserved for percussion).

Called by streamToMidiFile()

The process:

  1. makes a deepcopy of the Stream (Developer TODO: could this be done with a shallow copy? Not if ties are stripped and volume realized.)

  2. we make a list of all instruments that are being used in the piece.

Changed in v.6 – acceptableChannelList is keyword only. addStartDelay is new. Changed in v.6.5 – Track 0 (tempo/conductor track) always exported.

music21.midi.translate.streamToPackets(s: music21.stream.Stream, trackId: int = 1, addStartDelay: bool = False) → List[Dict[str, Any]]

Convert a (flattened, sorted) Stream to packets.

This assumes that the Stream has already been flattened, ties have been stripped, and instruments, if necessary, have been added.

In converting from a Stream to MIDI, this is called first, resulting in a collection of packets by offset. Then, packets to events is called.

music21.midi.translate.tempoToMidiEvents(tempoIndication, includeDeltaTime=True)

Given any TempoIndication, convert it to list of MidiEvent objects that signifies a MIDI tempo indication.

>>> mm = tempo.MetronomeMark(number=90)
>>> events = midi.translate.tempoToMidiEvents(mm)
>>> events
[<MidiEvent DeltaTime...>, <MidiEvent SET_TEMPO...>]
>>> len(events)
2
>>> events[0]
<MidiEvent DeltaTime, t=0, track=None, channel=None>
>>> evt1 = events[1]
>>> evt1
<MidiEvent SET_TEMPO, t=0, track=None, channel=1, data=b'\n,+'>
>>> evt1.data
b'\n,+'
>>> microSecondsPerQuarterNote = midi.getNumber(evt1.data, len(evt1.data))[0]
>>> microSecondsPerQuarterNote
666667
>>> round(60_000_000 / microSecondsPerQuarterNote, 1)
90.0

If includeDeltaTime is False then the DeltaTime object is omitted:

>>> midi.translate.tempoToMidiEvents(mm, includeDeltaTime=False)
[<MidiEvent SET_TEMPO...>]

Test round-trip. Note that for pure tempo numbers, by default we create a text name if there’s an appropriate one:

>>> midi.translate.midiEventsToTempo(events)
<music21.tempo.MetronomeMark maestoso Quarter=90.0>
music21.midi.translate.ticksToDuration(ticks, ticksPerQuarter=None, inputM21DurationObject=None)

Converts a number of MIDI Ticks to a music21 duration.Duration() object.

Optional parameters include ticksPerQuarter – in case something other than the default.ticksPerQuarter (1024) is used in this file. And it can take a Duration object to modify, specified as inputM21DurationObject

>>> d = midi.translate.ticksToDuration(1024)
>>> d
<music21.duration.Duration 1.0>
>>> d.type
'quarter'
>>> n = note.Note()
>>> midi.translate.ticksToDuration(3072, inputM21DurationObject=n.duration)
<music21.duration.Duration 3.0>
>>> n.duration.type
'half'
>>> n.duration.dots
1

More complex rhythms can also be set automatically:

>>> d2 = duration.Duration()
>>> d2reference = midi.translate.ticksToDuration(1200, inputM21DurationObject=d2)
>>> d2 is d2reference
True
>>> d2.quarterLength
1.171875
>>> d2.type
'complex'
>>> d2.components
(DurationTuple(type='quarter', dots=0, quarterLength=1.0),
 DurationTuple(type='32nd', dots=0, quarterLength=0.125),
 DurationTuple(type='128th', dots=1, quarterLength=0.046875))
>>> d2.components[2].type
'128th'
>>> d2.components[2].dots
1
music21.midi.translate.timeSignatureToMidiEvents(ts, includeDeltaTime=True)

Translate a TimeSignature to a pair of events: a DeltaTime and a MidiEvent TIME_SIGNATURE.

Returns a two-element list

>>> ts = meter.TimeSignature('5/4')
>>> eventList = midi.translate.timeSignatureToMidiEvents(ts)
>>> eventList[0]
<MidiEvent DeltaTime, t=0, track=None, channel=None>
>>> eventList[1]
<MidiEvent TIME_SIGNATURE, t=0, track=None, channel=1, data=b'\x05\x02\x18\x08'>
music21.midi.translate.updatePacketStorageWithChannelInfo(packetStorage: Dict[int, Dict[str, Any]], channelByInstrument: Dict[Optional[int], int]) → None

Take the packetStorage dictionary and using information from ‘initInstrument’ and channelByInstrument, add an ‘initChannel’ key to each packetStorage bundle and to each rawPacket in the bundle[‘rawPackets’]