WinRT MIDI Output wrong device names

Hello,
I’ve noticed a problem with MIDI output device naming, only on Windows and with WinRT enabled.

This is the detected input devices :
image

And this is the detected output devices :
image

“MIDI” and “MIDI-2” should show “Cool” and “loopMIDI Port”.

When disabling WinRT, this works just fine, output devics are shown the right way, without any change in the code.

This is a Microsoft problem. Unfortunately there is nothing that Juce can do about it.
This was brought to Microsoft’s attention years ago, but to date has not been fixed. They eventually fixed the SysEx problem, but not the device name problem. :frowning:

Thanks for the update, this is such a shame… Well I’ll just disable WinRT until this is in a better shape, this just feels like a shitty bug from the user perspective, and nothing I can do about it so…

Some update, I’m very curious because the software MIDIBerry is able to list the good names in the MIDI outputs… does someone know how they manage it ?

EDIT : From MIDIBerry description " Windows 10 does not report the port name correctly, so we analyzed it independently"
That may be the best outcome for now to implement in JUCE, since Windows will likely not move a finger on this one…

1 Like

Following up on this unresolved problem…
This is the WINRT_LOG from Juce using 2 loopMidi ports (“loopMIDI Port” and “DrumLoopback”) the 2 “MIDI” devices are the outputs detected by JUCE that correspond to the 2 loopMidi ports.

Detected MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A388.P_0000#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814}
Adding MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A388.P_0000#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814} {00000000-0000-0000-FFFF-FFFFFFFFFFFF} MIDI
Detected MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A389.P_0004#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b}
Adding MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A389.P_0004#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b} {00000000-0000-0000-FFFF-FFFFFFFFFFFF} loopMIDI Port [1]
Detected MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A388.P_0004#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b}
Adding MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A388.P_0004#{504be32c-ccf6-4d2c-b73f-6f8b3747e22b} {00000000-0000-0000-FFFF-FFFFFFFFFFFF} DrumLoopback [1]
Detected MIDI device: \\?\SWD#MMDEVAPI#MicrosoftGSWavetableSynth#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814}
Adding MIDI device: \\?\SWD#MMDEVAPI#MicrosoftGSWavetableSynth#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814} {00000000-0000-0000-FFFF-FFFFFFFFFFFF} Microsoft GS Wavetable Synth
OSC Remote Control::Now receiving on port : 42000
Detected MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A389.P_0000#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814}
Adding MIDI device: \\?\SWD#MMDEVAPI#MIDII_0AB1A389.P_0000#{6dc23320-ab33-4ce4-80d4-bbb3ebbf2814} {00000000-0000-0000-FFFF-FFFFFFFFFFFF} MIDI

We can see that there is a way to match input devices and output devices, they have the same path except for P_0000 for output and P_0004 for input. their id next to it (I don’t know what it is but it’s not the device info apparently) are different between input and output, but the same for all loopMIDI ports, even after restarting loopMidi.

Unfortunately the only info we get from Juce’s MidiDeviceInfo class is the deviceInfo property {00000000-0000-0000-FFFF-FFFFFFFFFFFF} and the name MIDI so there is no way to differentiate any of the loop midi devices if there are more than one.

There seems that the order of detection is not predictable, and everything happens multithread, which does not facilitate the task, but I guess if somehow we can first look for inputs and then outputs, and if the output is weird or with some recognizable pattern, then we can fetch the name from the input device ? That would at least make it readable for users, and definitely not waiting for Microsoft to deal with this sh*t…

The same problem still exists.

I have a temporary fix for this - which is to take names from their corresponding MIDI input names, when the midiOutputSelector comboBox gets updated:
In AudioDeviceSelectorComp::updateAllControls(),


if (midiOutputSelector != nullptr)
    {
        auto newMidiOutputs = MidiOutput::getAvailableDevices();
        auto newMidiInputs = MidiInput::getAvailableDevices();

        if (currentMidiOutputs != newMidiOutputs)
        {
            midiOutputSelector->clear();

            midiOutputSelector->addItem(getNoDeviceString(), -1);
            midiOutputSelector->addSeparator();           

            auto defaultOutputIdentifier = deviceManager.getDefaultMidiOutputIdentifier();
            int i = 1;

            for (auto& out : newMidiOutputs)
            {

#if JUCE_USE_WINRT_MIDI // Temporary fix till https://forum.juce.com/t/winrt-midi-output-wrong-device-names/43301/2 gets solved

                int j = 0, numInputs = newMidiInputs.size();

                while(j < numInputs)
                {
                    if (out.identifier == newMidiInputs[j].identifier)
                        break;
                    j++;
                }

                if(j < numInputs)
                    midiOutputSelector->addItem(newMidiInputs[j].name, i);
                else
#endif
                    midiOutputSelector->addItem(out.name, i);


                if (defaultOutputIdentifier.isNotEmpty() && out.identifier == defaultOutputIdentifier)
                    midiOutputSelector->setSelectedId(i, dontSendNotification);

                ++i;
            }

            currentMidiOutputs = newMidiOutputs;
        }
    }

image

I just wanted to auto-open the MIDI input with the name and identifier of the Xml file saved by the AudioDeviceManager class in the same way as JuceDemo, so I worked around it: All I had to do was issue a dummy scan of Input / Output and it worked.

void AudioDeviceManager::scanDevicesIfNeeded()
{
:

#if JUCE_USE_WINRT_MIDI
auto inputs = MidiInput::getAvailableDevices();
auto outputs = MidiOutput::getAvailableDevices();
#endif
}

@yosogawa I don’t really understand what you mean, these are already the functions I use to get the devices… are you also trying to get the actual names of the output or something else ?

@bcsuganthan Thank you I had not see that ! That’s a good start, but not completely working :
The device ID’s get something like :
{00000000-0000-0000-FFFF-FFFFFFFFFFFF}-#
where # is the index in the list.
But event without any external midi device, the Microsoft GS Wavetable synth is messing up the order since it has also the same identifier problem.

Following up and adding a piece to work around the GS Wavetable synth

Array<MidiDeviceInfo> inputInfos = MidiInput::getAvailableDevices();
Array<MidiDeviceInfo> outputInfos = MidiOutput::getAvailableDevices();
	
	int idIndex = 1; //keep track of ids
	for (auto& i : outputInfos)
	{

		if (i.name == "Microsoft GS Wavetable Synth") continue; // remove this, nobody wants it anyway

		//This is a ugly hack to take name from ordered input with same identifier, because WinRT stack has a bug and is still not fixed.
		//See https://forum.juce.com/t/winrt-midi-output-wrong-device-names/43301/6

		if (i.identifier.startsWith("{00000000-0000-0000-FFFF-FFFFFFFFFFFF}"))
		{
			String expectedID = "{00000000-0000-0000-FFFF-FFFFFFFFFFFF}";
			if (idIndex > 1) expectedID += "-" + String(idIndex);

			for (auto& ii : inputInfos)
			{
				if (ii.identifier == expectedID)
				{
					i.name = ii.name;
					break;
				}
			}

			idIndex++;
		}

		addOutputDeviceIfNotThere(i);
	}

Hi Ben,

I am also skipping the “Microsoft GS Wavetable Synth” entry here. But I’m incrementing the idIndex value even if I just continue on if (i.name == "Microsoft GS Wavetable Synth"). I’m not sure how you implmented addOutputDeviceIfNotThere(), but please check if selecting the midi output in the combobox selects the corresponding desired midioutput.

@benkuper I don’t know the exact reason
The first getAvailableDevices () returns NULL
The second and subsequent getAvailableDevices () will return the desired list. It’s an empirical workaround, so don’t use it if you’re not convinced. It worked in my case. (jp → en translation)

I checked Microsoft’s WinRT MIDI sample program.

It seems to get the name of the MIDI port using the C#'s ‘await’ syntax. JUCE’s WinRT getArraivableDevices() doesn’t do that. I think it is necessary to implement an asynchronous standby equivalent to C#'s await in C++ of JUCE (I have never used it, but std :: future of C++11 is similar). I would like to request improvements in JUCE.

1 Like