Open the-t-in-rtf opened 7 years ago
The issues are a bit subtle, but I'll try to summarize here:
At the moment, Flocking's MIDI implementation on Node.js instantiates a new set of Port objects for all connected input and output ports each time flock.midi.nodejs.getAllPorts() is invoked. This is due to limitations in node-midi and its underlying RTMidi library, which provides no stable way for uniquely identifying ports across all platforms.
However, node-midi and RTMidi have a bug, which the maintainers have not responded to, in which native RTMIDI Port objects are not correctly released when they are no longer being used. This means that, using its current strategy and libraries, Flocking leaks memory whenever Ports are accessed but not used. Combined with polling, this causes ALSA to eventually crash once too many ports have been allocated. This is documented in Flocking #197.
The new, unfinished flocking-midi library addresses this by only working with modelized representations of ports until the user actually connects to a port. This, in combination with a hand-assembled fork of node-midi that I created, ensures that polling the MIDI system won't cause crashes.
However, flocking-midi isn't yet ready for prime time, in that it doesn't yet implement the ability to connect to ports via model-bound dynamic components. This is coming, and crucially needed, but I haven't yet had an opportunity to finish the implementation.
One solution might be to look into mixing the polling functionality of flocking-midi with the current implementation built into Flocking? It could be complex, and may require changes, but it might work.
Note, also, that none of these issues are present in the browser. The Web MIDI API provides a much better interface for accessing and creating ports, including events that fire whenever a port is added or removed. Much of the problem on Node.js stem from the fact that RTMidi has a very poor interface that makes it hard to enumerate ports and does not provide stable port identification across platforms; issues have been filed and pull requests submitted, but it seems not much has been done about it.
Does this help?
I'm not sure what the limitations are preventing the strategy @colinbdclark had in mind for managing (re)connection as devices are connected and disconnected.
My thought is to use the same functionality that powers the --list-ports option, and to have an outer "connection manager" component whose model has the available inputs and outputs. Whenever the available inputs and outputs change, it would recreate the router instance, which would be bound to an appropriate
createOnEvent
option. The "connection manager" would poll the ports intermittently (say every 15 seconds) and update its model with the latest available inputs and outputs.The "connection manager" would stay alive indefinitely, so we'd need to display instructions about how to abort it ("hit ctrl-c to exit..."). If no matching inputs and outputs are found, the router throws an error and aborts as before. If new devices are connected, a new router will be given the chance to wire things up.