Skip to content

(old) In-box Dev (and advanced Customers) Preview 8

Pre-release
Pre-release

Choose a tag to compare

@Psychlist1972 Psychlist1972 released this 14 Sep 05:24
· 329 commits to main since this release
baa0bf5

In-Box Developer and Advanced/Technical Customer Preview 8

This release is for developers and technical customers with an interest to test, file bugs, and provide feedback. There are almost certainly bugs and missing/incomplete features. Do not install anything unless you have read these release notes and are comfortable with what is here.

This release note is cumulative. Previews 1 through 7 each documented only what changed since the one before it, which made it hard to see the whole picture. Everything from those releases has been folded in here, so a developer picking this up for the first time can read one document and understand every change since the rc4 App SDK. Preview-by-preview history is at the bottom, under
Change history, Preview 1 through Preview 7.

Plan is to have all of these transports and the API in Windows 11 25h2 and higher starting during the last week of November 2026. The cutoff for getting into that release is in September, so that is what we are working towards. Any issues found after the cutoff will be fixed in subsequent Windows updates.

Important notes:

  • You cannot edit the MIDI 2 loopbacks using the tools here. Required features are not present until the November CFR. For customers who need to use the MIDI 2 loopbacks, continue to use the older SDK and Tools release from https://aka.ms/midi
  • Those same older tools will not work with the Basic Loopback, Network MIDI 2.0, or Bluetooth MIDI transports included in this release.
  • All service-related changes will ship as Controlled Feature Rollout (CFR) starting at the end of November for 25h2 and up. It takes up to 45 days for features to be enabled on all PCs that are up to date with updates. Until those features are enabled, anything in this release which depends on feature enablement will not yet function at the levels covered here.
  • Windows 11 24h2 will not receive the new API or any of the November features or fixes. 24h2 customers are advised to either update to 25h2 or turn on Legacy API Mode

Contents


Permitted use

We want to ensure customers have the best experience going forward. Because of this, we want to ensure that these app-local binaries are not present on customer systems which have the binaries in System32. There is nothing in these binaries to enforce this, so it is entirely on you, the app or library developer, to ensure you do not distribute these files in situations where that happens.

"Binaries" here refers to the .dll, .pri and .pdb files included in the packages below, as well as any tool .exe files included. "Product" here refers to your application, library, service, or other code you are writing against these files.

Use Permitted?
Development Your developers may use the binaries here for development and testing of future releases of a product
Testing Your testing team(s) may use these binaries with your product
Customer Preview You may distribute the WinRT API binaries with an alpha/beta/preview version of your app as long as that app has an enforced (through code or obvious and explicit agreement) expiration date of no later than January 15, 2027, and you clearly indicate that this is using pre-release code which may not work in production. You are responsible for all support
Production / Release app These WinRT API binaries are not permitted for this use. Do not distribute these binaries with a production application unless you have received explicit emailed permission from Pete Brown at Microsoft

Do not redistribute any of the installers or transports.


What is new in Preview 8

Breaking API changes

There are very few here, and they are targeted. All of them require a recompile against the NuGet package in this release.

MidiEndpointConnection.AddMessageProcessingPlugin now returns a result.

// before
[noexcept] void AddMessageProcessingPlugin(IMidiEndpointMessageProcessingPlugin plugin);

// after
[noexcept] MidiMessageProcessingPluginAddResult AddMessageProcessingPlugin(IMidiEndpointMessageProcessingPlugin plugin);

There were several ways to add a plugin that would silently never be called, and no way for an app or a library to find out. The new Windows.Devices.Midi2.MidiMessageProcessingPluginAddResult enum reports which one happened:

Value Meaning
Succeeded The plugin was added
FailedPluginIsNull The plugin passed in was null
FailedRawCallbackRegistered The connection has a COM extensions messages-received callback registered. That callback bypasses all message processing plugins, so the plugin would never be called. Use one approach or the other
FailedPluginAlreadyAdded A plugin with this same PluginId has already been added to this connection
FailedPluginInitializationError The plugin was added, but threw while being initialized, so it may not be functional. Remove it with RemoveMessageProcessingPlugin if that matters to you

This matters most to library authors. If your library adds a listener on a connection the app also uses, the app can now be told why the listener did nothing, instead of debugging silence.

MidiEndpointDeviceInformation.IsMidi1PortCreationEnabled has been removed. It was never populated by anything, so it was always true regardless of the endpoint. Removing it before production is better than shipping a property that cannot be trusted. Fixes
#1192.

Midi1PortNamingApproach gains UseAutomatic = 3. See MIDI 1.0 port naming rework below. This is an additive enum change, but it is also the new default behavior, so read that section before assuming port names are stable
from Preview 7.

COM Extensions: SetMessagesReceivedCallback now has a defined contract. It previously accepted calls it could not honor. It must be called before Open() on the connection, and only on a connection which has no message processing plugins attached. It now returns:

HRESULT Meaning
E_INVALIDARG The callback is null
E_ILLEGAL_METHOD_CALL The connection has already been opened
E_ILLEGAL_STATE_CHANGE The connection has message processing plugins attached, which this callback would bypass

If you were relying on the previous silent behavior, you were relying on a bug.

