Skip to main content
September 21, 2016
Mobile

MIDI Enhancements in Windows 10



As Windows 10 evolves, we are continuing to build in support for musician-focused technologies.

Let’s take a look at MIDI. Windows has had built-in MIDI support going back to the 16-bit days. Since then, most MIDI interfaces have moved to USB and our in-box support has kept pace, with a class driver and APIs that support those new interfaces.

Those unfamiliar with music technology may think of MIDI as just .mid music files. But that’s only a tiny part of what MIDI really is. Since its standardization in 1983, MIDI has remained the most used and arguably most important communications protocol in music production. It’s used for everything from controlling synthesizers and sequencers and changing patches for set lists, to synchronizing mixers and even switching cameras on podcasts using a MIDI control surface. Even the Arduino Firmata protocol is based on MIDI.

In this post, we’ll talk about several new things we’ve created to make MIDI even more useful in your apps:

  • UWP MIDI Basics – using MIDI in Windows Store apps
  • New Bluetooth LE MIDI support in Windows 10 Anniversary Update
  • The Win32 wrapper for UWP MIDI (making the API accessible to desktop apps)
  • MIDI Helper libraries for C# and PowerShell

In addition, we included a number of audio-focused enhancements when Windows 10 was released last summer. These enhancements included: low-latency improvements to WASAPI, additional driver work with partners to opt-in to smaller buffers for lower latency on modern Windows 10 devices like Surface and phones like the 950/950xl; tweaks to enable raw audio processing without any latency-adding DSP; a new low-latency UWP Audio and effects API named AudioGraph; and, of course, a new UWP MIDI API.

We’ve also recently added support for spatial audio for immersive experiences. This past fall, in the 1511 update, we enabled very forward-looking OS support for Thunderbolt 3 Audio devices, to ensure we’re there when manufacturers begin creating these devices and their high performance audio drivers. Cumulatively, this was a lot of great work by Windows engineering, all targeting musicians and music creation apps.

UWP MIDI Basics

In Windows 10 RTM last year we introduced a new MIDI API, accessible to UWP Apps on virtually all Windows 10 devices, which provides a modern way to access these MIDI interfaces. We created this API to provide a high performance and flexible base upon which we can build support for new MIDI interfaces.

We originally put this API out for comment as a NuGet package in Windows 8.1 and received a lot of feedback from app developers. What you see in Windows 10 is a direct result of that feedback and our testing.

The API plugs in nicely with the device enumeration and watcher APIs in UWP, making it easy to detect hot plug/unplug of devices while your app is running.

Here’s a simple way to get a list of MIDI devices and their IDs, using C#:

[code lang=”csharp”]

using Windows.Devices.Midi;
using Windows.Devices.Enumeration;

private async void ListMidiDevices()
{
// Enumerate Input devices

var deviceList = await DeviceInformation.FindAllAsync(
MidiInPort.GetDeviceSelector());

foreach (var deviceInfo in deviceList)
{
System.Diagnostics.Debug.WriteLine(deviceInfo.Id);
System.Diagnostics.Debug.WriteLine(deviceInfo.Name);
System.Diagnostics.Debug.WriteLine("———-");
}

// Output devices are enumerated the same way, but
// using MidiOutPort.GetDeviceSelector()
}

[/code]

And here’s how to set up a watcher and handle enumeration/watcher events, and also get the list of connected interfaces. This is a bit more code, but it’s a more appropriate approach for most apps:

[code lang=”csharp”]

private void StartWatchingInputDevices()
{
var watcher = DeviceInformation.CreateWatcher(
MidiInPort.GetDeviceSelector());

watcher.Added += OnMidiInputDeviceAdded;
watcher.Removed += OnMidiInputDeviceRemoved;
watcher.EnumerationCompleted += OnMidiInputDeviceEnumerationCompleted;

watcher.Start();
}

private void OnMidiInputDeviceEnumerationCompleted(
DeviceWatcher sender, object args)
{
// Initial enumeration is complete. This is when
// you might present a list of interfaces to the
// user of your application.
}

private void OnMidiInputDeviceRemoved(
DeviceWatcher sender, DeviceInformationUpdate args)
{
// handle the removal of a MIDI input device
}

private void OnMidiInputDeviceAdded(
DeviceWatcher sender, DeviceInformation args)
{
// handle the addition of a new MIDI input device
}

[/code]

Using a watcher for listing devices and handling add/remove is a best practice to follow in your apps. No one wants to restart their app just because they forgot to plug in or turn on their MIDI controller. Using the watcher makes it easy for your app to appropriately handle those additions/removals at runtime.

The API is simple to use, with strongly typed classes for all standard messages, as well as support for SysEx and buffer-based operations. This C# example shows how to open input and output ports, and respond to specific MIDI messages.

[code lang=”csharp”]

using Windows.Devices.Midi;
using Windows.Devices.Enumeration;

private async void MidiExample()
{
string outPortId = "id you get through device enumeration";
string inPortId = "id you get through device enumeration";

// open output port and send a message
var outPort = await MidiOutPort.FromIdAsync(outPortId);
var noteOnMessage = new MidiNoteOnMessage(0, 110, 127);
outPort.SendMessage(noteOnMessage);

// open an input port and listen for messages
var inPort = await MidiInPort.FromIdAsync(inPortId);
inPort.MessageReceived += OnMidiMessageReceived;
}

private void OnMidiMessageReceived(MidiInPort sender,
MidiMessageReceivedEventArgs args)
{
switch (args.Message.Type)
{
case MidiMessageType.NoteOn:
break;
case MidiMessageType.PolyphonicKeyPressure:
break;
// etc.
}
}

[/code]

In most cases, you would inspect the type of the message, and then cast the IMidiMessage to one of the strongly-typed messages defined in the Windows.Devices.Midi namespace, such as MidiNoteOnMessage or MidiPitchBendChangeMessage. You’re not required to do this, however; you can always work from the raw data bytes if you prefer.

The Windows 10 UWP MIDI API is suitable for creating all kinds of music-focused Windows Store apps. You can create control surfaces, sequencers, synthesizers, utility apps, patch librarians, lighting controllers, High Voltage Tesla Coil Synthesizers and much more.

Just like the older MIDI APIs, the Windows 10 UWP MIDI API works well with third-party add-ons such as Tobias Erichsen’s great rtpMIDI driver, providing support for MIDI over wired and Wi-Fi networking.

One great feature of the new API is that it is multi-client. As long as all apps with the port open are using the Windows 10 UWP MIDI API and not the older Win32 MME or DirectMusic APIs, they can share the same device. This is something the older APIs don’t handle without custom drivers and was a common request from our partners and customers.

Finally, it’s important to note that the Windows 10 UWP MIDI API works with all recognized MIDI devices, whether they use class drivers or their own custom drivers. This includes many software-based MIDI utilities implemented as drivers on Windows 10.

New Bluetooth LE MIDI support in UWP MIDI

In addition to multi-client support and the improvements we’ve made in performance and stability, a good reason to use the Windows 10 UWP MIDI API is because of its support for new standards and transports.

Microsoft actively participates in the MIDI standards process and has representatives in the working groups. There are several of us inside Microsoft who participate directly in the creation, vetting and voting of standards for MIDI, and for audio in general.

One exciting and relatively new MIDI standard which has been quickly gaining popularity is Bluetooth LE MIDI. Microsoft voted to ratify the standard based upon the pioneering work that Apple did in this space; as a result, Apple, Microsoft and others are compatible with a standard that is seeing real traction in the musician community, and already has a number of compatible peripherals.

In Windows 10 Anniversary Edition, we’ve included in-box support for Bluetooth LE MIDI for any app using the Windows 10 UWP MIDI API.

In Windows 10 Anniversary Edition, we’ve included in-box support for Bluetooth LE MIDI for any app using the Windows 10 UWP MIDI API. This is an addition which requires no changes to your code, as the interface itself is simply another transparent transport surfaced by the MIDI API.

