MIDI 2.0 Preview Branch

Hello everybody,

We’re excited to announce the first batch of MIDI 2.0 support is now available on the midi2 branch:

This preview branch introduces OS/Hardware level MIDI 2.0 support across all JUCE supported platforms.

If you are working on a DAW, a plugin host or a standalone app and are interested in MIDI 2.0, please do give this preview branch a spin — it’s a great opportunity to provide feedback before the work lands on develop.

We’d also appreciate anyone using the MidiInput and MidiOutput classes (for example, standalone synths) to help confirm behavior is unchanged.

Higher-resolution note/channel message format

MIDI 2.0 brings a new format for MIDI messages: “Universal MIDI Packet” or UMP. Each message contains more data than a classic MIDI 1.0 message. For example, Velocity and CC can now express a large 16-bit range (0-65,535) instead of the classic 7-bit (0-127).

This branch adds the ump::Input and ump::Output types that speak the new UMP MIDI format. These types can send MIDI 1.0 or MIDI 2.0 channel-voice messages. There’s also some other quality-of-life improvements, like being able to detect when a particular input or output gets disconnected.

Because the new types support everything that the old MidiInput and MidiOutput supports (aka MIDI 1.0 messages), we’ve re–implemented MidiInput and MidiOutput entirely in terms of the new types — a big under-the-hood change.

New UMP demo

To help you debug UMP, a new Demo is available in DemoRunner.app > Audio > UmpDemo.

Session API

The new Session API manages MIDI 2.0 Inputs and Outputs.

Session also takes advantage of Microsoft’s new OS-level API, called Windows Midi Services, currently in preview. On “Canary” builds of Windows with the SDK installed, this allows management of separate documents (i.e. multiple DAW sessions or browser tabs) independently.

Endpoint API handles device discovery/negotiation

MIDI 2.0 brings a new way of reporting detailed information about connected MIDI devices.

Endpoints::getStaticDeviceInfo reports detailed immutable information such as manufacturer, product name, transport type — all information available from the OS before a MIDI connection is established.

After establishing a connection, MIDI device discovery can report more information via Endpoints::getEndpoint. This includes advanced information about the MIDI 2.0 “function block layout,” allowing developers to discover and present user-friendly naming when dealing with connector routing.

Android support

JUCE’s MIDI 2.0 implementation for Android was more involved than other platforms.

On Windows/Linux/Apple, multiple apps can send/receive messages to the same device at the same time — it makes sense then that the OS handles the device discovery, so each app can share the discovery results.

On Android, output connections are exclusive. Only one app can send messages to a device at a time. This makes the OS-level API simpler, but means that each app must handle the discovery and negotiation details. JUCE handles this piece of the work for you in this branch.

JUCE’s MIDI 2.0 roadmap

We are working on MIDI 2.0 from the outside-in. If you imagine where a plugin sits in relation to physical hardware, there are (at least) two layers of APIs:

  • The OS APIs — to get messages between the computer and hardware
  • The plugin APIs — to send messages between the plugin and the DAW

This preview branch’s scope is OS-level APIs.

MIDI 2.0 work will continue. Keep in mind that MIDI 2.0 isn’t just one thing — it’s a bunch of different features that can be mixed and matched. Synth plugin developers can eventually expect to see AudioProcessor support UMP (Universal MIDI Packets), etc.

In the meantime, if OS-level MIDI 2.0 support is something that interests you, please do checkout the branch and let us know how it’s working.

31 Likes

This is outstanding news! Looking forward to digging into it.

5 Likes

Forgot to mention: the new branch also includes support for creating virtual MIDI ports on Android, which is a feature that’s been missing from JUCE up until now. This makes it easier to route MIDI between apps, e.g. a synth app might want to expose a virtual MIDI input, and controllers/sequencers may decide to export a virtual MIDI output. The virtual inputs and outputs can be set up to behave like a full UMP endpoint, exposing function blocks and other metadata.

3 Likes

Excellent news, well done JUCE team! I will be putting this into some lab testing in the next few days .. exciting feature!

This branch incorrectly merged features and now completely breaks JACK:

1 Like

Apologies - this one slipped through as we rebased the MIDI work onto the develop branch.

It is fixed here:

Thank you for reporting.

1 Like

Ah I see. That was already fixed before I reported it, but not yet pushed :wink:

Hope this rebasing didn’t break anything else :#

Me too! :crossed_fingers:

2 Likes

Intruiging - something to maybe make me move to JUCE 8 finally - quick Q, are virtual ports and multi-client supported on Windows? thx

This depends on the MIDI backend you use. Current versions of Windows don’t support these features, but the upcoming Windows MIDI Services (WMS) does. Currently, in order to use WMS you’ll need to install a “canary” preview build of Windows 11, and install the WMS SDK from github. Eventually, WMS will be supported on upcoming releases of Windows 10 and 11.

