Skip to content
This repository was archived by the owner on Nov 21, 2025. It is now read-only.
This repository was archived by the owner on Nov 21, 2025. It is now read-only.

MIDI Device Hot-Plug Detection Not Working on macOS #11

Description

@amiable-dev

MIDI Device Hot-Plug Detection Not Working on macOS

Problem Description

When using the MIDIMon GUI, newly connected or disconnected MIDI devices are not detected by the refresh button or auto-refresh (every 5 seconds). Users must restart the entire GUI application to see device changes.

Current Behavior

  • ❌ Refresh button does not detect newly plugged MIDI devices
  • ❌ Auto-refresh (5 second interval) does not detect device changes
  • ❌ Removing a device shows "Unknown Device" in the list
  • ✅ Restarting the GUI application picks up all device changes

Expected Behavior

  • ✅ Refresh button should immediately detect newly connected/disconnected devices
  • ✅ Auto-refresh should detect device changes without user interaction
  • ✅ Device list should dynamically update as devices are plugged/unplugged

Root Cause

This is a known limitation of the midir crate on macOS, not a bug in MIDIMon.

Evidence

From midir GitHub Issue #78: "hotplug support with CoreMIDI?":

"On macOS (CoreMIDI), when you create a MidiInput/MidiOutput and iterate the available ports, devices that have been plugged in since the program started are not available (even when you create a new MidiInput/MidiOutput after the device was plugged in)."

Technical Details

  • midir uses CoreMIDI internally on macOS but doesn't expose CoreMIDI's hot-plug notification system
  • CoreMIDI itself DOES support hot-plug detection - the limitation is in midir's abstraction layer
  • The coremidi Rust crate properly implements hot-plug notifications via CoreMIDI's device change callbacks

Impact

Severity: Medium
Affected Platforms: macOS only (Linux/Windows may have similar issues)
Workaround: Restart GUI application

User Impact:

  • Minor inconvenience for users who frequently connect/disconnect MIDI devices
  • Not critical for typical usage (devices rarely change during a session)
  • Common behavior in many MIDI applications

Proposed Solutions

Option 1: Document the Limitation (Quick Fix)

Effort: Low (1 hour)
Impact: Minimal

Add a note to the UI:

ℹ️ Note: Restart the application to detect newly connected devices

Pros:

  • ✅ No code changes required
  • ✅ Maintains cross-platform simplicity
  • ✅ Common behavior in MIDI apps

Cons:

  • ❌ Doesn't solve the problem
  • ❌ Poor UX compared to modern apps

Option 2: Hybrid Approach - Use coremidi for macOS (Recommended)

Effort: Medium (4-8 hours)
Impact: High

Use coremidi for device enumeration on macOS, keep midir for MIDI I/O:

// midimon-gui/src-tauri/src/commands.rs

#[cfg(target_os = "macos")]
async fn list_midi_devices_macos() -> Result<Vec<MidiDevice>, String> {
    use coremidi::{Client, Sources};
    
    let client = Client::new("MIDIMon Scanner")?;
    let sources = Sources::new();
    
    let mut devices = Vec::new();
    for (index, source) in sources.enumerate() {
        let name = source.display_name()?;
        devices.push(MidiDevice {
            index,
            name,
            connected: false,
        });
    }
    
    Ok(devices)
}

#[cfg(not(target_os = "macos"))]
async fn list_midi_devices_cross_platform() -> Result<Vec<MidiDevice>, String> {
    // Current midir implementation
}

#[tauri::command]
pub async fn list_midi_devices(_state: State<'_, AppState>) -> Result<Vec<MidiDevice>, String> {
    #[cfg(target_os = "macos")]
    return list_midi_devices_macos().await;
    
    #[cfg(not(target_os = "macos"))]
    return list_midi_devices_cross_platform().await;
}

Pros:

  • ✅ Proper hot-plug detection on macOS
  • ✅ Maintains cross-platform support
  • ✅ Better UX for macOS users
  • ✅ Leverages existing coremidi dependency (already in workspace)

Cons:

  • ⚠️ Platform-specific code complexity
  • ⚠️ Need to test both code paths
  • ⚠️ Maintain two implementations

Option 3: Implement CoreMIDI Notifications (Advanced)

Effort: High (12-16 hours)
Impact: Very High

Implement full CoreMIDI device change notifications:

use coremidi::{Client, Notifications};

// Register for device change notifications
client.notifications().subscribe(|notification| {
    match notification {
        Notifications::SetupChanged => {
            // Trigger device list refresh
            refresh_device_list();
        }
        _ => {}
    }
});

Pros:

  • ✅ Real-time device detection (no polling needed)
  • ✅ Most efficient solution
  • ✅ Best user experience

Cons:

  • ❌ Significant implementation effort
  • ❌ Requires event bus/callback architecture
  • ❌ More complex testing

Recommendation

Implement Option 2 (Hybrid Approach) as it provides:

  • Significant UX improvement with moderate effort
  • Clean separation of concerns
  • Maintains cross-platform support
  • Leverages existing dependencies

Option 3 can be implemented later if polling-based refresh proves insufficient.

Implementation Checklist

  • Add platform-specific device enumeration using coremidi on macOS
  • Keep midir for cross-platform fallback and MIDI I/O
  • Update list_midi_devices command with conditional compilation
  • Test hot-plug detection on macOS
  • Test cross-platform fallback on Linux/Windows
  • Update auto-refresh to work with new enumeration
  • Document platform-specific behavior
  • Update MINOR_ISSUES_FIXED.md with final solution

Related Files

  • midimon-gui/src-tauri/src/commands.rs:357-408 - Current device enumeration
  • midimon-gui/ui/src/lib/components/DeviceList.svelte - UI component
  • midimon-gui/ui/src/lib/stores.js:168-176 - Auto-refresh logic
  • Cargo.toml:73 - coremidi workspace dependency (already available)

References


Labels: enhancement, macos, midi, good first issue (for Option 1), help wanted (for Option 2/3)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions