Julusian / node-midi

A node.js wrapper for RtMidi providing MIDI I/O
https://www.npmjs.com/package/@julusian/midi
MIT License
22 stars 7 forks source link

Allow multiple instances to open the same port #1

Open hrueger opened 1 year ago

hrueger commented 1 year ago

Hi @Julusian, I thought I'd open the issue here and not in the PR, since it has nothing to do with the rewrite.

In my application, I have multiple plugins each running in its own worker_thread. I'd like all those plugins to have access to all the midi ports. Currently, if one port is already opened in one worker_thread, it's not possible to open it again from another worker_thread but instead get the following error:


MidiInWinMM::openPort: error creating Windows MM MIDI input port.

Error: Internal RtMidi error

This goes for Inputs as well as for Outputs.

It would be cool if node-midi could allow that. Maybe node-midi can hold all the internal RtMidi Inputs and Outputs in a global scope, open them if port.openPort(idx) is called for the first time and just reuse that port if port.openPort(idx) is called again? Incoming Messages would be forwarded to all Inputs, outgoing Messages would be send to the single output.

What do you think?

hrueger commented 1 year ago

After I slept on it for a night, I doubt if the poposed way if implementing this is even possible. I'm not sure if a scope global scope shared between worker_threads and the main thread? I don't think so anymore...

I'd rather not implement the connection using the worker_thread Event API because that means, all sync functions would now return promises...

Maybe the best way to solve this would be in RtMidi (or libremidi)? I don't know if they can open ports in non-exclusive mode. I did some tests on Windows with @julusian/node-midi and MIDI-OX:

Does that mean that the programms creating the ports can specify how many connections an input can have?

Edit: Interestingly, two worker_threads can neither open the same inputs nor the same outputs (even if they are created by loopMidi)...

Edit 2: On MacOS, it behaves very differently:

Julusian commented 1 year ago

It would be possible for this library to wrap the ports and share them, but it will make things complex and likely either require wrapping calls in mutexes (which could be bad for performance), or making things async. So we definitely should explore other options before doing this.

This comment https://github.com/thestk/rtmidi/issues/102#issuecomment-287558567 seems to sum up what you are seeing on windows. It looks like libremidi does support that new UWP backend, so this might be the argument needed to try switching to it. It reads like by default midi devices would only support one user, but could use a custom driver (which loopmidi likely is) and then allow shared usage.

Interestingly, two worker_threads can neither open the same inputs nor the same outputs (even if they are created by loopMidi)...

It wouldnt surprise me if this is an edge case in their sharing logic. Being opened from multiple rtmidi contexts from inside the same process is going to be very edge case.

So I think the thing to do here is to see what happens if this is built with libremidi and the uwp backend, and figure out where to go from there

hrueger commented 1 year ago

So we definitely should explore other options before doing this.

Yes, I also agree with you on that one.

So I think the thing to do here is to see what happens if this is built with libremidi and the uwp backend, and figure out where to go from there

That sounds good. Unfortunately, I'm not familiar with C++, I could only help with testing.

One more thing: it would be really cool if virtual ports could be created on windows, too. This would make it much easier for users as they did not have to install loopMidi or similar. I can't find any docs if the new UWP backend supports creating virtual ports, but I don't think so...