Skip to content

Commit 6e2210e

Browse files
committed
Fix MIDI imports when tracks don't configure instruments
1 parent b323968 commit 6e2210e

File tree

1 file changed

+30
-7
lines changed

1 file changed

+30
-7
lines changed

io/MidiImporter.gd

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ class MidiFileReader:
8080
# Read header bytes in order.
8181
_file.get_32() # Header size.
8282
format = _file.get_16()
83+
84+
if format != MidiFile.FileFormat.SINGLE_TRACK && format != MidiFile.FileFormat.MULTI_TRACK:
85+
printerr("MidiImporter: Failed to read the file at '%s', expected a single or multi track format, got format %d instead." % [ _file.get_path(), format ])
86+
return false
87+
8388
var track_num := _file.get_16()
8489
resolution = _file.get_16()
8590

@@ -220,19 +225,33 @@ class MidiFileReader:
220225
_extract_instrument(i, midi_payload, song)
221226

222227
if midi_payload.midi_type == MidiTrackEvent.MidiType.NOTE_ON:
223-
_extract_note(i, midi_payload, event.timestamp)
228+
_extract_note(i, midi_payload, event.timestamp, song)
224229

225230
if midi_payload.midi_type == MidiTrackEvent.MidiType.NOTE_OFF:
226-
_change_note_length(i, midi_payload, event.timestamp)
231+
_change_note_length(i, midi_payload, event.timestamp, song)
227232

228233
i += 1
229234

230235

231236
func _extract_instrument(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, song: Song) -> void:
237+
_create_midi_instrument(track_idx, midi_payload.channel_num, midi_payload.data[0], song)
238+
239+
240+
func _ensure_instrument(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, song: Song) -> void:
241+
# This check can fail if the track contains no PROGRAM CHANGE events, which is possible.
242+
# We can only create some fallback instrument in that case.
243+
var instrument_key := Vector2i(track_idx, midi_payload.channel_num)
244+
if _instruments_index_map.has(instrument_key):
245+
return
246+
247+
_create_midi_instrument(track_idx, midi_payload.channel_num, 0, song)
248+
249+
250+
func _create_midi_instrument(track_idx: int, channel_num: int, voice_idx: int, song: Song) -> void:
232251
var midi_instrument := MidiInstrument.new()
233252
midi_instrument.track_index = track_idx
234-
midi_instrument.channel_num = midi_payload.channel_num
235-
midi_instrument.midi_voice = midi_payload.data[0]
253+
midi_instrument.channel_num = channel_num
254+
midi_instrument.midi_voice = voice_idx
236255

237256
# Keep a map for future use by notes.
238257
var index_key := midi_instrument.get_index_key()
@@ -258,11 +277,13 @@ class MidiFileReader:
258277
song.instruments.push_back(bosca_instrument)
259278

260279

261-
func _extract_note(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, timestamp: int) -> void:
280+
func _extract_note(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, timestamp: int, song: Song) -> void:
281+
_ensure_instrument(track_idx, midi_payload, song)
282+
262283
var midi_volume := midi_payload.data[1]
263284
# When a note on event comes with zero velocity/volume, it's actually a note off event.
264285
if midi_volume == 0:
265-
_change_note_length(track_idx, midi_payload, timestamp)
286+
_change_note_length(track_idx, midi_payload, timestamp, song)
266287
return
267288

268289
var midi_track := _tracks[track_idx]
@@ -283,7 +304,9 @@ class MidiFileReader:
283304
instrument_notes.push_back(midi_note)
284305

285306

286-
func _change_note_length(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, timestamp: int) -> void:
307+
func _change_note_length(track_idx: int, midi_payload: MidiTrackEvent.MidiPayload, timestamp: int, song: Song) -> void:
308+
_ensure_instrument(track_idx, midi_payload, song)
309+
287310
var instrument_key := Vector2i(track_idx, midi_payload.channel_num)
288311
var instrument_notes: Array[MidiNote] = _notes_instrument_map[instrument_key]
289312
var midi_track := _tracks[track_idx]

0 commit comments

Comments
 (0)