-
Notifications
You must be signed in to change notification settings - Fork 78
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
Best practice to allow hot-plugging? #86
Comments
What OS/platform are you using/targeting? Hot-plugging really depends on the platform and behaves differently (see also #35 and #78). Unfortunately I cannot give you any more advice, because I don't know the details of how this could work on the various platforms.
Cloning probably won't work, because the relevant objects are not |
My app will be cross-platform on desktop, e.g. macOS/Windows/Linux. With "iteration" I mean each pass of the scan, currently done at an 1 second interval. On macOS, there strangely seems to be a limit how often |
Ok, here is some demo code that loops about 6 times and then raises the error "MIDI support could not be initialized". Platform is macOS 10.13 use midir::MidiOutput;
fn main() {
loop {
println!("Scanning MIDI ports");
let output = MidiOutput::new("midi scan output");
match output {
Ok(output) => {}
Err(error) => {
println!("{}", error)
}
}
std::thread::sleep(std::time::Duration::from_millis(1000));
}
} It seems that MidiOutput::new() acquires some resource from the OS that is not released again. Do I miss something here? Running the same code on Linux loops forever without any error. |
That would be a bug in the backend or in the coremidi crate ... it would be interesting to know if it can be reproduced with However, you don't need to call |
Yes, I also had this idea and implemented it that way today. Errors are gone now. Nevertheless it would be nice to have the issue fixed in the |
I agree. Unfortunately I don't own any macOS hardware, so I can't investigate this ... |
I changed the demo code to use coremidi directly and filed an issue at its repository. |
I've investigated the problem, and it seems that it is a limitation of CoreMIDI. |
It seems that you already have a solution that re-uses the clients, but I think that if you need a robust solution, either midir implements some mechanism to scan ports, or you implement your own using the underlying libs (coremidi, ...). |
Some interesting stuff I discovered: When I replace |
Hi everyone. I encountered this issue when I was fiddling with my pet project. I wanted to enable hot-plugging of midi devices, but after a couple of hours of poking around and trying to make it work it feels like it was me who was hot-plugged to present it lightly. In the end I forced it to work. So how does it work? Anyway, it's working. |
Thank you for sharing your investigations! As I said before, I currently don't own any macOS hardware, so it's hard for me to say anything about it. If there's someone who would be willing to help maintaining midir's macOS backend, please raise your hand ;-) So according to your gist, it is required to (a) use |
According to my experiments, if there are two event loops running on different threads, there are two possible errors that will occur when midi device is being plugged in: segfault and trace trap. Both are kinda bad and will immediately kill the process. Event loop is typically used by Mac/iOS applications that use core foundation framework as far as I understand. Applications that do not rely on it won't have event loop running. Any Rust application will have to manually enable it as gist shows. Maybe it's wise to start this loop under the hood only if feature is enabled. Otherwise start default client. Actually I stole event loop idea from an example of coremidi. It does contain couple of links with details on event loops. Maybe it's maintainer would have any clue how does it work. |
Oh, actually I just discovered that if you use |
Hi, I am planning to use this library in a new musical live performance application. Hotplugging is very important for live performance. A party should not be ruined because a USB cable falls out. 😄 |
Hello, thanks for project, in my case hotplugging is very important too. |
Hi I suspect I am running into a similar issue. I'm trying to write some code that will notify when a new device is plugged in or unplugged. On macos, scanning the midi ports by creating a new [Edit] After more research I found this it seems like in order to be notified of changes to the ports, your application must start using something like this from core_foundation. use core_foundation::runloop::CFRunLoop;
fn main() {
CFRunLoop::run_current();
} In order for midir to support notifications from coremidi, would we not need to create the core midi client using For reference here is the code that doesn't throw but that can't detect changes in available ports. I'm on macos 12.6.3 midir 0.9.1 use midir::MidiInput;
use std::{thread, time};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let midi_input = MidiInput::new("")?;
loop {
let ports = midi_input.ports();
println!("Devices:");
for (i, port) in ports.iter().enumerate() {
match midi_input.port_name(port) {
Ok(name) => {
println!("{}", name);
},
_ => {}
}
}
println!("----");
thread::sleep(time::Duration::from_millis(500));
}
Ok(())
} |
I'm working on an editor for a hardware synthesizer connected via USB MIDI. Ideally, the device is connected all the time so the application finds it right from the start. In reality, a more mature approach is required, meaning that the synth can be connected or disconnected at any time the editor is running.
My question is here, what is the best way to achieve this? Of course, something has to run periodically in the background and scan the ports, since change notification is not supported yet. Should this be done in a separate thread or just called from the main thread at an interval?
As soon as the port becomes available, a connect must be performed. It seems, that the connect() method takes the ownership, so the scanner object loses it. Either some cloning is required or the scanner object needs to be instanciated newly on each iteration. What is the preferred way here?
The text was updated successfully, but these errors were encountered: