python-midi
python-midi copied to clipboard
How can I access a NoteOnEvent?
Here's my code:
import midi
pattern = midi.read_midifile('Conquest of Paradise.mid')
trackCount = len(pattern)
eventCount = 0
for i in range(trackCount):
for j in range(i):
eventCount += 1
if pattern[i][j].name == 'NoteOnEvent':
print(pattern[i][j])
But when I run this it returns no events.
Thanks in advance
First, don't use the name property, but the class. For example:
[...]
if isinstance(pattern[i][j], midi.events.NoteOnEvent):
print(pattern[i][j])
Then, your code is wrong: the second for
cycle uses the range from the number of track, meaning that the first nested for
cycle won't be executed at all (the first i
is 0, resulting in for j in range(0)
), and the next cycles will only iter through the track number you feed them with; so, if you have a pattern with a single track, the cycle will not be executed at all, the second will only have the first event, the third only its first two, etc. Also, if you have lots of tracks with few (or no) events, your code will raise an IndexError
.
You need to cycle through the contents of the tracks, and to cycle through this kind of data structures (which are, essentially, lists of objects, no matter what kind of objects they are), you just iter its elements - if you need a counter, use enumerate
:
eventCount = 0
for track in pattern:
for event_number, event in enumerate(track, eventCount):
# the 2nd optional argument of enumerate tells it the number to start from
if isinstance(event, midi.events.NoteOnEvent):
print('{n}: {e}'.format(n=event_number, e=event))
eventCount = event_number + 1
# update eventCount to the current event_number, adding 1 since the
# cycle is 0-based: if the first track has 5 events, you will want to start
# the counter from 6 on the next one.
in this way it's much faster than using multiple indexing each time (list[index][index]
is slower), and it is easier to read too.