2 Likes

thx for the update, will give that a go. finally having milti-client windows MIDI is going to be amazing. Is this something that can be detected at runtime through enquiry?

You can use ump::Endpoints::getBackend() to determine which MIDI implementation is currently in use. If you’re on Windows, and the backend isn’t WMS, then you can operate in a reduced functionality mode using the old MIDI APIs, and/or direct users to go and install the appropriate runtime. Another option might be to update your product’s installer to also install the WMS runtime.

2 Likes

thanks

When making decisions based on detection, it’s important to note that Windows MIDI Services comes in two parts:

  • The service and transports, distributed in-box (currently only in Insider Canary builds).
  • The Windows MIDI Services SDK Runtime and Tools (includes the SDK runtime, the command-line MIDI tools, MIDI PowerShell cmdlets, and the MIDI Settings app.). This is delivered out-of-band, and will be updated more frequently than Windows.

If you use WinMM APIs, and Windows MIDI Services is in-box, you get multi-client for free. You’ll also have access to MIDI 2.0 hardware, but downscaled to MIDI 1.0 and translated to the MIDI 1.0 byte format, so with reduced fidelity compared to MIDI 2.0 UMP.

If you want to use MIDI 2.0 features, create loopback endpoints, use the new app-to-app MIDI SDK, etc. You’ll need the new SDK. I’d need to look at the JUCE code to be sure, but I assume the initialization tries to initialize the SDK and falls back if that fails.

If you want finer-grained control:

This code shows how to detect if Windows MIDI Services in-box components are installed, without using anything in the Windows MIDI Services SDK. It’s just COM.

This code shows the full initialization routine (start up the service, initialize the SDK)

This docs page explains how to distribute the runtime

This docs page explains what happens during initialization, and why we did it this way

I’ll have a new “Customer Preview 3” release of the SDK out soon. Just trying to finish up some of the version checking and network MIDI 2.0 client code. It required some small breaks to the versioning to work correctly across both in-box and out-of-box components, and changes to UUIDs requiring a recompile, but that information will all be included in the release notes. It’s release-candidate quality at this point.

Main docs site:

Discord server, including the last couple developer-focused previews

PS, @reuk @t0m and team, fantastic work :slight_smile:

Pete
Microsoft

5 Likes

thx for all the info!

1 Like

New release of Windows MIDI Services today, with what we expect to be the final set of breaking changes.

Until the service makes its way to Windows Insider Canary (takes a few weeks to a month), the install will have several steps, as mentioned in the release notes. Once that service is out in the Windows builds, the install gets much simpler.

We have one set of bugs we’re currently tackling, and that is all around surprise removal of devices like USB (or other kernel streaming drivers). That is being actively worked on. Main bug for tracking is here. More than a quarter of all the remaining issues are directly related to this.

These releases do still require Windows Insider Canary. We’ll begin rolling it out to retail Windows 11, assuming the surprise removal bugs are fixed soon, this fall. We’ve already done all the infrastructure work requires to support that roll-out.

Pete

4 Likes

Just to confirm, there is no support yet for MidiMessage, right? Will that come when the plugin APIs are implemented?

Also to confirm, the MIDI 2.0 Flex data message has not been implemented yet, right?

I built the docs in the midi2 branch, though it doesn’t look like any of the new classes are being recorded by Doxygen. Struggling to find the ump::Input class in the sources.

Thanks!

Sorry, I missed your comment previously!

MidiMessage isn’t going to see any changes, it’s always going to represent a MIDI 1.0 bytestream message. If you want to send/receive bytestream messages through ump::Input or ump::Output, you’re responsible for converting between UMP and bytestream representations on either side. JUCE includes some mechanisms to assist: there’s GenericUMPConverter for conversion from bytestream to UMP-formatted MIDI 1.0 or MIDI 2.0; to go in the other direction, you can use ToBytestreamConverter. The new implementations of MidiInput and MidiOutput do this conversion internally, so you can look at those implementations for pointers if necessary.

We do intend to add some improved setters and getters for properties of MIDI 2.0 messages in UMP format, but those aren’t present in the initial release.

We don’t have a ‘flex data message’ type. But, there’s nothing stopping you from reading/writing flex data messages to a ump::Input or ump::Output. You may need to write your own helpers to pack/unpack plain data into UMP flex-data format. We already supply similar facilities for packing/unpacking 7-bit sysex data, so those might serve as a starting point.

That’s odd, thanks for letting us know!

Update: the midi2 preview branch has now been rebased and merged to develop. The midi2 tag will stick around for a bit on Github, but we encourage you to switch to referencing develop instead at your earliest convenience.

3 Likes