This type of MIDI interface uses the Bluetooth radio already in your PC, Phone, IoT device or other Windows 10 device to talk to Bluetooth MIDI peripherals such as keyboards, pedals and controllers. Currently the PC itself can’t be a peripheral, but we’re looking at that for the future. Although there are some great DIN MIDI to Bluetooth LE MIDI and similar adapters out there, no additional hardware is required for Bluetooth LE MIDI in Windows 10 as long as your PC has a Bluetooth LE capable radio available.

We know latency is important to musicians, so we made sure our implementation is competitive with other platforms. Of course, Bluetooth has higher latency than a wired USB connection, but that tradeoff can be worth it to eliminate the cable clutter.

When paired, the Bluetooth LE MIDI peripheral will show up as a MIDI device in the device explorer, and will be automatically included in the UWP MIDI device enumeration. This is completely transparent to your application.

For more information on how to discover and pair devices, including Bluetooth LE MIDI devices, please see the Device Enumeration and Pairing example on GitHub.

We added this capability in Windows 10 Anniversary Edition as a direct result of partner and customer feedback. I’m really excited about Bluetooth LE MIDI in Windows 10 and the devices which can now be used on Windows 10.

image1

Desktop application support for the UWP MIDI API

We know that the majority of musicians use desktop Win32 DAWs and utilities when making music. The UWP MIDI API is accessible to desktop applications, but we know that accessing UWP APIs from different languages and build environments can be challenging.

To help desktop app developers with the new API and to reduce friction, my colleague Dale Stammen on our WDG/PAX Spark team put together a Win32 wrapper for the Windows 10 UWP MIDI API.

The work our team does, including this API wrapper, is mostly partner-driven. That means that as a result of requests and feedback, we create things to enable partners to be successful on Windows. One of the partners we worked with when creating this is Cakewalk, makers of the popular SONAR desktop DAW application.

This is what their developers had to say about the Win32 wrapper for the UWP MIDI API, and our support for Bluetooth LE MIDI:

“We’re happy to see Microsoft supporting the Bluetooth MIDI spec and exposing it to Windows developers through a simplified API. Using the new Win32 wrapper for the UWP MIDI API, we were able to prototype Bluetooth MIDI support very quickly.   At Cakewalk we’re looking ahead to support wireless peripherals, so this is a very welcome addition from Microsoft.”

Noel Borthwick, CTO, Cakewalk

 

image2

We love working with great partners like Cakewalk, knowing that the result will directly benefit our mutual customers.

This Win32 wrapper makes it simple to use the API just like any flat Win32 API. It surfaces all the capabilities of the Windows 10 UWP MIDI API, and removes the requirement for your Win32 application to be UWP-aware. Additionally, there’s no requirement to use C++/CX or otherwise change your build tools and processes. Here’s a C++ Win32 console app example:

[code lang=”csharp”]

// open midi out port 0
result = gMidiOutPortOpenFunc(midiPtr, 0, &gMidiOutPort);
if (result != WINRT_NO_ERROR)
{
cout << "Unable to create Midi Out port" << endl;
goto cleanup;
}

// send a note on message to the midi out port
unsigned char buffer[3] = { 144, 60 , 127 };
cout << "Sending Note On to midi output port 0" << endl;
gMidiOutPortSendFunc(gMidiOutPort, buffer, 3);

Sleep(500);

// send a note off message to the midi out port
cout << "Sending Note Off to midi output port 0" << endl;
buffer[0] = 128;
gMidiOutPortSendFunc(gMidiOutPort, buffer, 3);

[/code]

This API is optimized for working with existing Win32 applications, so we forgo strongly typed MIDI messages and work instead with byte arrays, just like Win32 music app developers are used to.

