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

@amiable-dev

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions