MIDI Input game crashes when many notes are played

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Promixe

Hello, I have a simple game where MIDI input is used to trigger signals, which are then connected to several child nodes to emit other nodes programmatically:

func _input(event : InputEvent):
if (event is InputEventMIDI):
	match event.message:
		MidiMessageType.MIDI_MESSAGE_NOTE_ON:
			emit_signal("key_on", event.pitch - 21, event.velocity)
		MidiMessageType.MIDI_MESSAGE_NOTE_OFF:
			emit_signal("key_off", event.pitch - 21)

However the game crashes randomly after (this is my guess) too many child notes emitted. The only error message I get (in the Godot Engine text window) is either:

ERROR: is_greater_than: Condition "!data.inside_tree" is true. Returned: false
   At: scene/main/node.cpp:1445
ERROR: is_greater_than: Condition "!data.inside_tree" is true. Returned: false
   At: scene/main/node.cpp:1445
ERROR: is_greater_than: Condition "!data.inside_tree" is true. Returned: false
   At: scene/main/node.cpp:1445
ERROR: is_greater_than: Condition "p_node->data.depth < 0" is true. Returned: false
   At: scene/main/node.cpp:1449

Or this message:

ERROR: is_greater_than: Index idx = -1 is out of bounds (data.depth = 0).
   At: scene/main/node.cpp:1468
ERROR: is_greater_than: Index idx = -1 is out of bounds (data.depth = 0).
   At: scene/main/node.cpp:1468

Unfortunately, I don’t know what any of them mean and don’t know how to get more detailed debug info on WHERE in my GDScript this happens, because the game exits without warnings/errors in the editor (the editor remains opened).
Could you please point me in the right direction as to where to look next? Thanks!

PS: The number of child nodes emitted from pressing MIDI keys is definitely below 1000…Probably close to 500 when the game crashes…
PPS: Godot 3.2.1 on Windows 10 1903

:bust_in_silhouette: Reply From: MintSoda

Can’t see why from the code that you provided. ( maybe upload your full source code? )

Looks like some node left the scene tree when it was needed. It looks like an engine bug to me anyway,

Did you try queue_free() your note nodes after they finished making a sound? Maybe not producing too many nodes will help.


Also, some optimization advice.

it’s always nice to avoid too many nodes. Check out When and how to avoid using nodes for everything.

For example, a full-key range midi keyboard has 88 notes. If you’re working only with 12-EDO, these 88 notes produce fixed pitch, produce predictable sound. So these notes can be stored as custom Resources. (But I honestly don’t if it helps with this situation.)

When the engine loads a resource from disk, it only loads it once. If a copy of that resource is already in memory, trying to load the resource again will return the same copy every time. As resources only contain data, there is no need to duplicate them.
:bust_in_silhouette: Reply From: Promixe

Now the weirdest thing is happening. Where do I start…
The game used to run for a while before crashing (if at all crashing) but now it can’t even emit a single note node, it just hangs, all without changing a single line of code. This happens within the editor AND with packaged .exe game outside of the editor (that worked on the same computer before!).
When trying to narrow down where exactly it hangs, it appears that it can’t instance new nodes of any type EXCEPT for the root Node type. The stripped code is something like this:

in Main.gd:

func _ready():
    OS.open_midi_inputs()

func _unhandled_input(event : InputEvent):
if (event is InputEventMIDI):
	match event.message:
		MidiMessageType.MIDI_MESSAGE_NOTE_ON:
			emit_signal("key_on", event.pitch - 21, event.velocity)
		MidiMessageType.MIDI_MESSAGE_NOTE_OFF:
			emit_signal("key_off", event.pitch - 21)

In NoteLane.gd (child node of Main/PianoRoll):

extends Control

onready var note_rect = preload("res://PianoRoll/Note.tscn")

func _ready():
	var _err1 = get_node("/root/Main").connect("key_on", self, "_on_key_on")
	var _err2 = get_node("/root/Main").connect("key_off", self, "_on_key_off")

func _on_key_on(note, velocity):
	if note == midi_note:
		var new_note = note_rect.instance()

func _on_key_off(note):
	if note == midi_note:
.....

So, in _on_key_on() triggered by MIDI event doing note_rect.instance() hangs the game. If I swap this specific scene for any generic node type it hangs the game, i.e. Node2D.instance(). The only node that doesn’t hang the game is Node.instance(). (but that’s useless for my purposes).

The weirdest things are:

  1. This code WORKED on muptiple computers before. Nothing was changed, no Godot version update, no Windows updates, no changes to anything whatsoever, now the game hangs in that spot with no error/debug messages… ((
  2. If instead of signals being emitted by MIDI events in Main.gd I use a key from the input map (i.e. “K”) everything WORKS as expected, the nodes are being instanced in _on_key_on() inside NoteLane.gd without changing any code anywhere.

Restarts of the computer don’t help. Windows 10 x64 1903…

Oh and I forgot to add: in parallel with NoteLane.gd receiving signals from MIDI events I have a Keyboard.gd that also receives same signals and lights up keys, consisting of individual scenes, but all preloaded and instanced and “static” in that sense, i.e. no nodes instanciate inside of Keyboard.gd.

The keyboard.gd works just fine receiving these signals from MIDI events, so it’s somehow a combination of MIDI Events + Scene instancing programmatically.

MIDI Events without instancing work fine. Scene instancing without MIDI Events works fine (i.e. via a computer keyboard input events).

Promixe | 2020-05-02 01:45