New API surface

Network MIDI 2.0 typed configuration for entry updates and saved client decisions. Until now, changing settings on an existing host or client entry meant tearing it down and creating it again. These new types change an entry in place.

Type Purpose
MidiNetworkHostUpdateConfig Changes to an existing host entry, applied without taking the host down
MidiNetworkClientUpdateConfig Changes to an existing client entry, applied without disconnecting it
MidiNetworkClientUpdateResponse Result of a client update, with Success, ErrorCode and ErrorMessage
MidiNetworkClientUpdateErrorCode Error codes for the above
MidiNetworkKnownRemoteClient A remote client this PC has already decided about: name, product instance id, and whether it is allowed
MidiNetworkHostKnownClientsConfig The complete set of allow/deny decisions for a host, so those decisions survive a service restart
MidiNetworkRemoteClientForgetConfig Identifies one remote client whose remembered decision is to be dropped
MidiNetworkRemoteClientForgetResponse Result of a forget, with Success, ErrorCode and ErrorMessage
MidiNetworkRemoteClientForgetErrorCode Error codes for the above

New methods on MidiNetworkTransportManager:

[noexcept] static Windows.Foundation.IAsyncOperation<MidiNetworkHostUpdateResponse> UpdateNetworkHostAsync(
    MidiNetworkHostUpdateConfig updateConfig);

[noexcept] static Windows.Foundation.IAsyncOperation<MidiNetworkClientUpdateResponse> UpdateNetworkClientAsync(
    MidiNetworkClientUpdateConfig updateConfig);

[noexcept] static Windows.Foundation.IAsyncOperation<MidiNetworkRemoteClientForgetResponse> ForgetRemoteClientAsync(
    MidiNetworkRemoteClientForgetConfig forgetConfig);

Note the split in how the two kinds of setting behave. Whether an endpoint has MIDI 1.0 ports at all is decided when the endpoint is created, so CreateMidi1Ports is recorded for the next connection rather than applied to one already up. FallbackMidi1PortCount applies to an endpoint which is already up.

MidiNetworkHostKnownClientsConfig is save-only. There is nothing to send: the service is told about a single decision through ApproveOrDenyRemoteClientConnectRequestAsync, and this type is the configuration file record of every decision made so far. Both saved lists are replaced by what it holds, so it must be the complete set for the host and not only what changed.

Withdrawing a decision takes both halves. Leaving a client out of MidiNetworkHostKnownClientsConfig removes it from the saved set, but that only changes what the next service start reads — the running service keeps its own copy of the allow and deny lists and goes on applying the old decision. ForgetRemoteClientAsync is what makes the running service drop it, so a device stops being blocked, or stops being admitted silently, straight away rather than after a restart. Do both: save the list without that client, and call ForgetRemoteClientAsync.

Forgetting is not blocking. A session which is already established is left running; only the remembered decision goes, so the remote is asked about again the next time it invites. Forgetting an identity the host holds no decision for reports success, because what the caller asked for is already true — there is deliberately no RemoteClientNotFound in MidiNetworkRemoteClientForgetErrorCode. An older service which does not have the command reports UnrecognizedCommand, which is how an application can tell the difference between "done" and "saved, but not applied until restart".

Fallback MIDI 1.0 port count. MidiNetworkClientConnectConfig and MidiNetworkHostCreationConfig each gain:

[noexcept] UInt8 FallbackMidi1PortCount;

A Network MIDI 2.0 device describes itself with function blocks, and the MIDI 1.0 ports are built from those. A device which never completes discovery declares none, and would previously get no MIDI 1.0 ports at all, permanently and silently. It now gets this many source and destination ports instead. Ignored when the device does describe itself, and when CreateOnlyUmpEndpoints is true. Valid values are 1 through 16. This fixes issue 1190

Bluetooth: MidiBluetoothDeviceConnectErrorCode.GattCallFailed. The call failed rather than running out of time. The device was present and answering, so it refused or dropped the request instead of ignoring it. Previously this was indistinguishable from a timeout.

MidiClock fixes

MidiClock had arithmetic bugs that only showed up with negative offsets, which is exactly what latency compensation needs, and which the IDL has always declared as Int64.

  • OffsetTimestampByMicroseconds and OffsetTimestampByMilliseconds returned a very large positive timestamp for any negative offset. Both are now correct. OffsetTimestampBySeconds uses the same corrected arithmetic.
  • The clamp in OffsetTimestampByTicks could never fire, so underflow wrapped to a huge timestamp which the service then rejected as too far in the future. It now clamps.
  • GetCurrentSystemTimerInfo had its conversion inverted. This was a no-op on every machine we measured, x64 and Arm64 alike, but it is now correct rather than accidentally correct.
  • Behavior change: BeginLowLatencySystemTimerPeriod and EndLowLatencySystemTimerPeriod are now reference counted. Begin now returns true when the period is already held, where it used to return false. This is required for it to compose. The SDK loads into hosts which also load plugins, and a second caller has to be told it is covered rather than being told it failed.

MIDI 1.0 port naming rework

