madmom.utils.midi¶
This module contains MIDI functionality.
Almost all code is taken from Giles Hall’s python-midi package: https://github.com/vishnubob/python-midi
It combines the complete package in a single file, to make it easier to distribute. Most notable changes are MIDITrack and MIDIFile classes which handle all data i/o and provide a interface which allows to read/display all notes as simple numpy arrays. Also, the EventRegistry is handled differently.
The last merged commit is 3053fefe.
Since then the following commits have been added functionality-wise:
- 0964c0b (prevent multiple tick conversions)
- c43bf37 (add pitch and value properties to AfterTouchEvent)
- 40111c6 (add 0x08 MetaEvent: ProgramNameEvent)
- 43de818 (handle unknown MIDI meta events gracefully)
Additionally, the module has been updated to work with Python3.
The MIT License (MIT) Copyright (c) 2013 Giles F. Hall
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
madmom.utils.midi.
read_variable_length
(data)[source]¶ Read a variable length variable from the given data.
Parameters: data : bytearray
Data of variable length.
Returns: length : int
Length in bytes.
-
madmom.utils.midi.
write_variable_length
(value)[source]¶ Write a variable length variable.
Parameters: value : bytearray
Value to be encoded as a variable of variable length.
Returns: bytearray
Variable with variable length.
-
class
madmom.utils.midi.
EventRegistry
[source]¶ Class for registering Events.
Event classes should be registered manually by calling EventRegistry.register_event(EventClass) after the class definition.
Normal events are registered in the events dictionary and use the event’s status_msg as a key; meta events are registered in the meta_events dictionary and use their meta_command as key.
-
class
madmom.utils.midi.
NoteEvent
(**kwargs)[source]¶ NoteEvent is a special subclass of Event that is not meant to be used as a concrete class. It defines the generalities of NoteOn and NoteOff events.
-
pitch
¶ Pitch of the note event.
-
velocity
¶ Velocity of the note event.
-
-
class
madmom.utils.midi.
AfterTouchEvent
(**kwargs)[source]¶ After Touch Event.
-
pitch
¶ Pitch of the after touch event.
-
value
¶ Value of the after touch event.
-
-
class
madmom.utils.midi.
ControlChangeEvent
(**kwargs)[source]¶ Control Change Event.
-
control
¶ Control ID.
-
value
¶ Value of the controller.
-
-
class
madmom.utils.midi.
ProgramChangeEvent
(**kwargs)[source]¶ Program Change Event.
-
value
¶ Value of the Program Change Event.
-
-
class
madmom.utils.midi.
ChannelAfterTouchEvent
(**kwargs)[source]¶ Channel After Touch Event.
-
value
¶ Value of the Channel After Touch Event.
-
-
class
madmom.utils.midi.
PitchWheelEvent
(**kwargs)[source]¶ Pitch Wheel Event.
-
pitch
¶ Pitch of the Pitch Wheel Event.
-
-
class
madmom.utils.midi.
MetaEvent
(**kwargs)[source]¶ MetaEvent is a special subclass of Event that is not meant to be used as a concrete class. It defines a subset of Events known as the Meta events.
-
class
madmom.utils.midi.
UnknownMetaEvent
(**kwargs)[source]¶ Unknown Meta Event.
Parameters: meta_command : int
Value of the meta command.
-
class
madmom.utils.midi.
SetTempoEvent
(**kwargs)[source]¶ Set Tempo Event.
-
microseconds_per_quarter_note
¶ Microseconds per quarter note.
-
-
class
madmom.utils.midi.
TimeSignatureEvent
(**kwargs)[source]¶ Time Signature Event.
-
numerator
¶ Numerator of the time signature.
-
denominator
¶ Denominator of the time signature.
-
metronome
¶ Metronome.
-
thirty_seconds
¶ Thirty-seconds of the time signature.
-
-
class
madmom.utils.midi.
KeySignatureEvent
(**kwargs)[source]¶ Key Signature Event.
-
alternatives
¶ Alternatives of the key signature.
-
minor
¶ Major / minor.
-
-
class
madmom.utils.midi.
MIDITrack
(events=None)[source]¶ MIDI Track.
Parameters: events : list
MIDI events.
Notes
The events must be sorted. Consider using from_notes() method.
Examples
Create a MIDI track from a list of events. Please note that the events must be sorted.
>>> e1 = NoteOnEvent(tick=100, pitch=50, velocity=60) >>> e2 = NoteOffEvent(tick=300, pitch=50) >>> e3 = NoteOnEvent(tick=200, pitch=62, velocity=90) >>> e4 = NoteOffEvent(tick=600, pitch=62) >>> t = MIDITrack(sorted([e1, e2, e3, e4])) >>> t <madmom.utils.midi.MIDITrack object at 0x...> >>> t.events [<madmom.utils.midi.NoteOnEvent object at 0x...>, <madmom.utils.midi.NoteOnEvent object at 0x...>, <madmom.utils.midi.NoteOffEvent object at 0x...>, <madmom.utils.midi.NoteOffEvent object at 0x...>]
It can also be created from an array containing the notes. The from_notes method also takes care of creating tempo and time signature events.
>>> notes = np.array([[0.1, 50, 0.3, 60], [0.2, 62, 0.4, 90]]) >>> t = MIDITrack.from_notes(notes) >>> t <madmom.utils.midi.MIDITrack object at 0x...> >>> t.events [<madmom.utils.midi.SetTempoEvent object at 0x...>, <madmom.utils.midi.TimeSignatureEvent object at 0...>, <madmom.utils.midi.NoteOnEvent object at 0x...>, <madmom.utils.midi.NoteOnEvent object at 0x...>, <madmom.utils.midi.NoteOffEvent object at 0x...>, <madmom.utils.midi.NoteOffEvent object at 0x...>]
-
data_stream
¶ MIDI data stream representation of the track.
-
classmethod
from_stream
(midi_stream)[source]¶ Create a MIDI track by reading the data from a stream.
Parameters: midi_stream : open file handle
MIDI file stream (e.g. open MIDI file handle)
Returns: MIDITrack
instanceMIDITrack
instance
-
classmethod
from_notes
(notes, tempo=120, time_signature=(4, 4), resolution=480)[source]¶ Create a MIDI track from the given notes.
Parameters: notes : numpy array
Array with the notes, one per row. The columns must be: (onset time, pitch, duration, velocity, [channel]).
tempo : float, optional
Tempo of the MIDI track, given in beats per minute (bpm).
time_signature : tuple, optional
Time signature of the track, e.g. (4, 4) for 4/4.
resolution : int
Resolution (i.e. ticks per quarter note) of the MIDI track.
Returns: MIDITrack
instanceMIDITrack
instanceNotes
All events including the generated tempo and time signature events is included in the returned track (i.e. as defined in MIDI format 0).
-
-
class
madmom.utils.midi.
MIDIFile
(tracks=None, resolution=480, file_format=0)[source]¶ MIDI File.
Parameters: tracks : list
List of
MIDITrack
instances.resolution : int, optional
Resolution (i.e. microseconds per quarter note).
file_format : int, optional
Format of the MIDI file.
Notes
Writing a MIDI file assumes a tempo of 120 beats per minute (bpm) and a 4/4 time signature and writes all events into a single track (i.e. MIDI format 0).
Examples
Create a MIDI file from an array with notes. The format of the note array is: ‘onset time’, ‘pitch’, ‘duration’, ‘velocity’, ‘channel’. The last column can be omitted, assuming channel 0.
>>> notes = np.array([[0, 50, 1, 60], [0.5, 62, 0.5, 90]]) >>> m = MIDIFile.from_notes(notes) >>> m <madmom.utils.midi.MIDIFile object at 0x...>
The notes can be accessed as a numpy array in various formats (default is seconds):
>>> m.notes() array([[ 0. , 50. , 1. , 60. , 0. ], [ 0.5, 62. , 0.5, 90. , 0. ]]) >>> m.notes(unit='ticks') array([[ 0., 50., 960., 60., 0.], [ 480., 62., 480., 90., 0.]]) >>> m.notes(unit='beats') array([[ 0., 50., 2., 60., 0.], [ 1., 62., 1., 90., 0.]])
>>> m = MIDIFile.from_notes(notes, tempo=60) >>> m.notes(unit='ticks') array([[ 0., 50., 480., 60., 0.], [ 240., 62., 240., 90., 0.]]) >>> m.notes(unit='beats') array([[ 0. , 50. , 1. , 60. , 0. ], [ 0.5, 62. , 0.5, 90. , 0. ]])
>>> m = MIDIFile.from_notes(notes, tempo=60, time_signature=(2, 2)) >>> m.notes(unit='ticks') array([[ 0., 50., 960., 60., 0.], [ 480., 62., 480., 90., 0.]]) >>> m.notes(unit='beats') array([[ 0. , 50. , 1. , 60. , 0. ], [ 0.5, 62. , 0.5, 90. , 0. ]])
>>> m = MIDIFile.from_notes(notes, tempo=240, time_signature=(3, 8)) >>> m.notes(unit='ticks') array([[ 0., 50., 960., 60., 0.], [ 480., 62., 480., 90., 0.]]) >>> m.notes(unit='beats') array([[ 0., 50., 4., 60., 0.], [ 2., 62., 2., 90., 0.]])
-
ticks_per_quarter_note
¶ Number of ticks per quarter note.
-
tempi
(suppress_warnings=False)[source]¶ Tempi of the MIDI file.
Returns: tempi : numpy array
Array with tempi (tick, seconds per tick, cumulative time).
-
time_signatures
(suppress_warnings=False)[source]¶ Time signatures of the MIDI file.
Returns: time_signatures : numpy array
Array with time signatures (tick, numerator, denominator).
-
notes
(unit='s')[source]¶ Notes of the MIDI file.
Parameters: unit : {‘s’, ‘seconds’, ‘b’, ‘beats’, ‘t’, ‘ticks’}
Time unit for notes, seconds (‘s’) beats (‘b’) or ticks (‘t’)
Returns: notes : numpy array
Array with notes (onset time, pitch, duration, velocity, channel).
-
data_stream
¶ MIDI data stream representation of the MIDI file.
-
classmethod
from_file
(midi_file)[source]¶ Create a MIDI file instance from a .mid file.
Parameters: midi_file : str
Name of the .mid file to load.
Returns: MIDIFile
instanceMIDIFile
instance
-
classmethod
from_notes
(notes, tempo=120, time_signature=(4, 4), resolution=480)[source]¶ Create a MIDIFile from the given notes.
Parameters: notes : numpy array
Array with the notes, one per row. The columns must be: (onset time, pitch, duration, velocity, [channel]).
tempo : float, optional
Tempo of the MIDI track, given in beats per minute (bpm).
time_signature : tuple, optional
Time signature of the track, e.g. (4, 4) for 4/4.
resolution : int
Resolution (i.e. ticks per quarter note) of the MIDI track.
Returns: MIDIFile
instanceMIDIFile
instance with all notes collected in one track.Notes
All note events (including the generated tempo and time signature events) are written into a single track (i.e. MIDI file format 0).
-
static
add_arguments
(parser, length=None, velocity=None, channel=None)[source]¶ Add MIDI related arguments to an existing parser object.
Parameters: parser : argparse parser instance
Existing argparse parser object.
length : float, optional
Default length of the notes [seconds].
velocity : int, optional
Default velocity of the notes.
channel : int, optional
Default channel of the notes.
Returns: argparse argument group
MIDI argument parser group object.
-
-
madmom.utils.midi.
process_notes
(data, output=None)[source]¶ This is a simple processing function. It either loads the notes from a MIDI file and or writes the notes to a file.
The behaviour depends on the presence of the output argument, if ‘None’ is given, the notes are read, otherwise the notes are written to file.
Parameters: data : str or numpy array
MIDI file to be loaded (if output is ‘None’) / notes to be written.
output : str, optional
Output file name. If set, the notes given by data are written.
Returns: notes : numpy array
Notes read/written.