@@ -40,6 +40,7 @@ def exitScript(errMessage, exitCode,):
4040def process_midi (MIDI_filename ):
4141 A440_REF = 69 #MIDI index value of A4, the universal reference note.
4242
43+ counter = 0
4344 current_time = 0
4445 start = 0
4546 MIDI_time = []
@@ -60,6 +61,11 @@ def process_midi(MIDI_filename):
6061 #Process MIDI file
6162 print ("Processing MIDI file." )
6263 try :
64+ MIDI_file_list = list (MIDI_file )
65+ # We must have a 1:1 ratio of note_offs for note_ons. This will create a space in note_durations which will be filled later.
66+ for i in range (len (MIDI_file_list )):
67+ note_durations .append ("NULL" )
68+
6369 for msg in MIDI_file :
6470 current_time = float (msg .time )+ current_time
6571 # Change this so that we don't look at the if statement except the first few times.
@@ -71,14 +77,29 @@ def process_midi(MIDI_filename):
7177 continue
7278 else :
7379 MIDI_time .append (current_time )
74- # End of note.
80+ # Start of note.
7581 if msg .type == "note_on" and msg .velocity != 0 :
82+ counter += 1
7683 note_channels .append (msg .channel )
7784 note_tones .append (msg .note )
7885 note_starts .append (current_time )
79- # We must have a 1:1 ratio of note_offs for note_ons. This will create a space in note_durations which will be filled later.
80- note_durations .append ("NULL" )
81- # Start of note
86+
87+ #Forward note search
88+ current_time_2 = current_time
89+ for counter_2 in range (1 , len (MIDI_file_list )- counter ):
90+ msg2 = MIDI_file_list [counter + counter_2 ]
91+ current_time_2 = current_time_2 + msg2 .time
92+ #we need to confirm the type has the velocity attribute before checking if the velocity is 0, otherwise an error is thrown
93+ if msg2 .type == "note_off" or msg2 .type == "note_on" :
94+ if msg2 .type == "note_off" or (msg2 .type == "note_on" and msg2 .velocity == 0 ):
95+ note_duration = current_time_2 - current_time
96+ #Avoid zero-duration notes, which may cause crashes.
97+ if note_duration == 0 :
98+ continue
99+ note_durations [counter ] = note_duration
100+ break
101+
102+ # End of note
82103 elif msg .type == "note_off" or msg .velocity == 0 :
83104 #note_durations.append(msg.time) #I think this was originally used for legato?
84105 # Reverse search the note starts list and find the note_on message that was probably linked to this note_off
@@ -88,6 +109,15 @@ def process_midi(MIDI_filename):
88109 list_match = i
89110 note_durations [list_match ]= current_time - note_starts [i ]
90111 break
112+
113+ #Forward search notes. This should probably be an optional feature, but for now it prevents notes from getting stuck on.
114+ # for i in range(0, len(note_starts), 1):
115+ # if note_durations[i] == "NULL":
116+ # try:
117+ # note_durations[i] = note_durations[i+1]
118+ # except IndexError:
119+ # pass
120+
91121 except Exception as error :
92122 exitScript (str (error )+ ". MIDI processing failed." , 1 )
93123
0 commit comments