This is the largest change in the release, and most of it is service-side, so it arrives with Windows in November rather than in the packages here. The SDK-visible part is the new Midi1PortNamingApproach.UseAutomatic value, which will not be usable until the November release.

The problem: the previous choice was binary and global. "Classic compatible" gave the WinMM names people have had for decades, which for many devices are MIDIOUT2 (Some Device) and carry no information. "New style" took the device-supplied port name, which is much better when a device supplies one, and much worse when it does not.

Automatic makes that choice per device rather than per PC:

  • Where a device supplies real port names, those are used and composed with the endpoint name.
  • Where a device supplies nothing useful, the classic WinMM names are kept byte for byte. If there is no new information to convey, we do not change a name people depend on.
  • Endpoint names now prefer the device's own product name where the device supplies one, rather than the driver's description. This alone is a material improvement for several device families where two physically different products previously showed identical names.
  • Names are made unique across endpoints, not just within one device.
  • Non-ASCII characters are now preserved in legacy WinMM port names. Names containing accented or non-Latin characters were previously mangled or truncated.
  • Group terminal block names are kept in sync when you customize a port name. Developers and users have reported the mismatch as confusing.
  • Network MIDI 2.0 and Bluetooth MIDI endpoints always use new-style names. Their ports never existed under the old WinMM stack, so there is no compatibility to preserve. This is declared by the transport rather than hardcoded in the service, so a third-party transport can make the same choice for itself.

A new KB article covers the whole scheme, including worked examples:
How MIDI 1.0 port names are generated.

Message scheduler rework

Also service-side, so it arrives with Windows in November rather than in these packages. Recorded here because it changes timing behavior that apps can observe.

The outgoing message scheduler used to wait for a message by spinning on a time-critical thread for anything scheduled less than two seconds in the future, which is the ordinary case for a sequencer. Measured on one test PC, a single endpoint streaming 100 scheduled messages per second consumed approximately one full processor core inside the service, and two endpoints consumed two. It now
uses a high-resolution waitable timer with a very small guard band, and the same test measured roughly a tenth of that. Scheduling accuracy is unchanged, and the service no longer raises its own process priority.

Alongside it, outgoing latency compensation is now actually consumed. The endpoint properties for calculated latency, custom latency, and which of the two wins have existed and been documented for some time, but nothing read them. The Bluetooth transport now publishes a calculated value derived from the negotiated connection interval, and Network MIDI 2.0 publishes one derived from its
measured round trip. USB deliberately does not publish a calculated value: we measured a range of USB interfaces and the compensatable offset varies from effectively zero to several milliseconds with nothing in a descriptor or a VID/PID able to predict which. See USB MIDI device round trip measurements
for the data and the method.

