Enumerating MIDI devices


In addition to audio playback and recording, Windows Multimedia (WinMM) provides a Musical Instrument Digital Interface (MIDI) API.

Here's how to make a list of all the MIDI devices on the system, their capabilities, and the hardware device interface associated with each of them.

Source and binaries attached.

Pseudocode:

midiInGetNumDevs or midiOutGetNumDevs
for each device
    midiInGetDevCaps or midiOutGetDevCaps
    log device capabilities
    midiInMessage or midiOutMessage
        with DRV_QUERYDEVICEINTERFACESIZE
        and DRV_QUERYDEVICEINTERFACE
    log the device interface

Output:

>midienum.exe
midiIn devices: 1
-- 0: USB2.0 MIDI Device --
    Device ID: 0
    Manufacturer identifier: 65535
    Product identifier: 65535
    Driver version: 1.6
    Product name: USB2.0 MIDI Device
    Support: 0x0
    Device interface: "\\?\usb#vid_xxxx&pid_yyyy&..."
midiOut devices: 2
-- 0: Microsoft GS Wavetable Synth --
    Device ID: 0
    Manufacturer identifier: 1
    Product identifier: 27
    Driver version: 1.0
    Product name: Microsoft GS Wavetable Synth
    Technology: 7 (MOD_SWSYNTH)
    Voices: 32
    Notes: 32
    Channel mask: 0xffff
    Support: 0x1
        MIDICAPS_VOLUME
    Device interface: ""
-- 1: USB2.0 MIDI Device --
    Device ID: 1
    Manufacturer identifier: 65535
    Product identifier: 65535
    Driver version: 1.6
    Product name: USB2.0 MIDI Device
    Technology: 1 (MOD_MIDIPORT)
    Voices: 0
    Notes: 0
    Channel mask: 0xffff
    Support: 0x0
    Device interface: "\\?\usb#vid_xxxx&pid_yyyy&..."

(Actual device interface string suppressed.)

Note the Microsoft GS Wavetable Synth device, which is always present.

Why would you want to know the device interface? In our case, because we want to test all the audio-related interfaces of a particular device on the system.

EDIT September 22 2015: moved source to github https://github.com/mvaneerde/blog/tree/master/midienum

midienum.zip

Comments (4)

  1. Mike Horgan says:

    I stumbled on your blog post while investigating whether there is some way to associate a specific MIDI device to a particular (specific) USB device. I have an application which is responsible for updating firmware for a variety of our (Line 6) devices. These are all USB devices. The application enumerates the USB devices using SetupDi calls to identify instances of our devices. There is one particular devices which exposes a USB class 1 audio/MIDI interface. The MIDI interface is used to update the firmware on this device. When instanced the abstraction for this device enumerates system MIDI devices to locate the MIDI in/out port to use. It uses midiInGetDevCaps and midiOutGetDevCaps calls and matches the name string. The problem I’d like to solve is how to make this association in cases where there are more than one of this particular device. I don’t believe the string returned from sending DRV_QUERYDEVICEINTERFACE message provides a means for this.

    1. You can use the “container ID” device property to see if two device interfaces are on the same piece of physical hardware. This is how the “Devices and Printers” control panel works.

  2. Hermann Seib says:

    I’m pulling my hair out trying to get a “device has been (re)attached, so (re)open the matching MIDI Input and Output devices with midiInOpen() and midiOutOpen()” logic to work. It works partially with MIDI devices that do report a device interface. “Partially”, because the midiIn… and midiOut… functionality refuses to acknowledge any changes when a USB MIDI device is attached or detached, so I can’t open a MIDI device that has been attached AFTER the program has been started. That’s all on Windows 7, by the way; I haven’t tried it on other versions yet.

    With a KORG nanoKEY2, which is what I got here, I’m totally out of luck. While I do get WM_DEVICECHANGE messages when it’s pluggied in or out, I can’t match the reported device ID to any of the nanoKEY2’s MIDI device names.

    Using SetupDiGetClassDevs() / SetupDiGetDeviceInstanceId() / SetupDiGetDeviceRegistryProperty(), I can only find out the attached device’s device description, which is “KORG nanoKEY2”; the nanoKEY2 device doesn’t report a friendly name. The device description has nothing to do with the names reported by midiInGetDevCaps() and midiOutGetDevCaps(), which are
    in: nanoKEY2 1 KEYBOARD
    out: nanoKEY2 1 CTRL
    Neither input nor output MIDI device report a device interface, so I can’t try to match that.

    I tried to use the “container ID” device property for the attached device, but that doesn’t work.
    Assuming that you mean (Pseudocode):
    SetupDiGetDeviceProperty(…, DEVPKEY_ContainerId, guid …)
    hdi2 = SetupDiGetClassDevs(NULL,NULL,NULL,DIGCF_ALLCLASSES)
    for each SetupDiEnumDeviceInfo(did2) in hdi2
    SetupDiGetDeviceProperty(…, DEVPKEY_ContainerId, guid2 …)
    if (guid equals guid2)
    we got a match!

    … there’s exactly one device with this container ID – the one being attached or detached. No other devnodes.

    Do you have any idea how to match the attached/detached device to the corresponding MIDI devices? How is this done in the WinMM system (apart from the unfortunate little fact that it’s obviously only done once, when winmm.dll is loaded)?

    1. A MIDI device may afford multiple MIDI interfaces. These interfaces will have unique interface IDs.

      You can discover the interface ID via the MIDI APIs as outlined above.

      With the interface ID in hand, you can query the associated device instance, container ID, etc.

      The WinMM MIDI API is considered “legacy” at this point. New apps should use the WinRT API. There’s a sample here:

      https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/MIDI

Skip to main content