We’re still getting feedback from partners and developers on the API wrapper, and would love yours. You can find the source code on GitHub. We may change the location later, so the aka.ms link ( http://aka.ms/win10midiwin32 ) is the one you want to keep handy.

For developers using recent versions of Visual Studio, we’ve also made available a handy NuGet package.

We’re already working with desktop app partners to incorporate into their applications this API using this wrapper, as well as other audio and user experience enhancements in Windows 10. If you have a desktop app targeting pro musicians and have questions, please contact me at @pete_brown on Twitter, or pete dot brown at Microsoft dot com.

MIDI Helper libraries for Windows Store apps

In addition to the Win32 API wrapper, we also have some smaller helper libraries for store app developers and PowerShell users.

The first is my Windows 10 UWP MIDI API helper, for C#, VB, and C++ Windows Store apps. This is designed to make it easier to enumerate MIDI devices, bind to the results in XAML and respond to any hot plug/unplug changes. It’s available both as source and as a compiled NuGet package.

It includes a watcher class with XAML-friendly bindable / observable collections for the device information instances.

RPN and NRPN Messages

Additionally, the helper library contains code to assist with RPN (Registered Parameter Number) and NRPN (Non-Registered Parameter Number) messages. These can be more challenging for new developers to work with because they are logical messages comprised of several different messages aggregated together, sent in succession.

image3

Because we exposed the Windows.Devices.Midi.IMidiMessage interface in UWP, and the underlying MIDI output code sends whatever is in the buffer, creating strongly typed aggregate message classes was quite easy. When sending messages, you use these classes just like any other strongly typed MIDI message.

I’m investigating incorporating support for the proposed MPE (Multidimensional Polyphonic Expression), as well as for parsing and aggregating incoming RPN and NRPN messages. If these features would be useful to you in your own apps, please contact me and let me know.

MIDI Clock Generator

One other piece the library includes is a MIDI clock generator. If you need a MIDI clock generator (not for a sequencer control loop, but just to produce outgoing clock messages), the library contains an implementation that you will find useful. Here’s how you use it from C#:

[code lang=”csharp”]

private MidiClockGenerator _clock = new MidiClockGenerator();


_clock.SendMidiStartMessage = true;
_clock.SendMidiStopMessage = true;

foreach (DeviceInformation info in deviceWatcher.OutputPortDescriptors)
{
var port = (MidiOutPort)await MidiOutPort.FromIdAsync(info.Id);

if (port != null)
_clock.OutputPorts.Add(port);
}

public void StartClock()
{
_clock.Start();
}

public void StopClock()
{
_clock.Stop();
}

public double ClockTempo
{
get { return _clock.Tempo; }
set
{
_clock.Tempo = value;
}
}

[/code]

My GitHub repo includes the C++/CX source and a C#/XAML client app. As an aside: This was my first C++/CX project. Although I still find C# easier for most tasks, I found C++ CX here quite approachable. If you’re a C# developer who has thought about using C++ CX, give it a whirl. You may find it more familiar than you expect!

This library will help developers follow best practices for MIDI apps in the Windows Store. Just like with desktop apps, if you’re building a musician-focused app here and have questions, please contact me at @pete_brown on Twitter, or pete dot brown at Microsoft dot com.

The second helper library is a set of PowerShell commands for using the Windows 10 UWP MIDI API. I’ve talked with individuals who are using this to automate scripting of MIDI updates to synchronize various mixers in a large installation and others who are using it as “glue” for translating messages between different devices. There’s a lot you can do with PowerShell in Windows 10, and now MIDI is part of that. The repo includes usage examples, so I won’t repeat that here.

Conclusion

I’m really excited about the work we continue to do in the audio space to help musicians and music app developers on Windows.

Altogether, the UWP MIDI API, the Win32 wrapper for the UWP MIDI API, and the helper libraries for Windows Store apps and for PowerShell scripting make it possible for apps and scripts to take advantage of the latest MIDI tech in Windows 10, including Bluetooth MIDI.

I’m really looking forward to the upcoming desktop and Windows Store apps which will support this API, and technologies like Bluetooth LE MIDI. And, as I mentioned above, please contact me directly if you’re building a pro musician-targeted app and need guidance or otherwise have questions.

Resources

Download Visual Studio to get started.

The Windows team would love to hear your feedback.  Please keep the feedback coming using our Windows Developer UserVoice site. If you have a direct bug, please use the Windows Feedback tool built directly into Windows 10.