Modality-toolkit
Modality-toolkit copied to clipboard
Feature request: Auto-reconnect device
It would be great to have an auto-reconnect feature, in case of accidental unplug of a device during a performance.
Here is how I see it could be done:
- an external "poller" polls midi sources on a regular basis. MKtl optionally registers connected devices to it, so that if one of them disappears and then re-appears, the poller calls MKtl(x).reconnect.
- MKtl(x).reconnect could just trash the previous device and make a new one (
try{this.closeDevice}; this.device = nil; this.openDevice
)
MIDI does usually "just" reconnect (on OSX). Which devices are you thinking of?
MIDI. On linux I have to set up automatic reconnection through another program, something like qjackctl's patchbays. I thought it could have been specific to a MIDI device, so I tried with a couple of others... and no, it doesn't reconnect on linux.
// device is plugged
MIDIClient.init;
MIDIIn.connectAll;
MIDIdef.cc(\test){|...args| args.postln};
// getting messages
// now unplug/replug: not getting messages anymore
However, there is something specific to the pedalboard I'm using, which is that when I plug it in, I have to send a special sysex for it to be in "hosted" mode.
I want to add that what currently blocks me from implementing this separately is #372. I posted the present feature request because I thought it could be an interesting feature to add to Modality, not knowing that on mac it "just" works :)
did not intend to bully, just tried to understand what's wrong...
Opssss some communication didnt work right here! I didn't intend to sound pissed, and havent felt bullied at all! Sorry if yiu got that impression, and thanks for your work and replies!
no worries :) As for your request, I am currently with my head in other projects (and languages), so I am not the right person to talk to when it comes to implementation details... I guess @adcxyz knows better about these issues...
Just tested on macOS, can confirm what @LFSaw said, plugging and unplugging a device just magically reconnects. @elgiano, this would have to be linux specific, so maybe you can try to write it and submit a PR.
hm, this should actually be in SC itself - it reconnects without modality already:
// plug in a MIDI device to test, then:
MIDIClient.init;
MIDIIn.connectAll;
// listen to all midi cc messages:
MIDIdef.cc(\x, { |val, num, chan| [val, num, chan].postln });
/// now unplug the device ...
/// then plug it back in, and wiggle a controller:
/// reconnects automagically on macOS
I can confirm that automagic reconnection doesn't happen on Linux without an external program doing it. On mac, I guess it's macosx itself doing it, or at least sc's coremidi interface. One thing that would be nice to know is whether, when you plug in a new device after MIDIIn.connectAll, that device shows up in MIDIClient.sources/destinations or not. It doesn't on Linux until you call MIDIClient.list.
I think this is then out of Modality's scope. If such a feature would be implemented in SC, maybe Modality could have some hooks to it, but probably that wouldn't really be needed anymore. So feel free to close this issue :)
If anyone is interested, I sketched a (working :)) Linux implementation, that extends SC_AlsaMIDI's processEvent() to forward port-related messages to sclang, so that MIDIFunc/defs can respond to them: https://github.com/elgiano/supercollider/tree/feature/midi-watch-client
Thanks for your collaboration!
I can confirm that automagic reconnection doesn't happen on Linux without an external program doing it. On mac, I guess it's macosx itself doing it, or at least sc's coremidi interface. One thing that would be nice to know is whether, when you plug in a new device after MIDIIn.connectAll, that device shows up in MIDIClient.sources/destinations or not. It doesn't on Linux until you call MIDIClient.list.
Newly connected devices do not show up until you call MIDIClient.init:
MIDIClient.list; MIDIClient.sources.printAll; MIDIClient.destinations.printAll; "";
and there is no automatic system notification when a new device was connected.
I think this is then out of Modality's scope. If such a feature would be implemented in SC, maybe Modality could have some hooks to it, but probably that wouldn't really be needed anymore. So feel free to close this issue :)
OK, will do when we know that is the way to go.
If anyone is interested, I sketched a (working :)) Linux implementation, that extends SC_AlsaMIDI's processEvent() to forward port-related messages to sclang, so that MIDIFunc/defs can respond to them: https://github.com/elgiano/supercollider/tree/feature/midi-watch-client
I checked, polling MIDIClient.prList is really cheap, so one could do a little polling Updater class - sketch:
+ MIDIUpdater {
classvar <skipJack;
classvar <>onSourceAdded, <>onSourceRemoved;
classvar <>onDestAdded, <>onDestRemoved;
*run { |dt|
if (skipJack.isNil) {
skipJack = SkipJack({
this.checkUpdate
}, 2, false, this.name, AppClock, false);
};
if (dt.notNil) { skipJack.dt = dt };
skipJack.play;
}
*stop { skipJack.stop }
*checkUpdate {
// get new list
var rawlists = MIDIClient.prList.clump(3);
// split into newSources, newDests;
var newSourceSpecs = rawlists[0].flop;
var newDestSpecs = rawlists[1].flop;
// compare with old list, and only if the lists are different, do:
// update sources & dests
// if new source was added, onSourceAdded.(new source);
// if source was removed, onSourceAdded.(removed source);
// if new dest was added, onDestAdded.(new dest);
// if dest was removed, onDestRemoved.(removed dest);
}
}
I also thought about polling initially, then my problem was that if you disconnect and reconnect a device quicker than the poll rate, you loose that event, and that would be meaningful to me in case I have to call a function every time a device is connected (e.g. setting the device in "hosted" mode by sending a sysex).
The advantage of a poller though, is that it would be automatically cross-platform, leaving communication with the specific midi driver as a responsibility for a lower level...
@elgiano - do you have any numbers how short these dropouts can get?
If the poller is cheap, and the poll rate can be set individually,
you can tweak the rate to be fast enough for all likely cases.