MIDIUtil icon indicating copy to clipboard operation
MIDIUtil copied to clipboard

deInterleaveNotes() crashes when there are two many to handle

Open tobiah opened this issue 3 years ago • 2 comments

Here is an example that will usually crash:

from midiutil import MIDIFile
import random

R = random.random

degrees  = [60, 62, 64, 65, 67, 69, 71, 72]  # MIDI note number
track    = 0
channel  = 0
time     = 0    # In beats
duration = 1    # In beats
tempo    = 60   # In BPM
volume   = 100  # 0-127, as per the MIDI standard

MyMIDI = MIDIFile(1)  # One track
MyMIDI.addTempo(track, time, tempo)

for i in range(100000):
    pitch = 20 + int(R() * 80)
    time = .1 + R() * 100
    volume = random.randint(10, 100)
    dur = .1 + R() * 4
    MyMIDI.addNote(track, channel, pitch, time, dur, volume)

with open("new_song.mid", "wb") as output_file:
    MyMIDI.writeFile(output_file)

tobiah avatar Jun 09 '21 23:06 tobiah

Same here, here's the output:

Traceback (most recent call last):
  File "/usr/local/Cellar/[email protected]/3.9.1_8/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "/usr/local/Cellar/[email protected]/3.9.1_8/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "/Users/angus/delphos/mds-vinyls/mds-vinyls/prototypes/spiral_1.py", line 11, in <module>
    write_tracklist_to_midi_file('delete_spiral1.midi', midi_tracks)
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midi_python/midi_file_writer.py", line 13, in write_tracklist_to_midi_file
    exporter.writeFile(output_file)
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midiutil/MidiFile.py", line 1637, in writeFile
    self.close()
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midiutil/MidiFile.py", line 1688, in close
    self.tracks[i].closeTrack()
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midiutil/MidiFile.py", line 826, in closeTrack
    self.processEventList()
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midiutil/MidiFile.py", line 789, in processEventList
    self.deInterleaveNotes()
  File "/Users/angus/.local/share/virtualenvs/mds-vinyls-O2eeAYrs/lib/python3.9/site-packages/midiutil/MidiFile.py", line 889, in deInterleaveNotes
    stack[noteeventkey].pop()
IndexError: pop from empty list

A quick look at the code:

        for event in self.MIDIEventList:
            if event.evtname in ['NoteOn', 'NoteOff']:
                # !!! Pitch 101 channel 5 produces the same key as pitch 10 channel 15.
                # !!! This is not the only pair of pitch,channel tuples which
                # !!! collide to the same key, just one example.  Should fix by
                # !!! putting a separator char between pitch and channel.
                noteeventkey = str(event.pitch) + str(event.channel)

...So there's something easily fixed there, not sure if it'll resolve this issue...?

angusmoncrieff avatar Feb 16 '22 11:02 angusmoncrieff

I have the same problem. What is exactly the purpose of the stack in this method? Passing the tick between NoteOn and NoteOff events?

Pull request #36 seems to address this problem, but does not seem to take tick passing into account

DataGreed avatar Apr 30 '22 00:04 DataGreed