Search code examples
pythonmidimusic21mido

Music21: get track index of a note


I have a multi-track midi file that I'm reading with music21:

import music21

f = music21.midi.MidiFile()
f.open('1079-02.mid')
f.read()
stream = music21.midi.translate.midiFileToStream(f).flat
note_filter = music21.stream.filters.ClassFilter('Note')
for n in stream.recurse().addFilter(note_filter):
  offset = n.offset # offset from song start in beats
  note = n.pitch # letter of the note, e.g. C4, F5
  midi_note = n.pitch.midi # midi number of the pitch, e.g. 60, 72
  duration = n.duration # duration of the note in beats
  instrument = n.activeSite.getInstrument() # instrument voice

I'd like to figure out which track each note in this stream belongs to. E.g. when I open the file in GarageBand, the notes are organized into tracks:

enter image description here

In mido, each MidiFile has a tracks attribute that contains one list of notes for each track.

Is there a way to get the same with music21? Any help would be appreciated!


Solution

  • The music tracks are parsed into separate stream.Part objects, so you can just walk through the parts of the stream.Score that you produced if you avoid flattening it (here, I've just produced a stream with converter.parse():

    s = converter.parse('1079-02.mid')
    for part in s.parts:
        for note in part.recurse().notes:
           print("I WAS IN PART ", part)
    

    or look up the containing part:

    s = converter.parse('1079-02.mid')
    for note in s.recurse().notes:
        part = note.sites.getObjByClass('Part')
        print("I WAS IN PART ", part)
    

    I doubt you really need to flatten anything. Good luck!