Network MIDI 2.0

  • MIDI 1.0 ports are now created for network endpoints by default.
  • A remote which never completes discovery declares no function blocks and previously received no MIDI 1.0 ports at all. It now receives a configurable fallback number of them. See FallbackMidi1PortCount above.
  • MIDI 1.0 port settings on a host or a client can be changed without disconnecting.
  • The synthesized fallback group terminal block is now named, and every group it covers is named with it, instead of leaving groups unnamed.
  • Saved allow/deny decisions for remote clients now survive a service restart.
  • An endpoint customization can now be withdrawn. Saving a customization merges into what is already there, so this is the only way to take an entry back out of the configuration file.
  • Configuration file handling was hardened against malformed and hostile input.
  • Fixed: a restarted host could never accept another invitation (#1190).
  • There's now a system tray app that will show toast when an invite comes in and you need to take action to accept it.
  • Blocking a connected device now disconnects it. denyRemoteClient only acted on clients awaiting approval, so blocking one that was already connected recorded the decision, reported success, and left the session streaming until the device happened to reconnect. The confirmation dialog had been promising a disconnect the service never performed.
  • Forgetting a decision now takes effect immediately rather than at the next service restart, per the paragraph above.

If you used Network MIDI prior to Dev Preview 6, you will still want to fix up your configuration file, as the older entries are not compatible. The Network Config repair script in the assets will do that for you.

image

Bluetooth MIDI

  • Scheduled send timing on BLE endpoints now accounts for the negotiated connection interval, which is typically 7.5 to 15 ms and dominates everything else on the path.
  • Compatibility fixes for more devices, including the PartyKeys.
  • New GattCallFailed connect error code so a refusal is distinguishable from a timeout.
  • General cleanup sweep across the transport and the setup app.

Reminders that still apply:

  • If you are using the KORG BLE MIDI 1.0 driver, fully and completely uninstall it before trying to use BLE MIDI 1.0 devices.
  • If you are using a third-party Bluetooth bridge-type app, or an app which provides Bluetooth MIDI functionality by directly connecting to the devices, do not use it while using the in-box Bluetooth components.
  • Current tested device list: #1173.

Apps and tools

image

New app: MIDI Clock. A dedicated MIDI beat clock generator, laid out as tiles like the Windows Clock app. Each saved clock has a name, an endpoint, a group, and a tempo. It follows the same UI approach as all the other new apps, so colors and backdrop style are user preferences, and the app can be pinned to always be on top if desired.

image - image -
  • Multiple clocks can run at once, on different endpoints and at different tempos.
  • Clocks started together share a single origin timestamp, so they begin on the same tick rather than whenever each connection happened to finish opening.
  • Tap tempo, rounded to the nearest 0.5 BPM. Typing a tempo directly is left free-form so a DAW tempo such as 148.26 can still be entered.
  • Tempo can be changed while a clock is running. The beat re-bases rather than jumping.
  • Command line arguments so MIDI Settings and other apps can hand an endpoint over, optionally with a group and tempo, and optionally start it.
  • Clocks are saved and restored between runs.

Building this also fixed a latent bug in midi.exe: the MIDI Stop message was scheduled one pulse after the last clock pulse, but callers were told to stop draining at the last clock pulse, so the Stop message never reached the wire. Both the app and the console now send it.

image

MIDI Console.

  • midi endpoint properties --include-name-table is back. It shows the MIDI 1.0 port name table for an endpoint: the legacy-compatible name, the new-style name, and any custom name, per group and direction. With the naming rework above, this is the fastest way to see what a device will actually be called and why.
  • Function block direction is now reported from the user's point of view, matching the MIDI 1.0 port table, instead of from the block's point of view. On asymmetric devices the two tables previously disagreed using identical wording.
  • Beat clock generation is now shared with the MIDI Clock app rather than duplicated.
  • midi forward is a new command to bridge endpoints in one direction. Useful for connecting one device to another.
image

mididiag. Output now includes the MIDI 1.0 port name table and the function blocks for each endpoint. If you are asking a customer for a diagnostic dump to investigate a naming or port count problem, this is the tool to ask for.

MIDI Troubleshooting and Repair. The driver switching page no longer assumes that changing a device's driver requires a reboot. It now handles the cases where it does not.

MIDI Monitor. The per-message "note" is now called a "comment", which is considerably less confusing in an application that is full of musical notes.

MIDI Network Setup. Gains the MIDI 1.0 port settings described above, in a Customize dialog alongside device name, description and image. Also has a companion app now which sits in the system tray and tells you when a connect request that requires your approval comes in. Settings for the notifications are in the MIDI Settings app, as this tray will also be used for any similar types of needed notifications.

MIDI Keyboard. Now attempts to get a program list using MIDI-CI. It also has program controls on the UI. This is very early functionality so may not be working 100% yet. There are also some UI layout issues with the flyout for program changes.

Samples

The sample set was substantially reworked. This is the first preview where a developer can find a worked example of most common tasks in both C++/WinRT and C#.

New C++/WinRT samples: detect Windows MIDI Services, get VID/PID, identify endpoint type, scheduled message send, scheduled message send through the COM extensions, SysEx file sender, SysEx file receiver, SysEx byte sender.

New C# samples: endpoint listeners, get VID/PID, identify endpoint type, basic loopback endpoints, MIDI 2.0 loopback endpoints, scheduled message send, send speed, static endpoint enumeration, SysEx file sender, SysEx file receiver, SysEx byte sender, watch endpoints, watch MIDI 1.0 ports.

New PowerShell samples: enumerate groups, enumerate MIDI 1.0 ports, basic loopback endpoints, MIDI 2.0 loopback endpoints, network information, SysEx send, SysEx receive.

Removed: the old samples/cpp detection samples, which were superseded by the new C++/WinRT detection sample; the Electron/JS sample, which had not been updated for the in-box API; and the empty Rust placeholder. Rust projections will come from the official Windows metadata once we ship.

Documentation

New articles:

Substantially updated: the SDK reference for MidiClock, the COM extensions, the client plugin interfaces, the enumeration types, the Network and Bluetooth transport types, MidiSession, MidiReporting, and the SysEx transfer utilities. The transport plugin development guide now covers what a transport must declare about its MIDI 1.0 port names. A number of broken links were repaired.


Corrections to earlier release notes

These changes shipped in Preview 6 and Preview 7 but were not listed in those release notes. They are recorded here so this document is a complete record.

Missing from the Preview 7 notes

All Bluetooth. The Preview 7 notes listed MidiBluetoothTimestampSource and MidiBluetoothDeviceInformation.TimestampSource, but not these:

Addition Notes
MidiBluetoothConnectionState enum NotConnected, WaitingForDevice, Connecting, Connected
MidiBluetoothDeviceInformation.ConnectionState Connecting is asynchronous and a wanted device is retried until it appears, so IsConnected on its own cannot tell an attempt under way from a device which is simply switched off
MidiBluetoothDeviceInformation.RequiresPairing True once the device has refused an operation until the link is authenticated. Nothing in a Bluetooth advertisement declares this, so it is only known after an attempt has been made
MidiBluetoothDeviceInformation.PacketsReceived / PacketsSent GATT packets, counted before any decoding. Packets climbing while MessagesReceived stays at zero means the device is transmitting something this transport cannot decode. Both at zero means the device is sending nothing at all
MidiBluetoothPeripheralStatus.PacketsReceived / PacketsSent Same, for the peripheral role
MidiBluetoothDeviceConnectErrorCode.PairingRequired The device will not talk until the link is authenticated. Automatic reconnection is suspended for it, because every attempt raises another Windows pairing prompt
MidiBluetoothDeviceConnectErrorCode.GattTimeout Nothing came back at all before the operation timed out. Distinct from DeviceUnreachable, which is the radio positively reporting it could not reach the device

Missing from the Preview 6 notes

The Preview 6 notes listed two corrected UUIDs and the Network MIDI 2.0 configuration format changes, but not the 28 types that were added to the API in that release.

Twenty-three of those are the new Windows.Devices.Midi2.Transports.Bluetooth namespace, which
arrived with the Bluetooth MIDI transport itself: MidiBluetoothTransportManager,
MidiBluetoothDeviceInformation, MidiBluetoothRadioInformation, MidiBluetoothAddressType,
MidiBluetoothProtocol, MidiBluetoothApprovalScope, MidiBluetoothDeviceConnectConfig,
MidiBluetoothDeviceConnectResponse, MidiBluetoothDeviceConnectErrorCode,
MidiBluetoothDeviceDisconnectConfig, MidiBluetoothDeviceDisconnectResponse,
MidiBluetoothDeviceDisconnectErrorCode, MidiBluetoothOfflineRetentionConfig,
MidiBluetoothOfflineRetention, MidiBluetoothPeripheralConfig, MidiBluetoothPeripheralResponse,
MidiBluetoothPeripheralErrorCode, MidiBluetoothPeripheralStatus,
MidiBluetoothPeripheralClient, MidiBluetoothPeripheralClientPolicy,
MidiBluetoothPeripheralClientListConfig, MidiBluetoothPeripheralClientDecisionResponse,
MidiBluetoothRememberedClient.

Two of them are worth calling out individually because they are not obvious from the names:

  • MidiBluetoothOfflineRetention controls how long an endpoint stays after its device goes away. This exists because an app on WinMM or WinRT MIDI 1.0 cannot ask whether a device is present, so whether the endpoint exists is the only presence signal it gets. Set per device, with a transport-level default: keep always (the default), remove immediately, or remove after a number of seconds.
  • The peripheral types are for Windows acting as a Bluetooth MIDI peripheral rather than a central, with a policy for which remote clients may connect.

The other five additions in Preview 6 were not Bluetooth:

Type Purpose
MidiServiceConfigSaveResponse Result of persisting a configuration section: Result, Success, a localized ErrorMessage, the configuration file path, and the backup file path when one was taken
MidiServiceConfigSaveResult Why a save failed. Includes ErrorNoConfigFileRegistered, ErrorConfigFileNotValidJson (the file is left untouched rather than overwritten, because replacing it would discard settings the customer may be able to recover), ErrorAccessDenied, ErrorConfigFileBusy, and ErrorNotPersistable for things which are never persisted
MidiServiceEndpointCustomizationRemovalConfig Deletes a stored endpoint customization outright, rather than overwriting it with empty values
MidiNetworkTransportSettings Settings which apply to the Network MIDI 2.0 transport as a whole rather than to one host or client. Values outside the supported range are clamped rather than refused, so read the object back after sending to see what was taken
MidiNetworkAdvertisedHostChangedProperties Flags enum saying what actually changed about an advertised host, so a handler can ignore an update it does not care about rather than re-reading everything

Install instructions

As in the past, these previews are not signed and require you to turn on Developer Mode in Windows Settings > System > Advanced. They also require you to accept a few SmartScreen prompts and choose "keep" so the downloads are not automatically deleted. If you use third-party antivirus or anti-malware software, it may also delete the installs after they happen. You will need to refer
to your own software's settings.

Minimum OS version: Windows 11 25h2.

  1. Make sure you have read all of the information above. Do not install anything without reading and understanding what is in this release.
  2. Before installing anything, completely uninstall all previous loopback previews, network previews, Bluetooth previews, and SDK Runtime and Tools packages. Uninstall the previous in-box developer previews as well as the older release candidates. Ensure that your Program Files\Windows MIDI Services directory is empty or missing, and delete the contents if not.
  3. Install the Basic Loopback, Network, and Bluetooth transport packages. The order is not important.
  4. Install the Tools package. Again, the order is not important.

A common question is "will I need to uninstall these bits before the November release?". In general yes, but other than possibly with the PowerShell cmdlets, we do not anticipate issues if you do not. Just some confusion when you have multiple versions of the same app installed.

Firewall

If you are using Network MIDI 2.0, you may need to let the MIDI Service through the firewall. Additionally, you will need to let the Network MIDI 2.0 Setup app through the firewall; it will prompt on first use. See Network MIDI firewall. If you are using a third-party firewall product, please refer to their instructions. Both the app and the service need access.

Packages

Windows MIDI Services itself is already installed on your PC. These packages are add-ons which preview functionality coming to Windows. They are logically broken up so you do not need to install something you do not need.

Package Contents
Network install The Network MIDI 2.0 Setup app and the Network MIDI 2.0 transport
Bluetooth install The Bluetooth MIDI Setup app and the Bluetooth MIDI transport
Basic Loopback The basic loopback transport. The app, which also supports MIDI 2.0 loopbacks, is in the tools install
Tools install All the other console and GUI tools including the MIDI Console, MIDI Settings, MIDI Monitor, MIDI Clock, Troubleshooting, and the PowerShell cmdlets for MIDI. Everyone will want this
NuGet package For developers to build against in preparation for the November release
Samples zips Source for the C++/WinRT, C# and PowerShell samples

Change history, Preview 1 through Preview 7

This section is the condensed text of the earlier release notes, so that this one document covers everything since the rc4 App SDK.

Preview 1 — the in-box restructure

This was the release that changed the structure and activation of the WinRT API in order to bring it into Windows as a normal WinRT API. It has the largest set of breaking changes of any preview.

Namespaces. Everything moved out of Microsoft.Windows.Devices.Midi2.* and into Windows.Devices.Midi2.*:

Area Before After
All Microsoft::Windows::Devices::Midi2::* Windows::Devices::Midi2::*
Client Plugins Microsoft::...::Midi2::ClientPlugins Windows::Devices::Midi2::ClientPlugins
Diagnostics Microsoft::...::Midi2::Diagnostics Windows::Devices::Midi2::Diagnostics
Enumeration Microsoft::...::Midi2 Windows::Devices::Midi2::Enumeration
MIDI 1 Enumeration Microsoft::...::Midi2 Windows::Devices::Midi2::Enumeration::Legacy
Reporting Microsoft::...::Midi2::Endpoints::Reporting Windows::Devices::Midi2::Reporting
Service Config Microsoft::...::Midi2::ServiceConfig Windows::Devices::Midi2::ServiceConfig
Basic Loopback Microsoft::...::Midi2::Endpoints::BasicLoopback Windows::Devices::Midi2::Transports::BasicLoopback
Loopback Microsoft::...::Midi2::Endpoints::Loopback Windows::Devices::Midi2::Transports::Loopback
Virtual Device Microsoft::...::Midi2::Endpoints::Virtual Windows::Devices::Midi2::Transports::Virtual
Message Utilities Microsoft::...::Midi2::Messages Windows::Devices::Midi2::Utilities::Messages

Note the change from Endpoints to Transports. "Legacy" here refers to the older MIDI 1 APIs, not to MIDI 1 itself. MIDI 1.0 is a first-class citizen of the new API.

Initialization. There is no more COM initializer, no SDK update functionality, and no versioning, because no special logic is required to load an in-box API. EnsureServiceAvailable() moved to a static member of Windows::Devices::Midi2::MidiApi. Use standard WinRT API detection, such as handling REGDB_E_CLASSNOTREG or ApiInformation.IsTypePresent. If you use a COM interface such as IBufferByteAccess or the raw connection interface, you must release those references before calling winrt::uninit_apartment().

Connection. IMidiEndpointConnectionSettings was removed and MidiEndpointConnectionBasicSettings was renamed to MidiEndpointConnectionSettings. The JSON field and customization were not used.

Loopback and Basic Loopback. "Endpoint" was removed from type names and "Loopback" promoted from adjective to noun. MidiBasicLoopbackEndpointManager became MidiBasicLoopbackManager, MidiLoopbackEndpointManager became MidiLoopbackManager, *Result types became *Response types and changed from structs to runtime classes, and *EndpointXConfig became *XConfig. Response types were added for all calls.

Enumeration. All enumeration types moved into the Enumeration namespace or a child of it. Windows.Devices.Midi2.Enumeration.Legacy holds the equivalent types for MIDI 1.0 API ports, plus functions to find the MIDI 1.0 ports for a given endpoint. The functions to enumerate MIDI 1 ports were removed from MidiEndpointDeviceInformation; use MidiLegacyPortDeviceWatcher instead, because MIDI 1 ports are created asynchronously after the endpoint, and the watcher caches and synchronizes centrally. MidiDeclaredDeviceIdentity uses arrays instead of discrete properties for SysExId and SoftwareRevisionLevel. Because several types changed from struct to runtime class, the GetXYZ() methods on MidiEndpointDeviceInformation can now return nullptr when the information is not provided, which is more useful than a placeholder but does need handling.

ServiceConfig. MidiServiceConfig became MidiServiceTransportPluginConfig.

Utilities removed. MidiUniversalSystemExclusiveMessageBuilder (all functions were no-ops in rc4), MidiClockGenerator, MidiClockDestination, MidiRuntimeRelease, MidiRuntimeUpdateUtility and the RuntimeInformation namespace (no more need for versioning or download information).

Fixes. Fixed a potential deadlock caused by using certain enumeration APIs within a coroutine or event handler on an STA thread such as the WinUI UI thread. Considerably more exception handling throughout.

Migration troubleshooting. Error C3867 and error E0300 almost always mean you are reading or assigning a field on something which is now a runtime class, so SomeField needs to become SomeField() and SomeField = x needs to become SomeField(x). If Visual Studio still shows errors everywhere after you have fixed the package references, close and reopen it; IntelliSense does not
cope well with NuGet package changes of this size.

Preview 2

  • Fixed the MIDI 1 port off-by-one problem, issue #1046.
  • Added MidiLegacyPortDeviceWatcher::GetEnumeratedPortsForAssociatedEndpointAndGroup for parity with the rc4 SDK.
  • Added Arm64X binaries to the Arm64EC section of the NuGet package.
  • Considerable hardening of input parameters and exception handling throughout.
  • SDK reference documentation significantly updated for the Preview 1 changes.

Preview 3

  • Chunked SysEx in MidiMessageConverter. A new overload of ConvertMidi1CompleteMessageBytesToUmpWords takes a
    Windows.Devices.Midi2.Utilities.Messages.MidiBytestreamToUmpMessageConverterState object. With no state object, SysEx state is dumped when the input data in a single call runs out, and there is no way to continue SysEx in a later call without a new opening 0xF0. With a state object, SysEx continues across calls and state is not dumped until an 0xF7 is received. Malformed SysEx with no opening and closing pairs still has to be handled manually; these functions have to assume some basic level of data integrity.
  • Corrected UUID for UUID_IMidiSystemExclusive7MessageHelperStatics.
  • Updated Basic Loopback transport matched to this API version.
  • New KB article: Moving from WinMM to Windows MIDI Services,
    plus a cleanup of the KB section.
  • Known issue discovered after release and since fixed: #1070, Basic Loopback not working correctly from WinMM.

Preview 4

  • Added MidiBasicLoopbackErrorCode::EndpointRemovalFailed.
  • Client plugins and message listeners. MidiEndpointConnection now checks a plugin'sIsEnabled() before calling ProcessIncomingMessage. IsEnabled does not affect initialization or cleanup. The three in-box listeners (Channel, Group, Message Type) only set skipFurtherListeners and skipMainMessageReceivedEvent when they actually handle the message, and skipMainMessageReceivedEvent can be set by any one plugin and stays true from that point on. Cleanup() is now called on a listener before it is removed. MidiChannelEndpointListener gains IncludeSystemCommonAndRealTimeMessages, defaulting to false; set it to include clock and other message type 1 messages, which have no channel field. Plugin collection operations are guarded by a lock, and there is additional exception handling around calls into plugins.
  • Additional exception handling and fast data checks inside the COM callback code, for cases such as null incoming data or a packet smaller than a single UMP word.
  • Lock guards for receiving messages, removing the callback, and setting the callback pointer. No ABI change.
  • Mute, unmute and list support added to the MIDI 2.0 Loopback API so it matches the Basic Loopback.
  • MidiLegacyPortDeviceInformation gains TransportId, so you can identify the transport which owns a MIDI 1.0 port.
  • The SysEx Sender is back, as Windows.Devices.Midi2.Utilities.SysExTransfer. It takes a stream of the complete SysEx and manages sending it across the wire.
  • Fixed #1088, #1086,
    #1083.
  • A new command-line tool for changing the API mode was included.

Preview 5

Breaking changes.

  • Network MIDI 2.0 configuration format. The new format requires a GUID for the host id. Any host whose id is not a valid GUID will fail. The connectionPolicyIpv4 key is no longer used and is ignored if present. Symptoms of a stale file were the Network MIDI Setup app not opening, or your host not being advertised.

  • MidiEndpointDeviceWatcher now passes the entire MidiEndpointDeviceInformation object in all events, like the Legacy device watcher does. Without this there was no way to get information such as TransportId from a removal event, because the object had already left the watcher's collection. So in each of those event args, the Id was replaced by the full object:

    // before
    runtimeclass MidiEndpointDeviceInformationUpdatedEventArgs
    {
        [noexcept] String EndpointDeviceId {get; };
        [noexcept] Windows.Devices.Enumeration.DeviceInformationUpdate DeviceInformationUpdate{ get; };
        [noexcept] Boolean IsNameUpdated{ get; };
    }
    
    // after
    runtimeclass MidiEndpointDeviceInformationUpdatedEventArgs
    {
        [noexcept] MidiEndpointDeviceInformation RemovedDevice{ get; };
        [noexcept] Windows.Devices.Enumeration.DeviceInformationUpdate DeviceInformationUpdate{ get; };
        [noexcept] Boolean IsNameUpdated{ get; };
    }
  • MidiEndpointDeviceInformation.CreateFromId and MidiLegacyPortDeviceInformation.CreateFromId now validate that the correct type of id was passed in and return nullptr if not. Previously you received a seemingly valid object filled only with the properties common to both.

  • MidiServiceSessionConnectionInfo.EndpointDeviceId became EndpointOrPortDeviceId, because it can contain either.

  • MidiReporting return types changed from IVector to IVectorView, for consistency with other read-only collections.

  • MidiEndpointDeviceIdHelper became MidiEndpointDeviceHelper and gained validation functions for UMP endpoint name, product instance id and similar.

  • Basic Loopback association id and Loopback association id are now read-only on the creation config and are generated inside the class, consistent with the new Network types. Loopback and Basic Loopback generate their unique identifier from the association id when it is empty. MidiLoopbackEndpointDefinition and MidiBasicLoopbackEndpointDefinition constructors changed as a result. Note the change in parameter order.

Other API changes.

  • Added IsMutedStateChanged to MidiEndpointDeviceInformationUpdatedEventArgs.
  • Added QueryAllCapabilities to MidiServiceTransportPluginConfigManager.
  • Added FindAllSessionsWithOpenEndpoint to MidiReporting, and MidiReporting functions for getting active sessions that include specific port or endpoint ids.
  • UTF-8 length validation and UTF-8 aware truncation for endpoint and function block names across Virtual Device, Loopback, Basic Loopback and Network, plus better UTF-8 aware string handling generally.
  • The Virtual Device has a new event and a new property so you know whether any client apps are connected.

Network MIDI 2.0 became code complete apart from authentication modes, and passes all the protocol specification tests. Completing it and testing it under load also surfaced a number of race conditions and deadlocks in the service which produced hangs requiring the midisrv process to be killed; those were fixed.

Apps. The monolithic MIDI Settings app began being broken apart into separate apps, so that a future in-Windows Settings UI for MIDI can call out to them rather than having to contain them. Third-party apps can launch them too. Each has the same customization options (dark or light theme, Acrylic, Mica or solid backdrop, optional background color). This release introduced Windows MIDI Monitor, Windows MIDI Scratchpad, Windows SysEx Utility, Windows Network MIDI Setup and Windows MIDI Loopback Setup, and removed the equivalent functionality from MIDI Settings.

Preview 6

The first release with all three preview transports and the new app set.

  • Bluetooth MIDI 1.0 transport, new. Unlike the old BLE MIDI 1.0 support, most devices do not need to be paired to function, and BLE MIDI 1.0 devices which simply did not work with Windows now work. Important caveat for this preview only: if you have already paired a BLE MIDI device it will likely be picked up by the old BLE MIDI 1.0 support in WinRT MIDI 1.0, and will not appear on the new transport. Unpair it, or delete the paired BLE device from the "Sound, video and game controllers" section of Device Manager. Once this transport is in production this will not be an issue.
  • Network MIDI 2.0 is feature complete for the first in-box release. It does not support authentication, and will not in the first in-box release.
  • The mDNS/DNS-SD device watcher was rebuilt from the ground up on base Win32 APIs. It is no longer backed by a WinRT device watcher but retains the same shape; threading may be slightly different. The reason: the DNS-SD implementation in the base WinRT device watcher does not fire Updated or Removed events, returns null for the TTL property, and has no other presence indicator.
  • Corrected two broken UUIDs: MidiLegacyPortDeviceInformation had an auto-generated static interface id, and IMidiServiceConfigResponse had an incorrect interface id.
  • 28 new API types, listed in Corrections to earlier release notes above.
  • The new MIDI Settings app, rewritten in C++, deliberately simplified, and the launching point for all the other apps. Individual MIDI 1.0 port renaming was not in it at this point.
  • Dedicated setup apps shipped for Loopback, Network and Bluetooth, plus MIDI Monitor, MIDI SysEx Utility and MIDI Scratch Pad.
  • The in-box Loopback transport at the time did not support all the features used by the app (muting, listing), so MIDI 2.0 loopbacks could not be fully configured with these tools until those features shipped in Windows. Existing MIDI 2.0 loopbacks kept working.

Preview 7

Breaking API changes.

  • Added MidiServiceTransportPluginConfigManager.EnsureConfigurationFile(), to support tools which need to save to the configuration file. Before this, a PC that had only ever had a transport preview installed had no registered configuration file and could not persist anything.
  • MidiBasicLoopbackEntry gained a message count. This requires a recompile if you use basic loopback entries.
  • Added the MidiBluetoothTimestampSource enum and MidiBluetoothDeviceInformation.TimestampSource. BLE MIDI carries a 13-bit millisecond timestamp, and several inexpensive devices never advance theirs. When that happens, arrival time is substituted and reported here as an estimate. It is observed from received traffic rather than declared, so it stays Unknown until enough has been received to judge, and it is re-evaluated for the life of the connection. A device whose firmware is updated to keep time is picked up automatically.
  • Endpoint Connection COM Extensions gained const correctness. A small breaking compile-time change which should avoid the need for const_cast.
  • Several Bluetooth additions that were not listed at the time; see Corrections to earlier release notes.

MIDI Console rewritten in C++. Ported completely from C#/.NET. It uses approximately a quarter of the memory and a quarter of the CPU, is much better at keeping up with dense streams of MIDI messages during monitoring, and does not require a .NET runtime install. Fixed #1171 (console lags behind incoming messages when monitoring, slow to start) and #1023 (keyboard input during monitoring).

New app: Virtual Keyboard, a touch-enabled MIDI keyboard. Its virtual device mode was disabled in that release because of #1047, which locks up the service.

Apps folded into other apps. midifixreg and midiapimode were removed; registry check and repair, and API mode switching, are now in the MIDI Troubleshooting and Repair app. midimdnsinfo was removed; it is now midi network browse in the MIDI Console, with a --verbose switch.

Bluetooth. Connection and disconnection became considerably more robust, devices which do not correctly report BLE message timestamps are handled, more types of device and BLE advertising are handled, and the app reports when a device requires pairing or has failed to connect. Timestamp fixes here also resolved cases where WinMM saw no data.

Basic Loopback reports a message count. Network MIDI was unchanged from Preview 6. The BLE, Network and Loopback setup apps will now create a default configuration file if none exists, and the loopback setup app gained a button to import third-party loopbacks and create basic loopbacks from them.