Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disconnect/Reconnect events? #226

Open
tiagosiebler opened this issue Jun 22, 2022 · 5 comments
Open

Disconnect/Reconnect events? #226

tiagosiebler opened this issue Jun 22, 2022 · 5 comments

Comments

@tiagosiebler
Copy link

Firstly, thanks for making this! Having fun with an 8x8 neotrellis button matrix over midi.

If I disconnect the device (after successfully connecting before), everything works perfectly once I reconnect the device.

I was hoping to send midi events to the device after it reconnects (e.g. to reset device state such as brightness, colour, etc per button). Is there a way to detect if a midi device disconnected & reconnected? I had a brief glance at the c++ implementation of input.cpp but I lack familiarity with how that might look.

I would imagine to emit an event for this, so an implementation like mine can use that as a trigger to re-sync all device states.

@aolsenjazz
Copy link

The only way I've found to do this (using this MIDI library) is to constantly poll available devices. I've done this in a project of mine and made a similar service available here.

Likely not the solution you're looking for, but I was in a similar situation.

@tiagosiebler
Copy link
Author

The only way I've found to do this (using this MIDI library) is to constantly poll available devices. I've done this in a project of mine and made a similar service available here.

Likely not the solution you're looking for, but I was in a similar situation.

Thank you, cool projects too!

@GottZ
Copy link

GottZ commented Aug 16, 2023

.. well the console says MidiOutWinMM::sendMessage: error sending MIDI message. when sending data to a disconnected device.

it would be much cleaner if this message was thrown into a error handler on midi.Output()..
like literally.. output.on("error"... or something.

this is kind of annoying tbh.

also polling the device list is not really a good idea.

imagine a usb midi device disconnecting for a second due to a loose usb connection..
it could re-appear in polling before you check the device list if it's firmware takes no time to initialize.

@tiagosiebler:
rtmidi-python exits when this occurs..

so.. it is catchable somwhow. (i'm digging through sources atm)

there is also this in node-midi:

node-midi/src/input.cpp

Lines 217 to 226 in 1356985

NAN_METHOD(NodeMidiInput::IsPortOpen)
{
Nan::HandleScope scope;
NodeMidiInput* input = Nan::ObjectWrap::Unwrap<NodeMidiInput>(info.This());
if (!input->in) return;
v8::Local<v8::Boolean> result = Nan::New<v8::Boolean>(input->in->isPortOpen());
info.GetReturnValue().Set(result);
}

node-midi/src/output.cpp

Lines 145 to 154 in 1356985

NAN_METHOD(NodeMidiOutput::IsPortOpen)
{
Nan::HandleScope scope;
NodeMidiOutput* output = Nan::ObjectWrap::Unwrap<NodeMidiOutput>(info.This());
if (!output->out) return;
v8::Local<v8::Boolean> result = Nan::New<v8::Boolean>(output->out->isPortOpen());
info.GetReturnValue().Set(result);
}

which does not reset to false when I unplug my midi device:

image

let tick = 0;
while(true) {
    tick++;
    tick %= 2;
    try {
        console.log("input:", input.isPortOpen());
        console.log("output:", output.isPortOpen());
        output.sendMessage([176,71,tick * 127]);
    } catch (e) {
        console.log("such e", e);
    }
    await sleep(200);
}

first of all, I'd suggest upgrading to rtmidi 6.0.0
http://www.music.mcgill.ca/~gary/rtmidi/
which has been released on 3rd of august this year.

secondly I suggest adding this to node-midi
https://github.com/justinlatimer/rtmidi/blob/c01a721217ab5b83a44e9b01f94cbea2e952a995/RtMidi.h#L79-L119

the authors page also lists a couple error handling cases.
might be a good idea to include them in node-midi.
http://www.music.mcgill.ca/~gary/rtmidi/index.html#error

will leave for today in half an hour so.. I'll fork this tomorrow and see what I can do.. (cuz when I set my laptop into sleep, I want it to reconnect after it wakes back up)

edit:
this half hour is over now..
my solution to this problem so far:
image

const sleep = time => new Promise(resolve => setTimeout(resolve, time));

const input = new midi.Input();
const output = new midi.Output();

const getMidiDevices = () => {
    const inp = {}, out = {};
    const inpc = input.getPortCount();
    const outc = output.getPortCount();
    for (let i = 0; i < inpc; i++) {
        inp[input.getPortName(i)] = i;
    }
    for (let i = 0; i < outc; i++) {
        out[output.getPortName(i)] = i;
    }
    
    return {inp, inpc, out, outc};
};

let midiDevices = getMidiDevices();
console.log(midiDevices);

input.openPort(midiDevices.inp.nanoKONTROL2);
output.openPort(midiDevices.out.nanoKONTROL2);

// ...
// various stuff that just sends commands to voicemeeter etc.
// ...

let tick = 0;
while(true) {
    tick++;
    tick %= 2;
    try {
        const old = JSON.stringify(midiDevices);
        midiDevices = getMidiDevices();
        if (old !== JSON.stringify(midiDevices)) {
            console.log("change detected:", midiDevices);

            console.log(midiDevices.inp);
            if (!("nanoKONTROL2" in midiDevices.inp))
                console.log("disconnecting");
                if (input.isPortOpen()) input.closePort();
            else {
                console.log("connecting input to", midiDevices.inp.nanoKONTROL2);
                if (!input.isPortOpen()) input.openPort(midiDevices.inp.nanoKONTROL2);
            }

            if (!("nanoKONTROL2" in midiDevices.out))
                console.log("disconnecting");
                if (output.isPortOpen()) output.closePort();
            else {
                console.log("connecting output to", midiDevices.out.nanoKONTROL2);
                if (!output.isPortOpen()) output.openPort(midiDevices.out.nanoKONTROL2);
            }
        }
        if (output.isPortOpen()) output.sendMessage([176,71,tick * 127]);
    } catch (e) {
        console.log("such e", e);
    }
    await sleep(200);
}

@fedekrum
Copy link

Hi,
Any progress on this issue?
Any suggestion on what other lib does this?

@aolsenjazz
Copy link

Have you seen this fork: https://github.com/Julusian/node-midi ?

Actively maintained, contains several fixes and QOL improvements. Not sure if it solves the problems you’ve highlighted, but probably worth a check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants