Skip to content
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

Windows 10 UWP MIDI API to enable MIDI over Bluetooth? #145

Open
bharris222 opened this issue Nov 17, 2017 · 30 comments
Open

Windows 10 UWP MIDI API to enable MIDI over Bluetooth? #145

bharris222 opened this issue Nov 17, 2017 · 30 comments
Labels
feature request A feature request with incomplete or no implementation offfered.

Comments

@bharris222
Copy link

Hi. I am a music hobbyist with no programming experience. The developer of certain music software that I am interested in purchasing (XotoPad 2) advised me that he uses the rtmidi library. When I inquired of this developer whether I would be able to use XotoPad 2 with MIDI over Bluetooth on a Windows 10 tablet, he indicated that the rtmidi library would need to be updated to use the Windows 10 UWP MIDI API. Can you please let me know if there are any plans to update the rtmidi library to use the Windows 10 UWP MIDI API to permit MIDI over Bluetooth, rather than the Windows Multimedia API that I understand rtmidi currently uses?

Thank you!

@radarsat1
Copy link
Contributor

Not aware of any plans as such.

@radarsat1
Copy link
Contributor

(ps., leaving this open in case anyone wants to contribute an implementation..)

@sagamusix
Copy link
Contributor

In case it's a motivation for anyone to work on this: The new MIDI API also brings other improvements such as being able to open a MIDI port from more than one application at the same time.
This may also be helpful, a "flat" C interface for the new UWP MIDI interface: https://github.com/stammen/winrtmidi

@jcelerier
Copy link
Contributor

jcelerier commented Jun 27, 2018

hello, I've been working on a fork of RtMidi which starts to have some support for UWP MIDI if anyone's interested : https://github.com/jcelerier/RtMidi17/blob/master/rtmidi17/detail/winuwp.hpp (feel free to port it back to RtMidi proper)

@sagamusix
Copy link
Contributor

Nice work on that fork! Personally I'd try putting all the UWP stuff into a separate DLL to support older OSes but this is definitely a great start.

@pthorod
Copy link

pthorod commented Jun 28, 2018

@jcelerier What a timing! I just started fiddling with C++/WinRT MIDI myself with the aim of using it as the windows implementation in a cross platform CMake based midi library. Nice work 👍

@jcelerier
Copy link
Contributor

jcelerier commented Jun 28, 2018

I would just like to note, for anyone wanting to use it that the implementation has a LOT of problems (on the windows internal side of things - even in plain UWP apps written in C# as can be found in the windows store).

  • Naming of detected MIDI devices is fairly inconsistent and even less useful than the old MME naming
  • Some devices are flat out not recognized - had this problem for some Keith McMillen BopPad - out of ten, between two and four would not be recognized by the UWP stack depending on the reboot. The MME API saw them all.
  • In some cases, sending sysexes can lock the entire MIDI stack and even require a windows reboot.

see for instance :

so unless you have an absolute need for it, I'd say, stay with MME, it just works better.

@sagamusix
Copy link
Contributor

Fantastic job, Microsoft.

@radarsat1 radarsat1 added the feature request A feature request with incomplete or no implementation offfered. label Jul 19, 2018
@marksyzm
Copy link

Does anyone know if the new UWP MIDI format supports making virtual ports? As that's an issue I was about to make

@symdeb
Copy link

symdeb commented Jul 1, 2022

@marksyzm - The UWP WIn32 API does not support that. (At least not using the Win32 wrapper)

Steinberg has enabled "Bluetooth" MIDI in Cubase 12. which is actually just UWP MIDI, and you can see the several warning that things may not work, and it's got nothing to do with "older" devices. (unless Microsoft/Steinberg points out the details why this is )

https://helpcenter.steinberg.de/hc/en-us/articles/4501438703122-WinRT-MIDI-and-Windows-Bluetooth-MIDI-support-in-Cubase-12

image

Cubase is probably using that WIN32 wrapper or an alternative coded inhouse one. I used the wrapper from Microsoft in a client to enable UWP MIDI. and bumped into issues. No matter the Microsoft wrapper or custom one, the key problem is not in the WIN32 but in the core of UWP. For example, UWP cannot handle multiple same hardware devices and upon plug/in out weird things happen. I cannot recall all the details, but I have the nitty gritty details and evidence of debugging somewhere . After that nightmare, dumped the whole UWP MIDI part. The developer of the wrapper at Microsoft informed the port naming issues are due to Microsoft's implementation of UWP and it would be up to the Microsoft developers to fix this. Mainly issues arise when you unplug or plug a device , not only Bluetooth, and you can read this between the lines in the Cubase 12 warnings as well .Sysex is another problems. I have the Bobpad (great features, terrible quality) and it does a lot of sysex. UWP MIDI has been broken from the start since Windows 10 came out. No evidence win11 is better - still have to try it. I informed the person who is supposed to lead all the MIDI/audio Windows stuff (you can find him easily on twitter or other social networks), but nothing happened. It seem no one can push the UWP team at Microsoft and musical stuff just does not have priority. It is ultimately frustrating. You can find several posts on Microsoft Forums as well about this topic that jcelerier pointed out. Nobody at the dev team at Microsoft cares or perhaps there isn't even a real solution. Probably nobody at Microsoft likes to read this, but well , we need to keep raising this flag.

A few more posts:
MicrosoftDocs/windows-dev-docs#1424
https://answers.microsoft.com/en-us/insider/forum/all/windows-10-uwp-win32-wrapper-virtual-midi-port/804a0727-2171-4e89-8d85-75a25f5b7c67

https://www.midi.org/midi-articles/midi-enhancements-in-windows-10
https://blogs.windows.com/windowsdeveloper/2016/09/21/midi-enhancements-in-windows-10/#gAqpA2ecH0Uym9ut.97

With MIDI 2.0 UMP coming, the question is really if Microsoft will revamp the whole UWP API (and finally fix this as well). Likely they have to if DAW's need to use MIDI 2.0 since it is unlikely Microsoft will change the Win32 API, and that should then go along with a well supported and stable Win32 wrapper. But now comes the worry, if the new UWP MIDI API only support UMP, the legacy MIDI issues may stay forever. Hopefully Bitwig or other DAW providers can push, but Steinberg seems to have given up and "adopted" the bugs

What really would be nice is that after 6 years to see a formal statement and reaction from Microsoft.
Until a fix, MIDI UWP is a prototype and we need to keep looking ahead .... :-) ..black hole..

image

And BTW, on Ubuntu BLE MIDI it is now starting to work pretty well - even with the BobPad.

There is a new SDK, WinAppSDK a.k.a Project Reunion)
https://github.com/microsoft/WindowsAppSDK
But there is nothing on this API here
https://github.com/microsoft/WindowsAppSDK/blob/main/docs/roadmap.md
https://docs.microsoft.com/en-us/windows/apps/develop/audio-video-camera
It seems it's main target is to use UWP UI functionality on win32 code.

For those who wish to play around with UWP MIDI API:
https://docs.microsoft.com/en-us/windows/uwp/audio-video-camera/midi
https://docs.microsoft.com/en-us/samples/microsoft/windows-universal-samples/midi/

For those who wish to use the UWP Win32 wrapper (requires Visual Studio 2015)
https://github.com/stammen/winrtmidi

@trueroad
Copy link
Contributor

I'm implementing Windows UWP MIDI API to enable BLE MIDI (Bluetooth MIDI) in #299.
Currently, you can enumerate and get the names of UWP MIDI devices.
The following are not yet implemented.

  • MIDI port open/close
  • MIDI message input/output

Building requires: Visual Studio Community 2019

@marksyzm
Copy link

Very cool! I'm reviving a project soon so your timing is perfect :)

@trueroad
Copy link
Contributor

In #299, I've implemented MIDI port open/close and MIDI message output.
MIDI message input is not yet implemented.

@trueroad
Copy link
Contributor

In #299, I've implemented MIDI message input.
In my experiment, both MIDI IN/OUT with a BLE MIDI device works fine.

@marksyzm
Copy link

Fantastic! Thanks so much for your hard work

@symdeb
Copy link

symdeb commented Aug 21, 2022

Adding another issue found a few years back: Unplugging an BLE device still causes the MIDI device to show up in the enumeration of UWP MIDI devices. Not sure if this still happens with the latest W10 and W11 versions. With the coming of MIDI 2.0 perhaps Microsoft has picked up MIDI UWP and started fixes,. YMMV. Take a look a above reported problem before creating new issues. A warning in RTMIDI possibly might be justified that potentially major problems may persist in the UWP implementation.

@trueroad
Copy link
Contributor

@symdeb
In my experiments with Windows 10 21H1, UWP MIDI only finds BLE-MIDI devices that are paired at that time. It does not find them once paired and then unpaired.

The issue of some MIDI OUT port names being simply MIDI remains, but my pull request fixes that by getting the names in another way.

@symdeb
Copy link

symdeb commented Aug 23, 2022

As far as I used UWP about 3 years ago, after enumerating, then adding/removing devices and then enumerating once again it is a problem to correctly indentify which ports were added or removed because of the port naming issues. Perhaps MS has made fixes in the past three years for BLE/UWP.

@trueroad
Copy link
Contributor

trueroad commented Sep 11, 2022

I've found that Windows UWP timestamp bug.
At least in Windows 10 21H2, UWP MIDI produces wrong timestamps from BLE-MIDI IN ports.
https://github.com/trueroad/BLE_MIDI_packet_data_set#page-7-overflow-low
https://github.com/trueroad/BLE_MIDI_packet_data_set#page-7-overflow-both

So I've added a workaround to fix the wrong timestamps.
#299

For example, YAMAHA MD-BT01 V1.0.7 (the latest firmware) generates such BLE packets, so the timestamps are incorrect without the workaround.

@Psychlist1972
Copy link

Psychlist1972 commented Mar 18, 2023

@symdeb "What really would be nice is that after 6 years to see a formal statement and reaction from Microsoft.
Until a fix, MIDI UWP is a prototype and we need to keep looking ahead .... :-) ..black hole.."

Hi All

I just ran across this thread today. Naming issues we know about. BLE SysEx is something else we fixed a few years ago, so if there are still problems there, they are not known to the team. But some of the other issues reported here have never popped up before, like wrong timestamps from the Yamaha BT01. Were they reported in some way? I don't know if they were and somehow lost, or if they were never actually reported.

I also don't know how many of the bugs here, going back to 2017 in this thread, (other than naming, of course) are ones folks are still running into.

Aside: not sure why people keep referring to WinRT MIDI as a "wrapper". It's not. It talks to the same kernel streaming layers WinMM/MME MIDI API does. (unless you're referring to Dale's C++ wrapper which was needed prior to C++/WinRT. That's actually a wrapper :) )

Pete - Microsoft

@trueroad
Copy link
Contributor

Hi @Psychlist1972

I just ran across this thread today. Naming issues we know about. BLE SysEx is something else we fixed a few years ago, so if there are still problems there, they are not known to the team. But some of the other issues reported here have never popped up before, like wrong timestamps from the Yamaha BT01. Were they reported in some way? I don't know if they were and somehow lost, or if they were never actually reported.

I reported the issue with the timestamps generated by YAMAHA MD-BT01 on the Feedback Hub at the following URL.

If I understand correctly, there are other issues with BLE-MIDI packet parser in WinRT MIDI.

I created a test data set for BLE-MIDI packet parser.
It can be used to verify that the parser (i.e., WinRT MIDI) for BLE-MIDI packets is working properly.
https://github.com/trueroad/BLE_MIDI_packet_data_set

In my experiments on Windows 10 21H2, the following BLE-MIDI packets are incorrectly parsed by WinRT MIDI.

The following two BLE-MIDI packet parsing issues were reported in the Feedback Hub above.

@Psychlist1972
Copy link

@trueroad thank you so much for the detailed response. We will look into this.

Pete

@symdeb
Copy link

symdeb commented Mar 22, 2023

Not sure if the sudden interest for the issues with MIDI UWP is related to adding MIDI 2.0 in Windows. No matter what, It would be nice if Microsoft could list all the claims of issues mentioned above and provide feedback if each of them has been fixed (when in the kernel ) or "cannot reproduce" and when.

The issues are not limited to BLE but also to enumeration.

Regarding:" not sure why people keep referring to WinRT MIDI as a "wrapper": The "wrapper" refers here to the code that wraps around the UWP API to make it available for legacy (C) windows clients, which can be found at https://github.com/stammen/winrtmidi. The README states:

_This GitHub WinRTMidi project wraps the Windows Runtime Windows::Devices::Midi API in a Win32 DLL

I used two identical MIDI to USB devices with multiple MIDI ports.

1/ Port naming issue and port re-numeration after hot in/out plug event

I programmed a C client for Mac OSX, Linux MIDI ALSA sequencer, ALSA raw and Win32 API and could make it work to update the ports status by enumeration when hot plugging devices, when some ports were already open to identify after a hot plug event to re-enumerate to trace back in the list which ports after enumeration mapped to the port after the hot plug event. This worked well except using the windows UWP API. After trying to fix the wrapper, the conclusion was that there is a problem in the windows UWP. The bug is in the UWP API call "MidiOutGetInterfaceID"

After having a discussion with Dale via email, this was confirmed on Feb 28, 2020: "Unfortunately the port naming issue is a Windows 10 MIDI bug that has not been fixed. There is nothing I can do about it". 'They are already aware of this issue but have not fixed it in Windows 10. You can use the Feedback Hub app in Windows 10 to report your issue".

The issues was posted on the feedback up, but can't recall any update. The feedback seems a one way path.Perhaps catch up with the team if they may remember this ? if confirmed that this was fixed, would be glad to spend some time in the nearby future (or new API with MIDI 2.0) to verify it.

2/ Port change callback issue

For this item, did not receive a response. BTW, Here is the contents of the email of March 22, 2020:

[1] What is left is the port change callback. Is there a way to uniquely identify the port from the port callback?
Since the port name is not unique due to the Windows 10 bug it seems not possible to 100% determine the port that was added or removed from it's name. I did find that if the port is removed, and the port is written or read, it crashes the client, I wish to prevent this from happening.

In port_change_callback(const void *portWatcher, const int update) I can use gWatcherPortNameFunc(portWatcher, 0);
But wish to have a unique id. This ID could for example be a hash of the time when the port was added by the OS Another way is to scan through all ports again in the port change callback with gWatcherPortCountFunc(watcher); and then
gWatcherPortNameFunc(portWatcher, 0); Though even then, due to identical port-names, it seems impossible to 100% make sure which port was removed or added comparing it with the previous enumerated list The only option I have now to be it stable is that if an port add/remove occurs, to stop the application, terminate all MIDI I/O and re-scan the ports.

[2] Would it be possible to add a custom data pointer to the data and port change callback ? This can avoid to declare a global variable to the client application data, The legacy win32 API supports this as well, for example: void change_callback(const void *portWatcher, const int update, void *ptr) void input_callback(void input_port, double timeStamp, unsigned char message, unsigned int nBytes, void *ptr) and declare this pointer in gMidiInitFunc(change_callback, midiPtr, ptr);

There are other issues with UWP MIDI, for example, when a Bluetooth device is not present it still gets returned by the PortWatcher and when accessing it causes a crash. Hopefully these issues can be addressed in the next update of UWP MIDI.

I would like to open the new port without having to close all already opened ports that have a gMidiPtr already assigned in the OpenFunc. gMidiOutPortOpenFunc(midiPtr, id, &gMidiPort); is there a way to get the ID from the Portwatcher in the callback ?
change_callback(const void *portWatcher, const int update, void *arg) Should 0 be used as the Id to open the new port ?

I tried to add in WinRTMidi the following new function to obtain the ID of the port, but calling it with 0 as index crashes.
const char winrt_watcher_get_port_id(WinRTMidiPortWatcherPtr watcher, unsigned int index)
{
MidiPortWatcherWrapper
wrapper = (MidiPortWatcherWrapper*)watcher;
return (char *)wrapper->GetWatcher()->GetPortId(index);
}

To find which port was removed, can only the "name" be used to identify it ? To obtain the (unique) Id of the port would be perfect.

--- end note

Even if the UWP API was changed and fixed these issues, the wrapper is not supported anymore. Hopefully someone can pick this up and provide an updated wrapper on Github to make the fixes accessible for Win32 legacy application ? What also could help is a to have a Microsoft test application to test /validate enumeration and MIDI functionality to that developer can create units tests and validate the API they developed works as expected using a legacy Win32 client.

@Psychlist1972
Copy link

Psychlist1972 commented Mar 22, 2023

I only just found this GH issue randomly, which is why I'm replying here.

FWIW, with C++/WinRT, the wrapper Dale (Dale and I are on the same team) wrote is no longer needed, but he does have good code in there for fixing up names. C++/WinRT is standard C++ code with a nuget package. The wrapper was created because the only reasonable way to use WinRT from C++ at the time was C++/CX which had proprietary extensions.

Device/Port naming is being redone as part of the MIDI 2.0 project which will go public later this year. After the initial release, WinMM MIDI and WinRT MIDI will have their implementations repointed to the new code to get some of the new features, but apps which use the new API (which is also built on WinRT) will have access to everything.

Device hot plug/unplug is made worse with the name bugs. I agree. But on that specific thing, what I really want is for device manufacturers to implement USB iSerialNumber in their devices so that the different operating systems don't have to jump through hoops to figure out if the device is the same one that was previously plugged in. Without that, we don't really have a reliable unique ID for a port. Other operating systems have the same issues with identifying devices, especially when there's more than one of the same. But maybe they are a little cleaner about the impacts.

The BLE connection issue is known as well. The timestamp issue was new, but I've made folks aware now. The connection issue has to do with how BLE devices work on Windows compared to other Bluetooth standards: we don't know if the device is still there until we try to access it. We need to handle this better, though.

The new USB Driver, API, SDK, and other future transports are all open source (edit: unless they are existing code. We're investigating the right approach for BLE going forward). The repo at github.com/Microsoft/midi will be public as soon as the MIDI Association votes to approve the latest standards update (the vote is in progress now). I can't open the repo until that NDA is lifted. But once that happens, we will be happy to take issues, PRs, etc. in a more transparent way. Feedback hub is necessary for some things, but it's difficult to close the loop there.

@symdeb
Copy link

symdeb commented Mar 23, 2023

It is great to have someone from Microsoft here paying attention as the feedback hub did not provide any progress for the many posts placed in the past 6 years .

I have been using MSYS /GCC which I don't think it can link nuget packages. A working Win32 wrapper for WINRT would be very welcome.

I can't recall ever having unrecoverable hot-plug issues with Mac OSX (BLE+USB) and ALSA (BLE+USB) Linux and the legacy Win32 (USB) devices. Could identify the open/close port after hot plug without issues, even using 2 identical devices. Some devices do not provide serial-numbers though.

@Psychlist1972
Copy link

@symdeb

I'll keep in mind the non-Nuget folks. We'll have the winmds and whatnot on github for people who can't use the package manager. But any wrapper would need to be written and maintained by others. MIDI 2.0 is significantly more complex and continues to evolve (new transports etc.) so better to use the delivered API and SDK directly if at all possible.

I really don't think a wrapper will be needed, but I'm not familiar with how GCC on Windows works today, or what it can consume. But C++/WinRT has support for more than just Visual Studio. Everything it produces is just standard C++.

https://en.wikipedia.org/wiki/C++/WinRT
https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/
https://github.com/microsoft/cppwinrt

BLE: Thanks. I said "how BLE works on Windows", but that likely wasn't exactly correct. It's more about how the BLE/GATT APIs used worked on Windows at the time BLE MIDI was written. It's being looked at with an eye on these and other concerns, and also with it being fully open source.

Pete

@sagamusix
Copy link
Contributor

I guess this issue should be closed as RtMidi 6.0.0 adds support for UWP.

@Psychlist1972 would you be able to comment on the fact why most MIDI output devices do appear to have nonsensical device names in Windows 10? @trueroad added a workaround for this in the RtMidi code but the workaround doesn't work if there's more than one of the same device. I added another pull request to address this (#321), but it would be good to know why this happens in the first place. Is it to be considered an OS bug?

@Psychlist1972
Copy link

I guess this issue should be closed as RtMidi 6.0.0 adds support for UWP.

@Psychlist1972 would you be able to comment on the fact why most MIDI output devices do appear to have nonsensical device names in Windows 10? @trueroad added a workaround for this in the RtMidi code but the workaround doesn't work if there's more than one of the same device. I added another pull request to address this (#321), but it would be good to know why this happens in the first place. Is it to be considered an OS bug?

I consider it an OS bug with our enumeration code for WinRT MIDI 1.0. It's being addressed as part of the stack update, but that would mean anything to WinRT MIDI until next year when we repoint the API to the new service. Names come from so many places, and devices are not consistent in how they supply them, and there are differences depending on driver model used, so some (in my opinion) incorrect choices were made when sorting out naming for that API. WinRT MIDI's uptake is low compared to WinMM, so we haven't prioritized changes there and instead are dealing with it in the new stack.

FWIW, this is where we are with the new stack today:
https://github.com/microsoft/MIDI/releases/tag/dev-preview-1

Pete

@sagamusix
Copy link
Contributor

Thanks for the explanation Pete. As you probably know much more than us about the issue with output port names, maybe you could have a look at the PR I mentioned (#321) and just confirm that in general RtMidi is doing the right thing? Is the substring comparison in that function even sensible, or should it instead only check for exact matches?

WinRT MIDI's uptake is low compared to WinMM, so we haven't prioritized changes there and instead are dealing with it in the new stack.

Unfortunately I think this is also a bit of a chicken/egg problem. At least for me the naming issue is definitely one reason why I wouldn't consider enabling the WinRT API by default in my project (@OpenMPT) yet and still use WinMM as the default choice, even though I would be really happy to offer the improvements it brings to my users.

@Psychlist1972
Copy link

Thanks for the explanation Pete. As you probably know much more than us about the issue with output port names, maybe you could have a look at the PR I mentioned (#321) and just confirm that in general RtMidi is doing the right thing? Is the substring comparison in that function even sensible, or should it instead only check for exact matches?

WinRT MIDI's uptake is low compared to WinMM, so we haven't prioritized changes there and instead are dealing with it in the new stack.

Unfortunately I think this is also a bit of a chicken/egg problem. At least for me the naming issue is definitely one reason why I wouldn't consider enabling the WinRT API by default in my project (@OpenMPT) yet and still use WinMM as the default choice, even though I would be really happy to offer the improvements it brings to my users.

The substring search is probably reasonable, but needs testing, of course. Devices have all sorts of names, and some include "MIDI" in various positions.

Note that this will change when we repoint the WinRT and WinMM APIs, and the related device enumeration, to Windows MIDI Services in 2024, so you'll want to make sure your code doesn't break there. After that change, the names will be consistent across APIs.

Pete

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request A feature request with incomplete or no implementation offfered.
Projects
None yet
Development

No branches or pull requests

9 participants