From 5f7cc7b8c1a071c484840b52b6c590601da3c448 Mon Sep 17 00:00:00 2001 From: Pete Brown Date: Wed, 7 Feb 2024 13:50:15 -0500 Subject: [PATCH 1/6] Docs updates --- docs/_site/api-back-compat.html | 2 +- docs/_site/assets/js/search-data.json | 494 +++++++++--------- docs/_site/config-json.html | 2 +- .../Windows.Devices.Midi2/README.html | 2 +- .../clock/MidiClock.html | 2 +- .../IMidiEndpointConnectionSettings.html | 1 + .../connections/MidiEndpointConnection.html | 2 +- .../MidiMessageReceivedEventArgs.html | 2 +- .../connections/README.html | 2 +- .../MidiEndpointDeviceInformation.html | 2 +- ...pointDeviceInformationUpdateEventArgs.html | 2 +- .../MidiEndpointDeviceWatcher.html | 2 +- .../enumeration/README.html | 2 +- .../message-utilities/MidiMessageBuilder.html | 2 +- .../MidiMessageConverter.html | 2 +- .../MidiMessageTranslator.html | 2 +- .../message-utilities/MidiMessageUtility.html | 2 +- .../MidiStreamMessageBuilder.html | 2 +- .../message-utilities/README.html | 2 +- .../messages/IMidiUniversalPacket.html | 2 +- .../messages/MidiMessage128.html | 2 +- .../messages/MidiMessage32.html | 2 +- .../messages/MidiMessage64.html | 2 +- .../messages/MidiMessage96.html | 2 +- .../messages/MidiMessageStruct.html | 2 +- .../messages/MidiMessageTypeEnum.html | 2 +- .../messages/MidiPacketTypeEnum.html | 2 +- .../messages/README.html | 2 +- .../metadata/MidiFunctionBlock.html | 2 +- .../metadata/MidiGroupTerminalBlock.html | 2 +- .../metadata/README.html | 2 +- .../IMidiEndpointMessageProcessingPlugin.html | 2 +- .../MidiChannelEndpointListener.html | 2 +- .../MidiGroupEndpointListener.html | 2 +- .../MidiMessageTypeEndpointListener.html | 2 +- .../processing-plugins/README.html | 2 +- .../service/MidiService.html | 2 +- ...iceMessageProcessingPluginInformation.html | 2 +- .../service/MidiServicePingResponse.html | 2 +- .../MidiServicePingResponseSummary.html | 2 +- ...MidiServiceTransportPluginInformation.html | 2 +- .../MidiSessionConnectionInformation.html | 2 +- .../service/MidiSessionInformation.html | 2 +- .../Windows.Devices.Midi2/service/README.html | 2 +- .../session/MidiSession.html | 2 +- .../session/MidiSessionSettings.html | 2 +- .../Windows.Devices.Midi2/session/README.html | 2 +- .../simple-types/MidiChannel.html | 2 +- .../simple-types/MidiGroup.html | 2 +- .../simple-types/MidiUniqueId.html | 2 +- .../simple-types/README.html | 2 +- ...ConfigurationRequestReceivedEventArgs.html | 2 +- .../MidiVirtualEndpointDevice.html | 2 +- .../MidiVirtualEndpointDeviceDefinition.html | 2 +- .../virtual-device/README.html | 2 +- docs/_site/developer-docs/best-practices.html | 2 +- .../developer-docs/consuming-midi-api.html | 2 +- .../developer-docs/diagnostic-endpoints.html | 2 +- docs/_site/developer-docs/endpoint-ids.html | 2 +- .../faq-programming-languages.html | 2 +- .../midi2-implementation-details.html | 2 +- docs/_site/index.html | 2 +- docs/_site/midi-console.html | 2 +- .../IMidiEndpointConnectionSettings.md | 22 + .../connections/MidiEndpointConnection.md | 12 +- 65 files changed, 355 insertions(+), 296 deletions(-) create mode 100644 docs/_site/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html create mode 100644 docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.md diff --git a/docs/_site/api-back-compat.html b/docs/_site/api-back-compat.html index 26f976fa..bafdbc33 100644 --- a/docs/_site/api-back-compat.html +++ b/docs/_site/api-back-compat.html @@ -1 +1 @@ - API Backwards Compatibility | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

API Backwards Compatibility

Our intention is for developers to begin adopting Windows MIDI Services in place of the older WinMM, WinRT, and (deprecated) DirectMusic APIs in their applications. All new MIDI features, transports, and more will be implemented in Windows MIDI Services and the new API. A select number of features, slightly more than their current baseline, will be available to WinMM and WinRT APIs through our backwards-compatibility shims and abstractions, but this is simply to ensure existing applications continue to function on systems using Windows MIDI Services. Please note that we are not providing backwards compatibility to support DirectMusic MIDI APIs.

The existing MIDI APIs on Windows talk (almost) directly to MIDI 1.0 drivers through kernel calls. In Windows MIDI Services, the architecture is built around a central Windows Service, much like our audio system today. It also uses a much faster IO mechanism for communication with the USB driver vs what our MIDI 1.0 API uses today. This provides much more flexibility, including the potential for multi-client use, and good baseline speed with our new class driver. We are working on shims and abstractions which will allow some of the existing MIDI 1.0 APIs to talk to the service rather than directly to the driver.

Here is where we currently stand with planned backwards compatibility. Backwards compatibility for WinMM and WinRT APIs will be a post-1.0 feature, but shortly after that first release.

API What you should expect
Windows MIDI Services This project. 100% of all supported features for MIDI 1.0 and MIDI 2.0, including multi-client. API/SDK uses UMP as its internal data format even for MIDI 1.0 devices. Transports and the service handle translation.
WinMM (Win32 API most apps use today) Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release.
WinRT (MIDI API Introduced with Windows 10) Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release.
DirectMusic No compatibility planned. Not part of our testing.

Note that we are also investigating and experimenting with how to best incorporate the existing in-box Roland GS / General MIDI Synth into this architecture. It’s likely we will handle it as an additional transport, but we need to test some of the MIDI file players today as many of them make assumptions about which synth index is the GS synth, so this compatibility may come after the initial release.

\ No newline at end of file + API Backwards Compatibility | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

API Backwards Compatibility

Our intention is for developers to begin adopting Windows MIDI Services in place of the older WinMM, WinRT, and (deprecated) DirectMusic APIs in their applications. All new MIDI features, transports, and more will be implemented in Windows MIDI Services and the new API. A select number of features, slightly more than their current baseline, will be available to WinMM and WinRT APIs through our backwards-compatibility shims and abstractions, but this is simply to ensure existing applications continue to function on systems using Windows MIDI Services. Please note that we are not providing backwards compatibility to support DirectMusic MIDI APIs.

The existing MIDI APIs on Windows talk (almost) directly to MIDI 1.0 drivers through kernel calls. In Windows MIDI Services, the architecture is built around a central Windows Service, much like our audio system today. It also uses a much faster IO mechanism for communication with the USB driver vs what our MIDI 1.0 API uses today. This provides much more flexibility, including the potential for multi-client use, and good baseline speed with our new class driver. We are working on shims and abstractions which will allow some of the existing MIDI 1.0 APIs to talk to the service rather than directly to the driver.

Here is where we currently stand with planned backwards compatibility. Backwards compatibility for WinMM and WinRT APIs will be a post-1.0 feature, but shortly after that first release.

API What you should expect
Windows MIDI Services This project. 100% of all supported features for MIDI 1.0 and MIDI 2.0, including multi-client. API/SDK uses UMP as its internal data format even for MIDI 1.0 devices. Transports and the service handle translation.
WinMM (Win32 API most apps use today) Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release.
WinRT (MIDI API Introduced with Windows 10) Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release.
DirectMusic No compatibility planned. Not part of our testing.

Note that we are also investigating and experimenting with how to best incorporate the existing in-box Roland GS / General MIDI Synth into this architecture. It’s likely we will handle it as an additional transport, but we need to test some of the MIDI file players today as many of them make assumptions about which synth index is the GS synth, so this compatibility may come after the initial release.

\ No newline at end of file diff --git a/docs/_site/assets/js/search-data.json b/docs/_site/assets/js/search-data.json index c9974c13..72f77cc7 100644 --- a/docs/_site/assets/js/search-data.json +++ b/docs/_site/assets/js/search-data.json @@ -1,1621 +1,1649 @@ {"0": { + "doc": "IMidiEndpointConnectionSettings", + "title": "IMidiEndpointConnectionSettings", + "content": "Settings which are optionally provided when connecting to an endpoint. Typically, the implementation of the endpoint will come with a concrete settings class which implements this interface, and translates the settings into JSON which is sent up to the service and read by the abstraction. ", + "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html", + + "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html" + },"1": { + "doc": "IMidiEndpointConnectionSettings", + "title": "Properties", + "content": "| Property | Description | . | SettingsJson | The JSON representation of the settings. | . ", + "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html#properties", + + "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html#properties" + },"2": { + "doc": "IMidiEndpointConnectionSettings", + "title": "IDL", + "content": "IMidiEndpointConnectionSettings IDL . ", + "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html#idl", + + "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html#idl" + },"3": { "doc": "IMidiEndpointMessageProcessingPlugin", "title": "IMidiEndpointMessageProcessingPlugin", "content": "This interface is implemented by any type which can be an endpoint processing plugin in the client API. These plugins are used to process or manipulate messages coming from an endpoint. Microsoft provides several plugins in the API, including the MidiVirtualEndpointDevice, the MidiChannelEndpointListener, and the MidiGroupEndpointListener. All of these types implement the IMidiEndpointMessageProcessingPlugin interface and operate in the same way. The main part of message processing is the ProcessIncomingMessage callback. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html" - },"1": { + },"4": { "doc": "IMidiEndpointMessageProcessingPlugin", "title": "Properties", "content": "| Property | Description | . | Id | Generated GUID for this plugin instance. This is needed if you want to remove the plugin from the endpoint connection | . | Name | Optional application-supplied name for this plugin instance. | . | Tag | Optional application-supplied arbitrary data to associate with this plugin instance | . | IsEnabled | True if the plugin is enabled and should participate in message processing | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#properties" - },"2": { + },"5": { "doc": "IMidiEndpointMessageProcessingPlugin", "title": "Functions", "content": "| Function | Description | . | Initialize(endpointConnection) | Called by the endpoint connection. Perform any setup code which requires the endpoint connection pointer here. | . | OnEndpointConnectionOpened() | Callback when the endpoint connection is opened. If the plugin is added after the endpoint connection has already been opened, this is called immediately. | . | ProcessIncomingMessage(args, skipFurtherListeners, skipMainMessageReceivedEvent) | Callback for processing an incoming message. If the code sets skipFurtherListeners to true, any plugins after this one will not be called. If the code sets skipMainMessageReceivedEvent to true, the endpoint’s MessageReceived event will not be called for this message. Note: this callback is synchronous, so code in this should execute quickly and return immediately when complete. | . | Cleanup() | Called when the endpoint is tearing down | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#functions" - },"3": { + },"6": { "doc": "IMidiEndpointMessageProcessingPlugin", "title": "IDL", "content": "IMidiEndpointMessageProcessingPlugin IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html#idl" - },"4": { + },"7": { "doc": "IMidiUniversalPacket", "title": "IMidiUniversalPacket", "content": "This interface is implemented by the rich MidiMessageXX runtime class types. It may also be used as the interface for message-specific classes you create yourself. | Property | Description | . | Timestamp | 64 bit timestamp set by the receiving transport in the case of incoming messages, or by the sender in the case of outgoing messages | . | MessageType | A MidiMessageType enumeration value which represents the 4 bit MIDI Message type 0x0 - 0xF as defined by the MIDI UMP standard. | . | PacketType | A MidiPacketType enumeration value which can be cast to an int to get the number of 32-bit words in the message packet | . | Function | Description | . | PeekFirstWord() | Provides access to the first word of data, even if the message type and size is not yet known by the API user | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html" - },"5": { + },"8": { "doc": "IMidiUniversalPacket", "title": "IDL", "content": "IMidiUniversalPacket IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html#idl" - },"6": { + },"9": { "doc": "MidiChannel", "title": "MidiChannel", "content": "The MidiChannel class is used to provide formatting and data validation for MIDI 1.0 and MIDI 2.0 channels. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html" - },"7": { + },"10": { "doc": "MidiChannel", "title": "Properties", "content": "| Property | Description | . | Index | The data value, or channel Index (0-15) | . | NumberForDisplay | The number that should be displayed in any UI. (1-16) | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#properties" - },"8": { + },"11": { "doc": "MidiChannel", "title": "Static Properties", "content": "| Static Property | Description | . | LabelShort | Returns the localized abbreviation. For example, “Ch” in English. | . | LabelFull | Returns the localized full name. For example, “Channel” in English. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#static-properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#static-properties" - },"9": { + },"12": { "doc": "MidiChannel", "title": "Functions", "content": "| Function | Description | . | MidiChannel() | Constructs an empty MidiChannel | . | MidiChannel(index) | Constructs a MidiChannel with the specified index | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#functions" - },"10": { + },"13": { "doc": "MidiChannel", "title": "Static Functions", "content": "| Static Function | Description | . | IsValidChannelIndex(index) | Verifies that the provided index is valid (between 0 and 15) | . MidiChannel IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html#static-functions" - },"11": { + },"14": { "doc": "MidiChannelEndpointListener", "title": "MidiChannelEndpointListener", "content": "This class acts as a filter. Incoming messages with the specified group and channel will be provided through the MessageReceived event. Other messages will be ignored. In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following: . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html" - },"12": { + },"15": { "doc": "MidiChannelEndpointListener", "title": "Properties", "content": "| Property | Description | . | IncludeGroup | The MidiGroup that this listener will listen to. | . | IncludeChannels | The channels that this listener will listen to on the group. | . | PreventCallingFurtherListeners | True if this plugin should prevent further listeners from processing a message that is in-scope for this processor. | . | PreventFiringMainMessageReceivedEvent | True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#properties" - },"13": { + },"16": { "doc": "MidiChannelEndpointListener", "title": "Functions", "content": "| Property | Description | . | MidiChannelEndpointListener() | Construct a new instance of this type | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#functions" - },"14": { + },"17": { "doc": "MidiChannelEndpointListener", "title": "IDL", "content": "MidiChannelEndpointListener IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html#idl" - },"15": { + },"18": { "doc": "MidiClock", "title": "MidiClock", "content": "The MidiClock is what is used for all timestamps in Windows MIDI Services. Although it is internally backed by QueryPerformanceCounter, we recommend using the MidiClock type directly instead of calling QPC yourself. Also note that QueryPerformanceCounter technically returns a signed 64 bit integer, but the timestamp values used in Windows MIDI Services are unsigned 64 bit integers. Typically, this is of no practical concern as the tick resolution is currently 100ns and takes tens of thousands of years to wrap around even with a 64 bit signed integer. Note: The MIDI Clock is unrelated to wall clock time. It is an ever-increasing value of period 1/TimestampFrequency seconds that starts over when the PC is rebooted. To convert to wall clock time, you need to get the MidiClock.Now value at a known time, and then use that as a baseline until the next time you reboot the PC. You can learn more about high-resolution timestamps in Windows at https://aka.ms/miditimestamp. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html" - },"16": { + },"19": { "doc": "MidiClock", "title": "Static Properties", "content": "| Static Property | Description | . | Now | Returns the current timestamp | . | TimestampFrequency | Returns the number of timestamp ticks per second. This is calculated the first time it is called, and then cached for future calls. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#static-properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#static-properties" - },"17": { + },"20": { "doc": "MidiClock", "title": "Static Functions", "content": "The static functions are for convenience in calculating offsets to a timestamp, and for converting between units. | Static Function | Description | . | ConvertTimestampToMicroseconds(timestampValue) | Converts the provided timestamp to microseconds | . | ConvertTimestampToMilliseconds(timestampValue) | Converts the provided timestamp to milliseconds | . | ConvertTimestampToSeconds(timestampValue) | Converts the provided timestamp to seconds | . | OffsetTimestampByTicks(timestampValue, offsetTicks) | Offsets a given timestamp by the provided (signed) number of ticks | . | OffsetTimestampByMicroseconds(timestampValue, offsetMicroseconds) | Offsets a given timestamp by the provided (signed) number of microseconds | . | OffsetTimestampByMilliseconds(timestampValue, offsetMilliseconds) | Offsets a given timestamp by the provided (signed) number of milliseconds | . | OffsetTimestampBySeconds(timestampValue, offsetSeconds) | Offsets a given timestamp by the provided (signed) number of seconds | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#static-functions" - },"18": { + },"21": { "doc": "MidiClock", "title": "IDL", "content": "MidiClock IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html#idl" - },"19": { + },"22": { "doc": "MidiEndpointConnection", "title": "MidiEndpointConnection", "content": "The MidiEndpointConnection type represents a single connection to a single endpoint managed by Windows MIDI Services. It is created using the functions of the MidiSession, and is tied to the lifetime of that session. Connections allocate resources including send/receive buffers, and processing threads. For that reason, a session should generally not open more than one connection to a single endpoint. If you need to partition out messages more easily (by group or channel, for example) the MessageProcessingPlugins collection will help you do that. To ensure an application is able to wire up processing plugins and event handlers before the connection is active, the connection returned by the MidiSession is not yet open. Once the connection is acquired, the application should assign event handlers, and optionally assign any message processing plugins. Once complete, the application calls the Open() function to connect to the service, create the queues, and begin sending and receiving messages. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html" - },"20": { + },"23": { + "doc": "MidiEndpointConnection", + "title": "A note on sending messages", + "content": "All SendMessageXX functions send a single Universal MIDI Packet message at a time. The pluralized versions SendMessagesXX will send multiple packets, in order, with the same timestamp. Currently, in the implementation behind the scenes, the service receives each timestamped message one at a time. We have the functions for sending more than one message as a developer convenience for similarity with other platforms, and also to allow for possible future optimization in the service communication code. ", + "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#a-note-on-sending-messages", + + "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#a-note-on-sending-messages" + },"24": { "doc": "MidiEndpointConnection", "title": "Properties", - "content": "| Property | Description | . | ConnectionId | The generated GUID which uniquely identifes this connection instance. This is what is provided to the MidiSession when disconnecting an endpoint | . | EndpointDeviceId | The system-wide identifier for the device connection. This is returned through enumeration calls. | . | Tag | You may use this Tag property to hold any additional information you wish to have associated with the connection. | . | IsOpen | True if this connection is currently open. When first created, the connection is not open until the consuming code calls the Open method | . | Settings | Settings used to create this connection. | . | MessageProcessingPlugins | Collection of all message processing plugins which will optionally handle incoming messages. | . ", + "content": "| Property | Description | . | ConnectionId | The generated GUID which uniquely identifes this connection instance. This is what is provided to the MidiSession when disconnecting an endpoint | . | EndpointDeviceId | The system-wide identifier for the device connection. This is returned through enumeration calls. | . | Tag | You may use this Tag property to hold any additional information you wish to have associated with the connection. | . | IsOpen | True if this connection is currently open. When first created, the connection is not open until the consuming code calls the Open method | . | Settings | Settings used to create this connection. Treat this as read-only. | . | MessageProcessingPlugins | Collection of all message processing plugins which will optionally handle incoming messages. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#properties" - },"21": { + },"25": { "doc": "MidiEndpointConnection", "title": "Static Member Functions", "content": "| Static Function | Description | . | GetDeviceSelector() | Returns the device selector used for enumerating endpoint devices compatible with this API. | . | SendMessageSucceeded(sendResult) | Helper function to decipher the return result of a message sending function to tell if it succeeded. | . | SendMessageFailed(sendResult) | Helper function to decipher the return result of a message sending function to tell if it failed. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#static-member-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#static-member-functions" - },"22": { + },"26": { "doc": "MidiEndpointConnection", "title": "Functions", - "content": "| Function | Description | . | Open() | Open the connection and start receiving messages. Wire up the message event handler before calling this method. | . | SendMessagePacket(message) | Send an IMidiUniversalPacket-implementing type such as MidiMessage64 or a strongly-typed message class. | . | SendMessageStruct(timestamp, message, wordCount) | Send a fixed-sized MidiMessageStruct containing wordCount valid words. Additional words are ignored. | . | SendMessageWordArray(timestamp, words, startIndex, wordCount) | Note: Some projections will send the entire array as a copy, so this may not be the most effecient way to send messages from your language. | . | SendMessageWords(timestamp, word0) | Send a single 32-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1) | Send a single 64-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1, word2) | Send a single 96-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1, word2, word3) | Send a single 128-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageBuffer(timestamp, buffer, byteOffset, byteLength) | Send a single Universal MIDI Packet as bytes from a buffer. The number of bytes sent must match the size read from the first 4 bits of the data starting at the specified offset, and must be laid out correctly with the first byte corresponding to the MSB of the first word of the UMP (the word which contains hte message type). If you want to manage a chunk of buffer memory, the IMemoryBuffer type is the acceptable WinRT approach, and is as close as you get to sending a pointer into a buffer. | . | AddEndpointProcessingPlugin(plugin) | Add an endpoint processing plugin to this connection | . | RemoveEndpointProcessingPlugin(id) | Remove an endpoint processing plugin | . Tip: In all the functions which accept a timestamp to schedule the message, you can send a timestamp of 0 (zero) to bypass the scheduler and send the message immediately. Otherwise, the provided timestamp is treated as an absolute time for when the message should be sent from the service. Note that the service-based scheduler (currently based on a std::priority_queue) gets less efficient when there are thousands of messages in it, so it’s recommended that you not schedule too many messages at a time or too far out into the future. ", + "content": "| Function | Description | . | Open() | Open the connection and start receiving messages. Wire up the message event handler before calling this method. | . | SendMessagePacket(message) | Send an IMidiUniversalPacket-implementing type such as MidiMessage64 or a strongly-typed message class. | . | SendMessageStruct(timestamp, message, wordCount) | Send a fixed-sized MidiMessageStruct containing wordCount valid words. Additional words are ignored. | . | SendMessageWordArray(timestamp, words, startIndex, wordCount) | Note: Some projections will send the entire array as a copy, so this may not be the most effecient way to send messages from your language. | . | SendMessageWords(timestamp, word0) | Send a single 32-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1) | Send a single 64-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1, word2) | Send a single 96-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageWords(timestamp, word0, word1, word2, word3) | Send a single 128-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message | . | SendMessageBuffer(timestamp, buffer, byteOffset, byteLength) | Send a single Universal MIDI Packet as bytes from a buffer. The number of bytes sent must match the size read from the first 4 bits of the data starting at the specified offset, and must be laid out correctly with the first byte corresponding to the MSB of the first word of the UMP (the word which contains hte message type). If you want to manage a chunk of buffer memory, the IMemoryBuffer type is the acceptable WinRT approach, and is as close as you get to sending a pointer into a buffer. | . | SendMessagesWordList(timestamp,words) | This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully. | . | SendMessagesWordArray(timestamp,words) | This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully. | . | AddEndpointProcessingPlugin(plugin) | Add an endpoint processing plugin to this connection | . | RemoveEndpointProcessingPlugin(id) | Remove an endpoint processing plugin from this connection | . Tip: In all the functions which accept a timestamp to schedule the message, you can send a timestamp of 0 (zero) to bypass the scheduler and send the message immediately. Otherwise, the provided timestamp is treated as an absolute time for when the message should be sent from the service. Note that the service-based scheduler (currently based on a std::priority_queue) gets less efficient when there are thousands of messages in it, so it’s recommended that you not schedule too many messages at a time or too far out into the future. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#functions" - },"23": { + },"27": { "doc": "MidiEndpointConnection", "title": "Events", "content": "| Event | Description | . | MessageReceived(source, args) | From IMidiMessageReceivedEventSource. This is the event for receiving MIDI Messages, one at a time. | . When processing the MessageReceived event, do so quickly. This event is synchronous. If you need to do long-running processing of incoming messages, add them to your own incoming queue structure and have them processed by another application thread. Note: Wire up event handlers and add message processing plugins prior to calling Open(). ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#events", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#events" - },"24": { + },"28": { "doc": "MidiEndpointConnection", "title": "IDL", "content": "MidiEndpointConnection IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#idl" - },"25": { + },"29": { "doc": "MidiEndpointConnection", "title": "Sample", "content": "Here’s an excerpt from the full “API client basics” sample. It shows sending and receiving messages using the two built-in loopback endpoints. For more information on the loopback endpoints, see diagnostics endpoints. using (var session = MidiSession.CreateSession(\"API Sample Session\")) { // get the endpoint Ids. Normally, you'd use enumeration functions to get this // for non-diagnostics endpoints. var endpointAId = MidiEndpointDeviceInformation.DiagnosticsLoopbackAEndpointId; var endpointBId = MidiEndpointDeviceInformation.DiagnosticsLoopbackBEndpointId; Console.WriteLine(\"Connecting to Sender UMP Endpoint: \" + endpointAId); Console.WriteLine(\"Connecting to Receiver UMP Endpoint: \" + endpointBId); var sendEndpoint = session.CreateEndpointConnection(endpointAId); var receiveEndpoint = session.CreateEndpointConnection(endpointBId); void MessageReceivedHandler(object sender, MidiMessageReceivedEventArgs args) { var ump = args.GetMessagePacket(); Console.WriteLine(); Console.WriteLine(\"Received UMP\"); Console.WriteLine(\"- Current Timestamp: \" + MidiClock.Now); Console.WriteLine(\"- UMP Timestamp: \" + ump.Timestamp); Console.WriteLine(\"- UMP Msg Type: \" + ump.MessageType); Console.WriteLine(\"- UMP Packet Type: \" + ump.PacketType); Console.WriteLine(\"- Message: \" + MidiMessageUtility.GetMessageFriendlyNameFromFirstWord(args.PeekFirstWord())); if (ump is MidiMessage32) { var ump32 = ump as MidiMessage32; if (ump32 != null) Console.WriteLine(\"- Word 0: 0x{0:X}\", ump32.Word0); } }; // wire up the event handler before opening the endpoint receiveEndpoint.MessageReceived += MessageReceivedHandler; Console.WriteLine(\"Opening endpoint connection\"); receiveEndpoint.Open(); sendEndpoint.Open(); Console.WriteLine(\"Creating MIDI 1.0 Channel Voice 32-bit UMP...\"); var ump32 = MidiMessageBuilder.BuildMidi1ChannelVoiceMessage( MidiClock.Now, // use current timestamp 5, // group 5 Midi1ChannelVoiceMessageStatus.NoteOn, // 9 3, // channel 3 120, // note 120 - hex 0x78 100); // velocity 100 hex 0x64 sendEndpoint.SendMessagePacket((IMidiUniversalPacket)ump32); // could also use the SendWords methods, etc. Console.WriteLine(\" ** Wait for the message to arrive, and then press enter to cleanup. ** \"); Console.ReadLine(); // you should unregister the event handler as well receiveEndpoint.MessageReceived -= MessageReceivedHandler; // not strictly necessary if the session is going out of scope or is in a using block session.DisconnectEndpointConnection(sendEndpoint.ConnectionId); session.DisconnectEndpointConnection(receiveEndpoint.ConnectionId); } . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#sample", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html#sample" - },"26": { + },"30": { "doc": "MidiEndpointDeviceInformation", "title": "MidiEndpointDeviceInformation", "content": "This class is a specialized equivalent of the DeviceInformation WinRT class. It handles requesting all of the additional properties necessary for MIDI devices, and also goes a step further to retrieve parent device information so that applications can display the endpoints and parent devices in context. We’ve heard from developers that we did not provide sufficient information about devices in the past, so we created this class and the associated properties to remedy that. We also heard that Async calls were a non-starter for most DAW applications, so everything in this class is synchronous. Note: the MidiEndpointDeviceWatcher is a better way to retrieve devices because you can then keep the watcher open in a background thread, and be notified of property changes, device add/remove, etc. When displaying endpoint devices to users, you’ll typically want to stick to the defaults: IncludeClientUmpNative | IncludeClientByteStreamNative. You do not want to show the Diagnostic Ping ever, and you typically will not want to show the system-wide Diagnostic Loopback singletons. Finally, you don’t want to show the Virtual Device Responder endpoints because those should be reserved only for the “device” application in app-to-app MIDI. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html" - },"27": { + },"31": { "doc": "MidiEndpointDeviceInformation", "title": "In-protocol discovered information", "content": "When a device is first enumerated by the MIDI Service, if it is a UMP-native device, we will attempt endpoint discover and protocol negotiation. During that, we request all endpoint information and all function block information. The received data is then cached in the device properties so that applications do not need to perform this process themselves. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#in-protocol-discovered-information", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#in-protocol-discovered-information" - },"28": { + },"32": { "doc": "MidiEndpointDeviceInformation", "title": "Properties", "content": "| Property | Source | Description | . | Id | Windows | The endpoint device interface id | . | ContainerId | Windows | The device container | . | DeviceInstanceId | Windows | The device instance id without the interface information | . | Name | Various | This is the name which should be displayed in any application. It calculates the correct name based on the hierarchy of possible names, including a user-specified name. Always respect the user’s choice here. | . | TransportSuppliedName | Transports | The name provided by the driver or the endpoint transport. | . | EndpointSuppliedName | MIDI 2.0 | The name provided by MIDI 2.0 endpoint information. This is discovered in-protocol. | . | UserSuppliedName | Configuration | The name provided by the user. | . | ProductInstanceId | MIDI 2.0 | Property of the same name discovered by MIDI 2.0 in-protocol endpoint information. | . | SpecificationVersionMajor | MIDI 2.0 | Discovered UMP version | . | SpecificationVersionMinor | MIDI 2.0 | Discovered UMP version | . | SupportsMidi10Protocol | MIDI 2.0 | Discovered protocol support | . | SupportsMidi20Protocol | MIDI 2.0 | Discovered protocol support | . | `ConfiguredToReceiveJRTimestamps | MIDI 2.0 | Note that JR timestamps are handled entirely in the service and are not sent back down to the client. | . | `ConfiguredToSendJRTimestamps | MIDI 2.0 | Note that JR timestamps are handled entirely in the service and are not sent back down to the client. | . | DeviceIdentitySystemExclusiveId | MIDI 2.0 | Device Identity information | . | DeviceIdentityDeviceFamilyLsb | MIDI 2.0 | Device Identity information | . | DeviceIdentityDeviceFamilyMsb | MIDI 2.0 | Device Identity information | . | DeviceIdentityDeviceFamilyModelNumberLsb | MIDI 2.0 | Device Identity information | . | DeviceIdentityDeviceFamilyModelNumberMsb | MIDI 2.0 | Device Identity information | . | DeviceIdentitySoftwareRevisionLevel | MIDI 2.0 | Device Identity information | . | TransportId | Windows | The Id of the transport abstraction that manages this endpoint | . | TransportMnemonic | Windows | A short abbreviation for the transport. This can be used as a transport identifier. | . | TransportSuppliedSerialNumber | Windows | iSerialNumber, when available in USB, and other ids from other transports. | . | ManufacturerName | Windows | The name of the manufacturer of the device, if available | . | SupportsMultiClient | Windows | True if this endpoint supports multi-client use | . | NativeDataFormat | Windows | Because the driver and service handle data format translation, it’s not immediately obvious if the device is natively UMP or natively Byte Stream. This property provides that information | . | GroupTerminalBlocks | Windows | A collection of Group Terminal Blocks. These are used only in USB. For MIDI 2.0 devices, Function Blocks are preferred. | . | HasStaticFunctionBlocks | MIDI 2.0 | True if the function blocks are static. That is, the groups never change. | . | FunctionBlockCount | MIDI 2.0 | The number of function blocks the endpoint has declared. Function blocks always start at index zero and go to FunctionBlockCount-1 | . | EndpointPurpose | Windows | The purpose of the endpoint. This is used primarily for filtering. | . | Description | Configuration | An endpoint description which is typically provided by the user | . | LargeImagePath | Configuration | The path to a png or jpg image that represents this endpoint. Typically user-supplied. | . | SmallImagePath | Configuration | The path to a png or jpg image that represents this endpoint. Typically user-supplied. | . | RequiresNoteOffTranslation | Configuration | True if the endpoint requires internal translation of Note On with zero velocity (in the case of MIDI 1.0) to a Note Off message. Typically user-supplied. | . | RecommendedCCAutomationIntervalMS | Configuration | Number of milliseconds between automation value changes. This is usually only for old and slow MIDI 1.0 devices that are prone to data flooding. User-supplied. | . | Properties | Windows | A collection of all the raw properties. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#properties" - },"29": { + },"33": { "doc": "MidiEndpointDeviceInformation", "title": "Static Properties", "content": "| Static Property | Description | . | DiagnosticsLoopbackAEndpointId | Endpoint Id for the diagnostic loopback used for development and support purposes. | . | DiagnosticsLoopbackBEndpointId | Endpoint Id for the diagnostic loopback used for development and support purposes. | . | EndpointInterfaceClass | The class GUID which appears at the end of the Endpoint Ids | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#static-properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#static-properties" - },"30": { + },"34": { "doc": "MidiEndpointDeviceInformation", "title": "Functions", "content": "| Function | Description | . | GetParentDeviceInformation() | Finds and then retrieves the parent DeviceInformation type with appropriate properties. | . | GetContainerInformation() | Gets the device container information and returns its DeviceInformation with appropriate properties | . | UpdateFromDeviceInformation(deviceInformation) | For use by any watcher which must update this object | . | UpdateFromDeviceInformationUpdate(deviceInformationUpdate) | For use by any watcher which must update this object | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#functions" - },"31": { + },"35": { "doc": "MidiEndpointDeviceInformation", "title": "Static Functions", "content": "| Static Function | Description | . | CreateFromId(id) | Creates a new MidiEndpointDeviceInformation object from the specified id | . | FindAll() | Searches for all endpoint devices and returns a list in the default sort order | . | FindAll(sortOrder) | Searches for all endpoint devices and returns a list in the specified sort order | . | FindAll(sortOrder, endpointFilter) | Searches for all endpoint devices which match the filter, and returns a list in the specified sort order. | . | DeviceMatchesFilter(deviceInformation, endpointFilter) | A helper function to compare a device against the filter. | . | GetAdditionalPropertiesList() | This returns the list of properties which must be requested during enumeration. Typically not needed for applications, as the watcher calls this function | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#static-functions" - },"32": { + },"36": { "doc": "MidiEndpointDeviceInformation", "title": "IDL", "content": "MidiEndpointDeviceInformation IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#idl" - },"33": { + },"37": { "doc": "MidiEndpointDeviceInformation", "title": "Sample", "content": "What follows is an excerpt of the larger C++/WinRT enumeration sample. #include \"pch.h\" #include <iostream> using namespace winrt::Windows::Devices::Midi2; // API int main() { winrt::init_apartment(); bool includeDiagnosticsEndpoints = true; // enumerate all endpoints. A normal application should enumerate only // IncludeClientByteStreamNative | IncludeClientUmpNative auto endpoints = MidiEndpointDeviceInformation::FindAll( MidiEndpointDeviceInformationSortOrder::Name, MidiEndpointDeviceInformationFilter::IncludeClientByteStreamNative | MidiEndpointDeviceInformationFilter::IncludeClientUmpNative | MidiEndpointDeviceInformationFilter::IncludeDiagnosticLoopback | MidiEndpointDeviceInformationFilter::IncludeVirtualDeviceResponder ); std::cout << endpoints.Size() << \" endpoints returned\" << std::endl << std::endl; for (auto const& endpoint : endpoints) { std::cout << \"Identification\" << std::endl; std::cout << \"- Name: \" << winrt::to_string(endpoint.Name()) << std::endl; std::cout << \"- Id: \" << winrt::to_string(endpoint.Id()) << std::endl; std::cout << std::endl << \"Endpoint Metadata\" << std::endl; std::cout << \"- Product Instance Id: \" << winrt::to_string(endpoint.ProductInstanceId()) << std::endl; std::cout << \"- Endpoint-supplied Name: \" << winrt::to_string(endpoint.EndpointSuppliedName()) << std::endl; std::cout << std::endl << \"User-supplied Metadata\" << std::endl; std::cout << \"- User-supplied Name: \" << winrt::to_string(endpoint.UserSuppliedName()) << std::endl; std::cout << \"- Description: \" << winrt::to_string(endpoint.Description()) << std::endl; std::cout << \"- Small Image Path: \" << winrt::to_string(endpoint.SmallImagePath()) << std::endl; std::cout << \"- Large Image Path: \" << winrt::to_string(endpoint.LargeImagePath()) << std::endl; // ... } } . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#sample", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html#sample" - },"34": { + },"38": { "doc": "MidiEndpointDeviceInformationUpdateEventArgs", "title": "MidiEndpointDeviceInformationUpdateEventArgs", "content": "Represents a notification that endpoint properties have been updated . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html" - },"35": { + },"39": { "doc": "MidiEndpointDeviceInformationUpdateEventArgs", "title": "Functions", "content": "| Property | Description | . | Id | Id of the endpoint which has been updated | . | UpdatedName | True if the name properties have been updated | . | UpdatedEndpointInformation | True if the in-protocol endpoint information has been updated | . | UpdatedDeviceIdentity | True if the in-protocol device identity information has been updated | . | UpdatedStreamConfiguration | True if protocol negotiation changed configuration of the endpoint | . | UpdatedFunctionBlocks | True if any function blocks have been updated | . | UpdatedUserMetadata | True if any user-supplied metadata fields have been updated | . | UpdatedAdditionalCapabilities | True if the additional capabilities have been updated | . | DeviceInformationUpdate | The source Windows.Devices.Enumeration.DeviceInformationUpdate object. | . If none of the UpdatedXX properties are true, then other properties have been updated. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html#functions" - },"36": { + },"40": { "doc": "MidiEndpointDeviceInformationUpdateEventArgs", "title": "IDL", "content": "MidiEndpointDeviceInformationUpdateEventArgs IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html#idl" - },"37": { + },"41": { "doc": "MidiEndpointDeviceWatcher", "title": "MidiEndpointDeviceWatcher", "content": "WinRT provides a Windows.Devices.Enumeration namespace with a DeviceWatcher class. That class is generic to any type of device, and so requires additional work to use with MIDI devices. Because of that, we’ve wrapped that functionality in the MidiEndpointDeviceWatcher class and the related MidiEndpointDeviceInformation class. This is the class applications should use when they want to find devices, and also be notified when devices are added or removed, or when properties like function blocks or device names change. Create a MidiEndpointDeviceWatcher on a background thread, and use the internal list of Endpoints as your source of record for device properties. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html" - },"38": { + },"42": { "doc": "MidiEndpointDeviceWatcher", "title": "Properties", "content": "| Function | Description | . | Status | The current status. See the Windows.Devices.Enumeration.DeviceWatcherStatus enumeration | . | EnumeratedEndpointDevices | The list of enumerated devices. Provided here for convenience so applications do not need to keep their own list of MIDI devices. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#properties" - },"39": { + },"43": { "doc": "MidiEndpointDeviceWatcher", "title": "Functions", "content": "| Function | Description | . | Start() | Begin device enumeration. Wire up event handlers before calling this function. | . | Stop() | Stop device enumeration. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#functions" - },"40": { + },"44": { "doc": "MidiEndpointDeviceWatcher", "title": "Static Functions", "content": "| Static Function | Description | . | CreateWatcher(endpointFilter) | Create a watcher which will enumerate devices based on the provided filter | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#static-functions" - },"41": { + },"45": { "doc": "MidiEndpointDeviceWatcher", "title": "Events", "content": "| Event | Description | . | Added(source, deviceInformation) | A new endpoint has been added. | . | Removed(source, deviceInformationUpdate) | An endpoint has been removed. | . | Updated(source endpointDeviceInformationUpdate) | Properties of an endpoint have been updated. This is much more common than it was with the older MIDI 1.0 APIs due to both in-protocol endpoint information, and user configuration. | . | EnumerationCompleted(source) | Raised when the initial device enumeration has been completed. Devices may still be added or removed after this event, but use this to decide when you have enough information to display an initial list. | . | Stopped(source) | Enumeration has been stopped. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#events", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#events" - },"42": { + },"46": { "doc": "MidiEndpointDeviceWatcher", "title": "IDL", "content": "MidiEndpointDeviceWatcher IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html#idl" - },"43": { + },"47": { "doc": "MidiFunctionBlock", "title": "MidiFunctionBlock", "content": "The original MIDI 2.0 USB specification includes the concept of a Group Terminal Block. After ratification of that specification, it was found that Group Terminal Blocks were insufficient for two main reasons: . | Group Terminal Blocks are USB-specific, and so are not available on other transports like Network or Virtual. | Group Terminal Blocks are static, defined in USB descriptors, and so cannot change during runtime. | . Group Terminal Blocks are still available, but function blocks are the preferred approach for defining capapbilities of a device. When both are available, you should use the function block information. A function block represents a function of a MIDI 2.0 device. A function block may span one or more groups, and if not a static function block, those group numbers may change during operation. For example, a Tone Generator function of a device may need 64 channels to represent its multi-timbral nature. One way it can accomplish this is to declare a function block which spans 4 groups, each of which has 16 channels of data (16x4 = 64). Function blocks also represent the valid groups for communication with an endpoint. If an endpoint declares 4 function blocks, which together cover only group indexes 0-5, and all of those blocks are marked active, only those groups should be available to users of an application. This helps cut down on clutter caused by always displaying 16 groups. Function blocks have names which should be displayed to the user along with the group numbers. In the end, the actual addressible entity is the endpoint stream with the group number in the Universal MIDI Packet. But the function block provides context for that group number. Per the specification, function blocks can span more than one group, and can overlap with each other so that different functions can be available on the same group. Function blocks are used in the Windwos MIDI Services API in three ways: . | A property of a MidiEndpointDeviceInformation object, representing function blocks discovered through endpoint discovery. These function blocks are read-only. | The return value of the AsEquivalentFunctionBlock method of the GroupTerminalBlock class. This is a convenience function. These function blocks are read-only | Provided by the application as part of the device definition for a virtual device in app-to-app MIDI. These function blocks are editable before adding them to the device definition. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html" - },"44": { + },"48": { "doc": "MidiFunctionBlock", "title": "Properties", "content": "Most properties are 1:1 with the MIDI 2.0 UMP specification section on function blocks. We assemble the name for you and map values to enumerations when possible. | Property | Description | . | IsReadOnly | True if this function block should be treated as read-only. If you attempt to assign a value to a property in a read-only function block, the assignment will silently fail. | . | Number | The index of the block 0-31. We use “number” here to be consistent with the specification | . | Name | The assembled name of the function block | . | IsActive | True if this block is active | . | Direction | The direction of the block from the block’s point of view. | . | UIHint | A hint which tells you how this block should be treated in a user interface. This should be considered a “soft filter” for display, not a mechanism to keep blocks completely hidden from a user. | . | Midi10Connection | How to treat this block if it is a MIDI 1.0 connection | . | FirstGroupIndex | Zero-based index of the first group spanned by this block. | . | GroupCount | The number of groups spanned. | . | MidiCIMessageVersionFormat | MIDI CI version format value | . | MaxSystemExclusive8Streams | The maximum number of System Exclusive 8 streams allowed. Please refer to the UMP specification for how to treat this value. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#properties" - },"45": { + },"49": { "doc": "MidiFunctionBlock", "title": "Functions", "content": "| Function | Description | . | MidiFunctionBlock() | Construct an empty function block | . | IncludesGroup(group) | Helper function which returns true if this function exists on the supplied group | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#functions" - },"46": { + },"50": { "doc": "MidiFunctionBlock", "title": "IDL", "content": "MidiFunctionBlock IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html#idl" - },"47": { + },"51": { "doc": "MidiGroup", "title": "MidiGroup", "content": "The MidiGroup class is used to provide formatting and data validation for UMP (Universal MIDI Packet) groups. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html" - },"48": { + },"52": { "doc": "MidiGroup", "title": "Properties", "content": "| Property | Description | . | Index | The data value, or group Index (0-15) | . | NumberForDisplay | The number that should be displayed in any UI. (1-16) | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#properties" - },"49": { + },"53": { "doc": "MidiGroup", "title": "Static Properties", "content": "| Static Property | Description | . | LabelShort | Returns the localized abbreviation. For example, “Gr” in English. | . | LabelFull | Returns the localized full name. For example, “Group” in English. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#static-properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#static-properties" - },"50": { + },"54": { "doc": "MidiGroup", "title": "Functions", "content": "| Function | Description | . | MidiGroup() | Constructs an empty MidiGroup | . | MidiGroup(index) | Constructs a MidiGroup with the specified index | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#functions" - },"51": { + },"55": { "doc": "MidiGroup", "title": "Static Functions", "content": "| Static Function | Description | . | IsValidGroupIndex(index) | Verifies that the provided index is valid (between 0 and 15) | . MidiGroup IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html#static-functions" - },"52": { + },"56": { "doc": "MidiGroupEndpointListener", "title": "MidiGroupEndpointListener", "content": "This class acts as a filter. Incoming messages with the specified group will be provided through the MessageReceived event. Other messages will be ignored. For a MIDI 1.0 device, where the ports (virtual MIDI cables) have been mapped to UMP groups, this class can provide the equivalent of a MIDI 1.0 port to an application, ignoring all other inputs and operating only on the included groups. In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following: . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html" - },"53": { + },"57": { "doc": "MidiGroupEndpointListener", "title": "Properties", "content": "| Property | Description | . | IncludeGroups | The list of MidiGroup numbers that this listener will listen to. | . | PreventCallingFurtherListeners | True if this plugin should prevent further listeners from processing a message that is in-scope for this processor. | . | PreventFiringMainMessageReceivedEvent | True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#properties" - },"54": { + },"58": { "doc": "MidiGroupEndpointListener", "title": "Functions", "content": "| Property | Description | . | MidiGroupEndpointListener() | Construct a new instance of this type | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#functions" - },"55": { + },"59": { "doc": "MidiGroupEndpointListener", "title": "IDL", "content": "MidiGroupEndpointListener IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html#idl" - },"56": { + },"60": { "doc": "MidiGroupTerminalBlock", "title": "MidiGroupTerminalBlock", "content": "A Group Terminal Block is a USB-only feature used to describe the groups on a device. When available, Function Blocks are the preferred mechanism for finding active groups, names, and more, meaning that the Group Terminal Block can typically be ignored in those cases. For more context, please see the documentation for the MidiFunctionBlock type. Note: In Windows MIDI Services, we translate MIDI 1.0 device “ports” into individual Group Terminal Blocks. Each virtual cable number in the stream, which used to become a separate input or output port, now maps to a group number. For example, a 5 port MIDI 1.0 device will now show up as a single endpoint with 5 Group Terminal Blocks each spanning a single group. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html" - },"57": { + },"61": { "doc": "MidiGroupTerminalBlock", "title": "Properties", "content": "| Property | Description | . | Number | Block number | . | Name | Name provided by USB. In the case of MIDI 1.0 devices, when available, this is the iJack string | . | Direction | Direction of the block, from the block’s point of view | . | Protocol | Information about the protocol in use. Note that the Jitter Reduction values here should be ignored. Jitter reduction timestamp handling is negotiated through protocol negotiation, and is entirely handled by the service | . | FirstGroupIndex | The index of the first group spanned by this block | . | GroupCount | The number of groups spanned | . | MaxDeviceInputBandwidthIn4KBitsPerSecondUnits | Please see the USB MIDI 2.0 specification for the actual value for this field. | . | MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits | Please see the USB MIDI 2.0 specification for the actual value for this field. | . | CalculatedMaxDeviceInputBandwidthBitsPerSecond | Bits-per-second calculated value for the MaxDeviceInputBandwidthIn4KBitsPerSecondUnits property | . | CalculatedMaxDeviceOutputBandwidthBitsPerSecond | Bits-per-second calculated value for the MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits property | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#properties" - },"58": { + },"62": { "doc": "MidiGroupTerminalBlock", "title": "Functions", "content": "| Function | Description | . | IncludesGroup(group) | Helper function which returns true if this function exists on the supplied group | . | AsEquivalentFunctionBlock() | Helper function which returns a MidiFunctionBlock that is approximately equivalent to this MidiGroupTerminalBlock. This is to enable applications to be able to deal with only a single type of block when showing the metadata | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#functions" - },"59": { + },"63": { "doc": "MidiGroupTerminalBlock", "title": "IDL", "content": "MidiGroupTerminalBlock IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html#idl" - },"60": { + },"64": { "doc": "MidiMessage128", "title": "MidiMessage128", "content": "MidiMessage128 is used for some data messages as well as important “Type F” stream metadata messages. Includes all functions and properties in IMidiUniversalPacket, as well as: . | Property | Description | . | Word0 | First 32-bit MIDI word | . | Word1 | Second 32-bit MIDI word | . | Word2 | Third 32-bit MIDI word | . | Word3 | Fourth 32-bit MIDI word | . | Function | Description | . | MidiMessage128() | Default constructor | . | MidiMessage128(timestamp, word0, word1, word2, word3) | Construct a new message with a timestamp and all 32 bit MIDI words | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html" - },"61": { + },"65": { "doc": "MidiMessage128", "title": "IDL", "content": "MidiMessage128 IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html#idl" - },"62": { + },"66": { "doc": "MidiMessage32", "title": "MidiMessage32", "content": "MidiMessage32 is used for short messages such as utility messages and MIDI 1.0 messages in UMP format. Includes all functions and properties in IMidiUniversalPacket, as well as: . | Property | Description | . | Word0 | First 32-bit MIDI word | . | Function | Description | . | MidiMessage32() | Default constructor | . | MidiMessage32(timestamp, word0) | Construct a new message with a timestamp and 32 bit MIDI word | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html" - },"63": { + },"67": { "doc": "MidiMessage32", "title": "IDL", "content": "MidiMessage32 IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html#idl" - },"64": { + },"68": { "doc": "MidiMessage64", "title": "MidiMessage64", "content": "MidiMessage64 is used for some data messages and for MIDI 2.0 Channel Voice messages. Includes all functions and properties in IMidiUniversalPacket, as well as: . | Property | Description | . | Word0 | First 32-bit MIDI word | . | Word1 | Second 32-bit MIDI word | . | Function | Description | . | MidiMessage64() | Default constructor | . | MidiMessage64(timestamp, word0, word1) | Construct a new message with a timestamp and all 32 bit MIDI words | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html" - },"65": { + },"69": { "doc": "MidiMessage64", "title": "IDL", "content": "MidiMessage64 IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html#idl" - },"66": { + },"70": { "doc": "MidiMessage96", "title": "MidiMessage96", "content": "MidiMessage96 is currently unused in the MIDI 2.0 UMP specification. Includes all functions and properties in IMidiUniversalPacket, as well as: . | Property | Description | . | Word0 | First 32-bit MIDI word | . | Word1 | Second 32-bit MIDI word | . | Word2 | Third 32-bit MIDI word | . | Function | Description | . | MidiMessage96() | Default constructor | . | MidiMessage96(timestamp, word0, word1, word2) | Construct a new message with a timestamp and all 32 bit MIDI words | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html" - },"67": { + },"71": { "doc": "MidiMessage96", "title": "IDL", "content": "MidiMessage96 IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html#idl" - },"68": { + },"72": { "doc": "MidiMessageBuilder", "title": "MidiMessageBuilder", "content": "(In progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html" - },"69": { + },"73": { "doc": "MidiMessageBuilder", "title": "Functions", "content": "| Function | Description | . |   |   | . |   |   | . |   |   | . |   |   | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html#functions" - },"70": { + },"74": { "doc": "MidiMessageBuilder", "title": "IDL", "content": "MidiMessageBuilder IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html#idl" - },"71": { + },"75": { "doc": "MidiMessageConverter", "title": "MidiMessageConverter", "content": "(In progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html" - },"72": { + },"76": { "doc": "MidiMessageConverter", "title": "Functions", "content": "| Function | Description | . |   |   | . |   |   | . |   |   | . |   |   | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html#functions" - },"73": { + },"77": { "doc": "MidiMessageConverter", "title": "IDL", "content": "MidiMessageConverter IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html#idl" - },"74": { + },"78": { "doc": "MidiMessageReceivedEventArgs", "title": "MidiMessageReceivedEventArgs", "content": "This is the main class to use when receving MIDI data from a message source such as a connection or a message processing plugin. Note: Do not keep a copy of the MidiMessageReceivedEventArgs class, as the data it points to is guaranteed to exist for only the duration of the event handler call for which this instance was an argument. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html" - },"75": { + },"79": { "doc": "MidiMessageReceivedEventArgs", "title": "Properties", "content": "| Property | Description | . | Timestamp | The 64-bit MIDI Clock timestamp set by the service when this message was received | . | PacketType | Type of Universal MIDI Packet. This value can be cast to get the number of valid words in the data. You can use this value to determine which of the FillMessageXX methods would be appropriate to call. For example, if the value is MidiPacketType.UniversalMidiPacket64 you would call FillMessage64 | . | MessageType | The type of Universal MIDI Packet Message. This comes from the first 4 bits of the data. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#properties" - },"76": { + },"80": { "doc": "MidiMessageReceivedEventArgs", "title": "Functions", "content": "| Function | Description | . | PeekFirstWord() | Returns the first word of the message data without removing it. | . | GetMessagePacket() | Returns an IMidiUniversalPacket runtime class representing the data. This requires an allocation. | . | FillWords(word0, word1, word2, word3) | Puts the data in the supplied words and returns the number of valid words to read. If the return value is 2, for example, then only word0 and word1 contain valid data. | . | FillMessageStruct(message) | Fills the provided lightweight structure with the message data. Returns the number of valid words in the updated struct. | . | FillMessage32(message) | Adds the data to the provided MidiMessage32 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written. | . | FillMessage64(message) | Adds the data to the provided MidiMessage64 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written. | . | FillMessage96(message) | Adds the data to the provided MidiMessage96 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written. | . | FillMessage128(message) | Adds the data to the provided MidiMessage128 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written. | . | FillWordArray(words, startIndex) | Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of words written. | . | FillByteArray(bytes, startIndex) | Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of bytes written. | . | FillBuffer(buffer, byteOffset) | Writes the data to the buffer starting at byteOffset. Returns the number of bytes written. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#functions" - },"77": { + },"81": { "doc": "MidiMessageReceivedEventArgs", "title": "IDL", "content": "MidiMessageReceivedEventArgs IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html#idl" - },"78": { + },"82": { "doc": "MidiMessageStruct", "title": "MidiMessageStruct", "content": "MidiMessageStruct is provided for cases where the API consumer wants to have a fixed value type they can use to send and receive messages. In the case of receiving messages, a function which fills the struct will typically return a count of valid words. The MidiMessageStruct struct type is simpler than the other runtime class types and may therefore perform better in some projections and for some uses. Note that this type does not include the timestamp field. | Field | Description | . | Word0 | First 32-bit MIDI word | . | Word1 | Second 32-bit MIDI word | . | Word2 | Third 32-bit MIDI word | . | Word3 | Fourth 32-bit MIDI word | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html" - },"79": { + },"83": { "doc": "MidiMessageStruct", "title": "IDL", "content": "MidiMessageStruct IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html#idl" - },"80": { + },"84": { "doc": "MidiMessageTranslator", "title": "MidiMessageTranslator", "content": "(In progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html" - },"81": { + },"85": { "doc": "MidiMessageTranslator", "title": "Functions", "content": "| Function | Description | . |   |   | . |   |   | . |   |   | . |   |   | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html#functions" - },"82": { + },"86": { "doc": "MidiMessageTranslator", "title": "IDL", "content": "MidiMessageTranslator IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html#idl" - },"83": { + },"87": { "doc": "MidiMessageTypeEndpointListener", "title": "MidiMessageTypeEndpointListener", "content": "This class acts as a filter. Incoming messages with the specified message type will be provided through the MessageReceived event. Other messages will be ignored. In this way, the listener can be set up to, for example, only pay attention to MIDI 2.0 Channel Voice messages, leaving stream messages and System Exclusive by the wayside. In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following: . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html" - },"84": { + },"88": { "doc": "MidiMessageTypeEndpointListener", "title": "Properties", "content": "| Property | Description | . | IncludeMessageTypes | The list of MidiMessageType values that this listener will listen to. | . | PreventCallingFurtherListeners | True if this plugin should prevent further listeners from processing a message that is in-scope for this processor. | . | PreventFiringMainMessageReceivedEvent | True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#properties" - },"85": { + },"89": { "doc": "MidiMessageTypeEndpointListener", "title": "Functions", "content": "| Property | Description | . | MidiGroupEndpointListener() | Construct a new instance of this type | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#functions" - },"86": { + },"90": { "doc": "MidiMessageTypeEndpointListener", "title": "IDL", "content": "MidiMessageTypeEndpointListener IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html#idl" - },"87": { + },"91": { "doc": "MidiMessageType", "title": "MidiMessageType Enumeration", "content": "The values correspond directly to the “mt” field in the MIDI UMP packet and may be cast as such if trimmed to 4 bits and shifted into place. | Property | Value | Description | . | UtilityMessage32 | 0x0 | 32-bit utility message | . | SystemCommon32 | 0x1 | 32-bit system common message | . | Midi1ChannelVoice32 | 0x2 | 32-bit MIDI 1.0 channel voice message | . | DataMessage64 | 0x3 | 64-bit data message (including MIDI 1.0 System Exclusive) | . | Midi2ChannelVoice64 | 0x4 | 64-bit MIDI 2.0 channel voice message | . | DataMessage128 | 0x5 | 128-bit Data Message | . | FutureReserved632 | 0x6 | Reserved for future use by the MIDI standards bodies | . | FutureReserved732 | 0x7 | Reserved for future use by the MIDI standards bodies | . | FutureReserved864 | 0x8 | Reserved for future use by the MIDI standards bodies | . | FutureReserved964 | 0x9 | Reserved for future use by the MIDI standards bodies | . | FutureReservedA64 | 0xA | Reserved for future use by the MIDI standards bodies | . | FutureReservedB96 | 0xB | Reserved for future use by the MIDI standards bodies | . | FutureReservedC96 | 0xC | Reserved for future use by the MIDI standards bodies | . | FlexData128 | 0xD | 128-bit Flex Data message including song file data messages | . | FutureReservedE128 | 0xE | Reserved for future use by the MIDI standards bodies | . | Stream128 | 0xF | 128-bit stream message, including endpoint discovery and function block messages | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html#midimessagetype-enumeration", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html#midimessagetype-enumeration" - },"88": { + },"92": { "doc": "MidiMessageType", "title": "IDL", "content": "MidiMessageType IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html#idl" - },"89": { + },"93": { "doc": "MidiMessageType", "title": "MidiMessageType", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html" - },"90": { + },"94": { "doc": "MidiMessageUtility", "title": "MidiMessageUtility", "content": "This class contains a number of static helper functions for reading information from Universal MIDI Packets, and also manipulating that information. In most cases, the calling application needs to do some validation before calling functions which return specific fields. If, for example, the application asks for the Flex Data Status, but doesn’t provide a valid Flex Data message, the function will happily return whatever other data is in the position of that field. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html" - },"91": { + },"95": { "doc": "MidiMessageUtility", "title": "Validation Functions", "content": "| Function | Description | . | ValidateMessage32MessageType(word0) | Validate that the message type field in the word is for a 32-bit UMP | . | ValidateMessage64MessageType(word0) | Validate that the message type field in the word is for a 64-bit UMP | . | ValidateMessage96MessageType(word0) | Validate that the message type field in the word is for a 96-bit UMP | . | ValidateMessage128MessageType(word0) | Validate that the message type field in the word is for a 128-bit UMP | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#validation-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#validation-functions" - },"92": { + },"96": { "doc": "MidiMessageUtility", "title": "Informational Functions", "content": "| Function | Description | . | MessageTypeHasGroupField(messageType) | Returns true if the message type is known to be one which contains a group field. Valid only for message types known at the type the API was written. | . | MessageTypeHasChannelField(messageType) | Returns true if the message type is known to be one which contains a channel field. Valid only for message types known at the type the API was written. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#informational-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#informational-functions" - },"93": { + },"97": { "doc": "MidiMessageUtility", "title": "Field Access Functions", "content": "| Function | Description | . | GetMessageTypeFromMessageFirstWord(word0) | Returns the MidiMessageType for the message | . | GetPacketTypeFromMessageFirstWord(word0) | Returns the MidiPacketType for the message | . | GetGroupFromMessageFirstWord(word0) | Returns the MidiGroup for the message. First check to see if the message type has a group field. | . | GetChannelFromMessageFirstWord(word0) | Returns the MidiChannel for the message. First check to see if the message type has a channel field. | . | GetStatusFromUtilityMessage(word0) | Returns the status byte | . | GetStatusFromMidi1ChannelVoiceMessage(word0) | When provided a MIDI 1.0 channel voice message, returns the Midi1ChannelVoiceMessageStatus for the message. | . | GetStatusFromMidi2ChannelVoiceMessageFirstWord(word0) | When provided a MIDI 2.0 channel voice message, returns the Midi2ChannelVoiceMessageStatus for the message. | . | GetStatusBankFromFlexDataMessageFirstWord(word0) | Returns the status bank byte | . | GetStatusFromFlexDataMessageFirstWord(word0) | Returns the status byte | . | GetStatusFromSystemCommonMessage(word0) | Returns the status byte | . | GetStatusFromDataMessage64FirstWord(word0) | Returns the status byte | . | GetNumberOfBytesFromDataMessage64FirstWord(word0) | Returns the byte count field | . | GetStatusFromDataMessage128FirstWord(word0) | Returns the status byte | . | GetNumberOfBytesFromDataMessage128FirstWord(word0) | Returns the byte count field | . | GetFormFromStreamMessageFirstWord(word0) | Returns the form nibble as a byte | . | GetStatusFromStreamMessageFirstWord(word0) | Returns the status byte | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#field-access-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#field-access-functions" - },"94": { + },"98": { "doc": "MidiMessageUtility", "title": "Field Manipulation Functions", "content": "| Function | Description | . | ReplaceGroupInMessageFirstWord(word0, newGroup) | Replaces the group field in word0 and returns the resulting MIDI word | . | ReplaceChannelInMessageFirstWord(word0, newChannel) | Replaces the channel field in word0 and returns the resulting MIDI word | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#field-manipulation-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#field-manipulation-functions" - },"95": { + },"99": { "doc": "MidiMessageUtility", "title": "Additional Functions", "content": "| Function | Description | . | GetMessageFriendlyNameFromFirstWord(UInt32 word0) | Returns the localized “Friendly Name” string for a message. For example, this is what is displayed in the console output when you are monitoring an endpoint in verbose mode. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#additional-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#additional-functions" - },"96": { + },"100": { "doc": "MidiMessageUtility", "title": "IDL", "content": "MidiMessageUtility IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html#idl" - },"97": { + },"101": { "doc": "MidiPacketType", "title": "MidiPacketType Enumeration", "content": "The values correspond to the number of 32-bit MIDI words in the packet. | Property | Value | Description | . | UnknownOrInvalid | 0 | An invalid zero-length Universal MIDI Packet | . | UniversalMidiPacket32 | 1 | 32-bit (1 word) Universal MIDI Packet | . | UniversalMidiPacket64 | 2 | 64-bit (2 words) Universal MIDI Packet | . | UniversalMidiPacket96 | 3 | 96-bit (3 words) Universal MIDI Packet | . | UniversalMidiPacket128 | 4 | 128-bit (4 words) Universal MIDI Packet | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html#midipackettype-enumeration", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html#midipackettype-enumeration" - },"98": { + },"102": { "doc": "MidiPacketType", "title": "IDL", "content": "MidiPacketType IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html#idl" - },"99": { + },"103": { "doc": "MidiPacketType", "title": "MidiPacketType", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html" - },"100": { + },"104": { "doc": "MidiService", "title": "MidiService", "content": "The MidiService class contains a number of static functions which enable working with the service outside of a specific session. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiService.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiService.html" - },"101": { + },"105": { "doc": "MidiService", "title": "Static Functions", "content": "| Static Function | Description | . | PingService(pingCount) | Send one or more ping messages to the ping endpoint and report on the status and time. Return if the responses are not received in a calculated timeout period. | . | PingService(pingCount, timeoutMilliseconds) | Send one or more ping messages to the ping endpoint and report on the status and time. Return if responses are not received in the specified timeout period. | . | GetInstalledTransportPlugins() | Returns a list of MidiServiceTransportPluginInformation representing all service transport plugins (also called Abstractions) | . | GetInstalledMessageProcessingPlugins() | Returns a list of MidiServiceMessageProcessingPluginInformation objects representing all service message processing plugins (also called Transforms) | . | GetActiveSessions() | Returns a list of MidiSessionInformation detailing all active Windows MIDI Services sessions on this PC. | . | UpdateRuntimeConfiguration(configurationUpdate) | Used by client-side SDK components for some transports and other plugins, and by the MIDI Settings app. The format of the data is dependent upon the target specified in the data. Use with caution. For more information, see the config JSON documentation | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiService.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiService.html#static-functions" - },"102": { + },"106": { "doc": "MidiService", "title": "A note on the ping process", "content": "Pinging the Windows service uses the same mechanism as sending any UMP message. The actual message sent is a prioprietary message. (At the time this was created, there was no standard MIDI 2.0 UMP ping message). The message itself is sent to the diagnostics endpoint in the service, which is implemented like any other transport. Therefore, the speed of the pings here and the success of the ping process is a reasonable indicator of service, cross-process queue, and client API health. The diagnostic ping endpoint does not understand any other type of message, and should not be used by applications other than through the ping functions here. The ping does not tell you if a specific transport or device is in a bad state. For example, if a specific USB MIDI device has crashed, this ping message will still work because it is not sent out over USB. Here’s an example of ping responses through the MIDI console app . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiService.html#a-note-on-the-ping-process", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiService.html#a-note-on-the-ping-process" - },"103": { + },"107": { "doc": "MidiService", "title": "A note on updating runtime configuration", "content": "In order to foster an open plugin ecosystem, we need a way to get settings and configuration for those plugins up to them in the Windows service. The way we’ve chosen to do that is JSON, because that same JSON, when not transient in nature, can also be saved into the permanent configuration file for the active MIDI setup. The runtime configuration update should only be used by code which understands exactly what will be done with the data, and can handle the response which is returned. It is not a general API endpoint, but is designed for components which will extend Windows MIDI Services. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiService.html#a-note-on-updating-runtime-configuration", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiService.html#a-note-on-updating-runtime-configuration" - },"104": { + },"108": { "doc": "MidiService", "title": "IDL", "content": "MidiService IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiService.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiService.html#idl" - },"105": { + },"109": { "doc": "MidiServiceMessageProcessingPluginInformation", "title": "MidiServiceMessageProcessingPluginInformation", "content": "(section in progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html" - },"106": { + },"110": { "doc": "MidiServiceMessageProcessingPluginInformation", "title": "IDL", "content": "MidiSessionMidiServiceMessageProcessingPluginInformationInformation IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html#idl" - },"107": { + },"111": { "doc": "MidiServicePingResponse", "title": "MidiServicePingResponse", "content": "This class represents a single ping message response. This is used to assess health and performance of the Windows service. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html" - },"108": { + },"112": { "doc": "MidiServicePingResponse", "title": "Static Functions", "content": "| Property | Description | . | SourceId | Id used to track this ping source connection instance, in the case of multiple applications using the same ping endpoint | . | Index | Index of the ping | . | ClientSendMidiTimestamp | The time the client sent the ping message | . | ServiceReportedMidiTimestamp | The time the service reported receiving the ping message | . | ClientReceiveMidiTimestamp | The time the client received the ping response | . | ClientDeltaTimestamp | The delta between the client sending the message and receiving the response | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html#static-functions" - },"109": { + },"113": { "doc": "MidiServicePingResponse", "title": "IDL", "content": "MidiServicePingResponse IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html#idl" - },"110": { + },"114": { "doc": "MidiServicePingResponseSummary", "title": "MidiServicePingResponseSummary", "content": "This class represents a summary of the ping attempts against the Windows service. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html" - },"111": { + },"115": { "doc": "MidiServicePingResponseSummary", "title": "Static Functions", "content": "| Property | Description | . | Success | True if the ping was a success | . | FailureReason | In case of a failure, this includes information about why the failure happened. | . | TotalPingRoundTripMidiClock | The total MIDI Clock time for all ping messages to be sent and received | . | AveragePingRoundTripMidiClock | Calculated average round trip time for ping messages | . | Responses | A list of all the responses for the ping messages | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html#static-functions" - },"112": { + },"116": { "doc": "MidiServicePingResponseSummary", "title": "IDL", "content": "MidiServicePingResponseSummary IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html#idl" - },"113": { + },"117": { "doc": "MidiServiceTransportPluginInformation", "title": "MidiServiceTransportPluginInformation", "content": "(section in progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html" - },"114": { + },"118": { "doc": "MidiServiceTransportPluginInformation", "title": "IDL", "content": "MidiServiceTransportPluginInformation IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html#idl" - },"115": { + },"119": { "doc": "MidiSession", "title": "MidiSession", "content": "Before you can connect to an endpoint, you must start a new MIDI session. An application may have any number of sessions open. For example, the application may open one session per open project, or one session per tab in the case of a browser. The lifetime of endpoint connections opened through a session are controlled through the session. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html" - },"116": { + },"120": { "doc": "MidiSession", "title": "Properties", "content": "| Property | Description | . | Id | Generated Id for the session | . | Name | Name for this session. To change the name after creating the session, use the UpdateName() function. This will update the service | . | Settings | The settings used to create this session | . | IsOpen | True if this session is open and ready to use | . | Connections | Map of all endpoint connections created through this session. Disconnecting an endpoint using DisconnectEndpointConnection will remove the connection from this map. The map key is the generated connection GUID that identifies an instance of an endpoint connection | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#properties" - },"117": { + },"121": { "doc": "MidiSession", "title": "Static Member Functions", "content": "The two static functions are factory-pattern methods for creating a new session. | Static Function | Description | . | CreateSession(sessionName) | Create and return a new session with the specified name | . | CreateSession(sessionName, settings) | Create and return a new session with the specified name and settings | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#static-member-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#static-member-functions" - },"118": { + },"122": { "doc": "MidiSession", "title": "Functions", "content": "| Function | Description | . | CreateEndpointConnection(endpointDeviceId) | Create a new connection to the specified endpoint device Id | . | CreateEndpointConnection(endpointDeviceId, options) | Create a new connection to the specified endpoint device Id, using the provided connection options | . | CreateEndpointConnection(endpointDeviceId, options, settings) | Create a new connection to the specified endpoint device Id, using the provided connection options and the endpoint-specific settings | . | CreateVirtualDeviceAndConnection(deviceDefinition) | Create the device-side of an app-to-app virtual endpoint. The calling application will perform as a MIDI device, responding to discovery and other MIDI 2.0 protocol messages. | . | DisconnectEndpointConnection(endpointConnectionId) | Cleanly disconnect an endpoint connection and remove it from the connection map | . | UpdateName(newName) | Update the name of this session locally and in the MIDI Service | . Note: If you manually close a MidiEndpointConnection using IClosable (or IDisposable), it will not be removed from the MidiSession’s collection of endpoints. Instead, use the DisconnectEndpointConnection method of the session to keep both in sync. For that reason, we do not recommend that you wrap the CreateEndpointConnection calls in a using statement. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#functions" - },"119": { + },"123": { "doc": "MidiSession", "title": "IDL", "content": "MidiSession IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#idl" - },"120": { + },"124": { "doc": "MidiSession", "title": "Sample", "content": "using (var session = MidiSession.CreateSession(\"API Sample Session\")) { ... } . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#sample", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSession.html#sample" - },"121": { + },"125": { "doc": "MidiSessionConnectionInformation", "title": "MidiSessionConnectionInformation", "content": "This class represents an open connection in a Windows MIDI Services session. This is an informational class only for reporting system-wide connection usage. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html" - },"122": { + },"126": { "doc": "MidiSessionConnectionInformation", "title": "Static Functions", "content": "| Property | Description | . | EndpointDeviceId | The endpoint device id for the connection | . | InstanceCount | The number of instances of this connection which are open in the parent session | . | EarliestConnectionTime | The date and time the first instance of the connection was opened | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html#static-functions" - },"123": { + },"127": { "doc": "MidiSessionConnectionInformation", "title": "IDL", "content": "MidiSessionConnectionInformation IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html#idl" - },"124": { + },"128": { "doc": "MidiSessionInformation", "title": "MidiSessionInformation", "content": "This class represents an open Windows MIDI Services session. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html" - },"125": { + },"129": { "doc": "MidiSessionInformation", "title": "Static Functions", "content": "| Property | Description | . | SessionId | The generated internal GUID for the session | . | ProcessId | The process id for the session | . | ProcessName | The process name for the session, captured when the session was created | . | SessionName | The name of the session provided through the API | . | StartTime | The date and time the session was created | . | Connections | A list of MidiSessionConnectionInformation objects detailing the connections currently open for this session | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#static-functions" - },"126": { + },"130": { "doc": "MidiSessionInformation", "title": "Example", "content": "The Windows MIDI Services Console app uses the MidiSessionInformation MidiSessionConnectionInformation and the MidiService class to display active sessions. In this case, you can see three open sessions. The process name and process id are on the left. The session name is in the text on the right, after the word “Session”, and the start time is the date and time in green. Finally, the list of connections for each session is underneath the session information. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#example", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#example" - },"127": { + },"131": { "doc": "MidiSessionInformation", "title": "IDL", "content": "MidiSessionInformation IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html#idl" - },"128": { + },"132": { "doc": "MidiSessionSettings", "title": "MidiSessionSettings", "content": "MidiSessionSettings are currently unused. We are evaluating keeping this in the API. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html" - },"129": { + },"133": { "doc": "MidiSessionSettings", "title": "IDL", "content": "MidiSessionSettings IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html#idl" - },"130": { + },"134": { "doc": "MidiStreamConfigurationRequestReceivedEventArgs", "title": "MidiStreamConfigurationRequestReceivedEventArgs", "content": "(in development) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html" - },"131": { + },"135": { "doc": "MidiStreamConfigurationRequestReceivedEventArgs", "title": "IDL", "content": "MidiStreamConfigurationRequestReceivedEventArgs IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html#idl" - },"132": { + },"136": { "doc": "MidiStreamMessageBuilder", "title": "MidiStreamMessageBuilder", "content": "(In progress) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html" - },"133": { + },"137": { "doc": "MidiStreamMessageBuilder", "title": "Functions", "content": "| Function | Description | . |   |   | . |   |   | . |   |   | . |   |   | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html#functions" - },"134": { + },"138": { "doc": "MidiStreamMessageBuilder", "title": "IDL", "content": "MidiStreamMessageBuilder IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html#idl" - },"135": { + },"139": { "doc": "MidiUniqueId", "title": "MidiUniqueId", "content": "The MidiUniqueId class is used to provide formatting and data validation for MIDI-CI MUID types used in Function Blocks and MIDI CI transactions. In the specification, Byte1 is the LSB and Byte4 is the MSB. We follow that convention here. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html" - },"136": { + },"140": { "doc": "MidiUniqueId", "title": "Properties", "content": "| Property | Description | . | Byte1 | The data value for byte 1 of the MUID | . | Byte2 | The data value for byte 2 of the MUID | . | Byte3 | The data value for byte 3 of the MUID | . | Byte4 | The data value for byte 4 of the MUID | . | As28BitInteger | The data value converted to a 28 bit integer | . | IsBroadcast | True if this is the broadcast MUID value | . | IsReserved | True if this is the reserved MUID value | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#properties" - },"137": { + },"141": { "doc": "MidiUniqueId", "title": "Static Properties", "content": "| Static Property | Description | . | LabelShort | Returns the localized abbreviation. | . | LabelFull | Returns the localized full name. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#static-properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#static-properties" - },"138": { + },"142": { "doc": "MidiUniqueId", "title": "Functions", "content": "| Function | Description | . | MidiUniqueId() | Constructs an empty MidiUniqueId | . | MidiUniqueId(integer28bit) | Constructs the MidiUniqueId from the given 28 bit integer | . | MidiUniqueId(byte1, byte2, byte3, byte4) | Constructs a MidiUniqueId with the specified bytes | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#functions" - },"139": { + },"143": { "doc": "MidiUniqueId", "title": "Static Functions", "content": "| Function | Description | . | CreateBroadcast() | Constructs a broadcast MidiUniqueId | . | CreateRandom() | Constructs a random MidiUniqueId | . MidiUniqueId IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#static-functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html#static-functions" - },"140": { + },"144": { "doc": "MidiVirtualEndpointDevice", "title": "MidiVirtualEndpointDevice", "content": "The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html" - },"141": { + },"145": { "doc": "MidiVirtualEndpointDevice", "title": "Properties", "content": "| Property | Description | . | DeviceDefinition | The MidiVirtualEndpointDeviceDefinition used to create this device. This should be treated as read-only data. | . | FunctionBlocks | Current list of function blocks for this device. | . | SuppressHandledMessages | True if the protocol messages handled by this class should be filtered out of the incoming message stream | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#properties" - },"142": { + },"146": { "doc": "MidiVirtualEndpointDevice", "title": "Functions", "content": "| Function | Description | . | UpdateFunctionBlock | Update the properties of a single function block. The number of actual function blocks cannot change after creation (per the UMP specification) but blocks may be marked as active or inactive. Changes here will result in the MIDI 2.0 function block notification messages being sent out. | . | UpdateEndpointName | Update the endpoint name, and send out the appropriate endpoint name notification messages. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#functions" - },"143": { + },"147": { "doc": "MidiVirtualEndpointDevice", "title": "Events", "content": "| Event | Description | . | StreamConfigurationRequestReceived(device, args) | Raised when this device receives a Stream Configuration Request UMP message. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#events", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#events" - },"144": { + },"148": { "doc": "MidiVirtualEndpointDevice", "title": "IDL", "content": "MidiVirtualEndpointDevice IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html#idl" - },"145": { + },"149": { "doc": "MidiVirtualEndpointDeviceDefinition", "title": "MidiVirtualEndpointDeviceDefinition", "content": "The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html" - },"146": { + },"150": { "doc": "MidiVirtualEndpointDeviceDefinition", "title": "Properties", "content": "| Property | Description | . | EndpointName | Name of the endpoint used for both the device enumeration and for responding to the endpoint name request UMP message | . | EndpointProductInstanceId | The unique identifier for this device. This value is used when creating the device Id, and is also used as the response for endpoint discovery when the id is requested. In general, this value should be kept to less than 32 characters and not include any special characters or symbols | . | SupportsMidi1ProtocolMessages | For endpoint discovery. True if this endpoint supports MIDI 1.0 protocol messages over UMP | . | SupportsMidi2ProtocolMessages | For endpoint discovery. True if this endpoint supports MIDI 2.0 protocol messages over UMP | . | SupportsReceivingJRTimestamps | For endpoint discovery. True if this endpoint supports recieving JR timestamps (typically, you’ll want to set this to false) | . | SupportsSendingJRTimestamps | For endpoint discovery. True if this endpoint supports sending JR timestamps (typically, you’ll want to set this to false) | . | DeviceManufacturerSystemExclusiveId | MIDI 2.0 UMP Device Identity value | . | DeviceFamilyLsb | MIDI 2.0 UMP Device Identity value | . | DeviceFamilyMsb | MIDI 2.0 UMP Device Identity value | . | DeviceFamilyModelLsb | MIDI 2.0 UMP Device Identity value | . | DeviceFamilyModelMsb | MIDI 2.0 UMP Device Identity value | . | SoftwareRevisionLevel | MIDI 2.0 UMP Device Identity value | . | AreFunctionBlocksStatic | True if the function blocks will not change in any way | . | FunctionBlocks | list of function blocks for this device | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#properties", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#properties" - },"147": { + },"151": { "doc": "MidiVirtualEndpointDeviceDefinition", "title": "Functions", "content": "| Function | Description | . | MidiVirtualEndpointDeviceDefinition() | Construct a new device definition | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#functions", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#functions" - },"148": { + },"152": { "doc": "MidiVirtualEndpointDeviceDefinition", "title": "IDL", "content": "MidiVirtualEndpointDeviceDefinition IDL . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#idl", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html#idl" - },"149": { + },"153": { "doc": "Service", "title": "Service", "content": "The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/service/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/service/README.html" - },"150": { + },"154": { "doc": "Session", "title": "Session", "content": "Interaction with a MIDI Endpoint always starts with creating a session. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/session/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/session/README.html" - },"151": { + },"155": { "doc": "Connections", "title": "Connecting to a MIDI Endpoint", "content": "In Windows MIDI Services, once you have opened a session, you will typically open one or more connections to device endpoints. The session class contains methods which return an initialized, but not open, connection to the specified endpoint. The remainder of your interaction for sending and receiving data is with the MidiEndpointConnection class. All endpoints in Windows MIDI Services send and receive messages using the Universal MIDI Packet format. Any required translation (for MIDI 1.0 devices, for example) is handled in the service and/or in the USB driver. Workflow . | Open a session | Using an endpoint id discovered through enumeration or another mechanism, create an endpoint connection | Wire up to the connection any event handlers or message processors | Open the connection | Send and receive messages | Using the session, disconnect the connection when you are done with it. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/README.html#connecting-to-a-midi-endpoint", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/README.html#connecting-to-a-midi-endpoint" - },"152": { + },"156": { "doc": "Connections", "title": "Connections", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/connections/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/connections/README.html" - },"153": { + },"157": { "doc": "Client Plugins", "title": "Client-side Processing Plugins", "content": "Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage. MIDI 1.0 had the concept of ports. Each port was just a single cable/jack from a MIDI stream exposed by the device. The API and driver were responsible for merging all of the different cables into the single stream for outgoing data, or pulling them apart for incoming data. In MIDI 2.0, what used to be a Port is now morally equivalent to a Group address in the message data. Instead of speaking to N different enumerated entities for a device, the application speaks to a single bidirectional UMP endpoint which aggregates all of this information, much like the driver did behind the scenes in MIDI 1.0. We recognize that there are cases when the old model of MIDI Ports is more convenient for passing around in a DAW or similar app, particularly for incoming data. To help, there are plugins which implement IMidiEndpointMessageProcessingPlugin. The API includes a few stock plugins, but developers are free to provide their own. Listener instances are 1:1 with endpoint connections. We don’t support using the same listener on multiple endpoints. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html#client-side-processing-plugins", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html#client-side-processing-plugins" - },"154": { + },"158": { "doc": "Client Plugins", "title": "Client Plugins", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html" - },"155": { + },"159": { "doc": "Endpoint Enumeration", "title": "Enumerating Endpoints", "content": "Windows MIDI Services provides detailed information about each MIDI endpoint on the system. In addition to ids and names, you can also get user metadata, function blocks, group terminal blocks, in-protocol properties, the parent device and container, and much more. There are two ways to enumerate endpoint devices. | Static enumeration using the MidiEndpointDeviceInformation class. This is a snapshot in time and is not updated when in-protocol information is updated, or the user has specified new properties like the name. This approach is really only useful in the simplest of scenarios, as it does not handle device connects and disconnects after the initial enumeration. | Dynamic enumeration using the MidiEndpointDeviceWatcher. When you set up a watcher on a background thread, you will be notified when any new endpoints are connected to the system, or any existing endpoints are disconnected. You will also be alerted when properties change on an enumerated device. For example, when new function block information is sent in-protocol, the properties are updated and an event is raised. For these reasons, the device watcher approach is the approach any non-trival application should use to list and track MIDI endpoints. | . Note that you can enumerate endpoint devices using the stock Windows.Devices.Enumeration.DeviceInformation and Windows.Devices.Enumeration.DeviceWatcher classes. However, those classes do not automatically request the extended property set needed for MIDI, do not translate the binary properties like the group terminal blocks and function blocks, and also do not automatically resolve the relationship with the parent device. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/README.html#enumerating-endpoints", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/README.html#enumerating-endpoints" - },"156": { + },"160": { "doc": "Endpoint Enumeration", "title": "Endpoint Enumeration", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/enumeration/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/enumeration/README.html" - },"157": { + },"161": { "doc": "Simple Types", "title": "Simple Types", "content": "There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/simple-types/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/simple-types/README.html" - },"158": { + },"162": { "doc": "Metadata", "title": "Metadata", "content": "The Windows Service intercepts (but does not remove from the stream) Endpoint metadata notifications. For example, we’ll intercept Endpoint Name notifications and use those to provide a new endpoint-supplied name for the device. These are cached in the SWD properties for the Endpoint Device. In addition to the endpoint data, we also capture and store block data. The block data should be used by applications to identify which groups are active and how to display them to the user. For example, you may want to display a function block name including group numbers like “Sequencer (Groups 1, 2, 3)” in a way similar to how you treated ports in the past. Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint and so have their own discrete types. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/metadata/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/metadata/README.html" - },"159": { + },"163": { "doc": "Messages", "title": "Messages", "content": "Windows MIDI Services messages are all sent and received in Universal MIDI Packet (UMP) format, even if the device is a bytestream MIDI 1.0 device (we do the translation for you). a UMP is made up of 1-4 32 bit MIDI words, sized in 32 bit, 64 bit, 96 bit, and 128 bit packets. The first four bits of the packet are the message type, and from that, you can identify the type and size of message which follows. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/README.html" - },"160": { + },"164": { "doc": "Messages", "title": "Words", "content": "Several functions operate on one or more 32 bit MIDI words directly. This is efficient for transmission, but may not be convenient for storage or processing. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/README.html#words", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/README.html#words" - },"161": { + },"165": { "doc": "Messages", "title": "Rich Types", "content": "The rich UMP types are full runtime classes, and so have more overhead than the fixed types or raw words. However, they offer conveniences not offered by the other types, including storage of the timestamp, message and packet type enumerations, and interface-based polymorphism. If your send/receive speed is not super critical, these are often the easiest solution. If you are familiar with the Windows.Devices.Midi message types, these are the conceptual equivalent in UMP. For the most part, we do not provide strongly-typed discrete message types (like specific MIDI 2.0 Channel Voice messages or similar) in the API as that is a moving target, and many applications also include their own message creation and processing functions using their own libraries or any of the libraries included on https://midi2.dev. If there’s demand for strongly-typed messages, we may provide them in the future. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/README.html#rich-types", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/README.html#rich-types" - },"162": { + },"166": { "doc": "Messages", "title": "Fixed-Size Struct type", "content": "In addition to the richer types and raw words, the MidiMessageStruct type offers a fixed 128 bit message which can be used to send or receive any type of MIDI UMP. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/messages/README.html#fixed-size-struct-type", "relUrl": "/developer-docs/Windows.Devices.Midi2/messages/README.html#fixed-size-struct-type" - },"163": { + },"167": { "doc": "Message Utilities", "title": "Message Utilities", "content": "There are many open source and internal libraries that can be used for creating and parsing message data. For a functional MIDI API, however, we did have to create a number of these ourselves, and so surface them in the API so that you may take advantage of them in your own code. For other open source MIDI libraries, visit the official site midi2.dev, run by members of the MIDI Association. The Windows MIDI Services service and API code uses some of this open source internally. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/message-utilities/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/message-utilities/README.html" - },"164": { + },"168": { "doc": "Virtual Devices", "title": "Virtual Devices", "content": "Fully-featured app-to-app MIDI in a MIDI 2.0 world involves connections to a virtual device which must participate in the full MIDI 2.0 protocol, from discovery through protocol negotiation. To support this scenario, the way app-to-app MIDI works in Windows MIDI Services is for an application to define a device and then using the MidiSession, construct that device’s endpoint. Once the device endpoint is opened, Windows MIDI Services will then construct a second application-visible multi-client endpoint which applications will use to talk to the device app. During that conversation, the service will also handle discovery and protocol negotiation with the virtual device just like it would any physical device. In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/virtual-device/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/virtual-device/README.html" - },"165": { + },"169": { "doc": "Windows.Devices.Midi2 API", "title": "Windows.Devices.Midi2", "content": "The Windows.Devices.Midi2 types are documented in these pages. Typical API workflow: . | Create a new session, with an appropriate name. The name will be visible to users and so should be meaningful. Each application may open more than one session at a time (for example, different songs in a DAW, or different tabs in a browser). A single session manages the lifetime of the connections opened through it. | Connect to an endpoint. Typically, you’ll get the endpoint’s id through the enumeration functions. | Wire up a MidiMessageReceived event handler. This is how you will receive incoming messages from the endpoint. Messages are received individually, with one event per message. | Optionally, add any processing plugins. If you want to filter messages or provide multiple “views” into a stream, you can add the appropriate client message processing plugins. | Open the connection. Once the connection is open, you may send and receive messages. | . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#windowsdevicesmidi2", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#windowsdevicesmidi2" - },"166": { + },"170": { "doc": "Windows.Devices.Midi2 API", "title": "Endpoint Enumeration", "content": "Enumeration is how you discover endpoints and get notified of endpoints when they are added, updated, or removed. For the best user experience, keep a MidiEndpointDeviceWatcher running in a background thread so you can monitor device removal, and property updates (name, function blocks, etc.) . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#endpoint-enumeration", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#endpoint-enumeration" - },"167": { + },"171": { "doc": "Windows.Devices.Midi2 API", "title": "Session", "content": "Interaction with a MIDI Endpoint always starts with creating a session. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#session", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#session" - },"168": { + },"172": { "doc": "Windows.Devices.Midi2 API", "title": "Connections", "content": "Once you have a session, you will create one or more connections to send and receive messages. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#connections", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#connections" - },"169": { + },"173": { "doc": "Windows.Devices.Midi2 API", "title": "Clock", "content": "The MIDI clock is used for creating timestamps for use in sending MIDI messages. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#clock", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#clock" - },"170": { + },"174": { "doc": "Windows.Devices.Midi2 API", "title": "Messages", "content": "MIDI Messages are discrete packets of data of a known length. In the MIDI 2.0 specification, they are known as Universal MIDI Packets. In Windows MIDI Services, even MIDI 1.0 bytestream messages are presented in their equivalent Universal MIDI Packet format. The API includes several classes not only for the messages, but also to help construct and parse them. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#messages", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#messages" - },"171": { + },"175": { "doc": "Windows.Devices.Midi2 API", "title": "Metadata", "content": "Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#metadata", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#metadata" - },"172": { + },"176": { "doc": "Windows.Devices.Midi2 API", "title": "Client-Side Processing Plugins", "content": "Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#client-side-processing-plugins", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#client-side-processing-plugins" - },"173": { + },"177": { "doc": "Windows.Devices.Midi2 API", "title": "Virtual Devices", "content": "A virtual device is the mechanism through which app-to-app MIDI works through the API. One application acts as the MIDI Endpoint Device, and other applications connect to it. In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin . ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#virtual-devices", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#virtual-devices" - },"174": { + },"178": { "doc": "Windows.Devices.Midi2 API", "title": "Simple Types", "content": "There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#simple-types", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#simple-types" - },"175": { + },"179": { "doc": "Windows.Devices.Midi2 API", "title": "Service", "content": "The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service. ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html#service", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html#service" - },"176": { + },"180": { "doc": "Windows.Devices.Midi2 API", "title": "Windows.Devices.Midi2 API", "content": " ", "url": "/docs/developer-docs/Windows.Devices.Midi2/README.html", "relUrl": "/developer-docs/Windows.Devices.Midi2/README.html" - },"177": { + },"181": { "doc": "API Backwards Compatibility", "title": "API Backwards Compatibility", "content": "Our intention is for developers to begin adopting Windows MIDI Services in place of the older WinMM, WinRT, and (deprecated) DirectMusic APIs in their applications. All new MIDI features, transports, and more will be implemented in Windows MIDI Services and the new API. A select number of features, slightly more than their current baseline, will be available to WinMM and WinRT APIs through our backwards-compatibility shims and abstractions, but this is simply to ensure existing applications continue to function on systems using Windows MIDI Services. Please note that we are not providing backwards compatibility to support DirectMusic MIDI APIs. The existing MIDI APIs on Windows talk (almost) directly to MIDI 1.0 drivers through kernel calls. In Windows MIDI Services, the architecture is built around a central Windows Service, much like our audio system today. It also uses a much faster IO mechanism for communication with the USB driver vs what our MIDI 1.0 API uses today. This provides much more flexibility, including the potential for multi-client use, and good baseline speed with our new class driver. We are working on shims and abstractions which will allow some of the existing MIDI 1.0 APIs to talk to the service rather than directly to the driver. Here is where we currently stand with planned backwards compatibility. Backwards compatibility for WinMM and WinRT APIs will be a post-1.0 feature, but shortly after that first release. | API | What you should expect | . | Windows MIDI Services | This project. 100% of all supported features for MIDI 1.0 and MIDI 2.0, including multi-client. API/SDK uses UMP as its internal data format even for MIDI 1.0 devices. Transports and the service handle translation. | . | WinMM (Win32 API most apps use today) | Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release. | . | WinRT (MIDI API Introduced with Windows 10) | Access to MIDI 1.0 and most MIDI 2.0 devices, at a MIDI 1.0 compatibility level only. It is possible we will add multi-client support here after our initial release. | . | DirectMusic | No compatibility planned. Not part of our testing. | . Note that we are also investigating and experimenting with how to best incorporate the existing in-box Roland GS / General MIDI Synth into this architecture. It’s likely we will handle it as an additional transport, but we need to test some of the MIDI file players today as many of them make assumptions about which synth index is the GS synth, so this compatibility may come after the initial release. ", "url": "/docs/api-back-compat.html", "relUrl": "/api-back-compat.html" - },"178": { + },"182": { "doc": "Best Practices", "title": "Best Practices and Performance Optimizations", "content": "Here’s a list of best practices and performance optimizations for MIDI API-consuming applications. ", "url": "/docs/developer-docs/best-practices.html#best-practices-and-performance-optimizations", "relUrl": "/developer-docs/best-practices.html#best-practices-and-performance-optimizations" - },"179": { + },"183": { "doc": "Best Practices", "title": "Fast transmission of messages", "content": "For maximum compatibility across languages, and for safety, WinRT doesn’t allow pointers to be exposed by any properties or as parameters or return types for any function. In addition, the by-value and by-reference semantics for parameters are not always under the control of the API developer. For those reasons, and to maximize ease of use across a number of languages and use-cases, we have multiple ways to send and receive messages. You will want to do your own performance testing from your application and scenarios, but in general, the send/receives with the least overhead are those which send/receive individual 32 bit words, a single 128 bit structure, or the IMemoryBuffer. The word and struct methods do pass copies of data, but the amount of data, for most time critical messages, is still 64 bits or less (MIDI 1.0 channel voice messages are 32 bits, MIDI 2.0 channel voice messages are 64 bits). The IMemoryBuffer approach is a more advanced way to transfer data to and from the API. This wraps a buffer of data which you can reuse between calls, including send/receive, as long as you manage and avoid any potential overlaps. Internally, the COM types used to access this ensures that only pointers are passed into the API. There’s a bit more ceremony to using this approach, so we recommend investing time there only if it better fits your app’s programming model. In addition, because IMemoryBuffer deals with bytes and not 32 bit words, you need to ensure you are correctly copying the data in, following the endianness rules for our internal MIDI 2.0 data representation. The most flexible, but least performant approach, is to use the IMidiMessage interface and the methods which return strongly typed messages. These do involve additional type allocations either on the part of the caller or in the API code. Data copies . In the underlying implementation, copying of data is unavoidable in places. Here are the main places where it happens. When sending messages . | The individual WinRT projection for your language may enforce a copy or translation of the data going into the API. This varies. Arrays, in particular, vary here. | The API copies the data (typically a memcpy), regardless of how it is provided, into the cross-process queue for that client endpoint connection. This is shared cross-process memory on Windows. It’s also a circular queue, so we can’t hold onto pointers for long, which is why 4 below operates how it does. | On the service side, the pointers into the buffer are provided to the client connection and the plugins in that chain. No copying here. | There will be copies of the data created if there are any processing plugins which must significantly manipulate the data (each plugin decides how it deals with the data), or if you schedule the message to be sent in the future (see 2 above). | Finally, the messages may be copied when being supplied to the transport. In the case of USB, we make a call into a kernel driver, so have another cross process queue for that which requires we copy data into it to supply it to the driver. In the case of networking, we have to copy the data into the network buffers and transmit. In app-to-app / virtual MIDI, and also the built-in loopback endpoints, we typically just send the same message pointers through the entire process and do not copy any data in the transport. | . This code is all quite efficient, and the amount of data in a single message is small, so these happen quite quickly. Nevertheless, we’re always looking at places where we can further optimize, but still retain the flexibility provided by having a Windows Service which processes the messages. When receiving messages, the process is almost exactly the opposite of sending. There’s no in-bound message scheduling, but there may be data transformations that plugins perform. In addition, endpoints with multiple clients connected do require fanning out those messages into multiple queues, resulting in multiple copies across the different cross-process inbound client connection queues. That is a small price to pay for full multi-client MIDI support. ", "url": "/docs/developer-docs/best-practices.html#fast-transmission-of-messages", "relUrl": "/developer-docs/best-practices.html#fast-transmission-of-messages" - },"180": { + },"184": { "doc": "Best Practices", "title": "Displaying connections to your app users", "content": "Most apps need to display device and endpoint connection information to their users. Here are some details related to that. Use the MidiEndpointDeviceWatcher to respond to device changes . MIDI devices come and go based on connecting/disconnecting USB cables, or new network endpoints coming online. In addition, properties like Function Blocks and Endpoint Name are subject to change at any time. Use the MidiEndpointDeviceWatcher class on a background thread to monitor these endpoints, and receive notifications when anything changes. This is a much more robust approach vs simply enumerating a snapshot of devices up-front. There’s no API or service reason to require a customer to reboot or reload a MIDI DAW or other application to see newly added endpoints. Don’t include diagnostics endpoints for most apps . Unless the app is a utility / testing app, we recommend you do not display the UMP Loopback Endpoints to the user. These are for diagnostics and testing only. By default, they are excluded during enumeration. Enable drill-down into Groups (functions) . A single function block may exist on multiple groups, and multiple groups may overlap function blocks. That is the nature of the MIDI 2.0 specification. In most cases, you’ll find that a function is associated with one or more groups and those groups do not span other function blocks. We recommend that, when displaying a connection to the user, you connect them to the UMP Endpoint, but then enable some sort of drill-down to show the function block names and their associated groups. SynthCompany Foo Synth 5 - Synthesizer (Groups 1, 2, 3) - Sequencer (Groups 4, 5) - MIDI DIN Out (Group 6) . Or similar based on the conventions of your application. Note that a flat list, like what many apps used for MIDI 1.0 ports, is not as reasonable in a MIDI 2.0 world. Use the Function Block UI Hint to help you decide how to show functions . The UI Hint property of a Function Block was created to give the UI an indication of the intended direction of communication, as a user would see it, for a function block. This shouldn’t necessarily block functions from showing up in a list that contains, for example, input devices, but it may be that you want to prioritize the ones with an appropriate UI hint, and have a “see all” option or similar to display the rest. ", "url": "/docs/developer-docs/best-practices.html#displaying-connections-to-your-app-users", "relUrl": "/developer-docs/best-practices.html#displaying-connections-to-your-app-users" - },"181": { + },"185": { "doc": "Best Practices", "title": "Prefer not mixing legacy APIs and Windows MIDI Services in the same session", "content": "There’s nothing technically preventing you from using winmm or WinRT MIDI 1.0 in the same application, at the same time as the new API, but there’s also no need to beyond transitioning code. The new API will do everything the old does, plus a lot more. The older APIs don’t have access to a lot of the metadata you’ll need for devices, and in the case of MIDI 2.0 endpoints, will require additional message translation in the service. Of course, offering a choice between Windows MIDI Services and an older API in your application is perfectly acceptable, based on your use cases, and which versions of the operating systems you need to support. ", "url": "/docs/developer-docs/best-practices.html#prefer-not-mixing-legacy-apis-and-windows-midi-services-in-the-same-session", "relUrl": "/developer-docs/best-practices.html#prefer-not-mixing-legacy-apis-and-windows-midi-services-in-the-same-session" - },"182": { + },"186": { "doc": "Best Practices", "title": "Best Practices", "content": " ", "url": "/docs/developer-docs/best-practices.html", "relUrl": "/developer-docs/best-practices.html" - },"183": { + },"187": { "doc": "Config JSON", "title": "JSON Config File", "content": "It’s best to use the Settings application and the transport / processing plugins for Settings to manipulate the file. However, if you edit it by hand, here are some notes. ", "url": "/docs/config-json.html#json-config-file", "relUrl": "/config-json.html#json-config-file" - },"184": { + },"188": { "doc": "Config JSON", "title": "The File location is Restricted", "content": "The JSON configuration files are all stored in %allusersprofile%\\Microsoft\\MIDI which typically resolves to C:\\ProgramData\\Microsoft\\MIDI. For security reasons, we don’t allow the file to be stored in any other location. However, you can have as many files in that folder as you want, and switch between them as needed. The default config file is typically named Default.midiconfig.json. The actual name is stored in the registry under HKLM\\SOFTWARE\\Microsoft\\Windows MIDI Services in the CurrentConfig value. This value must not contain any non-filename path characters (no backslashes, colons, etc.). ", "url": "/docs/config-json.html#the-file-location-is-restricted", "relUrl": "/config-json.html#the-file-location-is-restricted" - },"185": { + },"189": { "doc": "Config JSON", "title": "JSON is Case-Sensitive", "content": "JSON is typically case-sensitive for all keys. The Windows.Data.Json parser used by Windows MIDI Services is case-sensitive with no option to ignore case. That includes GUID values. For example, the following two values are not equivalent JSON keys: . \"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}\": { \"_comment\": \"KS MIDI (USB etc.)\" } . and . \"{26fa740d-469c-4d33-beb1-3885de7d6df1}\": { \"_comment\": \"KS MIDI (USB etc.)\" } . ", "url": "/docs/config-json.html#json-is-case-sensitive", "relUrl": "/config-json.html#json-is-case-sensitive" - },"186": { + },"190": { "doc": "Config JSON", "title": "Schema", "content": "The JSON config file is such that each transport owns its own schema within the bucket associated with its class ID (GUID). We do not impose a schema on the transports or other plugins. Therefore there is no formal JSON Schema for this file. Here’s an example of a bare-bones file, with sections for three different transports. { \"header\": { \"_comment\": \"NOTE: All json keys are case-sensitive, including GUIDs.\", \"product\" : \"Windows MIDI Services\", \"fileVersion\": 1.0 }, \"endpointTransportPluginSettings\": { \"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}\": { \"_comment\": \"KS MIDI (USB etc.)\" }, \"{C95DCD1F-CDE3-4C2D-913C-528CB8A4CBE6}\": { \"_comment\": \"Network MIDI\" }, \"{8FEAAD91-70E1-4A19-997A-377720A719C1}\": { \"_comment\": \"Virtual MIDI\" } }, \"endpointProcessingPluginSettings\": { } } . Endpoint Properties . The basics of this are identical for each transport. We’ll use KS (USB) as an example . \"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}\": { \"_comment\": \"KS MIDI (USB etc.)\" \"SWD: \\\\\\\\?\\\\SWD#MIDISRV#MIDIU_KS_BIDI_6799286025327820155_OUTPIN.0_INPIN.2#{e7cce071-3c03-423f-88d3-f1045d02552b}\": { \"userSuppliedName\" : \"Pete's Kontrol S61\", \"userSuppliedDescription\" : \"This is my most favorite MIDI 2.0 controller in the whole world!\" } }, . Of those, the identification method SWD is the most important. This controls how we identify a matching device. In cases where the manufacturer doesn’t supply a unique iSerialNumber in USB, unplugging your device from one USB port and plugging it into another can result in a new Id. Similarly, if you have two or more of the same device, and they do not have unique serial numbers, it can be impossible for Windows to distinguish between them. Valid values for the identification method prefix . | SWD: : (The colon and trailing space are required). Use the full Windows Endpoint Device Interface Id. For example \\\\\\\\?\\\\SWD#MIDISRV#MIDIU_KS_BIDI_16024944077548273316_OUTPIN.0_INPIN.2#{e7cce071-3c03-423f-88d3-f1045d02552b}. (Note how the backslashes have to be escaped with additional backslashes.) If the device has an iSerialNumber or you never move it between USB ports, this tends to work fine. | (other methods to be added here when we implement them) | . Valid properties you can set across all supported endpoints . | Property | Type | Description | . | userSuppliedName | Quoted Text | The name you want to use for the endpoint. This will override the name displayed in correctly-coded applications, but won’t necessarily change what you see in Device Manager. These names should be relatively short so they display fully in all/most applications, but meaningful to you. | . | userSuppliedDescription | Quoted Text | A text description and/or notes about the endpoint. Applications may or may not use this data | . | forceSingleClientOnly | Boolean true/false (no quotes) | Most endpoints are multi-client (more than one application can use them simultaneously) by default. This setting is for forcing an endpoint to be single-client only (a value of true). It’s unusual to need this, but a typical use may be to disable multi-client for a device which has a custom driver which doesn’t gracefully handle multiple client applications at the same time. | . ", "url": "/docs/config-json.html#schema", "relUrl": "/config-json.html#schema" - },"187": { + },"191": { "doc": "Config JSON", "title": "Plugin-specific settings", "content": "This is not an exhaustive list, because the transport and processing plugins may be created by anyone. Virtual MIDI . TODO: Provide examples for this . For the persistent configuration file, typically “add” is all that is specified, as it doesn’t make sense to update or remove endpoints or routing on service start. NOTE: This document is not yet complete. We’ll add more details as the schemas are finalized . KS (USB etc) MIDI . TODO: Show how to update endpoint names and provide other properties here . ", "url": "/docs/config-json.html#plugin-specific-settings", "relUrl": "/config-json.html#plugin-specific-settings" - },"188": { + },"192": { "doc": "Config JSON", "title": "Config JSON", "content": " ", "url": "/docs/config-json.html", "relUrl": "/config-json.html" - },"189": { + },"193": { "doc": "Consuming the MIDI API", "title": "Consuming the Windows MIDI Services API", "content": "The Windows MIDI Services API is built using C++/WinRT. WinRT, a requirement for modern APIs on Windows, enables desktop applications, regardless of language, to be able to use APIs, SDKs, etc. that we create. The older tools, C++/CX, are arguably simpler to implement in, but because they include proprietary extensions to C++, we decided to go with standards-based C++/WinRT instead. ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-the-windows-midi-services-api", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-the-windows-midi-services-api" - },"190": { + },"194": { "doc": "Consuming the MIDI API", "title": "Prerequisites", "content": "To use the API, your application language and tools must be able to work with WinRT metadata and libraries, or the generated projection header file. | Visual Studio 2022+ if you are using Visual Studio | Windows SDK 10.0.20348 (Install with Visual Studio) | Windows 10 22H2, or preferably, the latest version of Windows 11. Our development machines are all running Windows 11. | C++ 17 (C++ 20 may work, C++ 14 will not) | The NuGet package(s) from the release | . Note that there are somewhat hacky ways to get traditional C to work with the COM interfaces, but it is a ton of work for you, and is not a scenario we support. If you find yourself in that situation, I recommend factoring out the MIDI code into its own lib and encapsulating all the C++ calls in there. NOTE: In the period of time before Windows MIDI Services ships in Windows, you will also need to run the latest Windows 11 Insider Canary build of Windows in order to be able to use the USB MIDI 2.0 driver. Click here to learn more and join the Windows Insider Program. CPU Architecture: The public GitHub releases currently support Intel/AMD x64 only. Our internal builds and in-box release support x64 as well as Arm64. There is no planned support for Arm(32) or x86. We only support 64 bit applications. ", "url": "/docs/developer-docs/consuming-midi-api.html#prerequisites", "relUrl": "/developer-docs/consuming-midi-api.html#prerequisites" - },"191": { + },"195": { "doc": "Consuming the MIDI API", "title": "Consuming from C++ with Visual Studio", "content": "Add the C++/WinRT Nuget package to your C++ project in Visual Studio. This installs the required tools and build process. See the C++/WinRT FAQ link below for using LLVM/Clang. Note that the Windows MIDI Services team does not provide any support for LLVM/Clang, but we will take PRs as required if we need to change something reasonable to ensure you are successful with those tools, within what C++/WinRT can support. In your project, set your target and minimum SDK versions to 10.0.20348.0 . Download the NuGet package for the Core SDK . | Until this is published on NuGet.org, you’ll need to set up a local package repository. This is easy to do inside the NuGet Package Manager in Visual Studio. You simply point to a folder. The structure I use in the local clone of the repo is a subfolder of the release folder for all NuGet packages. Specifically D:\\peteb\\Documents\\GitHub\\microsoft\\midi\\build\\release\\NuGet\\ | . If needed, modify the project file as required (info in the C++/WinRT docs, and you can also look at the sample application code). If you are not using Visual Studio as your toolchain for your project, you may want to pull out the MIDI code into a library in your project which does. It’s not strictly required, but it’s much easier to use C++/WinRT. (If you do not want to do this, you’ll need to manually set up the cppwinrt tools as part of your build process to generate the required Windows.Devices.Midi2.h projection header. After that, you can develop using your normal flow.). Read through this page, specifically the “If the API is implemented in a Windows Runtime component”. After that, you reference the types as you would anything else in C++. Only the toolchain is an extra step. What it produces is standard C++. We’re considering what we can do here to possibly eliminate even that step in the future, but it’s required for now. When in doubt, REbuild your project. C++/WinRT does a lot of code generation for the projections. | C++ Windows MIDI Services Example Code | Introduction to C++/WinRT | C++/WinRT on GitHub | C++/WinRT FAQ | C++/WinRT Troubleshooting | . ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-c-with-visual-studio", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-c-with-visual-studio" - },"192": { + },"196": { "doc": "Consuming the MIDI API", "title": "Consuming from C# Desktop App", "content": "Your project will currently need to target .NET 7 or above. We prefer .NET 8. Releases will eventually be in the official NuGet.org package source. For now, you can create a local package source and place the NuGet package in there. Then add it to your package sources in the NuGet Package Manager in Visual Studio. The package contains the .NET (C#) projection for .NET 7 and .NET 8. You will still need to install the C#/WinRT NuGet package in your project because we use other Windows SDK types from Windows.Foundation and more. Note that other .NET languages (like Visual Basic) may work, but have not been tested. | C# Windows MIDI Services Example Code | C#/WinRT on GitHub | . ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-c-desktop-app", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-c-desktop-app" - },"193": { + },"197": { "doc": "Consuming the MIDI API", "title": "Consuming from C# UWP", "content": "Support for this is not yet in place. We are evaluating the need for UWP support. Our top priority is desktop application support. ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-c-uwp", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-c-uwp" - },"194": { + },"198": { "doc": "Consuming the MIDI API", "title": "Consuming from Rust / RS WinRT", "content": "We will provide more information in the future. However, you will follow a similar approach to C++ using windows-rs instead of C++/WinRT. Note that the Rust WinRT tools are newer and are still in active development. Supporting non-Windows SDK winmd files is or will be supported, but is not intuitive at the moment. There is no existing crate for Windows MIDI Services right now. | Getting Started with windows-rs | Rust for Windows and the windows crate | Set up your Rust Development Environment | Rust Windows MIDI Services Example Code | windows-rs on GitHub | . ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-rust--rs-winrt", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-rust--rs-winrt" - },"195": { + },"199": { "doc": "Consuming the MIDI API", "title": "Consuming from C++ without Visual Studio (using cmake or other tools)", "content": "The C++/WinRT tool cppwinrt.exe will generate a standard C++ 17 header file Windows.Devices.Midi2.h which you can pull in and include in your project. The header file projections for WinRT types outside of Windows::Devices::Midi2 are included with the Windows SDK. When we ship Windows MIDI Services in-box in Windows, this API will be projected in the same way as all the others in the Windows SDK. First, install the Windows SDK. You can get the SDK from the Windows Dev Center . The SDK install includes the cppwinrt.exe tool. For the 10.0.22621.0 version of the SDK, it is found here on my PC: C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22621.0\\x64 and C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22621.0\\arm64 . Pick the version appropriate for your development PC architecture. Normally, all SDK header files, on my PC with the 10.0.22621.0 version of the SDK installed, are located here C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.22621.0\\cppwinrt\\winrt . Generating the Projection Headers . The tool produces the header files from from the .winmd file. This file can be found with the developer release of Windows MIDI Services either as a separate download in the release, or by opening the NuGet package (it’s just a zip file) and pulling it from there. The .winmd file is just metadata about the implementation dll. C:\\demos\\cppwinrt>dir Volume in drive C has no label. Volume Serial Number is 0AEC-1038 Directory of C:\\demos\\cppwinrt 11/09/2023 02:21 PM <DIR> . 11/09/2023 02:20 PM <DIR> .. 11/06/2023 08:48 PM 55,808 Windows.Devices.Midi2.winmd 1 File(s) 55,808 bytes 2 Dir(s) 32,987,725,824 bytes free C:\\demos\\cppwinrt> C:\\demos\\cppwinrt>set cppwinrt=\"C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.22621.0\\x64\\cppwinrt.exe\" C:\\demos\\cppwinrt>%cppwinrt% -input Windows.Devices.Midi2.winmd -reference 10.0.20348.0+ -output .\\projection C:\\demos\\cppwinrt>dir /s Volume in drive C has no label. Volume Serial Number is 0AEC-1038 Directory of C:\\demos\\cppwinrt 11/09/2023 02:26 PM <DIR> . 11/09/2023 02:20 PM <DIR> .. 11/09/2023 02:26 PM <DIR> projection 11/06/2023 08:48 PM 55,808 Windows.Devices.Midi2.winmd 1 File(s) 55,808 bytes Directory of C:\\demos\\cppwinrt\\projection 11/09/2023 02:26 PM <DIR> . 11/09/2023 02:26 PM <DIR> .. 11/09/2023 02:26 PM <DIR> winrt 0 File(s) 0 bytes Directory of C:\\demos\\cppwinrt\\projection\\winrt 11/09/2023 02:26 PM <DIR> . 11/09/2023 02:26 PM <DIR> .. 11/09/2023 02:26 PM <DIR> impl 11/09/2023 02:26 PM 349,214 Windows.Devices.Midi2.h 1 File(s) 349,214 bytes Directory of C:\\demos\\cppwinrt\\projection\\winrt\\impl 11/09/2023 02:26 PM <DIR> . 11/09/2023 02:26 PM <DIR> .. 11/09/2023 02:26 PM 155,054 Windows.Devices.Midi2.0.h 11/09/2023 02:26 PM 22,170 Windows.Devices.Midi2.1.h 11/09/2023 02:26 PM 26,886 Windows.Devices.Midi2.2.h 3 File(s) 204,110 bytes Total Files Listed: 5 File(s) 609,132 bytes 11 Dir(s) 32,988,221,440 bytes free C:\\demos\\cppwinrt> . The minimum SDK to build against is 10.0.20348.0, to support Windows 10. If you get a “Mismatched C++/WinRT headers” message, you can change the version in the command line to be the version of the SDK you downloaded. Typically, that is not necessary as long as you use the version of cppwinrt.exe from the same SDK root location where you reference the SDK headers from. Using the Projection . Once you have the header file referenced, you can use the same sample code used in the C++/WinRT examples. Note that the generated projection header takes care of referencing dependencies from the generated files and from the SDK. You will need to ensure that referenced tree of files is part of your build process by having the correct include path for the generated files and the SDK headers. NOTE: don’t use my example below. That is subject to change. Use what is actually generated. // WARNING: Please don't edit this file. It was generated by C++/WinRT v2.0.220110.5 #pragma once #ifndef WINRT_Windows_Devices_Midi2_H #define WINRT_Windows_Devices_Midi2_H #include \"winrt/base.h\" static_assert(winrt::check_version(CPPWINRT_VERSION, \"2.0.220110.5\"), \"Mismatched C++/WinRT headers.\"); #define CPPWINRT_VERSION \"2.0.220110.5\" #include \"winrt/Windows.Devices.h\" #include \"winrt/impl/Windows.Data.Json.2.h\" #include \"winrt/impl/Windows.Devices.Enumeration.2.h\" #include \"winrt/impl/Windows.Devices.Midi.2.h\" #include \"winrt/impl/Windows.Foundation.2.h\" #include \"winrt/impl/Windows.Foundation.Collections.2.h\" #include \"winrt/impl/Windows.Devices.Midi2.2.h\" ... Note: As of the time of this writing, the generated projections are compatible with C++/17. [They are not compatible with C++/20]https://github.com/microsoft/cppwinrt/issues/1322(). This issue is out of the control of the MIDI project. GCC Support . We haven’t tried it ourselves, but C++/WinRT does appear to be compatible with GCC. See this pull request from 2022. ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-c-without-visual-studio-using-cmake-or-other-tools", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-c-without-visual-studio-using-cmake-or-other-tools" - },"196": { + },"200": { "doc": "Consuming the MIDI API", "title": "Consuming from NodeJS / Electron", "content": "We are investigating projection support for node.js / Electron. We have a prelimary version working. In that version, the code to enumerate endpoints and then send messages in a loop looks like this: . function createWindow () { const mainWindow = new BrowserWindow({ width: 800, height: 600, webPreferences: { preload: path.join(__dirname, 'preload.js') } }) mainWindow.loadFile('index.html') // Enumerate endpoints const endpoints = midi2.MidiEndpointDeviceInformation.findAll( midi2.MidiEndpointDeviceInformationSortOrder.name, midi2.MidiEndpointDeviceInformationFilter.includeDiagnosticLoopback + midi2.MidiEndpointDeviceInformationFilter.includeClientUmpNative + midi2.MidiEndpointDeviceInformationFilter.includeClientByteStreamNative); console.log(endpoints); for (var i = 0; i < endpoints.size; i++) { var endpoint = endpoints.getAt(i); console.log(endpoint.id); console.log(endpoint.deviceInstanceId); console.log(endpoint.name); console.log(endpoint.description); console.log(endpoint.transportMnemonic); console.log(\"------------------------------------------------\"); console.log(\"\"); } const loopbackAId = midi2.MidiEndpointDeviceInformation.diagnosticsLoopbackAEndpointId; const loopbackBId = midi2.MidiEndpointDeviceInformation.diagnosticsLoopbackBEndpointId; // create a new session var session = midi2.MidiSession.createSession(\"Electron Test Session\"); // connect to loopback A var sendConnection = session.createEndpointConnection(loopbackAId); // connection needs to be opened before it is used sendConnection.open(); // send messages out to that endpoint for (var j = 0; j < 1000; j++) { sendConnection.sendMessageWords(midi2.MidiClock.now, 0x48675309, 0xDEADBEEF); } session.close(); } . You can see it’s very similar to the code for other languages like C# and C++. Here’s what the output looked like in the initial test. I also had a midi.exe console running and all 1000 messages were received. C:\\demos\\node-midi\\electron-midi>npm start > electron-midi@1.0.0 start > electron . Windows::Foundation::Collections:IVectorView { __winRtInstance__: true } \\\\?\\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_A#{e7cce071-3c03-423f-88d3-f1045d02552b} SWD\\MIDISRV\\MIDIU_DIAG_LOOPBACK_A Diagnostics Loopback A Diagnostics loopback endpoint. For testing purposes. DIAG ------------------------------------------------ \\\\?\\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_B#{e7cce071-3c03-423f-88d3-f1045d02552b} SWD\\MIDISRV\\MIDIU_DIAG_LOOPBACK_B Diagnostics Loopback B Diagnostics loopback endpoint. For testing purposes. DIAG ------------------------------------------------ \\\\?\\SWD#MIDISRV#MIDIU_KS_BIDI_14488056966904779946_OUTPIN.0_INPIN.1#{e7cce071-3c03-423f-88d3-f1045d02552b} SWD\\MIDISRV\\MIDIU_KS_BIDI_14488056966904779946_OUTPIN.0_INPIN.1 UM-ONE KS ------------------------------------------------ C:\\demos\\node-midi\\electron-midi> . ", "url": "/docs/developer-docs/consuming-midi-api.html#consuming-from-nodejs--electron", "relUrl": "/developer-docs/consuming-midi-api.html#consuming-from-nodejs--electron" - },"197": { + },"201": { "doc": "Consuming the MIDI API", "title": "Flutter / Dart", "content": "Once the API is in-box on Windows, it will be possible for the projections to be generated by the Flutter/Dart teams, like they do with the Windows SDK today. ", "url": "/docs/developer-docs/consuming-midi-api.html#flutter--dart", "relUrl": "/developer-docs/consuming-midi-api.html#flutter--dart" - },"198": { + },"202": { "doc": "Consuming the MIDI API", "title": "Webview2 Hosted / PWA", "content": "We are investigating. ", "url": "/docs/developer-docs/consuming-midi-api.html#webview2-hosted--pwa", "relUrl": "/developer-docs/consuming-midi-api.html#webview2-hosted--pwa" - },"199": { + },"203": { "doc": "Consuming the MIDI API", "title": "Python", "content": "Once the API is in the Windows SDK, tools like PyWinRT can be used to create projections. ", "url": "/docs/developer-docs/consuming-midi-api.html#python", "relUrl": "/developer-docs/consuming-midi-api.html#python" - },"200": { + },"204": { "doc": "Consuming the MIDI API", "title": "Consuming the MIDI API", "content": " ", "url": "/docs/developer-docs/consuming-midi-api.html", "relUrl": "/developer-docs/consuming-midi-api.html" - },"201": { + },"205": { "doc": "Diagnostics Endpoints", "title": "MIDI Diagnostic Endpoints", "content": "Windows MIDI Services comes with three diagnostic endpoints, two of which are there for application development, testing, and debugging. ", "url": "/docs/developer-docs/diagnostic-endpoints.html#midi-diagnostic-endpoints", "relUrl": "/developer-docs/diagnostic-endpoints.html#midi-diagnostic-endpoints" - },"202": { + },"206": { "doc": "Diagnostics Endpoints", "title": "Loopbacks A and B", "content": "Windows MIDI Services comes with two loopback endpoints which are always present if the Windows service is running. These cannot be turned off by applications or configuration, and so may be relied upon by customer support, unit tests, and more. The Endpoint Device Ids are available as static members of the MidiEndpointDeviceInformation class . winrt::hstring MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId(); winrt::hstring MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId(); . By default, these endpoints are not returned by enumeration calls, because most applications would not want to present them to the user. However, you can include them in the MidiEndpointDeviceInformation::FindAll and MidiEndpointDeviceWatcher::CreateWatcher device filters by using the MidiEndpointDeviceInformationFilter enum value IncludeDiagnosticLoopback if your application has a diagnostic need for them. MidiEndpointDeviceInformationFilter::IncludeDiagnosticLoopback . Diagnostic Loopback Endpoints A and B are cross-wired so that any message sent out on loopback A will come in on loopback B, and any message sent out on B will come in on A. In this way, the loopbacks function as a global app-to-app MIDI implementation for testing. Note that there is only one instance of each endpoint in the system, so if multiple applications use the loopback, the messages will get mixed together like any other endpoint. TIP: The Diagnostic Loopback Endpoints are in place for testing and development only. Applications should not present them to users, or use them for communication outside of testing and debugging. Don’t expose the diagnostic loopback endpoints as part of the list of endpoints in a production DAW application. Special Timestamp Behavior . Normally, an incoming MIDI message will receive a new timestamp when it first arrives from a remote endpoint. In this way, you know exactly when the Windows service first “saw” the message. The loopback endpoints are special-cased so that they do not alter the original sent timestamp. The entire message and timestamp, is sent back exactly as it is received. If you send a message to a loopback with a timestamp of 0 (send immediately), it will come back with the same 0 timestamp. Similarly, if you specify an actual timestamp, that same timestamp will come back in the received message. The latter can be helpful in unit testing when you need to correlate a sent message with a received message, or you need to verify that the specific timestamp you sent was actually sent. If you need the more typical timestamp behavior, you can set up app-to-app MIDI virtual endpoints. Metadata Capture . The Loopback endpoints capture Endpoint and Function Block metadata just like any other endpoint. Because of this, you can change the name of the endpoint through in-protocol messages. If you do that, simply change it back later using the same type of message. Note: We’re working to purge the endpoint metadata cache on device reconnection or service restart, which would reset those properties and names. Currently, it persists across service and Windows restarts. ", "url": "/docs/developer-docs/diagnostic-endpoints.html#loopbacks-a-and-b", "relUrl": "/developer-docs/diagnostic-endpoints.html#loopbacks-a-and-b" - },"203": { + },"207": { "doc": "Diagnostics Endpoints", "title": "Ping", "content": "The ping endpoint is not normally returned through any enumeration. It is for internal use only, and should not be used by any applications. It recognizes only one type of proprietary message. Behavior and implementation of the Ping endpoint is subject to change and should not be relied upon by any code outside of the API. ", "url": "/docs/developer-docs/diagnostic-endpoints.html#ping", "relUrl": "/developer-docs/diagnostic-endpoints.html#ping" - },"204": { + },"208": { "doc": "Diagnostics Endpoints", "title": "Diagnostics Endpoints", "content": " ", "url": "/docs/developer-docs/diagnostic-endpoints.html", "relUrl": "/developer-docs/diagnostic-endpoints.html" - },"205": { + },"209": { "doc": "Endpoint Device Ids", "title": "Endpoint Device Ids", "content": "The Endpoint Device Id (also referred to as a Device Id) is the way we identify individual devices and interfaces in Windows. Example for one of the built-in loopback endpoints: . \\\\?\\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_A#{e7cce071-3c03-423f-88d3-f1045d02552b} . | Part | Description | . | SWD | Software device. This is any device that is not a physical device connected to the PC, and which is created using the Software Device APIs. All MIDI endpoints are software devices and may or may not have a physical connected device as a parent. | . | MIDISRV | The name of the enumerator. For Windows MIDI Services, this is the MidiSrv Windows Service | . | MIDIU | Indicates a MIDI UMP interface. | . | DIAG | Mnemonic for the transport which created this device interface. | . | LOOPBACK_A | Arbitrary unique identification string provided by the transport. Typically includes a unique identifier like a serial number. It may also contain other information like the pin pairs used to provide the bidirectional communication. | . | MIDIU_DIAG_LOOPBACK_A | The entire string here is controlled by the transport. By convention it breaks down into the fields mentioned above, but that is not something you should count on. In general, parsing these strings is not recommended. | . | GUID | The interface Id. For Windows MIDI Services, every interface is a bidirectional interface, even if the connected device is MIDI 1.0 with a single unidirectional interface. For MIDI 1.0 devices, you can look at the group terminal blocks to identify active groups/directions. For MIDI 2.0 devices, you can look at the function blocks for the same information and more. | . If you look at the device in Device Manager, and look at Details/Device Instance Path, you’ll see all of the information here except for the interface Id. When you enumerate devices through Windows::Devices::Enumeration or through Windows MIDI Services, the interface Id is included and required. Tip: Although it was required in the past, we don’t recommend parsing these strings. If there’s information you need about the device which is not contained in the enumerated properties, please let us know and we’ll look into whether or not we can create a custom property to hold that. ", "url": "/docs/developer-docs/endpoint-ids.html", "relUrl": "/developer-docs/endpoint-ids.html" - },"206": { + },"210": { "doc": "Programming Languages FAQ", "title": "Programming Languages and App Models FAQ", "content": "This is a developer-focused FAQ. ", "url": "/docs/developer-docs/faq-programming-languages.html#programming-languages-and-app-models-faq", "relUrl": "/developer-docs/faq-programming-languages.html#programming-languages-and-app-models-faq" - },"207": { + },"211": { "doc": "Programming Languages FAQ", "title": "WinRT", "content": "Q: Why is the API and SDK WinRT instead of a set of C headers like classic APIs? Why not use classic COM? A: New APIs for Windows are required to be WinRT, unless there are really good reasons not to be. WinRT is enhanced COM with a richer type system with better support for use by most of the languages and frameworks used to develop Windows applications. Q: Does the fact that the API and SDK are WinRT mean they are sandboxed? A: No. WinRT is modern COM. The term has been overloaded in the past to also include an app model, Store requirements, and more. In this project, WinRT simply means the implementation flavor with support for projections. It does not impose any sandbox or other restrictions on consuming applications. Q: Why does the service plugin model use COM instead of WinRT? A: For our runtime discovery-based plugin model, “Classic” COM makes more sense. WinRT components need to be known at compile time. Q: Why do MIDI namespaces sometimes start with Microsoft instead of Windows? A: Anything targeted for delivery in-box can use Windows.Devices. Anything which is an additional component download for applications, like the SDK, use Microsoft as the top-level namespace as per our conventions. ", "url": "/docs/developer-docs/faq-programming-languages.html#winrt", "relUrl": "/developer-docs/faq-programming-languages.html#winrt" - },"208": { + },"212": { "doc": "Programming Languages FAQ", "title": "Projections", "content": "Q: Which projections will this project deliver? A: We will start with the basic projections: C++, C# (current .net versions), and JavaScript. We will add more (Rust, for example) as we proceed in development. We want to be as inclusive here as we can reasonably be. ", "url": "/docs/developer-docs/faq-programming-languages.html#projections", "relUrl": "/developer-docs/faq-programming-languages.html#projections" - },"209": { + },"213": { "doc": "Programming Languages FAQ", "title": "App Models", "content": "Q: What is the primary app model the API and SDK are targeting? A: Windows desktop apps of all types including C++, C#, Electron, and more. Q: Do the API and SDK support UWP Applications? A: During the initial testing rollout, the API is not built into Windows, and so may not be completely compatible with UWP apps. TBD which functions are usable from the UWP sandbox in the future, but we want to support as much as is possible. ", "url": "/docs/developer-docs/faq-programming-languages.html#app-models", "relUrl": "/developer-docs/faq-programming-languages.html#app-models" - },"210": { + },"214": { "doc": "Programming Languages FAQ", "title": "Project Implementation Languages", "content": "Q: Which languages are used in the project? A: Primarily, the project is C++ and C#. Q: Why is the API and SDK C++ instead of Rust? A: Rust supports WinRT, including authoring, through the rs/WinRT project. However, Rust does not currently support Arm64EC, which means apps on Arm64 devices which need to load x64 plugins (that is, most DAWs) would not be able to load the SDK into their process. Additionally, modern C++ can be used quite safely, it’s just not “safe by default” like Rust is. Q: Why is the API and SDK C++ instead of C#/.net? A: The majority of DAWs are written in C++ or similar languages. Although one can create WinRT components from C#, they carry along a runtime and garbage collection which most DAW developers do not want in their process. Additionally, C# does not support Arm64EC. Q: Why are the apps in C# /.net? A: C# is a great language for applications. Additionally, we want to encourage contributions from our enormous C#/.net development community. Q: Why is the Windows Service C++ instead of C#, Rust, or something else? A: Early prototypes of the service were in C#, which worked fine for most things, until you got into the kernel data transfer, integration with the PnP stack, and more. The implementation team already knows how to use those features and APIs, with great performance, in C++ based on their work with the audio services in Windows today, so the implementation is in C++. Q: Why does the driver have reimplementations of features we see in the standard library? A: In kernel mode drivers, the standard library is largely unavailable. ", "url": "/docs/developer-docs/faq-programming-languages.html#project-implementation-languages", "relUrl": "/developer-docs/faq-programming-languages.html#project-implementation-languages" - },"211": { + },"215": { "doc": "Programming Languages FAQ", "title": "Programming Languages FAQ", "content": " ", "url": "/docs/developer-docs/faq-programming-languages.html", "relUrl": "/developer-docs/faq-programming-languages.html" - },"212": { + },"216": { "doc": "Windows Midi Services", "title": "Windows MIDI Services", "content": "Source repo and developer releases on GitHub . Discord Server for discussion about this project . ", "url": "/docs/#windows-midi-services", "relUrl": "/#windows-midi-services" - },"213": { + },"217": { "doc": "Windows Midi Services", "title": "Key Features", "content": ". | Multi-client by default. Unless an endpoint is configured to not allow shared connections, or there is some issue around multi-client in a third-party driver, any endpoint (including MIDI 1.0 devices) can be used by multiple applications at the same time. So far, in our testing, we haven’t found any USB devices or drivers which cannot be multi-client. | Faster. In our testing, we’ve found that the new infrastructure is much faster at sending and receiving messages compared to the older API, even with plugins configured in the service. There are no built-in speed caps or throttling in Windows MIDI Services, even for older USB MIDI 1.0 devices. The driver is not limited USB full-speed, and supports USB 3.x speeds. | Lower Jitter. Along with higher speed comes lower jitter. This will vary by transport type (USB vs Network vs Virtual), and the device Windows is talking to, but the jitter is in the low microsecond range even without any compensation. | More Deterministic. Speaking of latency compensation, the new API enables timestamp-based message scheduling for outbound messages, and also will soon support Jitter Reduction timestamps for MIDI 2.0 devices which can use them. | Extensible. The service has been designed to be extensible by Microsoft and third-parties. New types of transports can be added at any time, including during prototyping of a new transport specification. (We’re working on Network MIDI 2.0, Bluetooth MIDI 1.0 and considering RTP, all using this model.) Similarly, message processing plugins can also be developed by Microsoft or third-parties and used for production and/or prototyping. No kernel driver experience required in most cases. | Includes app-to-App and Virtual MIDI. Windows MIDI Services includes virtual / app-to-app MIDI 2.0 to enable lightning fast communication between apps on the PC. We’re also investigating flexible routing between any MIDI endpoints as a future feature. | Better tools. We supply the midi.exe Windows MIDI Services Console for developers and power users, or anyone comfortable with the command line. You can use it to monitor endpoints, send and receive messages, send/capture SysEx data and much more. We’ll deliver the MIDI Settings GUI app after our initial release. That app enables renaming devices, configuring your MIDI setup, testing, and more. | UMP-Centric. The new API fully embraces MIDI 2.0 and the Universal MIDI Packet format and handles all required translation in the service and driver. This makes the app model simple while ensuring all your existing devices continue to work. | Open Source. The source code is open and available to everyone under a permissive license. Not sure how something works? Want to create a transport but aren’t sure how we did it? Want to investigate a bug or contribute a feature? The code is there for you to explore. | . Note: Additionally MIDI CI functionality, which does not technically require OS support, will be coming after version 1.0. We intend to add helpers for profiles, property exchange, MUID tracking, and more. In the meantime, applications can send and receive MIDI CI messages without anything in their way, using custom code or third-party libraries. MIDI CI is just MIDI 1.0-compatible SysEx. ", "url": "/docs/#key-features", "relUrl": "/#key-features" - },"214": { + },"218": { "doc": "Windows Midi Services", "title": "Developer Samples", "content": ". | Developer Samples in the repo | . ", "url": "/docs/#developer-samples", "relUrl": "/#developer-samples" - },"215": { + },"219": { "doc": "Windows Midi Services", "title": "Additional Resources", "content": "These are the updated MIDI 2.0 specifications which apply to this project today. | MIDI 2.0 UMP Specifications | . ", "url": "/docs/#additional-resources", "relUrl": "/#additional-resources" - },"216": { + },"220": { "doc": "Windows Midi Services", "title": "Windows Midi Services", "content": " ", "url": "/docs/", "relUrl": "/" - },"217": { + },"221": { "doc": "MIDI Console", "title": "Windows MIDI Services Console", "content": "If you have the midi console installed, you can invoke it from any command prompt using midi. We recommend using Windows Terminal for the best experience. ", "url": "/docs/midi-console.html#windows-midi-services-console", "relUrl": "/midi-console.html#windows-midi-services-console" - },"218": { + },"222": { "doc": "MIDI Console", "title": "General Information", "content": "Commands vs Options . MIDI Console commands are words with no symbol prefix. For example endpoint or send-message-file. Options are prefixed with two dashes if you use the full word, or a single dash if you use the single-letter abbreviation. For example --help or -h. There is no statement completion built in to the console, but there are some supported abbreviations for commands. These are not yet fully documented but are present in the Program.cs in the console source code. “Ports” vs “Streams” . In MIDI 1.0, specifically USB MIDI 1.0, a connected device would have a single input and single output stream. Inside that stream are packets of data with virtual cable numbers. Those numbers (16 total at most) identify the “port” the data is going to. Operating systems would then translate those into input and output ports. Those cable numbers were hidden from users. MIDI 2.0 does not have a concept of a port. Instead, you always work with the stream itself. The group number, which is in the MIDI message now, is the moral equivalent of that cable number. So where you may have seen a device with 5 input and 5 output ports in the past, you will now see a single bidirectional UMP Endpoint stream with 5 input groups and 5 output groups. We know this can take some getting used to, but it enables us to use MIDI 1.0 devices as though they are MIDI 2.0 devices, and provide a unified API. Help . Add the option --help or its short version -h to any command to get information and examples for that command. midi --help midi service --help midi enumerate --help midi enumerate endpoints --help . The --help option will always provide the most up-to-date list of commands and options supported by the MIDI Services Console. ", "url": "/docs/midi-console.html#general-information", "relUrl": "/midi-console.html#general-information" - },"219": { + },"223": { "doc": "MIDI Console", "title": "Check the MIDI Service Health", "content": "The heart of Windows MIDI Services is the Windows Service which processes and routes messages, creates endpoints, and more. The MIDI Services Console app includes a few commands to check the status and health of the service. Check MIDI Service Status . If you want to verify that the MIDI Service is running, you can check its status using the Service Control Manager, or through the MIDI Console. midi service status midi svc status . If you uset the --verbose or -v option, the console will display more information about the service. midi service status midi svc status . Ping the Service . If you want to verify that the service is transmitting and receiving messages, you can use the ping command, much like you would . midi service ping midi svc ping . This command also supports the --verbose or -v option to display the full results of the ping. It also supports a --count or -c parameter for the number of messages you want to send. Finally, the call supports a --timeout or -t parameter to set the timeout in milliseconds before the ping is considered to have failed. Here are examples of the command with various parameters. midi service ping --verbose midi service ping --verbose --count 20 --timeout 20000 . Stop / Start / Restart the Service . The MIDI console has three commands for managing the Windows service. These can be useful when developing or debugging service-side plugins. Note that these must be run from an Administrator console session. midi service stop midi service start midi service restart . ", "url": "/docs/midi-console.html#check-the-midi-service-health", "relUrl": "/midi-console.html#check-the-midi-service-health" - },"220": { + },"224": { "doc": "MIDI Console", "title": "See the Current Timestamp and Frequency", "content": "If you want to see the MIDI clock we’re using for timestamps and message scheduling, you can use the time command. It will display the current timestamp in ticks, and the number of ticks per second (the resolution) . midi time midi clock . ", "url": "/docs/midi-console.html#see-the-current-timestamp-and-frequency", "relUrl": "/midi-console.html#see-the-current-timestamp-and-frequency" - },"221": { + },"225": { "doc": "MIDI Console", "title": "Enumerate (List) MIDI Entities", "content": "A basic operation you may do with the tool is list the major entities (Endpoints and Plugins) in the system. The enumerate command has the aliases enum and list which may be used instead of the full enumerate command. Enumerate MIDI UMP Endpoints . The ump-endpoints parameter has the alias endpoints and the alias ump so either may be used with the same results. These commands are all equivalent: . midi enumerate ump-endpoints midi enumerate endpoints midi enum endpoints midi list endpoints midi list ump . All of the above statements will return a list of all the user-focused UMP endpoints on the system. Note: There are loopback endpoints A and B that are always available and are built into the service. They are crosswired to each other so that any message sent to A is received on B, and vice versa. They cannot be removed or disabled. Because these are more for support, testing, and developer scenarios, they are not returned from enumeration calls by default. Instead, you would supply the --include-loopback option for the enumeration commands. Enumerate Classic Byte-stream (MIDI 1.0) Endpoints . This uses the old WinRT API. Its primary reason for existance is so you can see what’s shown to older APIs vs what is shown for the new Windows MIDI Services API. As with the UMP endpoints, the commands have aliases, so the following are all equivalent . midi enumerate bytestream-endpoints midi enumerate legacy-endpoints midi enum legacy-endpoints midi list legacy . Enumerate Transport Plugins . TODO: This feature is actively in development. Enumerate Message Processing Plugins . TODO: This feature is actively in development. ", "url": "/docs/midi-console.html#enumerate-list-midi-entities", "relUrl": "/midi-console.html#enumerate-list-midi-entities" - },"222": { + },"226": { "doc": "MIDI Console", "title": "Watch UMP Endpoints for Changes", "content": "Enumerating endpoints gives you a snapshot of the list at a moment in time. Watching the endpoints will give you a constantly updating list, which reflects device add/remove as well as property updates. This is useful more for developers, or those who are using tools to modify endpoints and want to verify that the changes were reported. The watch-endpoints command has the alias watch, so these are equivalent: . midi watch-endpoints midi watch . Note that only UMP endpoints (or bytestream endpoints converted to UMP by the new USB driver and service) are watched for changes. The older MIDI API is not used here. When you want to stop watching the endpoints for changes, hit the escape key. ", "url": "/docs/midi-console.html#watch-ump-endpoints-for-changes", "relUrl": "/midi-console.html#watch-ump-endpoints-for-changes" - },"223": { + },"227": { "doc": "MIDI Console", "title": "Single-Endpoint Commands", "content": "There are a number of commands, including those for monitoring and sending messages, which operate on a single endpoint. In most any command which takes an Endpoint Device Id as a parameter, that parameter is optional. If you leave it out, and the command operates on a single endpoint, you will be prompted with a menu of available endpoints to work with. If you want to script the commands without requiring any user interaction, provide the endpoint device ID as the first parameter after the endpoint command. For example: . midi endpoint \\\\?\\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_B#{e7cce071-3c03-423f-88d3-f1045d02552b} properties --verbose . Get Detailed Endpoint Properties . In the Device Manager in Windows, you can only see a subset of properties for a device. The same goes with the pnputil utility. It can be useful to see all of the key properties of a MIDI Endpoint. Therefore, we’ve baked property reporting right into the MIDI Services Console. midi endpoint properties . By default, only key properties are displayed. If you want to see the complete list of all properties for the endpoint device, its container, and its parent device, add the --verbose parameter. midi endpoint properties --verbose . As with other endpoint commands, if you provide the endpoint device Id, it will be used. Otherwise, you will be prompted to select an endpoint. Monitor an Endpoint for Incoming Messages . By default, every UMP Endpoint in Windows MIDI Services is multi-client. That means that more than one application can open a connection to the endpoint and send and/or receive messages. This also makes it possible to monitor all the incoming messages on an endpoint, even when that endpoint is in use by another application. When run in verbose mode, the monitor will display each message as it arrives. It also displays helpful information about the type of the message, the group and channel when appropriate, the timestap offset (from the previous message if it was received recently), and more. This requires a fairly wide console window to allow formatting each message to take up only a single line. In a narrow window the format will be a bit ugly. We recommend using the Windows Terminal application, which has support for zooming in and out using the mouse wheel, different fonts, and more. When run without the --verbose option, the monitor displays only key data for the incoming messages. Default mode: . midi endpoint monitor . Verbose mode: . midi endpoint monitor --verbose . Saving messages to a file . When monitoring, you also have the option to save the messages to a file. This can be used to capture test data which you will send using the send-message-file command, or for storing something like a System Exclusive dump. midi endpoint monitor --capture-to-file %USERPROFILE%\\Documents\\MyMidiCapture.midi2 --annotate-capture --capture-field-delimiter Pipe . | The annotation option puts a comment before each message line, with additional details, including the timestamp. | The delimiter option enables you to specify how to delimit the MIDI words in the file. By default, the words are delimitated with spaces. | . The file you choose to write to will be appended to if it already exists. Use caution when specifying the file name, so that you don’t corrupt an unrelated file with this MIDI data. If no file extension is specified, the extension .midi2 will be automatically added to the filename. When you have completed monitoring an endpoint, hit the escape key to close the connection and the app. Send a Message from the Command Line . Sending a message to an endpoint is very helpful for testing, but can also be used in automation to, for example, change the current program, or set a MIDI CC value. It would be very easy for a person to build a batch file or PowerShell script which used midi.exe to synchronize different devices, or reset devices to a known state in preparation for a performance. The message data beyond the message type (first 4 bits) is not pre-validated, so the data can be anything. However, the number of 32 bit words must match the message type per the MIDI 2.0 specification. Send a single UMP32 message immediately . midi endpoint send-message 0x21234567 . Send a single UMP64 message ten times . midi endpoint send-message 0x41234567 0xDEADBEEF --count 10 . Send a single UMP64 message fifteen times, but with a delay of two seconds (2000 milliseconds) in between each message. Delays are in milliseconds because they are there primarily to prevent flooding with older devices. midi endpoint send-message 0x41234567 0xDEADBEEF --count 15 --pause 2000 . In general, we recommend sending messages in hexadecimal format (prefix 0x followed by 8 hexadecimal digits)as it is easier to visually inspect the information being sent. The 1-4 MIDI words are in order from left to right, from 1 to 4. Special debug messages . One thing that can be useful is to send otherwise valid UMP messages where the last word is incremented by 1 for each sent message. This helps to validate that all messages were received by your application, and in the correct order. Note that this requires a message type of at least two words. We don’t recommend sending Type F stream messages as those have the potential to corrupt data. Instead, a Type 4 MIDI 2.0 channel voice message is usually safer. midi endpoint send-message 0x41234567 0x00000000 --count 10000 --pause 2 --debug-auto-increment . When sent, you should see messages where the second word is updated from 0x00000000 through 0x00002710 (decimal 10000). We recommend the pause when sending large numbers of messages because a pause of 0 (“send as fast as possible”) can flood the buffers with more data than the client may be able to retrieve in time and may result in dropped messages. A warning is displayed when that possibility seems likely. Scheduling messages . NOTE: In current Developer Preview builds, message scheduling is turned off so the timestamp is ignored. Refer to the release notes. When sending messages, you have two options for timestamps: . --offset-microseconds is used to add a fixed time to each outgoing message so that it is scheduled that far into the future. Schedule a single UMP64 message 2 seconds from now (2 million microseconds). Offsets are in microseconds to provide more precise control compared to milliseconds. midi endpoint send-message 0x41234567 0xFEEDF00D --offset-microseconds 2000000 . You can also specify an absolute timestamp. Typically, this is used to be able to specify a timestamp of 0, which means to bypass any scheduling and send immediately. midi endpoint send-message 0x41234567 0xFEEDF00D --timestamp 0 . Of course, you can also use the midi time command to see the current timestamp, and then use that information to pick a future timestamp. Finally, if you do not specify a timestamp, the current time is used. Send a File full of Messages . If you want to send a file full of messages, for SysEx or testing, for example, the console has provision for this. The file needs to have one message per line, with 1-4 32 bit words as appropriate. There are options for delimeter (auto, space, comma, pipe, tab), word format (binary, hex, or decimal) as well as an option to change the group index. The latter is especially important when you have a SysEx file saved from one group and you want to send it on another group. The file name can include system variables which require expansion. midi endpoint send-message-file %userprofile%\\Documents\\SysExBank12.txt --new-group-index 5 . There are a number of options for this command both for the format it is reading, but also for the delay between messages (for older devices) and more. To get an explanation for each, type: . midi endpoint send-message-file --help . Here is one of the test files we use. It demonstrates comments, multiple representations for numbers, different delimeters, and more. # This is a test file for sending UMPs through Windows MIDI Services # It uses auto for the field delimiter so we can have different # delimiters on each line. Numeric format for this file is always hex. # The line above was empty. The next data line is a UMP32 0x22345678 # The messages aren't valid beyond their message type matching the number of words 0xF1345678 0x12345678 0x03263827 0x86753099 0xF2345678,0x12345678,0x86754321, 0x86753099 0xF3345678|0x12345678| 0x86754321|0x86753099 0x21345678 0x42345678 0x12341234 0x43345677 0x12341235 0x44345676 0x12341236 0x45345675 0x12341237 0x26989898 # The next two lines have different hex formatting 41345678h 12341234h 22989898h F3345678h 12345678h 86754321h 86753099h # The next lines have no hex formatting 41345678 12341234 22989898 # The next lines have inconsistent hex formatting 41345678 12341234 0xF2345678 12345678h 86754321 0x86753099 # bunch of empty lines above. And the file ends with a comment . Sending Endpoint Metadata Requests . The MIDI Services Console also makes it possible to send some common stream request messages without having to remember their exact format. Before sending the request, you may want to open another console window or tab with a device watcher active on the connected endpoint. This will tell you when the stored properties are changed. In addition, you may want to have a verbose monitoring tab/window open so you can see the response messages come back. These are primarily a convenience for developers. Note that in all the request commands, you may abbreviate request as req . Send a Function Block Request Message . In the command, you may abbreviate function-blocks as fb, functions, function or function-block. The singular versions are available to make the command make more sense when requesting a single block’s data. Request all function blocks from an endpoint . midi endpoint request function-blocks --all . Request a single function block . midi endpoint request function-blocks --function-block-number 3 . Note that you may abbreviate --function-block-number as -n or as --number . By default, you will request both the info notification and name notification messages. If you want to request only one of them, simply turn the other off. You must request at least one of the two types of messages. midi endpoint request function-blocks --all --request-name false midi endpoint request function-blocks --all --request-info false . Send an Endpoint Information Request Message . In the command, you may abbreviate endpoint-metadata as em or metadata. By default, you will request only the endpoint information notification. To request other types of information, specify the flag for that type, or simply use --all . Request all metadata notification messages . midi endpoint request endpoint-metadata --all . Request endpoint info (on by default) and name . midi endpoint request endpoint-metadata --name . Request only the name . midi endpoint request endpoint-metadata --name --endpoint-info false . Other request types . midi endpoint request endpoint-metadata --device-identity midi endpoint request endpoint-metadata --product-instance-id midi endpoint request endpoint-metadata --stream-configuration . Finally, note that you can provide a UMP version to send with the request. By default, the version is Major 1, Minor 1. The --ump-version-major and --ump-version-minor options are what you want to use here. ", "url": "/docs/midi-console.html#single-endpoint-commands", "relUrl": "/midi-console.html#single-endpoint-commands" - },"224": { + },"228": { "doc": "MIDI Console", "title": "Technical Information", "content": "The Windows MIDI Services Console app has been developed using C#, .NET 8, the MIT-licensed open source Spectre.Console library, and the Microsoft-developed open source C#/WinRT toolkit. The console uses the same Windows MIDI Services WinRT APIs available to other desktop applications. Its full source code is available on our Github repo. Pull-requests, feature requests, and bug reports welcome. The project is open source, but we request that instead of forking it to create your own version, you consider contributing to the project. ", "url": "/docs/midi-console.html#technical-information", "relUrl": "/midi-console.html#technical-information" - },"225": { + },"229": { "doc": "MIDI Console", "title": "MIDI Console", "content": " ", "url": "/docs/midi-console.html", "relUrl": "/midi-console.html" - },"226": { + },"230": { "doc": "MIDI 2.0 Implementation Details", "title": "Implementation Details", "content": "Specifications can be funny. As much as the MIDI Association, and all of us in it, try to be very specific and crisp on wording, there’s often room for interpretation. Most of these we work out among the various OS companies under the umbrella of the MIDI Association. But there are others were an approach may just not make sense on one OS or the other. Here are the ones that are Windows-specific, that you should be aware of as a developer. Of course, the full source code for Windows MIDI Services, including the USB MIDI 2.0 driver, is available in our repo, so you can review it at any time to better understand how a feature or function works. ", "url": "/docs/developer-docs/midi2-implementation-details.html#implementation-details", "relUrl": "/developer-docs/midi2-implementation-details.html#implementation-details" - },"227": { + },"231": { "doc": "MIDI 2.0 Implementation Details", "title": "Discovery and Protocol Negotiation", "content": "Windows MIDI Services supports only the UMP-based Endpoint Discovery and Protocol Negotiation. We do not implement the deprecated MIDI-CI equivalents. In addition, declaring the use of JR Timestamps in a USB MIDI 2.0 Group Terminal Block does not enable JR Timestamps in Windows MIDI Services. Instead, these must be negotiated using UMP-based Endpoint Discovery end Protocol Negotiation . ", "url": "/docs/developer-docs/midi2-implementation-details.html#discovery-and-protocol-negotiation", "relUrl": "/developer-docs/midi2-implementation-details.html#discovery-and-protocol-negotiation" - },"228": { + },"232": { "doc": "MIDI 2.0 Implementation Details", "title": "UMP Endpoint Names for native MIDI 2.0 UMP format devices", "content": "Although we make all the names available through the Enumeration API, we have an order of precedence we use when providing the recommended Name property value. In order from most preferred to least, we have: . | Any user-supplied endpoint name configured through the configuration files (these will be created by the MIDI Settings app in the future) | The name supplied through in-protocol Endpoint Name Notification messages | The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0. | . When we create MIDI 1.0-compatible “ports” for these endpoints, we’ll use the Function Block Names if available and Group Terminal Block names if not. ", "url": "/docs/developer-docs/midi2-implementation-details.html#ump-endpoint-names-for-native-midi-20-ump-format-devices", "relUrl": "/developer-docs/midi2-implementation-details.html#ump-endpoint-names-for-native-midi-20-ump-format-devices" - },"229": { + },"233": { "doc": "MIDI 2.0 Implementation Details", "title": "UMP Endpoint Names for MIDI 1.0 byte stream format devices", "content": "The API also creates UMP endpoints for MIDI 1.0 devices. This happens two ways: . | If the device is assigned to the USB MIDI 2.0 driver (this is preferred) the driver creates Group Terminal Blocks for each “cable” (a “port” in MIDI 1.0 API speak). In the new driver, we use the iJack names, if provided, to name the Group Terminal Blocks. This is the best way to ensure your endpoint and Group Terminal Block names are correct. | If the device is assigned a third-party driver or the legacy MIDI 1.0 driver (not preferred in most cases), the service creates the Group Terminal Blocks using the same algorithm. However, because much less information is available to the service from the legacy drivers, the name may not be identical. | . The precedence for naming is the same as with MIDI 2.0 devices, with the exception of the Endpoint Name Notification, which doesn’t exist in MIDI 1.0. | Any user-supplied endpoint name | The name supplied through in-protocol Endpoint Name Notification messages | The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0. | . ", "url": "/docs/developer-docs/midi2-implementation-details.html#ump-endpoint-names-for-midi-10-byte-stream-format-devices", "relUrl": "/developer-docs/midi2-implementation-details.html#ump-endpoint-names-for-midi-10-byte-stream-format-devices" - },"230": { + },"234": { "doc": "MIDI 2.0 Implementation Details", "title": "iSerialNumber Really Helps", "content": "If your device exposes a unique iSerialNumber, that will really help with retaining name and other information across physical USB connects and disconnects. We do our best to retain the correct information if you plug into the same physical port, but when you change ports, a device without an iSerialNumber essentially becomes a new device. This is not unique to Windows, but it’s important enough to mention here. More info and guidance in this blog post. ", "url": "/docs/developer-docs/midi2-implementation-details.html#iserialnumber-really-helps", "relUrl": "/developer-docs/midi2-implementation-details.html#iserialnumber-really-helps" - },"231": { + },"235": { "doc": "MIDI 2.0 Implementation Details", "title": "MIDI 2.0 Implementation Details", "content": " ", diff --git a/docs/_site/config-json.html b/docs/_site/config-json.html index 97a8c937..9e91a210 100644 --- a/docs/_site/config-json.html +++ b/docs/_site/config-json.html @@ -1,4 +1,4 @@ - Config JSON | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

JSON Config File

It’s best to use the Settings application and the transport / processing plugins for Settings to manipulate the file. However, if you edit it by hand, here are some notes.

The File location is Restricted

The JSON configuration files are all stored in %allusersprofile%\Microsoft\MIDI which typically resolves to C:\ProgramData\Microsoft\MIDI. For security reasons, we don’t allow the file to be stored in any other location. However, you can have as many files in that folder as you want, and switch between them as needed.

The default config file is typically named Default.midiconfig.json. The actual name is stored in the registry under HKLM\SOFTWARE\Microsoft\Windows MIDI Services in the CurrentConfig value. This value must not contain any non-filename path characters (no backslashes, colons, etc.).

JSON is Case-Sensitive

JSON is typically case-sensitive for all keys. The Windows.Data.Json parser used by Windows MIDI Services is case-sensitive with no option to ignore case. That includes GUID values. For example, the following two values are not equivalent JSON keys:

"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}":
+            Config JSON | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

JSON Config File

It’s best to use the Settings application and the transport / processing plugins for Settings to manipulate the file. However, if you edit it by hand, here are some notes.

The File location is Restricted

The JSON configuration files are all stored in %allusersprofile%\Microsoft\MIDI which typically resolves to C:\ProgramData\Microsoft\MIDI. For security reasons, we don’t allow the file to be stored in any other location. However, you can have as many files in that folder as you want, and switch between them as needed.

The default config file is typically named Default.midiconfig.json. The actual name is stored in the registry under HKLM\SOFTWARE\Microsoft\Windows MIDI Services in the CurrentConfig value. This value must not contain any non-filename path characters (no backslashes, colons, etc.).

JSON is Case-Sensitive

JSON is typically case-sensitive for all keys. The Windows.Data.Json parser used by Windows MIDI Services is case-sensitive with no option to ignore case. That includes GUID values. For example, the following two values are not equivalent JSON keys:

"{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}":
         {
             "_comment": "KS MIDI (USB etc.)"
         }
diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/README.html
index f6678642..62bfcff1 100644
--- a/docs/_site/developer-docs/Windows.Devices.Midi2/README.html
+++ b/docs/_site/developer-docs/Windows.Devices.Midi2/README.html
@@ -1 +1 @@
-            Windows.Devices.Midi2 API | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Windows.Devices.Midi2

The Windows.Devices.Midi2 types are documented in these pages.

Typical API workflow:

  1. Create a new session, with an appropriate name. The name will be visible to users and so should be meaningful. Each application may open more than one session at a time (for example, different songs in a DAW, or different tabs in a browser). A single session manages the lifetime of the connections opened through it.
  2. Connect to an endpoint. Typically, you’ll get the endpoint’s id through the enumeration functions.
  3. Wire up a MidiMessageReceived event handler. This is how you will receive incoming messages from the endpoint. Messages are received individually, with one event per message.
  4. Optionally, add any processing plugins. If you want to filter messages or provide multiple “views” into a stream, you can add the appropriate client message processing plugins.
  5. Open the connection. Once the connection is open, you may send and receive messages.

Endpoint Enumeration

Enumeration is how you discover endpoints and get notified of endpoints when they are added, updated, or removed. For the best user experience, keep a MidiEndpointDeviceWatcher running in a background thread so you can monitor device removal, and property updates (name, function blocks, etc.)

Session

Interaction with a MIDI Endpoint always starts with creating a session.

Connections

Once you have a session, you will create one or more connections to send and receive messages.

Clock

The MIDI clock is used for creating timestamps for use in sending MIDI messages.

Messages

MIDI Messages are discrete packets of data of a known length. In the MIDI 2.0 specification, they are known as Universal MIDI Packets. In Windows MIDI Services, even MIDI 1.0 bytestream messages are presented in their equivalent Universal MIDI Packet format. The API includes several classes not only for the messages, but also to help construct and parse them.

Metadata

Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint.

Client-Side Processing Plugins

Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage.

Virtual Devices

A virtual device is the mechanism through which app-to-app MIDI works through the API. One application acts as the MIDI Endpoint Device, and other applications connect to it. In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin

Simple Types

There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways.

Service

The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service.


Table of contents

\ No newline at end of file + Windows.Devices.Midi2 API | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Windows.Devices.Midi2

The Windows.Devices.Midi2 types are documented in these pages.

Typical API workflow:

  1. Create a new session, with an appropriate name. The name will be visible to users and so should be meaningful. Each application may open more than one session at a time (for example, different songs in a DAW, or different tabs in a browser). A single session manages the lifetime of the connections opened through it.
  2. Connect to an endpoint. Typically, you’ll get the endpoint’s id through the enumeration functions.
  3. Wire up a MidiMessageReceived event handler. This is how you will receive incoming messages from the endpoint. Messages are received individually, with one event per message.
  4. Optionally, add any processing plugins. If you want to filter messages or provide multiple “views” into a stream, you can add the appropriate client message processing plugins.
  5. Open the connection. Once the connection is open, you may send and receive messages.

Endpoint Enumeration

Enumeration is how you discover endpoints and get notified of endpoints when they are added, updated, or removed. For the best user experience, keep a MidiEndpointDeviceWatcher running in a background thread so you can monitor device removal, and property updates (name, function blocks, etc.)

Session

Interaction with a MIDI Endpoint always starts with creating a session.

Connections

Once you have a session, you will create one or more connections to send and receive messages.

Clock

The MIDI clock is used for creating timestamps for use in sending MIDI messages.

Messages

MIDI Messages are discrete packets of data of a known length. In the MIDI 2.0 specification, they are known as Universal MIDI Packets. In Windows MIDI Services, even MIDI 1.0 bytestream messages are presented in their equivalent Universal MIDI Packet format. The API includes several classes not only for the messages, but also to help construct and parse them.

Metadata

Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint.

Client-Side Processing Plugins

Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage.

Virtual Devices

A virtual device is the mechanism through which app-to-app MIDI works through the API. One application acts as the MIDI Endpoint Device, and other applications connect to it. In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin

Simple Types

There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways.

Service

The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html b/docs/_site/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html index dcaec247..6fe4cba8 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/clock/MidiClock.html @@ -1 +1 @@ - MidiClock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiClock

The MidiClock is what is used for all timestamps in Windows MIDI Services. Although it is internally backed by QueryPerformanceCounter, we recommend using the MidiClock type directly instead of calling QPC yourself.

Also note that QueryPerformanceCounter technically returns a signed 64 bit integer, but the timestamp values used in Windows MIDI Services are unsigned 64 bit integers. Typically, this is of no practical concern as the tick resolution is currently 100ns and takes tens of thousands of years to wrap around even with a 64 bit signed integer.

Note: The MIDI Clock is unrelated to wall clock time. It is an ever-increasing value of period 1/TimestampFrequency seconds that starts over when the PC is rebooted. To convert to wall clock time, you need to get the MidiClock.Now value at a known time, and then use that as a baseline until the next time you reboot the PC.

You can learn more about high-resolution timestamps in Windows at https://aka.ms/miditimestamp.

Static Properties

Static Property Description
Now Returns the current timestamp
TimestampFrequency Returns the number of timestamp ticks per second. This is calculated the first time it is called, and then cached for future calls.

Static Functions

The static functions are for convenience in calculating offsets to a timestamp, and for converting between units.

Static Function Description
ConvertTimestampToMicroseconds(timestampValue) Converts the provided timestamp to microseconds
ConvertTimestampToMilliseconds(timestampValue) Converts the provided timestamp to milliseconds
ConvertTimestampToSeconds(timestampValue) Converts the provided timestamp to seconds
OffsetTimestampByTicks(timestampValue, offsetTicks) Offsets a given timestamp by the provided (signed) number of ticks
OffsetTimestampByMicroseconds(timestampValue, offsetMicroseconds) Offsets a given timestamp by the provided (signed) number of microseconds
OffsetTimestampByMilliseconds(timestampValue, offsetMilliseconds) Offsets a given timestamp by the provided (signed) number of milliseconds
OffsetTimestampBySeconds(timestampValue, offsetSeconds) Offsets a given timestamp by the provided (signed) number of seconds

IDL

MidiClock IDL

\ No newline at end of file + MidiClock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiClock

The MidiClock is what is used for all timestamps in Windows MIDI Services. Although it is internally backed by QueryPerformanceCounter, we recommend using the MidiClock type directly instead of calling QPC yourself.

Also note that QueryPerformanceCounter technically returns a signed 64 bit integer, but the timestamp values used in Windows MIDI Services are unsigned 64 bit integers. Typically, this is of no practical concern as the tick resolution is currently 100ns and takes tens of thousands of years to wrap around even with a 64 bit signed integer.

Note: The MIDI Clock is unrelated to wall clock time. It is an ever-increasing value of period 1/TimestampFrequency seconds that starts over when the PC is rebooted. To convert to wall clock time, you need to get the MidiClock.Now value at a known time, and then use that as a baseline until the next time you reboot the PC.

You can learn more about high-resolution timestamps in Windows at https://aka.ms/miditimestamp.

Static Properties

Static Property Description
Now Returns the current timestamp
TimestampFrequency Returns the number of timestamp ticks per second. This is calculated the first time it is called, and then cached for future calls.

Static Functions

The static functions are for convenience in calculating offsets to a timestamp, and for converting between units.

Static Function Description
ConvertTimestampToMicroseconds(timestampValue) Converts the provided timestamp to microseconds
ConvertTimestampToMilliseconds(timestampValue) Converts the provided timestamp to milliseconds
ConvertTimestampToSeconds(timestampValue) Converts the provided timestamp to seconds
OffsetTimestampByTicks(timestampValue, offsetTicks) Offsets a given timestamp by the provided (signed) number of ticks
OffsetTimestampByMicroseconds(timestampValue, offsetMicroseconds) Offsets a given timestamp by the provided (signed) number of microseconds
OffsetTimestampByMilliseconds(timestampValue, offsetMilliseconds) Offsets a given timestamp by the provided (signed) number of milliseconds
OffsetTimestampBySeconds(timestampValue, offsetSeconds) Offsets a given timestamp by the provided (signed) number of seconds

IDL

MidiClock IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html new file mode 100644 index 00000000..f7e09515 --- /dev/null +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.html @@ -0,0 +1 @@ + IMidiEndpointConnectionSettings | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

IMidiEndpointConnectionSettings

Settings which are optionally provided when connecting to an endpoint. Typically, the implementation of the endpoint will come with a concrete settings class which implements this interface, and translates the settings into JSON which is sent up to the service and read by the abstraction.

Properties

Property Description
SettingsJson The JSON representation of the settings.

IDL

IMidiEndpointConnectionSettings IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html index bff817f1..649038d6 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.html @@ -1,4 +1,4 @@ - MidiEndpointConnection | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiEndpointConnection

The MidiEndpointConnection type represents a single connection to a single endpoint managed by Windows MIDI Services. It is created using the functions of the MidiSession, and is tied to the lifetime of that session.

Connections allocate resources including send/receive buffers, and processing threads. For that reason, a session should generally not open more than one connection to a single endpoint. If you need to partition out messages more easily (by group or channel, for example) the MessageProcessingPlugins collection will help you do that.

To ensure an application is able to wire up processing plugins and event handlers before the connection is active, the connection returned by the MidiSession is not yet open. Once the connection is acquired, the application should assign event handlers, and optionally assign any message processing plugins. Once complete, the application calls the Open() function to connect to the service, create the queues, and begin sending and receiving messages.

Properties

Property Description
ConnectionId The generated GUID which uniquely identifes this connection instance. This is what is provided to the MidiSession when disconnecting an endpoint
EndpointDeviceId The system-wide identifier for the device connection. This is returned through enumeration calls.
Tag You may use this Tag property to hold any additional information you wish to have associated with the connection.
IsOpen True if this connection is currently open. When first created, the connection is not open until the consuming code calls the Open method
Settings Settings used to create this connection.
MessageProcessingPlugins Collection of all message processing plugins which will optionally handle incoming messages.

Static Member Functions

Static Function Description
GetDeviceSelector() Returns the device selector used for enumerating endpoint devices compatible with this API.
SendMessageSucceeded(sendResult) Helper function to decipher the return result of a message sending function to tell if it succeeded.
SendMessageFailed(sendResult) Helper function to decipher the return result of a message sending function to tell if it failed.

Functions

Function Description
Open() Open the connection and start receiving messages. Wire up the message event handler before calling this method.
SendMessagePacket(message) Send an IMidiUniversalPacket-implementing type such as MidiMessage64 or a strongly-typed message class.
SendMessageStruct(timestamp, message, wordCount) Send a fixed-sized MidiMessageStruct containing wordCount valid words. Additional words are ignored.
SendMessageWordArray(timestamp, words, startIndex, wordCount) Note: Some projections will send the entire array as a copy, so this may not be the most effecient way to send messages from your language.
SendMessageWords(timestamp, word0) Send a single 32-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1) Send a single 64-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1, word2) Send a single 96-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1, word2, word3) Send a single 128-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageBuffer(timestamp, buffer, byteOffset, byteLength) Send a single Universal MIDI Packet as bytes from a buffer. The number of bytes sent must match the size read from the first 4 bits of the data starting at the specified offset, and must be laid out correctly with the first byte corresponding to the MSB of the first word of the UMP (the word which contains hte message type). If you want to manage a chunk of buffer memory, the IMemoryBuffer type is the acceptable WinRT approach, and is as close as you get to sending a pointer into a buffer.
AddEndpointProcessingPlugin(plugin) Add an endpoint processing plugin to this connection
RemoveEndpointProcessingPlugin(id) Remove an endpoint processing plugin

Tip: In all the functions which accept a timestamp to schedule the message, you can send a timestamp of 0 (zero) to bypass the scheduler and send the message immediately. Otherwise, the provided timestamp is treated as an absolute time for when the message should be sent from the service. Note that the service-based scheduler (currently based on a std::priority_queue) gets less efficient when there are thousands of messages in it, so it’s recommended that you not schedule too many messages at a time or too far out into the future.

Events

Event Description
MessageReceived(source, args) From IMidiMessageReceivedEventSource. This is the event for receiving MIDI Messages, one at a time.

When processing the MessageReceived event, do so quickly. This event is synchronous. If you need to do long-running processing of incoming messages, add them to your own incoming queue structure and have them processed by another application thread.

Note: Wire up event handlers and add message processing plugins prior to calling Open().

IDL

MidiEndpointConnection IDL

Sample

Here’s an excerpt from the full “API client basics” sample. It shows sending and receiving messages using the two built-in loopback endpoints. For more information on the loopback endpoints, see diagnostics endpoints.

using (var session = MidiSession.CreateSession("API Sample Session"))
+            MidiEndpointConnection | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiEndpointConnection

The MidiEndpointConnection type represents a single connection to a single endpoint managed by Windows MIDI Services. It is created using the functions of the MidiSession, and is tied to the lifetime of that session.

Connections allocate resources including send/receive buffers, and processing threads. For that reason, a session should generally not open more than one connection to a single endpoint. If you need to partition out messages more easily (by group or channel, for example) the MessageProcessingPlugins collection will help you do that.

To ensure an application is able to wire up processing plugins and event handlers before the connection is active, the connection returned by the MidiSession is not yet open. Once the connection is acquired, the application should assign event handlers, and optionally assign any message processing plugins. Once complete, the application calls the Open() function to connect to the service, create the queues, and begin sending and receiving messages.

A note on sending messages

All SendMessageXX functions send a single Universal MIDI Packet message at a time. The pluralized versions SendMessagesXX will send multiple packets, in order, with the same timestamp.

Currently, in the implementation behind the scenes, the service receives each timestamped message one at a time. We have the functions for sending more than one message as a developer convenience for similarity with other platforms, and also to allow for possible future optimization in the service communication code.

Properties

Property Description
ConnectionId The generated GUID which uniquely identifes this connection instance. This is what is provided to the MidiSession when disconnecting an endpoint
EndpointDeviceId The system-wide identifier for the device connection. This is returned through enumeration calls.
Tag You may use this Tag property to hold any additional information you wish to have associated with the connection.
IsOpen True if this connection is currently open. When first created, the connection is not open until the consuming code calls the Open method
Settings Settings used to create this connection. Treat this as read-only.
MessageProcessingPlugins Collection of all message processing plugins which will optionally handle incoming messages.

Static Member Functions

Static Function Description
GetDeviceSelector() Returns the device selector used for enumerating endpoint devices compatible with this API.
SendMessageSucceeded(sendResult) Helper function to decipher the return result of a message sending function to tell if it succeeded.
SendMessageFailed(sendResult) Helper function to decipher the return result of a message sending function to tell if it failed.

Functions

Function Description
Open() Open the connection and start receiving messages. Wire up the message event handler before calling this method.
SendMessagePacket(message) Send an IMidiUniversalPacket-implementing type such as MidiMessage64 or a strongly-typed message class.
SendMessageStruct(timestamp, message, wordCount) Send a fixed-sized MidiMessageStruct containing wordCount valid words. Additional words are ignored.
SendMessageWordArray(timestamp, words, startIndex, wordCount) Note: Some projections will send the entire array as a copy, so this may not be the most effecient way to send messages from your language.
SendMessageWords(timestamp, word0) Send a single 32-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1) Send a single 64-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1, word2) Send a single 96-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageWords(timestamp, word0, word1, word2, word3) Send a single 128-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message
SendMessageBuffer(timestamp, buffer, byteOffset, byteLength) Send a single Universal MIDI Packet as bytes from a buffer. The number of bytes sent must match the size read from the first 4 bits of the data starting at the specified offset, and must be laid out correctly with the first byte corresponding to the MSB of the first word of the UMP (the word which contains hte message type). If you want to manage a chunk of buffer memory, the IMemoryBuffer type is the acceptable WinRT approach, and is as close as you get to sending a pointer into a buffer.
SendMessagesWordList(timestamp,words) This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully.
SendMessagesWordArray(timestamp,words) This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully.
AddEndpointProcessingPlugin(plugin) Add an endpoint processing plugin to this connection
RemoveEndpointProcessingPlugin(id) Remove an endpoint processing plugin from this connection

Tip: In all the functions which accept a timestamp to schedule the message, you can send a timestamp of 0 (zero) to bypass the scheduler and send the message immediately. Otherwise, the provided timestamp is treated as an absolute time for when the message should be sent from the service. Note that the service-based scheduler (currently based on a std::priority_queue) gets less efficient when there are thousands of messages in it, so it’s recommended that you not schedule too many messages at a time or too far out into the future.

Events

Event Description
MessageReceived(source, args) From IMidiMessageReceivedEventSource. This is the event for receiving MIDI Messages, one at a time.

When processing the MessageReceived event, do so quickly. This event is synchronous. If you need to do long-running processing of incoming messages, add them to your own incoming queue structure and have them processed by another application thread.

Note: Wire up event handlers and add message processing plugins prior to calling Open().

IDL

MidiEndpointConnection IDL

Sample

Here’s an excerpt from the full “API client basics” sample. It shows sending and receiving messages using the two built-in loopback endpoints. For more information on the loopback endpoints, see diagnostics endpoints.

using (var session = MidiSession.CreateSession("API Sample Session"))
 {
     // get the endpoint Ids. Normally, you'd use enumeration functions to get this
     // for non-diagnostics endpoints.
diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html
index cbcbe2cc..ebc6bd8a 100644
--- a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html
+++ b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/MidiMessageReceivedEventArgs.html
@@ -1 +1 @@
-            MidiMessageReceivedEventArgs | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiMessageReceivedEventArgs

This is the main class to use when receving MIDI data from a message source such as a connection or a message processing plugin.

Note: Do not keep a copy of the MidiMessageReceivedEventArgs class, as the data it points to is guaranteed to exist for only the duration of the event handler call for which this instance was an argument.

Properties

Property Description
Timestamp The 64-bit MIDI Clock timestamp set by the service when this message was received
PacketType Type of Universal MIDI Packet. This value can be cast to get the number of valid words in the data. You can use this value to determine which of the FillMessageXX methods would be appropriate to call. For example, if the value is MidiPacketType.UniversalMidiPacket64 you would call FillMessage64
MessageType The type of Universal MIDI Packet Message. This comes from the first 4 bits of the data.

Functions

Function Description
PeekFirstWord() Returns the first word of the message data without removing it.
GetMessagePacket() Returns an IMidiUniversalPacket runtime class representing the data. This requires an allocation.
FillWords(word0, word1, word2, word3) Puts the data in the supplied words and returns the number of valid words to read. If the return value is 2, for example, then only word0 and word1 contain valid data.
FillMessageStruct(message) Fills the provided lightweight structure with the message data. Returns the number of valid words in the updated struct.
FillMessage32(message) Adds the data to the provided MidiMessage32 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage64(message) Adds the data to the provided MidiMessage64 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage96(message) Adds the data to the provided MidiMessage96 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage128(message) Adds the data to the provided MidiMessage128 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillWordArray(words, startIndex) Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of words written.
FillByteArray(bytes, startIndex) Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of bytes written.
FillBuffer(buffer, byteOffset) Writes the data to the buffer starting at byteOffset. Returns the number of bytes written.

IDL

MidiMessageReceivedEventArgs IDL

\ No newline at end of file + MidiMessageReceivedEventArgs | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageReceivedEventArgs

This is the main class to use when receving MIDI data from a message source such as a connection or a message processing plugin.

Note: Do not keep a copy of the MidiMessageReceivedEventArgs class, as the data it points to is guaranteed to exist for only the duration of the event handler call for which this instance was an argument.

Properties

Property Description
Timestamp The 64-bit MIDI Clock timestamp set by the service when this message was received
PacketType Type of Universal MIDI Packet. This value can be cast to get the number of valid words in the data. You can use this value to determine which of the FillMessageXX methods would be appropriate to call. For example, if the value is MidiPacketType.UniversalMidiPacket64 you would call FillMessage64
MessageType The type of Universal MIDI Packet Message. This comes from the first 4 bits of the data.

Functions

Function Description
PeekFirstWord() Returns the first word of the message data without removing it.
GetMessagePacket() Returns an IMidiUniversalPacket runtime class representing the data. This requires an allocation.
FillWords(word0, word1, word2, word3) Puts the data in the supplied words and returns the number of valid words to read. If the return value is 2, for example, then only word0 and word1 contain valid data.
FillMessageStruct(message) Fills the provided lightweight structure with the message data. Returns the number of valid words in the updated struct.
FillMessage32(message) Adds the data to the provided MidiMessage32 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage64(message) Adds the data to the provided MidiMessage64 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage96(message) Adds the data to the provided MidiMessage96 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillMessage128(message) Adds the data to the provided MidiMessage128 runtimeclass. The reference behavior is projection-dependent. Returns true if the provided type matches the expected packet type and the data has been written.
FillWordArray(words, startIndex) Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of words written.
FillByteArray(bytes, startIndex) Writes the data starting at the zero-based startIndex. Some projections pass a copy of all the data, so this may not always be an efficient approach. Returns the number of bytes written.
FillBuffer(buffer, byteOffset) Writes the data to the buffer starting at byteOffset. Returns the number of bytes written.

IDL

MidiMessageReceivedEventArgs IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/README.html index f3ab8a1f..31878d89 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/connections/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/connections/README.html @@ -1 +1 @@ - Connections | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Connecting to a MIDI Endpoint

In Windows MIDI Services, once you have opened a session, you will typically open one or more connections to device endpoints. The session class contains methods which return an initialized, but not open, connection to the specified endpoint.

The remainder of your interaction for sending and receiving data is with the MidiEndpointConnection class.

All endpoints in Windows MIDI Services send and receive messages using the Universal MIDI Packet format. Any required translation (for MIDI 1.0 devices, for example) is handled in the service and/or in the USB driver.

Workflow

  1. Open a session
  2. Using an endpoint id discovered through enumeration or another mechanism, create an endpoint connection
  3. Wire up to the connection any event handlers or message processors
  4. Open the connection
  5. Send and receive messages
  6. Using the session, disconnect the connection when you are done with it.

Table of contents

\ No newline at end of file + Connections | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Connecting to a MIDI Endpoint

In Windows MIDI Services, once you have opened a session, you will typically open one or more connections to device endpoints. The session class contains methods which return an initialized, but not open, connection to the specified endpoint.

The remainder of your interaction for sending and receiving data is with the MidiEndpointConnection class.

All endpoints in Windows MIDI Services send and receive messages using the Universal MIDI Packet format. Any required translation (for MIDI 1.0 devices, for example) is handled in the service and/or in the USB driver.

Workflow

  1. Open a session
  2. Using an endpoint id discovered through enumeration or another mechanism, create an endpoint connection
  3. Wire up to the connection any event handlers or message processors
  4. Open the connection
  5. Send and receive messages
  6. Using the session, disconnect the connection when you are done with it.

Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html index 21b64d91..66d63a82 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformation.html @@ -1,4 +1,4 @@ - MidiEndpointDeviceInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiEndpointDeviceInformation

This class is a specialized equivalent of the DeviceInformation WinRT class. It handles requesting all of the additional properties necessary for MIDI devices, and also goes a step further to retrieve parent device information so that applications can display the endpoints and parent devices in context.

We’ve heard from developers that we did not provide sufficient information about devices in the past, so we created this class and the associated properties to remedy that. We also heard that Async calls were a non-starter for most DAW applications, so everything in this class is synchronous.

Note: the MidiEndpointDeviceWatcher is a better way to retrieve devices because you can then keep the watcher open in a background thread, and be notified of property changes, device add/remove, etc.

When displaying endpoint devices to users, you’ll typically want to stick to the defaults: IncludeClientUmpNative | IncludeClientByteStreamNative. You do not want to show the Diagnostic Ping ever, and you typically will not want to show the system-wide Diagnostic Loopback singletons. Finally, you don’t want to show the Virtual Device Responder endpoints because those should be reserved only for the “device” application in app-to-app MIDI.

In-protocol discovered information

When a device is first enumerated by the MIDI Service, if it is a UMP-native device, we will attempt endpoint discover and protocol negotiation. During that, we request all endpoint information and all function block information. The received data is then cached in the device properties so that applications do not need to perform this process themselves.

Properties

Property Source Description
Id Windows The endpoint device interface id
ContainerId Windows The device container
DeviceInstanceId Windows The device instance id without the interface information
Name Various This is the name which should be displayed in any application. It calculates the correct name based on the hierarchy of possible names, including a user-specified name. Always respect the user’s choice here.
TransportSuppliedName Transports The name provided by the driver or the endpoint transport.
EndpointSuppliedName MIDI 2.0 The name provided by MIDI 2.0 endpoint information. This is discovered in-protocol.
UserSuppliedName Configuration The name provided by the user.
ProductInstanceId MIDI 2.0 Property of the same name discovered by MIDI 2.0 in-protocol endpoint information.
SpecificationVersionMajor MIDI 2.0 Discovered UMP version
SpecificationVersionMinor MIDI 2.0 Discovered UMP version
SupportsMidi10Protocol MIDI 2.0 Discovered protocol support
SupportsMidi20Protocol MIDI 2.0 Discovered protocol support
`ConfiguredToReceiveJRTimestamps MIDI 2.0 Note that JR timestamps are handled entirely in the service and are not sent back down to the client.
`ConfiguredToSendJRTimestamps MIDI 2.0 Note that JR timestamps are handled entirely in the service and are not sent back down to the client.
DeviceIdentitySystemExclusiveId MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyLsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyMsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyModelNumberLsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyModelNumberMsb MIDI 2.0 Device Identity information
DeviceIdentitySoftwareRevisionLevel MIDI 2.0 Device Identity information
TransportId Windows The Id of the transport abstraction that manages this endpoint
TransportMnemonic Windows A short abbreviation for the transport. This can be used as a transport identifier.
TransportSuppliedSerialNumber Windows iSerialNumber, when available in USB, and other ids from other transports.
ManufacturerName Windows The name of the manufacturer of the device, if available
SupportsMultiClient Windows True if this endpoint supports multi-client use
NativeDataFormat Windows Because the driver and service handle data format translation, it’s not immediately obvious if the device is natively UMP or natively Byte Stream. This property provides that information
GroupTerminalBlocks Windows A collection of Group Terminal Blocks. These are used only in USB. For MIDI 2.0 devices, Function Blocks are preferred.
HasStaticFunctionBlocks MIDI 2.0 True if the function blocks are static. That is, the groups never change.
FunctionBlockCount MIDI 2.0 The number of function blocks the endpoint has declared. Function blocks always start at index zero and go to FunctionBlockCount-1
EndpointPurpose Windows The purpose of the endpoint. This is used primarily for filtering.
Description Configuration An endpoint description which is typically provided by the user
LargeImagePath Configuration The path to a png or jpg image that represents this endpoint. Typically user-supplied.
SmallImagePath Configuration The path to a png or jpg image that represents this endpoint. Typically user-supplied.
RequiresNoteOffTranslation Configuration True if the endpoint requires internal translation of Note On with zero velocity (in the case of MIDI 1.0) to a Note Off message. Typically user-supplied.
RecommendedCCAutomationIntervalMS Configuration Number of milliseconds between automation value changes. This is usually only for old and slow MIDI 1.0 devices that are prone to data flooding. User-supplied.
Properties Windows A collection of all the raw properties.

Static Properties

Static Property Description
DiagnosticsLoopbackAEndpointId Endpoint Id for the diagnostic loopback used for development and support purposes.
DiagnosticsLoopbackBEndpointId Endpoint Id for the diagnostic loopback used for development and support purposes.
EndpointInterfaceClass The class GUID which appears at the end of the Endpoint Ids

Functions

Function Description
GetParentDeviceInformation() Finds and then retrieves the parent DeviceInformation type with appropriate properties.
GetContainerInformation() Gets the device container information and returns its DeviceInformation with appropriate properties
UpdateFromDeviceInformation(deviceInformation) For use by any watcher which must update this object
UpdateFromDeviceInformationUpdate(deviceInformationUpdate) For use by any watcher which must update this object

Static Functions

Static Function Description
CreateFromId(id) Creates a new MidiEndpointDeviceInformation object from the specified id
FindAll() Searches for all endpoint devices and returns a list in the default sort order
FindAll(sortOrder) Searches for all endpoint devices and returns a list in the specified sort order
FindAll(sortOrder, endpointFilter) Searches for all endpoint devices which match the filter, and returns a list in the specified sort order.
DeviceMatchesFilter(deviceInformation, endpointFilter) A helper function to compare a device against the filter.
GetAdditionalPropertiesList() This returns the list of properties which must be requested during enumeration. Typically not needed for applications, as the watcher calls this function

IDL

MidiEndpointDeviceInformation IDL

Sample

What follows is an excerpt of the larger C++/WinRT enumeration sample.

#include "pch.h"
+            MidiEndpointDeviceInformation | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiEndpointDeviceInformation

This class is a specialized equivalent of the DeviceInformation WinRT class. It handles requesting all of the additional properties necessary for MIDI devices, and also goes a step further to retrieve parent device information so that applications can display the endpoints and parent devices in context.

We’ve heard from developers that we did not provide sufficient information about devices in the past, so we created this class and the associated properties to remedy that. We also heard that Async calls were a non-starter for most DAW applications, so everything in this class is synchronous.

Note: the MidiEndpointDeviceWatcher is a better way to retrieve devices because you can then keep the watcher open in a background thread, and be notified of property changes, device add/remove, etc.

When displaying endpoint devices to users, you’ll typically want to stick to the defaults: IncludeClientUmpNative | IncludeClientByteStreamNative. You do not want to show the Diagnostic Ping ever, and you typically will not want to show the system-wide Diagnostic Loopback singletons. Finally, you don’t want to show the Virtual Device Responder endpoints because those should be reserved only for the “device” application in app-to-app MIDI.

In-protocol discovered information

When a device is first enumerated by the MIDI Service, if it is a UMP-native device, we will attempt endpoint discover and protocol negotiation. During that, we request all endpoint information and all function block information. The received data is then cached in the device properties so that applications do not need to perform this process themselves.

Properties

Property Source Description
Id Windows The endpoint device interface id
ContainerId Windows The device container
DeviceInstanceId Windows The device instance id without the interface information
Name Various This is the name which should be displayed in any application. It calculates the correct name based on the hierarchy of possible names, including a user-specified name. Always respect the user’s choice here.
TransportSuppliedName Transports The name provided by the driver or the endpoint transport.
EndpointSuppliedName MIDI 2.0 The name provided by MIDI 2.0 endpoint information. This is discovered in-protocol.
UserSuppliedName Configuration The name provided by the user.
ProductInstanceId MIDI 2.0 Property of the same name discovered by MIDI 2.0 in-protocol endpoint information.
SpecificationVersionMajor MIDI 2.0 Discovered UMP version
SpecificationVersionMinor MIDI 2.0 Discovered UMP version
SupportsMidi10Protocol MIDI 2.0 Discovered protocol support
SupportsMidi20Protocol MIDI 2.0 Discovered protocol support
`ConfiguredToReceiveJRTimestamps MIDI 2.0 Note that JR timestamps are handled entirely in the service and are not sent back down to the client.
`ConfiguredToSendJRTimestamps MIDI 2.0 Note that JR timestamps are handled entirely in the service and are not sent back down to the client.
DeviceIdentitySystemExclusiveId MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyLsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyMsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyModelNumberLsb MIDI 2.0 Device Identity information
DeviceIdentityDeviceFamilyModelNumberMsb MIDI 2.0 Device Identity information
DeviceIdentitySoftwareRevisionLevel MIDI 2.0 Device Identity information
TransportId Windows The Id of the transport abstraction that manages this endpoint
TransportMnemonic Windows A short abbreviation for the transport. This can be used as a transport identifier.
TransportSuppliedSerialNumber Windows iSerialNumber, when available in USB, and other ids from other transports.
ManufacturerName Windows The name of the manufacturer of the device, if available
SupportsMultiClient Windows True if this endpoint supports multi-client use
NativeDataFormat Windows Because the driver and service handle data format translation, it’s not immediately obvious if the device is natively UMP or natively Byte Stream. This property provides that information
GroupTerminalBlocks Windows A collection of Group Terminal Blocks. These are used only in USB. For MIDI 2.0 devices, Function Blocks are preferred.
HasStaticFunctionBlocks MIDI 2.0 True if the function blocks are static. That is, the groups never change.
FunctionBlockCount MIDI 2.0 The number of function blocks the endpoint has declared. Function blocks always start at index zero and go to FunctionBlockCount-1
EndpointPurpose Windows The purpose of the endpoint. This is used primarily for filtering.
Description Configuration An endpoint description which is typically provided by the user
LargeImagePath Configuration The path to a png or jpg image that represents this endpoint. Typically user-supplied.
SmallImagePath Configuration The path to a png or jpg image that represents this endpoint. Typically user-supplied.
RequiresNoteOffTranslation Configuration True if the endpoint requires internal translation of Note On with zero velocity (in the case of MIDI 1.0) to a Note Off message. Typically user-supplied.
RecommendedCCAutomationIntervalMS Configuration Number of milliseconds between automation value changes. This is usually only for old and slow MIDI 1.0 devices that are prone to data flooding. User-supplied.
Properties Windows A collection of all the raw properties.

Static Properties

Static Property Description
DiagnosticsLoopbackAEndpointId Endpoint Id for the diagnostic loopback used for development and support purposes.
DiagnosticsLoopbackBEndpointId Endpoint Id for the diagnostic loopback used for development and support purposes.
EndpointInterfaceClass The class GUID which appears at the end of the Endpoint Ids

Functions

Function Description
GetParentDeviceInformation() Finds and then retrieves the parent DeviceInformation type with appropriate properties.
GetContainerInformation() Gets the device container information and returns its DeviceInformation with appropriate properties
UpdateFromDeviceInformation(deviceInformation) For use by any watcher which must update this object
UpdateFromDeviceInformationUpdate(deviceInformationUpdate) For use by any watcher which must update this object

Static Functions

Static Function Description
CreateFromId(id) Creates a new MidiEndpointDeviceInformation object from the specified id
FindAll() Searches for all endpoint devices and returns a list in the default sort order
FindAll(sortOrder) Searches for all endpoint devices and returns a list in the specified sort order
FindAll(sortOrder, endpointFilter) Searches for all endpoint devices which match the filter, and returns a list in the specified sort order.
DeviceMatchesFilter(deviceInformation, endpointFilter) A helper function to compare a device against the filter.
GetAdditionalPropertiesList() This returns the list of properties which must be requested during enumeration. Typically not needed for applications, as the watcher calls this function

IDL

MidiEndpointDeviceInformation IDL

Sample

What follows is an excerpt of the larger C++/WinRT enumeration sample.

#include "pch.h"
 #include <iostream>
 
 using namespace winrt::Windows::Devices::Midi2;        // API
diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html
index ff0cb283..886039d0 100644
--- a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html
+++ b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationUpdateEventArgs.html
@@ -1 +1 @@
-            MidiEndpointDeviceInformationUpdateEventArgs | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiEndpointDeviceInformationUpdateEventArgs

Represents a notification that endpoint properties have been updated

Functions

Property Description
Id Id of the endpoint which has been updated
UpdatedName True if the name properties have been updated
UpdatedEndpointInformation True if the in-protocol endpoint information has been updated
UpdatedDeviceIdentity True if the in-protocol device identity information has been updated
UpdatedStreamConfiguration True if protocol negotiation changed configuration of the endpoint
UpdatedFunctionBlocks True if any function blocks have been updated
UpdatedUserMetadata True if any user-supplied metadata fields have been updated
UpdatedAdditionalCapabilities True if the additional capabilities have been updated
DeviceInformationUpdate The source Windows.Devices.Enumeration.DeviceInformationUpdate object.

If none of the UpdatedXX properties are true, then other properties have been updated.

IDL

MidiEndpointDeviceInformationUpdateEventArgs IDL

\ No newline at end of file + MidiEndpointDeviceInformationUpdateEventArgs | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiEndpointDeviceInformationUpdateEventArgs

Represents a notification that endpoint properties have been updated

Functions

Property Description
Id Id of the endpoint which has been updated
UpdatedName True if the name properties have been updated
UpdatedEndpointInformation True if the in-protocol endpoint information has been updated
UpdatedDeviceIdentity True if the in-protocol device identity information has been updated
UpdatedStreamConfiguration True if protocol negotiation changed configuration of the endpoint
UpdatedFunctionBlocks True if any function blocks have been updated
UpdatedUserMetadata True if any user-supplied metadata fields have been updated
UpdatedAdditionalCapabilities True if the additional capabilities have been updated
DeviceInformationUpdate The source Windows.Devices.Enumeration.DeviceInformationUpdate object.

If none of the UpdatedXX properties are true, then other properties have been updated.

IDL

MidiEndpointDeviceInformationUpdateEventArgs IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html index 0ac43e34..9db1bb06 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceWatcher.html @@ -1 +1 @@ - MidiEndpointDeviceWatcher | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiEndpointDeviceWatcher

WinRT provides a Windows.Devices.Enumeration namespace with a DeviceWatcher class. That class is generic to any type of device, and so requires additional work to use with MIDI devices. Because of that, we’ve wrapped that functionality in the MidiEndpointDeviceWatcher class and the related MidiEndpointDeviceInformation class.

This is the class applications should use when they want to find devices, and also be notified when devices are added or removed, or when properties like function blocks or device names change.

Create a MidiEndpointDeviceWatcher on a background thread, and use the internal list of Endpoints as your source of record for device properties.

Properties

Function Description
Status The current status. See the Windows.Devices.Enumeration.DeviceWatcherStatus enumeration
EnumeratedEndpointDevices The list of enumerated devices. Provided here for convenience so applications do not need to keep their own list of MIDI devices.

Functions

Function Description
Start() Begin device enumeration. Wire up event handlers before calling this function.
Stop() Stop device enumeration.

Static Functions

Static Function Description
CreateWatcher(endpointFilter) Create a watcher which will enumerate devices based on the provided filter

Events

Event Description
Added(source, deviceInformation) A new endpoint has been added.
Removed(source, deviceInformationUpdate) An endpoint has been removed.
Updated(source endpointDeviceInformationUpdate) Properties of an endpoint have been updated. This is much more common than it was with the older MIDI 1.0 APIs due to both in-protocol endpoint information, and user configuration.
EnumerationCompleted(source) Raised when the initial device enumeration has been completed. Devices may still be added or removed after this event, but use this to decide when you have enough information to display an initial list.
Stopped(source) Enumeration has been stopped.

IDL

MidiEndpointDeviceWatcher IDL

\ No newline at end of file + MidiEndpointDeviceWatcher | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiEndpointDeviceWatcher

WinRT provides a Windows.Devices.Enumeration namespace with a DeviceWatcher class. That class is generic to any type of device, and so requires additional work to use with MIDI devices. Because of that, we’ve wrapped that functionality in the MidiEndpointDeviceWatcher class and the related MidiEndpointDeviceInformation class.

This is the class applications should use when they want to find devices, and also be notified when devices are added or removed, or when properties like function blocks or device names change.

Create a MidiEndpointDeviceWatcher on a background thread, and use the internal list of Endpoints as your source of record for device properties.

Properties

Function Description
Status The current status. See the Windows.Devices.Enumeration.DeviceWatcherStatus enumeration
EnumeratedEndpointDevices The list of enumerated devices. Provided here for convenience so applications do not need to keep their own list of MIDI devices.

Functions

Function Description
Start() Begin device enumeration. Wire up event handlers before calling this function.
Stop() Stop device enumeration.

Static Functions

Static Function Description
CreateWatcher(endpointFilter) Create a watcher which will enumerate devices based on the provided filter

Events

Event Description
Added(source, deviceInformation) A new endpoint has been added.
Removed(source, deviceInformationUpdate) An endpoint has been removed.
Updated(source endpointDeviceInformationUpdate) Properties of an endpoint have been updated. This is much more common than it was with the older MIDI 1.0 APIs due to both in-protocol endpoint information, and user configuration.
EnumerationCompleted(source) Raised when the initial device enumeration has been completed. Devices may still be added or removed after this event, but use this to decide when you have enough information to display an initial list.
Stopped(source) Enumeration has been stopped.

IDL

MidiEndpointDeviceWatcher IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/README.html index 40d4ed0a..f99ba7f6 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/enumeration/README.html @@ -1 +1 @@ - Endpoint Enumeration | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Enumerating Endpoints

Windows MIDI Services provides detailed information about each MIDI endpoint on the system. In addition to ids and names, you can also get user metadata, function blocks, group terminal blocks, in-protocol properties, the parent device and container, and much more.

There are two ways to enumerate endpoint devices.

  1. Static enumeration using the MidiEndpointDeviceInformation class. This is a snapshot in time and is not updated when in-protocol information is updated, or the user has specified new properties like the name. This approach is really only useful in the simplest of scenarios, as it does not handle device connects and disconnects after the initial enumeration.
  2. Dynamic enumeration using the MidiEndpointDeviceWatcher. When you set up a watcher on a background thread, you will be notified when any new endpoints are connected to the system, or any existing endpoints are disconnected. You will also be alerted when properties change on an enumerated device. For example, when new function block information is sent in-protocol, the properties are updated and an event is raised. For these reasons, the device watcher approach is the approach any non-trival application should use to list and track MIDI endpoints.

Note that you can enumerate endpoint devices using the stock Windows.Devices.Enumeration.DeviceInformation and Windows.Devices.Enumeration.DeviceWatcher classes. However, those classes do not automatically request the extended property set needed for MIDI, do not translate the binary properties like the group terminal blocks and function blocks, and also do not automatically resolve the relationship with the parent device.


Table of contents

\ No newline at end of file + Endpoint Enumeration | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Enumerating Endpoints

Windows MIDI Services provides detailed information about each MIDI endpoint on the system. In addition to ids and names, you can also get user metadata, function blocks, group terminal blocks, in-protocol properties, the parent device and container, and much more.

There are two ways to enumerate endpoint devices.

  1. Static enumeration using the MidiEndpointDeviceInformation class. This is a snapshot in time and is not updated when in-protocol information is updated, or the user has specified new properties like the name. This approach is really only useful in the simplest of scenarios, as it does not handle device connects and disconnects after the initial enumeration.
  2. Dynamic enumeration using the MidiEndpointDeviceWatcher. When you set up a watcher on a background thread, you will be notified when any new endpoints are connected to the system, or any existing endpoints are disconnected. You will also be alerted when properties change on an enumerated device. For example, when new function block information is sent in-protocol, the properties are updated and an event is raised. For these reasons, the device watcher approach is the approach any non-trival application should use to list and track MIDI endpoints.

Note that you can enumerate endpoint devices using the stock Windows.Devices.Enumeration.DeviceInformation and Windows.Devices.Enumeration.DeviceWatcher classes. However, those classes do not automatically request the extended property set needed for MIDI, do not translate the binary properties like the group terminal blocks and function blocks, and also do not automatically resolve the relationship with the parent device.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html index 4fcae095..8527ab38 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageBuilder.html @@ -1 +1 @@ - MidiMessageBuilder | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageBuilder

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageBuilder IDL

\ No newline at end of file + MidiMessageBuilder | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageBuilder

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageBuilder IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html index eaf1c687..73fb1971 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageConverter.html @@ -1 +1 @@ - MidiMessageConverter | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageConverter

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageConverter IDL

\ No newline at end of file + MidiMessageConverter | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageConverter

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageConverter IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html index edc5c5c5..fb02f7be 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageTranslator.html @@ -1 +1 @@ - MidiMessageTranslator | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageTranslator

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageTranslator IDL

\ No newline at end of file + MidiMessageTranslator | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageTranslator

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiMessageTranslator IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html index dcc850c3..ff156d1f 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiMessageUtility.html @@ -1 +1 @@ - MidiMessageUtility | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageUtility

This class contains a number of static helper functions for reading information from Universal MIDI Packets, and also manipulating that information.

In most cases, the calling application needs to do some validation before calling functions which return specific fields. If, for example, the application asks for the Flex Data Status, but doesn’t provide a valid Flex Data message, the function will happily return whatever other data is in the position of that field.

Validation Functions

Function Description
ValidateMessage32MessageType(word0) Validate that the message type field in the word is for a 32-bit UMP
ValidateMessage64MessageType(word0) Validate that the message type field in the word is for a 64-bit UMP
ValidateMessage96MessageType(word0) Validate that the message type field in the word is for a 96-bit UMP
ValidateMessage128MessageType(word0) Validate that the message type field in the word is for a 128-bit UMP

Informational Functions

Function Description
MessageTypeHasGroupField(messageType) Returns true if the message type is known to be one which contains a group field. Valid only for message types known at the type the API was written.
MessageTypeHasChannelField(messageType) Returns true if the message type is known to be one which contains a channel field. Valid only for message types known at the type the API was written.

Field Access Functions

Function Description
GetMessageTypeFromMessageFirstWord(word0) Returns the MidiMessageType for the message
GetPacketTypeFromMessageFirstWord(word0) Returns the MidiPacketType for the message
GetGroupFromMessageFirstWord(word0) Returns the MidiGroup for the message. First check to see if the message type has a group field.
GetChannelFromMessageFirstWord(word0) Returns the MidiChannel for the message. First check to see if the message type has a channel field.
GetStatusFromUtilityMessage(word0) Returns the status byte
GetStatusFromMidi1ChannelVoiceMessage(word0) When provided a MIDI 1.0 channel voice message, returns the Midi1ChannelVoiceMessageStatus for the message.
GetStatusFromMidi2ChannelVoiceMessageFirstWord(word0) When provided a MIDI 2.0 channel voice message, returns the Midi2ChannelVoiceMessageStatus for the message.
GetStatusBankFromFlexDataMessageFirstWord(word0) Returns the status bank byte
GetStatusFromFlexDataMessageFirstWord(word0) Returns the status byte
GetStatusFromSystemCommonMessage(word0) Returns the status byte
GetStatusFromDataMessage64FirstWord(word0) Returns the status byte
GetNumberOfBytesFromDataMessage64FirstWord(word0) Returns the byte count field
GetStatusFromDataMessage128FirstWord(word0) Returns the status byte
GetNumberOfBytesFromDataMessage128FirstWord(word0) Returns the byte count field
GetFormFromStreamMessageFirstWord(word0) Returns the form nibble as a byte
GetStatusFromStreamMessageFirstWord(word0) Returns the status byte

Field Manipulation Functions

Function Description
ReplaceGroupInMessageFirstWord(word0, newGroup) Replaces the group field in word0 and returns the resulting MIDI word
ReplaceChannelInMessageFirstWord(word0, newChannel) Replaces the channel field in word0 and returns the resulting MIDI word

Additional Functions

Function Description
GetMessageFriendlyNameFromFirstWord(UInt32 word0) Returns the localized “Friendly Name” string for a message. For example, this is what is displayed in the console output when you are monitoring an endpoint in verbose mode.

IDL

MidiMessageUtility IDL

\ No newline at end of file + MidiMessageUtility | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageUtility

This class contains a number of static helper functions for reading information from Universal MIDI Packets, and also manipulating that information.

In most cases, the calling application needs to do some validation before calling functions which return specific fields. If, for example, the application asks for the Flex Data Status, but doesn’t provide a valid Flex Data message, the function will happily return whatever other data is in the position of that field.

Validation Functions

Function Description
ValidateMessage32MessageType(word0) Validate that the message type field in the word is for a 32-bit UMP
ValidateMessage64MessageType(word0) Validate that the message type field in the word is for a 64-bit UMP
ValidateMessage96MessageType(word0) Validate that the message type field in the word is for a 96-bit UMP
ValidateMessage128MessageType(word0) Validate that the message type field in the word is for a 128-bit UMP

Informational Functions

Function Description
MessageTypeHasGroupField(messageType) Returns true if the message type is known to be one which contains a group field. Valid only for message types known at the type the API was written.
MessageTypeHasChannelField(messageType) Returns true if the message type is known to be one which contains a channel field. Valid only for message types known at the type the API was written.

Field Access Functions

Function Description
GetMessageTypeFromMessageFirstWord(word0) Returns the MidiMessageType for the message
GetPacketTypeFromMessageFirstWord(word0) Returns the MidiPacketType for the message
GetGroupFromMessageFirstWord(word0) Returns the MidiGroup for the message. First check to see if the message type has a group field.
GetChannelFromMessageFirstWord(word0) Returns the MidiChannel for the message. First check to see if the message type has a channel field.
GetStatusFromUtilityMessage(word0) Returns the status byte
GetStatusFromMidi1ChannelVoiceMessage(word0) When provided a MIDI 1.0 channel voice message, returns the Midi1ChannelVoiceMessageStatus for the message.
GetStatusFromMidi2ChannelVoiceMessageFirstWord(word0) When provided a MIDI 2.0 channel voice message, returns the Midi2ChannelVoiceMessageStatus for the message.
GetStatusBankFromFlexDataMessageFirstWord(word0) Returns the status bank byte
GetStatusFromFlexDataMessageFirstWord(word0) Returns the status byte
GetStatusFromSystemCommonMessage(word0) Returns the status byte
GetStatusFromDataMessage64FirstWord(word0) Returns the status byte
GetNumberOfBytesFromDataMessage64FirstWord(word0) Returns the byte count field
GetStatusFromDataMessage128FirstWord(word0) Returns the status byte
GetNumberOfBytesFromDataMessage128FirstWord(word0) Returns the byte count field
GetFormFromStreamMessageFirstWord(word0) Returns the form nibble as a byte
GetStatusFromStreamMessageFirstWord(word0) Returns the status byte

Field Manipulation Functions

Function Description
ReplaceGroupInMessageFirstWord(word0, newGroup) Replaces the group field in word0 and returns the resulting MIDI word
ReplaceChannelInMessageFirstWord(word0, newChannel) Replaces the channel field in word0 and returns the resulting MIDI word

Additional Functions

Function Description
GetMessageFriendlyNameFromFirstWord(UInt32 word0) Returns the localized “Friendly Name” string for a message. For example, this is what is displayed in the console output when you are monitoring an endpoint in verbose mode.

IDL

MidiMessageUtility IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html index e0bc253c..f3451c1f 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/MidiStreamMessageBuilder.html @@ -1 +1 @@ - MidiStreamMessageBuilder | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiStreamMessageBuilder

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiStreamMessageBuilder IDL

\ No newline at end of file + MidiStreamMessageBuilder | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiStreamMessageBuilder

(In progress)

Functions

Function Description
   
   
   
   

IDL

MidiStreamMessageBuilder IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/README.html index c7eb7b50..30a8e739 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/message-utilities/README.html @@ -1 +1 @@ - Message Utilities | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Message Utilities

There are many open source and internal libraries that can be used for creating and parsing message data. For a functional MIDI API, however, we did have to create a number of these ourselves, and so surface them in the API so that you may take advantage of them in your own code.

For other open source MIDI libraries, visit the official site midi2.dev, run by members of the MIDI Association. The Windows MIDI Services service and API code uses some of this open source internally.


Table of contents

\ No newline at end of file + Message Utilities | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Message Utilities

There are many open source and internal libraries that can be used for creating and parsing message data. For a functional MIDI API, however, we did have to create a number of these ourselves, and so surface them in the API so that you may take advantage of them in your own code.

For other open source MIDI libraries, visit the official site midi2.dev, run by members of the MIDI Association. The Windows MIDI Services service and API code uses some of this open source internally.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html index badb5650..5be2add9 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/IMidiUniversalPacket.html @@ -1 +1 @@ - IMidiUniversalPacket | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

IMidiUniversalPacket

This interface is implemented by the rich MidiMessageXX runtime class types. It may also be used as the interface for message-specific classes you create yourself.

Property Description
Timestamp 64 bit timestamp set by the receiving transport in the case of incoming messages, or by the sender in the case of outgoing messages
MessageType A MidiMessageType enumeration value which represents the 4 bit MIDI Message type 0x0 - 0xF as defined by the MIDI UMP standard.
PacketType A MidiPacketType enumeration value which can be cast to an int to get the number of 32-bit words in the message packet
Function Description
PeekFirstWord() Provides access to the first word of data, even if the message type and size is not yet known by the API user

IDL

IMidiUniversalPacket IDL

\ No newline at end of file + IMidiUniversalPacket | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

IMidiUniversalPacket

This interface is implemented by the rich MidiMessageXX runtime class types. It may also be used as the interface for message-specific classes you create yourself.

Property Description
Timestamp 64 bit timestamp set by the receiving transport in the case of incoming messages, or by the sender in the case of outgoing messages
MessageType A MidiMessageType enumeration value which represents the 4 bit MIDI Message type 0x0 - 0xF as defined by the MIDI UMP standard.
PacketType A MidiPacketType enumeration value which can be cast to an int to get the number of 32-bit words in the message packet
Function Description
PeekFirstWord() Provides access to the first word of data, even if the message type and size is not yet known by the API user

IDL

IMidiUniversalPacket IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html index de4f5ee3..f0c9327b 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage128.html @@ -1 +1 @@ - MidiMessage128 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage128

MidiMessage128 is used for some data messages as well as important “Type F” stream metadata messages.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Word3 Fourth 32-bit MIDI word
Function Description
MidiMessage128() Default constructor
MidiMessage128(timestamp, word0, word1, word2, word3) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage128 IDL

\ No newline at end of file + MidiMessage128 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage128

MidiMessage128 is used for some data messages as well as important “Type F” stream metadata messages.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Word3 Fourth 32-bit MIDI word
Function Description
MidiMessage128() Default constructor
MidiMessage128(timestamp, word0, word1, word2, word3) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage128 IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html index a1b012a7..726f1460 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage32.html @@ -1 +1 @@ - MidiMessage32 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage32

MidiMessage32 is used for short messages such as utility messages and MIDI 1.0 messages in UMP format.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Function Description
MidiMessage32() Default constructor
MidiMessage32(timestamp, word0) Construct a new message with a timestamp and 32 bit MIDI word

IDL

MidiMessage32 IDL

\ No newline at end of file + MidiMessage32 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage32

MidiMessage32 is used for short messages such as utility messages and MIDI 1.0 messages in UMP format.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Function Description
MidiMessage32() Default constructor
MidiMessage32(timestamp, word0) Construct a new message with a timestamp and 32 bit MIDI word

IDL

MidiMessage32 IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html index d27c5012..5a4e3256 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage64.html @@ -1 +1 @@ - MidiMessage64 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage64

MidiMessage64 is used for some data messages and for MIDI 2.0 Channel Voice messages.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Function Description
MidiMessage64() Default constructor
MidiMessage64(timestamp, word0, word1) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage64 IDL

\ No newline at end of file + MidiMessage64 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage64

MidiMessage64 is used for some data messages and for MIDI 2.0 Channel Voice messages.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Function Description
MidiMessage64() Default constructor
MidiMessage64(timestamp, word0, word1) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage64 IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html index 2033555e..2ddc5b8c 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessage96.html @@ -1 +1 @@ - MidiMessage96 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage96

MidiMessage96 is currently unused in the MIDI 2.0 UMP specification.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Function Description
MidiMessage96() Default constructor
MidiMessage96(timestamp, word0, word1, word2) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage96 IDL

\ No newline at end of file + MidiMessage96 | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessage96

MidiMessage96 is currently unused in the MIDI 2.0 UMP specification.

Includes all functions and properties in IMidiUniversalPacket, as well as:

Property Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Function Description
MidiMessage96() Default constructor
MidiMessage96(timestamp, word0, word1, word2) Construct a new message with a timestamp and all 32 bit MIDI words

IDL

MidiMessage96 IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html index 9aee451d..ccb5ed3e 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageStruct.html @@ -1 +1 @@ - MidiMessageStruct | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageStruct

MidiMessageStruct is provided for cases where the API consumer wants to have a fixed value type they can use to send and receive messages. In the case of receiving messages, a function which fills the struct will typically return a count of valid words. The MidiMessageStruct struct type is simpler than the other runtime class types and may therefore perform better in some projections and for some uses. Note that this type does not include the timestamp field.

Field Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Word3 Fourth 32-bit MIDI word

IDL

MidiMessageStruct IDL

\ No newline at end of file + MidiMessageStruct | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageStruct

MidiMessageStruct is provided for cases where the API consumer wants to have a fixed value type they can use to send and receive messages. In the case of receiving messages, a function which fills the struct will typically return a count of valid words. The MidiMessageStruct struct type is simpler than the other runtime class types and may therefore perform better in some projections and for some uses. Note that this type does not include the timestamp field.

Field Description
Word0 First 32-bit MIDI word
Word1 Second 32-bit MIDI word
Word2 Third 32-bit MIDI word
Word3 Fourth 32-bit MIDI word

IDL

MidiMessageStruct IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html index 02acf2af..68f30cc6 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiMessageTypeEnum.html @@ -1 +1 @@ - MidiMessageType | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageType Enumeration

The values correspond directly to the “mt” field in the MIDI UMP packet and may be cast as such if trimmed to 4 bits and shifted into place.

Property Value Description
UtilityMessage32 0x0 32-bit utility message
SystemCommon32 0x1 32-bit system common message
Midi1ChannelVoice32 0x2 32-bit MIDI 1.0 channel voice message
DataMessage64 0x3 64-bit data message (including MIDI 1.0 System Exclusive)
Midi2ChannelVoice64 0x4 64-bit MIDI 2.0 channel voice message
DataMessage128 0x5 128-bit Data Message
FutureReserved632 0x6 Reserved for future use by the MIDI standards bodies
FutureReserved732 0x7 Reserved for future use by the MIDI standards bodies
FutureReserved864 0x8 Reserved for future use by the MIDI standards bodies
FutureReserved964 0x9 Reserved for future use by the MIDI standards bodies
FutureReservedA64 0xA Reserved for future use by the MIDI standards bodies
FutureReservedB96 0xB Reserved for future use by the MIDI standards bodies
FutureReservedC96 0xC Reserved for future use by the MIDI standards bodies
FlexData128 0xD 128-bit Flex Data message including song file data messages
FutureReservedE128 0xE Reserved for future use by the MIDI standards bodies
Stream128 0xF 128-bit stream message, including endpoint discovery and function block messages

IDL

MidiMessageType IDL

\ No newline at end of file + MidiMessageType | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageType Enumeration

The values correspond directly to the “mt” field in the MIDI UMP packet and may be cast as such if trimmed to 4 bits and shifted into place.

Property Value Description
UtilityMessage32 0x0 32-bit utility message
SystemCommon32 0x1 32-bit system common message
Midi1ChannelVoice32 0x2 32-bit MIDI 1.0 channel voice message
DataMessage64 0x3 64-bit data message (including MIDI 1.0 System Exclusive)
Midi2ChannelVoice64 0x4 64-bit MIDI 2.0 channel voice message
DataMessage128 0x5 128-bit Data Message
FutureReserved632 0x6 Reserved for future use by the MIDI standards bodies
FutureReserved732 0x7 Reserved for future use by the MIDI standards bodies
FutureReserved864 0x8 Reserved for future use by the MIDI standards bodies
FutureReserved964 0x9 Reserved for future use by the MIDI standards bodies
FutureReservedA64 0xA Reserved for future use by the MIDI standards bodies
FutureReservedB96 0xB Reserved for future use by the MIDI standards bodies
FutureReservedC96 0xC Reserved for future use by the MIDI standards bodies
FlexData128 0xD 128-bit Flex Data message including song file data messages
FutureReservedE128 0xE Reserved for future use by the MIDI standards bodies
Stream128 0xF 128-bit stream message, including endpoint discovery and function block messages

IDL

MidiMessageType IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html index 2499b793..7341a16c 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/MidiPacketTypeEnum.html @@ -1 +1 @@ - MidiPacketType | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiPacketType Enumeration

The values correspond to the number of 32-bit MIDI words in the packet.

Property Value Description
UnknownOrInvalid 0 An invalid zero-length Universal MIDI Packet
UniversalMidiPacket32 1 32-bit (1 word) Universal MIDI Packet
UniversalMidiPacket64 2 64-bit (2 words) Universal MIDI Packet
UniversalMidiPacket96 3 96-bit (3 words) Universal MIDI Packet
UniversalMidiPacket128 4 128-bit (4 words) Universal MIDI Packet

IDL

MidiPacketType IDL

\ No newline at end of file + MidiPacketType | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiPacketType Enumeration

The values correspond to the number of 32-bit MIDI words in the packet.

Property Value Description
UnknownOrInvalid 0 An invalid zero-length Universal MIDI Packet
UniversalMidiPacket32 1 32-bit (1 word) Universal MIDI Packet
UniversalMidiPacket64 2 64-bit (2 words) Universal MIDI Packet
UniversalMidiPacket96 3 96-bit (3 words) Universal MIDI Packet
UniversalMidiPacket128 4 128-bit (4 words) Universal MIDI Packet

IDL

MidiPacketType IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/README.html index 0bee91e5..5c1d743b 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/messages/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/messages/README.html @@ -1 +1 @@ - Messages | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Messages

Windows MIDI Services messages are all sent and received in Universal MIDI Packet (UMP) format, even if the device is a bytestream MIDI 1.0 device (we do the translation for you). a UMP is made up of 1-4 32 bit MIDI words, sized in 32 bit, 64 bit, 96 bit, and 128 bit packets. The first four bits of the packet are the message type, and from that, you can identify the type and size of message which follows.

Words

Several functions operate on one or more 32 bit MIDI words directly. This is efficient for transmission, but may not be convenient for storage or processing.

Rich Types

The rich UMP types are full runtime classes, and so have more overhead than the fixed types or raw words. However, they offer conveniences not offered by the other types, including storage of the timestamp, message and packet type enumerations, and interface-based polymorphism. If your send/receive speed is not super critical, these are often the easiest solution.

If you are familiar with the Windows.Devices.Midi message types, these are the conceptual equivalent in UMP.

For the most part, we do not provide strongly-typed discrete message types (like specific MIDI 2.0 Channel Voice messages or similar) in the API as that is a moving target, and many applications also include their own message creation and processing functions using their own libraries or any of the libraries included on https://midi2.dev. If there’s demand for strongly-typed messages, we may provide them in the future.

Fixed-Size Struct type

In addition to the richer types and raw words, the MidiMessageStruct type offers a fixed 128 bit message which can be used to send or receive any type of MIDI UMP.


Table of contents

\ No newline at end of file + Messages | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Messages

Windows MIDI Services messages are all sent and received in Universal MIDI Packet (UMP) format, even if the device is a bytestream MIDI 1.0 device (we do the translation for you). a UMP is made up of 1-4 32 bit MIDI words, sized in 32 bit, 64 bit, 96 bit, and 128 bit packets. The first four bits of the packet are the message type, and from that, you can identify the type and size of message which follows.

Words

Several functions operate on one or more 32 bit MIDI words directly. This is efficient for transmission, but may not be convenient for storage or processing.

Rich Types

The rich UMP types are full runtime classes, and so have more overhead than the fixed types or raw words. However, they offer conveniences not offered by the other types, including storage of the timestamp, message and packet type enumerations, and interface-based polymorphism. If your send/receive speed is not super critical, these are often the easiest solution.

If you are familiar with the Windows.Devices.Midi message types, these are the conceptual equivalent in UMP.

For the most part, we do not provide strongly-typed discrete message types (like specific MIDI 2.0 Channel Voice messages or similar) in the API as that is a moving target, and many applications also include their own message creation and processing functions using their own libraries or any of the libraries included on https://midi2.dev. If there’s demand for strongly-typed messages, we may provide them in the future.

Fixed-Size Struct type

In addition to the richer types and raw words, the MidiMessageStruct type offers a fixed 128 bit message which can be used to send or receive any type of MIDI UMP.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html index a80b2964..273b15c6 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlock.html @@ -1 +1 @@ - MidiFunctionBlock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiFunctionBlock

The original MIDI 2.0 USB specification includes the concept of a Group Terminal Block. After ratification of that specification, it was found that Group Terminal Blocks were insufficient for two main reasons:

  1. Group Terminal Blocks are USB-specific, and so are not available on other transports like Network or Virtual.
  2. Group Terminal Blocks are static, defined in USB descriptors, and so cannot change during runtime.

Group Terminal Blocks are still available, but function blocks are the preferred approach for defining capapbilities of a device. When both are available, you should use the function block information.

A function block represents a function of a MIDI 2.0 device. A function block may span one or more groups, and if not a static function block, those group numbers may change during operation. For example, a Tone Generator function of a device may need 64 channels to represent its multi-timbral nature. One way it can accomplish this is to declare a function block which spans 4 groups, each of which has 16 channels of data (16x4 = 64).

Function blocks also represent the valid groups for communication with an endpoint. If an endpoint declares 4 function blocks, which together cover only group indexes 0-5, and all of those blocks are marked active, only those groups should be available to users of an application. This helps cut down on clutter caused by always displaying 16 groups.

Function blocks have names which should be displayed to the user along with the group numbers. In the end, the actual addressible entity is the endpoint stream with the group number in the Universal MIDI Packet. But the function block provides context for that group number.

Per the specification, function blocks can span more than one group, and can overlap with each other so that different functions can be available on the same group.

Function blocks are used in the Windwos MIDI Services API in three ways:

  1. A property of a MidiEndpointDeviceInformation object, representing function blocks discovered through endpoint discovery. These function blocks are read-only.
  2. The return value of the AsEquivalentFunctionBlock method of the GroupTerminalBlock class. This is a convenience function. These function blocks are read-only
  3. Provided by the application as part of the device definition for a virtual device in app-to-app MIDI. These function blocks are editable before adding them to the device definition.

Properties

Most properties are 1:1 with the MIDI 2.0 UMP specification section on function blocks. We assemble the name for you and map values to enumerations when possible.

Property Description
IsReadOnly True if this function block should be treated as read-only. If you attempt to assign a value to a property in a read-only function block, the assignment will silently fail.
Number The index of the block 0-31. We use “number” here to be consistent with the specification
Name The assembled name of the function block
IsActive True if this block is active
Direction The direction of the block from the block’s point of view.
UIHint A hint which tells you how this block should be treated in a user interface. This should be considered a “soft filter” for display, not a mechanism to keep blocks completely hidden from a user.
Midi10Connection How to treat this block if it is a MIDI 1.0 connection
FirstGroupIndex Zero-based index of the first group spanned by this block.
GroupCount The number of groups spanned.
MidiCIMessageVersionFormat MIDI CI version format value
MaxSystemExclusive8Streams The maximum number of System Exclusive 8 streams allowed. Please refer to the UMP specification for how to treat this value.

Functions

Function Description
MidiFunctionBlock() Construct an empty function block
IncludesGroup(group) Helper function which returns true if this function exists on the supplied group

IDL

MidiFunctionBlock IDL

\ No newline at end of file + MidiFunctionBlock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiFunctionBlock

The original MIDI 2.0 USB specification includes the concept of a Group Terminal Block. After ratification of that specification, it was found that Group Terminal Blocks were insufficient for two main reasons:

  1. Group Terminal Blocks are USB-specific, and so are not available on other transports like Network or Virtual.
  2. Group Terminal Blocks are static, defined in USB descriptors, and so cannot change during runtime.

Group Terminal Blocks are still available, but function blocks are the preferred approach for defining capapbilities of a device. When both are available, you should use the function block information.

A function block represents a function of a MIDI 2.0 device. A function block may span one or more groups, and if not a static function block, those group numbers may change during operation. For example, a Tone Generator function of a device may need 64 channels to represent its multi-timbral nature. One way it can accomplish this is to declare a function block which spans 4 groups, each of which has 16 channels of data (16x4 = 64).

Function blocks also represent the valid groups for communication with an endpoint. If an endpoint declares 4 function blocks, which together cover only group indexes 0-5, and all of those blocks are marked active, only those groups should be available to users of an application. This helps cut down on clutter caused by always displaying 16 groups.

Function blocks have names which should be displayed to the user along with the group numbers. In the end, the actual addressible entity is the endpoint stream with the group number in the Universal MIDI Packet. But the function block provides context for that group number.

Per the specification, function blocks can span more than one group, and can overlap with each other so that different functions can be available on the same group.

Function blocks are used in the Windwos MIDI Services API in three ways:

  1. A property of a MidiEndpointDeviceInformation object, representing function blocks discovered through endpoint discovery. These function blocks are read-only.
  2. The return value of the AsEquivalentFunctionBlock method of the GroupTerminalBlock class. This is a convenience function. These function blocks are read-only
  3. Provided by the application as part of the device definition for a virtual device in app-to-app MIDI. These function blocks are editable before adding them to the device definition.

Properties

Most properties are 1:1 with the MIDI 2.0 UMP specification section on function blocks. We assemble the name for you and map values to enumerations when possible.

Property Description
IsReadOnly True if this function block should be treated as read-only. If you attempt to assign a value to a property in a read-only function block, the assignment will silently fail.
Number The index of the block 0-31. We use “number” here to be consistent with the specification
Name The assembled name of the function block
IsActive True if this block is active
Direction The direction of the block from the block’s point of view.
UIHint A hint which tells you how this block should be treated in a user interface. This should be considered a “soft filter” for display, not a mechanism to keep blocks completely hidden from a user.
Midi10Connection How to treat this block if it is a MIDI 1.0 connection
FirstGroupIndex Zero-based index of the first group spanned by this block.
GroupCount The number of groups spanned.
MidiCIMessageVersionFormat MIDI CI version format value
MaxSystemExclusive8Streams The maximum number of System Exclusive 8 streams allowed. Please refer to the UMP specification for how to treat this value.

Functions

Function Description
MidiFunctionBlock() Construct an empty function block
IncludesGroup(group) Helper function which returns true if this function exists on the supplied group

IDL

MidiFunctionBlock IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html index b9bd7b0b..10769d45 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlock.html @@ -1 +1 @@ - MidiGroupTerminalBlock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroupTerminalBlock

A Group Terminal Block is a USB-only feature used to describe the groups on a device. When available, Function Blocks are the preferred mechanism for finding active groups, names, and more, meaning that the Group Terminal Block can typically be ignored in those cases. For more context, please see the documentation for the MidiFunctionBlock type.

Note: In Windows MIDI Services, we translate MIDI 1.0 device “ports” into individual Group Terminal Blocks. Each virtual cable number in the stream, which used to become a separate input or output port, now maps to a group number. For example, a 5 port MIDI 1.0 device will now show up as a single endpoint with 5 Group Terminal Blocks each spanning a single group.

Properties

Property Description
Number Block number
Name Name provided by USB. In the case of MIDI 1.0 devices, when available, this is the iJack string
Direction Direction of the block, from the block’s point of view
Protocol Information about the protocol in use. Note that the Jitter Reduction values here should be ignored. Jitter reduction timestamp handling is negotiated through protocol negotiation, and is entirely handled by the service
FirstGroupIndex The index of the first group spanned by this block
GroupCount The number of groups spanned
MaxDeviceInputBandwidthIn4KBitsPerSecondUnits Please see the USB MIDI 2.0 specification for the actual value for this field.
MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits Please see the USB MIDI 2.0 specification for the actual value for this field.
CalculatedMaxDeviceInputBandwidthBitsPerSecond Bits-per-second calculated value for the MaxDeviceInputBandwidthIn4KBitsPerSecondUnits property
CalculatedMaxDeviceOutputBandwidthBitsPerSecond Bits-per-second calculated value for the MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits property

Functions

Function Description
IncludesGroup(group) Helper function which returns true if this function exists on the supplied group
AsEquivalentFunctionBlock() Helper function which returns a MidiFunctionBlock that is approximately equivalent to this MidiGroupTerminalBlock. This is to enable applications to be able to deal with only a single type of block when showing the metadata

IDL

MidiGroupTerminalBlock IDL

\ No newline at end of file + MidiGroupTerminalBlock | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroupTerminalBlock

A Group Terminal Block is a USB-only feature used to describe the groups on a device. When available, Function Blocks are the preferred mechanism for finding active groups, names, and more, meaning that the Group Terminal Block can typically be ignored in those cases. For more context, please see the documentation for the MidiFunctionBlock type.

Note: In Windows MIDI Services, we translate MIDI 1.0 device “ports” into individual Group Terminal Blocks. Each virtual cable number in the stream, which used to become a separate input or output port, now maps to a group number. For example, a 5 port MIDI 1.0 device will now show up as a single endpoint with 5 Group Terminal Blocks each spanning a single group.

Properties

Property Description
Number Block number
Name Name provided by USB. In the case of MIDI 1.0 devices, when available, this is the iJack string
Direction Direction of the block, from the block’s point of view
Protocol Information about the protocol in use. Note that the Jitter Reduction values here should be ignored. Jitter reduction timestamp handling is negotiated through protocol negotiation, and is entirely handled by the service
FirstGroupIndex The index of the first group spanned by this block
GroupCount The number of groups spanned
MaxDeviceInputBandwidthIn4KBitsPerSecondUnits Please see the USB MIDI 2.0 specification for the actual value for this field.
MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits Please see the USB MIDI 2.0 specification for the actual value for this field.
CalculatedMaxDeviceInputBandwidthBitsPerSecond Bits-per-second calculated value for the MaxDeviceInputBandwidthIn4KBitsPerSecondUnits property
CalculatedMaxDeviceOutputBandwidthBitsPerSecond Bits-per-second calculated value for the MaxDeviceOutputBandwidthIn4KBitsPerSecondUnits property

Functions

Function Description
IncludesGroup(group) Helper function which returns true if this function exists on the supplied group
AsEquivalentFunctionBlock() Helper function which returns a MidiFunctionBlock that is approximately equivalent to this MidiGroupTerminalBlock. This is to enable applications to be able to deal with only a single type of block when showing the metadata

IDL

MidiGroupTerminalBlock IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/README.html index 45b0b2e1..2c5fe7a4 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/metadata/README.html @@ -1 +1 @@ - Metadata | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Metadata

The Windows Service intercepts (but does not remove from the stream) Endpoint metadata notifications. For example, we’ll intercept Endpoint Name notifications and use those to provide a new endpoint-supplied name for the device. These are cached in the SWD properties for the Endpoint Device.

In addition to the endpoint data, we also capture and store block data. The block data should be used by applications to identify which groups are active and how to display them to the user. For example, you may want to display a function block name including group numbers like “Sequencer (Groups 1, 2, 3)” in a way similar to how you treated ports in the past.

Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint and so have their own discrete types.


Table of contents

\ No newline at end of file + Metadata | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Metadata

The Windows Service intercepts (but does not remove from the stream) Endpoint metadata notifications. For example, we’ll intercept Endpoint Name notifications and use those to provide a new endpoint-supplied name for the device. These are cached in the SWD properties for the Endpoint Device.

In addition to the endpoint data, we also capture and store block data. The block data should be used by applications to identify which groups are active and how to display them to the user. For example, you may want to display a function block name including group numbers like “Sequencer (Groups 1, 2, 3)” in a way similar to how you treated ports in the past.

Function Blocks and Group Terminal Blocks are important types of MIDI 2.0 metadata which describe an endpoint and so have their own discrete types.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html index 33424aae..55dd89c1 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/IMidiEndpointMessageProcessingPlugin.html @@ -1 +1 @@ - IMidiEndpointMessageProcessingPlugin | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

IMidiEndpointMessageProcessingPlugin

This interface is implemented by any type which can be an endpoint processing plugin in the client API. These plugins are used to process or manipulate messages coming from an endpoint.

Microsoft provides several plugins in the API, including the MidiVirtualEndpointDevice, the MidiChannelEndpointListener, and the MidiGroupEndpointListener. All of these types implement the IMidiEndpointMessageProcessingPlugin interface and operate in the same way.

The main part of message processing is the ProcessIncomingMessage callback.

Properties

Property Description
Id Generated GUID for this plugin instance. This is needed if you want to remove the plugin from the endpoint connection
Name Optional application-supplied name for this plugin instance.
Tag Optional application-supplied arbitrary data to associate with this plugin instance
IsEnabled True if the plugin is enabled and should participate in message processing

Functions

Function Description
Initialize(endpointConnection) Called by the endpoint connection. Perform any setup code which requires the endpoint connection pointer here.
OnEndpointConnectionOpened() Callback when the endpoint connection is opened. If the plugin is added after the endpoint connection has already been opened, this is called immediately.
ProcessIncomingMessage(args, skipFurtherListeners, skipMainMessageReceivedEvent) Callback for processing an incoming message. If the code sets skipFurtherListeners to true, any plugins after this one will not be called. If the code sets skipMainMessageReceivedEvent to true, the endpoint’s MessageReceived event will not be called for this message. Note: this callback is synchronous, so code in this should execute quickly and return immediately when complete.
Cleanup() Called when the endpoint is tearing down

IDL

IMidiEndpointMessageProcessingPlugin IDL

\ No newline at end of file + IMidiEndpointMessageProcessingPlugin | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

IMidiEndpointMessageProcessingPlugin

This interface is implemented by any type which can be an endpoint processing plugin in the client API. These plugins are used to process or manipulate messages coming from an endpoint.

Microsoft provides several plugins in the API, including the MidiVirtualEndpointDevice, the MidiChannelEndpointListener, and the MidiGroupEndpointListener. All of these types implement the IMidiEndpointMessageProcessingPlugin interface and operate in the same way.

The main part of message processing is the ProcessIncomingMessage callback.

Properties

Property Description
Id Generated GUID for this plugin instance. This is needed if you want to remove the plugin from the endpoint connection
Name Optional application-supplied name for this plugin instance.
Tag Optional application-supplied arbitrary data to associate with this plugin instance
IsEnabled True if the plugin is enabled and should participate in message processing

Functions

Function Description
Initialize(endpointConnection) Called by the endpoint connection. Perform any setup code which requires the endpoint connection pointer here.
OnEndpointConnectionOpened() Callback when the endpoint connection is opened. If the plugin is added after the endpoint connection has already been opened, this is called immediately.
ProcessIncomingMessage(args, skipFurtherListeners, skipMainMessageReceivedEvent) Callback for processing an incoming message. If the code sets skipFurtherListeners to true, any plugins after this one will not be called. If the code sets skipMainMessageReceivedEvent to true, the endpoint’s MessageReceived event will not be called for this message. Note: this callback is synchronous, so code in this should execute quickly and return immediately when complete.
Cleanup() Called when the endpoint is tearing down

IDL

IMidiEndpointMessageProcessingPlugin IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html index 1f817e2c..6e724c6e 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiChannelEndpointListener.html @@ -1 +1 @@ - MidiChannelEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiChannelEndpointListener

This class acts as a filter. Incoming messages with the specified group and channel will be provided through the MessageReceived event. Other messages will be ignored.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeGroup The MidiGroup that this listener will listen to.
IncludeChannels The channels that this listener will listen to on the group.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiChannelEndpointListener() Construct a new instance of this type

IDL

MidiChannelEndpointListener IDL

\ No newline at end of file + MidiChannelEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiChannelEndpointListener

This class acts as a filter. Incoming messages with the specified group and channel will be provided through the MessageReceived event. Other messages will be ignored.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeGroup The MidiGroup that this listener will listen to.
IncludeChannels The channels that this listener will listen to on the group.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiChannelEndpointListener() Construct a new instance of this type

IDL

MidiChannelEndpointListener IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html index e03592f4..0ee3c532 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiGroupEndpointListener.html @@ -1 +1 @@ - MidiGroupEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroupEndpointListener

This class acts as a filter. Incoming messages with the specified group will be provided through the MessageReceived event. Other messages will be ignored.

For a MIDI 1.0 device, where the ports (virtual MIDI cables) have been mapped to UMP groups, this class can provide the equivalent of a MIDI 1.0 port to an application, ignoring all other inputs and operating only on the included groups.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeGroups The list of MidiGroup numbers that this listener will listen to.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiGroupEndpointListener() Construct a new instance of this type

IDL

MidiGroupEndpointListener IDL

\ No newline at end of file + MidiGroupEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroupEndpointListener

This class acts as a filter. Incoming messages with the specified group will be provided through the MessageReceived event. Other messages will be ignored.

For a MIDI 1.0 device, where the ports (virtual MIDI cables) have been mapped to UMP groups, this class can provide the equivalent of a MIDI 1.0 port to an application, ignoring all other inputs and operating only on the included groups.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeGroups The list of MidiGroup numbers that this listener will listen to.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiGroupEndpointListener() Construct a new instance of this type

IDL

MidiGroupEndpointListener IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html index 9880c470..bc08d702 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/MidiMessageTypeEndpointListener.html @@ -1 +1 @@ - MidiMessageTypeEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageTypeEndpointListener

This class acts as a filter. Incoming messages with the specified message type will be provided through the MessageReceived event. Other messages will be ignored. In this way, the listener can be set up to, for example, only pay attention to MIDI 2.0 Channel Voice messages, leaving stream messages and System Exclusive by the wayside.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeMessageTypes The list of MidiMessageType values that this listener will listen to.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiGroupEndpointListener() Construct a new instance of this type

IDL

MidiMessageTypeEndpointListener IDL

\ No newline at end of file + MidiMessageTypeEndpointListener | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiMessageTypeEndpointListener

This class acts as a filter. Incoming messages with the specified message type will be provided through the MessageReceived event. Other messages will be ignored. In this way, the listener can be set up to, for example, only pay attention to MIDI 2.0 Channel Voice messages, leaving stream messages and System Exclusive by the wayside.

In addition to the properties and methods in IMidiEndpointMessageProcessingPlugin, and the MessageReceived event from IMidiMessageReceivedEventSource the class provides the following:

Properties

Property Description
IncludeMessageTypes The list of MidiMessageType values that this listener will listen to.
PreventCallingFurtherListeners True if this plugin should prevent further listeners from processing a message that is in-scope for this processor.
PreventFiringMainMessageReceivedEvent True if this plugin should prevent the endpoint’s MessageReceived event from firing if the message was in-scope for this plugin.

Functions

Property Description
MidiGroupEndpointListener() Construct a new instance of this type

IDL

MidiMessageTypeEndpointListener IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html index 885b308e..3d11a3c0 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/processing-plugins/README.html @@ -1 +1 @@ - Client Plugins | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Client-side Processing Plugins

Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage.

MIDI 1.0 had the concept of ports. Each port was just a single cable/jack from a MIDI stream exposed by the device. The API and driver were responsible for merging all of the different cables into the single stream for outgoing data, or pulling them apart for incoming data.

In MIDI 2.0, what used to be a Port is now morally equivalent to a Group address in the message data. Instead of speaking to N different enumerated entities for a device, the application speaks to a single bidirectional UMP endpoint which aggregates all of this information, much like the driver did behind the scenes in MIDI 1.0. We recognize that there are cases when the old model of MIDI Ports is more convenient for passing around in a DAW or similar app, particularly for incoming data.

To help, there are plugins which implement IMidiEndpointMessageProcessingPlugin. The API includes a few stock plugins, but developers are free to provide their own.

Listener instances are 1:1 with endpoint connections. We don’t support using the same listener on multiple endpoints.


Table of contents

\ No newline at end of file + Client Plugins | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Client-side Processing Plugins

Connections allocate service resources (time and memory), so we recommend applications maintain only a single connection to an endpoint within any session. But because the new endpoint stream-focused approach aggregates what used to be considered ports, we provide processing plugins to parcel out the incoming messages based on criteria set by the application. In this way, an application can have the logical equivalent of several input ports, without the associated resource usage.

MIDI 1.0 had the concept of ports. Each port was just a single cable/jack from a MIDI stream exposed by the device. The API and driver were responsible for merging all of the different cables into the single stream for outgoing data, or pulling them apart for incoming data.

In MIDI 2.0, what used to be a Port is now morally equivalent to a Group address in the message data. Instead of speaking to N different enumerated entities for a device, the application speaks to a single bidirectional UMP endpoint which aggregates all of this information, much like the driver did behind the scenes in MIDI 1.0. We recognize that there are cases when the old model of MIDI Ports is more convenient for passing around in a DAW or similar app, particularly for incoming data.

To help, there are plugins which implement IMidiEndpointMessageProcessingPlugin. The API includes a few stock plugins, but developers are free to provide their own.

Listener instances are 1:1 with endpoint connections. We don’t support using the same listener on multiple endpoints.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiService.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiService.html index 099ae831..56af8973 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiService.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiService.html @@ -1 +1 @@ - MidiService | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiService

The MidiService class contains a number of static functions which enable working with the service outside of a specific session.

Static Functions

Static Function Description
PingService(pingCount) Send one or more ping messages to the ping endpoint and report on the status and time. Return if the responses are not received in a calculated timeout period.
PingService(pingCount, timeoutMilliseconds) Send one or more ping messages to the ping endpoint and report on the status and time. Return if responses are not received in the specified timeout period.
GetInstalledTransportPlugins() Returns a list of MidiServiceTransportPluginInformation representing all service transport plugins (also called Abstractions)
GetInstalledMessageProcessingPlugins() Returns a list of MidiServiceMessageProcessingPluginInformation objects representing all service message processing plugins (also called Transforms)
GetActiveSessions() Returns a list of MidiSessionInformation detailing all active Windows MIDI Services sessions on this PC.
UpdateRuntimeConfiguration(configurationUpdate) Used by client-side SDK components for some transports and other plugins, and by the MIDI Settings app. The format of the data is dependent upon the target specified in the data. Use with caution. For more information, see the config JSON documentation

A note on the ping process

Pinging the Windows service uses the same mechanism as sending any UMP message. The actual message sent is a prioprietary message. (At the time this was created, there was no standard MIDI 2.0 UMP ping message). The message itself is sent to the diagnostics endpoint in the service, which is implemented like any other transport. Therefore, the speed of the pings here and the success of the ping process is a reasonable indicator of service, cross-process queue, and client API health.

The diagnostic ping endpoint does not understand any other type of message, and should not be used by applications other than through the ping functions here.

The ping does not tell you if a specific transport or device is in a bad state. For example, if a specific USB MIDI device has crashed, this ping message will still work because it is not sent out over USB.

Here’s an example of ping responses through the MIDI console app

MIDI Console Ping

A note on updating runtime configuration

In order to foster an open plugin ecosystem, we need a way to get settings and configuration for those plugins up to them in the Windows service. The way we’ve chosen to do that is JSON, because that same JSON, when not transient in nature, can also be saved into the permanent configuration file for the active MIDI setup.

The runtime configuration update should only be used by code which understands exactly what will be done with the data, and can handle the response which is returned. It is not a general API endpoint, but is designed for components which will extend Windows MIDI Services.

IDL

MidiService IDL

\ No newline at end of file + MidiService | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiService

The MidiService class contains a number of static functions which enable working with the service outside of a specific session.

Static Functions

Static Function Description
PingService(pingCount) Send one or more ping messages to the ping endpoint and report on the status and time. Return if the responses are not received in a calculated timeout period.
PingService(pingCount, timeoutMilliseconds) Send one or more ping messages to the ping endpoint and report on the status and time. Return if responses are not received in the specified timeout period.
GetInstalledTransportPlugins() Returns a list of MidiServiceTransportPluginInformation representing all service transport plugins (also called Abstractions)
GetInstalledMessageProcessingPlugins() Returns a list of MidiServiceMessageProcessingPluginInformation objects representing all service message processing plugins (also called Transforms)
GetActiveSessions() Returns a list of MidiSessionInformation detailing all active Windows MIDI Services sessions on this PC.
UpdateRuntimeConfiguration(configurationUpdate) Used by client-side SDK components for some transports and other plugins, and by the MIDI Settings app. The format of the data is dependent upon the target specified in the data. Use with caution. For more information, see the config JSON documentation

A note on the ping process

Pinging the Windows service uses the same mechanism as sending any UMP message. The actual message sent is a prioprietary message. (At the time this was created, there was no standard MIDI 2.0 UMP ping message). The message itself is sent to the diagnostics endpoint in the service, which is implemented like any other transport. Therefore, the speed of the pings here and the success of the ping process is a reasonable indicator of service, cross-process queue, and client API health.

The diagnostic ping endpoint does not understand any other type of message, and should not be used by applications other than through the ping functions here.

The ping does not tell you if a specific transport or device is in a bad state. For example, if a specific USB MIDI device has crashed, this ping message will still work because it is not sent out over USB.

Here’s an example of ping responses through the MIDI console app

MIDI Console Ping

A note on updating runtime configuration

In order to foster an open plugin ecosystem, we need a way to get settings and configuration for those plugins up to them in the Windows service. The way we’ve chosen to do that is JSON, because that same JSON, when not transient in nature, can also be saved into the permanent configuration file for the active MIDI setup.

The runtime configuration update should only be used by code which understands exactly what will be done with the data, and can handle the response which is returned. It is not a general API endpoint, but is designed for components which will extend Windows MIDI Services.

IDL

MidiService IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html index ac344e0f..e0c362ad 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceMessageProcessingPluginInformation.html @@ -1 +1 @@ - MidiServiceMessageProcessingPluginInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServiceMessageProcessingPluginInformation

(section in progress)

IDL

MidiSessionMidiServiceMessageProcessingPluginInformationInformation IDL

\ No newline at end of file + MidiServiceMessageProcessingPluginInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServiceMessageProcessingPluginInformation

(section in progress)

IDL

MidiSessionMidiServiceMessageProcessingPluginInformationInformation IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html index 4f8fa2af..3df0f2c8 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponse.html @@ -1 +1 @@ - MidiServicePingResponse | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServicePingResponse

This class represents a single ping message response. This is used to assess health and performance of the Windows service.

Static Functions

Property Description
SourceId Id used to track this ping source connection instance, in the case of multiple applications using the same ping endpoint
Index Index of the ping
ClientSendMidiTimestamp The time the client sent the ping message
ServiceReportedMidiTimestamp The time the service reported receiving the ping message
ClientReceiveMidiTimestamp The time the client received the ping response
ClientDeltaTimestamp The delta between the client sending the message and receiving the response

IDL

MidiServicePingResponse IDL

\ No newline at end of file + MidiServicePingResponse | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServicePingResponse

This class represents a single ping message response. This is used to assess health and performance of the Windows service.

Static Functions

Property Description
SourceId Id used to track this ping source connection instance, in the case of multiple applications using the same ping endpoint
Index Index of the ping
ClientSendMidiTimestamp The time the client sent the ping message
ServiceReportedMidiTimestamp The time the service reported receiving the ping message
ClientReceiveMidiTimestamp The time the client received the ping response
ClientDeltaTimestamp The delta between the client sending the message and receiving the response

IDL

MidiServicePingResponse IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html index baeff190..29c50cf3 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServicePingResponseSummary.html @@ -1 +1 @@ - MidiServicePingResponseSummary | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServicePingResponseSummary

This class represents a summary of the ping attempts against the Windows service.

Static Functions

Property Description
Success True if the ping was a success
FailureReason In case of a failure, this includes information about why the failure happened.
TotalPingRoundTripMidiClock The total MIDI Clock time for all ping messages to be sent and received
AveragePingRoundTripMidiClock Calculated average round trip time for ping messages
Responses A list of all the responses for the ping messages

IDL

MidiServicePingResponseSummary IDL

\ No newline at end of file + MidiServicePingResponseSummary | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServicePingResponseSummary

This class represents a summary of the ping attempts against the Windows service.

Static Functions

Property Description
Success True if the ping was a success
FailureReason In case of a failure, this includes information about why the failure happened.
TotalPingRoundTripMidiClock The total MIDI Clock time for all ping messages to be sent and received
AveragePingRoundTripMidiClock Calculated average round trip time for ping messages
Responses A list of all the responses for the ping messages

IDL

MidiServicePingResponseSummary IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html index 130e0a08..a99436c8 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiServiceTransportPluginInformation.html @@ -1 +1 @@ - MidiServiceTransportPluginInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServiceTransportPluginInformation

(section in progress)

IDL

MidiServiceTransportPluginInformation IDL

\ No newline at end of file + MidiServiceTransportPluginInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiServiceTransportPluginInformation

(section in progress)

IDL

MidiServiceTransportPluginInformation IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html index 1aac2564..95299009 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionConnectionInformation.html @@ -1 +1 @@ - MidiSessionConnectionInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSessionConnectionInformation

This class represents an open connection in a Windows MIDI Services session. This is an informational class only for reporting system-wide connection usage.

Static Functions

Property Description
EndpointDeviceId The endpoint device id for the connection
InstanceCount The number of instances of this connection which are open in the parent session
EarliestConnectionTime The date and time the first instance of the connection was opened

IDL

MidiSessionConnectionInformation IDL

\ No newline at end of file + MidiSessionConnectionInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSessionConnectionInformation

This class represents an open connection in a Windows MIDI Services session. This is an informational class only for reporting system-wide connection usage.

Static Functions

Property Description
EndpointDeviceId The endpoint device id for the connection
InstanceCount The number of instances of this connection which are open in the parent session
EarliestConnectionTime The date and time the first instance of the connection was opened

IDL

MidiSessionConnectionInformation IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html index 2f849d52..50382a3c 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/MidiSessionInformation.html @@ -1 +1 @@ - MidiSessionInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSessionInformation

This class represents an open Windows MIDI Services session.

Static Functions

Property Description
SessionId The generated internal GUID for the session
ProcessId The process id for the session
ProcessName The process name for the session, captured when the session was created
SessionName The name of the session provided through the API
StartTime The date and time the session was created
Connections A list of MidiSessionConnectionInformation objects detailing the connections currently open for this session

Example

The Windows MIDI Services Console app uses the MidiSessionInformation MidiSessionConnectionInformation and the MidiService class to display active sessions.

Console midi enum sessions

In this case, you can see three open sessions. The process name and process id are on the left. The session name is in the text on the right, after the word “Session”, and the start time is the date and time in green. Finally, the list of connections for each session is underneath the session information.

IDL

MidiSessionInformation IDL

\ No newline at end of file + MidiSessionInformation | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSessionInformation

This class represents an open Windows MIDI Services session.

Static Functions

Property Description
SessionId The generated internal GUID for the session
ProcessId The process id for the session
ProcessName The process name for the session, captured when the session was created
SessionName The name of the session provided through the API
StartTime The date and time the session was created
Connections A list of MidiSessionConnectionInformation objects detailing the connections currently open for this session

Example

The Windows MIDI Services Console app uses the MidiSessionInformation MidiSessionConnectionInformation and the MidiService class to display active sessions.

Console midi enum sessions

In this case, you can see three open sessions. The process name and process id are on the left. The session name is in the text on the right, after the word “Session”, and the start time is the date and time in green. Finally, the list of connections for each session is underneath the session information.

IDL

MidiSessionInformation IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/service/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/service/README.html index b1373c54..d2e67b6e 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/service/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/service/README.html @@ -1 +1 @@ - Service | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Service

The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service.


Table of contents

\ No newline at end of file + Service | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Service

The MidiService class is a utility class which provides access to health and status information related to the MidiSrv Service.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSession.html b/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSession.html index e95aa00c..3abb1c02 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSession.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSession.html @@ -1,4 +1,4 @@ - MidiSession | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSession

Before you can connect to an endpoint, you must start a new MIDI session.

An application may have any number of sessions open. For example, the application may open one session per open project, or one session per tab in the case of a browser. The lifetime of endpoint connections opened through a session are controlled through the session.

Properties

Property Description
Id Generated Id for the session
Name Name for this session. To change the name after creating the session, use the UpdateName() function. This will update the service
Settings The settings used to create this session
IsOpen True if this session is open and ready to use
Connections Map of all endpoint connections created through this session. Disconnecting an endpoint using DisconnectEndpointConnection will remove the connection from this map. The map key is the generated connection GUID that identifies an instance of an endpoint connection

Static Member Functions

The two static functions are factory-pattern methods for creating a new session.

Static Function Description
CreateSession(sessionName) Create and return a new session with the specified name
CreateSession(sessionName, settings) Create and return a new session with the specified name and settings

Functions

Function Description
CreateEndpointConnection(endpointDeviceId) Create a new connection to the specified endpoint device Id
CreateEndpointConnection(endpointDeviceId, options) Create a new connection to the specified endpoint device Id, using the provided connection options
CreateEndpointConnection(endpointDeviceId, options, settings) Create a new connection to the specified endpoint device Id, using the provided connection options and the endpoint-specific settings
CreateVirtualDeviceAndConnection(deviceDefinition) Create the device-side of an app-to-app virtual endpoint. The calling application will perform as a MIDI device, responding to discovery and other MIDI 2.0 protocol messages.
DisconnectEndpointConnection(endpointConnectionId) Cleanly disconnect an endpoint connection and remove it from the connection map
UpdateName(newName) Update the name of this session locally and in the MIDI Service

Note: If you manually close a MidiEndpointConnection using IClosable (or IDisposable), it will not be removed from the MidiSession’s collection of endpoints. Instead, use the DisconnectEndpointConnection method of the session to keep both in sync. For that reason, we do not recommend that you wrap the CreateEndpointConnection calls in a using statement.

IDL

MidiSession IDL

Sample

using (var session = MidiSession.CreateSession("API Sample Session"))
+            MidiSession | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiSession

Before you can connect to an endpoint, you must start a new MIDI session.

An application may have any number of sessions open. For example, the application may open one session per open project, or one session per tab in the case of a browser. The lifetime of endpoint connections opened through a session are controlled through the session.

Properties

Property Description
Id Generated Id for the session
Name Name for this session. To change the name after creating the session, use the UpdateName() function. This will update the service
Settings The settings used to create this session
IsOpen True if this session is open and ready to use
Connections Map of all endpoint connections created through this session. Disconnecting an endpoint using DisconnectEndpointConnection will remove the connection from this map. The map key is the generated connection GUID that identifies an instance of an endpoint connection

Static Member Functions

The two static functions are factory-pattern methods for creating a new session.

Static Function Description
CreateSession(sessionName) Create and return a new session with the specified name
CreateSession(sessionName, settings) Create and return a new session with the specified name and settings

Functions

Function Description
CreateEndpointConnection(endpointDeviceId) Create a new connection to the specified endpoint device Id
CreateEndpointConnection(endpointDeviceId, options) Create a new connection to the specified endpoint device Id, using the provided connection options
CreateEndpointConnection(endpointDeviceId, options, settings) Create a new connection to the specified endpoint device Id, using the provided connection options and the endpoint-specific settings
CreateVirtualDeviceAndConnection(deviceDefinition) Create the device-side of an app-to-app virtual endpoint. The calling application will perform as a MIDI device, responding to discovery and other MIDI 2.0 protocol messages.
DisconnectEndpointConnection(endpointConnectionId) Cleanly disconnect an endpoint connection and remove it from the connection map
UpdateName(newName) Update the name of this session locally and in the MIDI Service

Note: If you manually close a MidiEndpointConnection using IClosable (or IDisposable), it will not be removed from the MidiSession’s collection of endpoints. Instead, use the DisconnectEndpointConnection method of the session to keep both in sync. For that reason, we do not recommend that you wrap the CreateEndpointConnection calls in a using statement.

IDL

MidiSession IDL

Sample

using (var session = MidiSession.CreateSession("API Sample Session"))
 {
     ...
 }
diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html b/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html
index 29ed67b4..8ccf9ffa 100644
--- a/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html
+++ b/docs/_site/developer-docs/Windows.Devices.Midi2/session/MidiSessionSettings.html
@@ -1 +1 @@
-            MidiSessionSettings | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MidiSessionSettings

MidiSessionSettings are currently unused. We are evaluating keeping this in the API.

IDL

MidiSessionSettings IDL

\ No newline at end of file + MidiSessionSettings | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiSessionSettings

MidiSessionSettings are currently unused. We are evaluating keeping this in the API.

IDL

MidiSessionSettings IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/session/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/session/README.html index 76995d32..319e16e5 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/session/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/session/README.html @@ -1 +1 @@ - Session | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Session

Interaction with a MIDI Endpoint always starts with creating a session.


Table of contents

\ No newline at end of file + Session | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Session

Interaction with a MIDI Endpoint always starts with creating a session.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html index ecf3336e..23e4fcbf 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiChannel.html @@ -1 +1 @@ - MidiChannel | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiChannel

The MidiChannel class is used to provide formatting and data validation for MIDI 1.0 and MIDI 2.0 channels.

Properties

Property Description
Index The data value, or channel Index (0-15)
NumberForDisplay The number that should be displayed in any UI. (1-16)

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation. For example, “Ch” in English.
LabelFull Returns the localized full name. For example, “Channel” in English.

Functions

Function Description
MidiChannel() Constructs an empty MidiChannel
MidiChannel(index) Constructs a MidiChannel with the specified index

Static Functions

Static Function Description
IsValidChannelIndex(index) Verifies that the provided index is valid (between 0 and 15)

MidiChannel IDL

\ No newline at end of file + MidiChannel | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiChannel

The MidiChannel class is used to provide formatting and data validation for MIDI 1.0 and MIDI 2.0 channels.

Properties

Property Description
Index The data value, or channel Index (0-15)
NumberForDisplay The number that should be displayed in any UI. (1-16)

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation. For example, “Ch” in English.
LabelFull Returns the localized full name. For example, “Channel” in English.

Functions

Function Description
MidiChannel() Constructs an empty MidiChannel
MidiChannel(index) Constructs a MidiChannel with the specified index

Static Functions

Static Function Description
IsValidChannelIndex(index) Verifies that the provided index is valid (between 0 and 15)

MidiChannel IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html index a5a5490d..19876d90 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiGroup.html @@ -1 +1 @@ - MidiGroup | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroup

The MidiGroup class is used to provide formatting and data validation for UMP (Universal MIDI Packet) groups.

Properties

Property Description
Index The data value, or group Index (0-15)
NumberForDisplay The number that should be displayed in any UI. (1-16)

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation. For example, “Gr” in English.
LabelFull Returns the localized full name. For example, “Group” in English.

Functions

Function Description
MidiGroup() Constructs an empty MidiGroup
MidiGroup(index) Constructs a MidiGroup with the specified index

Static Functions

Static Function Description
IsValidGroupIndex(index) Verifies that the provided index is valid (between 0 and 15)

MidiGroup IDL

\ No newline at end of file + MidiGroup | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiGroup

The MidiGroup class is used to provide formatting and data validation for UMP (Universal MIDI Packet) groups.

Properties

Property Description
Index The data value, or group Index (0-15)
NumberForDisplay The number that should be displayed in any UI. (1-16)

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation. For example, “Gr” in English.
LabelFull Returns the localized full name. For example, “Group” in English.

Functions

Function Description
MidiGroup() Constructs an empty MidiGroup
MidiGroup(index) Constructs a MidiGroup with the specified index

Static Functions

Static Function Description
IsValidGroupIndex(index) Verifies that the provided index is valid (between 0 and 15)

MidiGroup IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html index 1c360eec..a6bbbe5c 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/MidiUniqueId.html @@ -1 +1 @@ - MidiUniqueId | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiUniqueId

The MidiUniqueId class is used to provide formatting and data validation for MIDI-CI MUID types used in Function Blocks and MIDI CI transactions.

In the specification, Byte1 is the LSB and Byte4 is the MSB. We follow that convention here.

Properties

Property Description
Byte1 The data value for byte 1 of the MUID
Byte2 The data value for byte 2 of the MUID
Byte3 The data value for byte 3 of the MUID
Byte4 The data value for byte 4 of the MUID
As28BitInteger The data value converted to a 28 bit integer
IsBroadcast True if this is the broadcast MUID value
IsReserved True if this is the reserved MUID value

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation.
LabelFull Returns the localized full name.

Functions

Function Description
MidiUniqueId() Constructs an empty MidiUniqueId
MidiUniqueId(integer28bit) Constructs the MidiUniqueId from the given 28 bit integer
MidiUniqueId(byte1, byte2, byte3, byte4) Constructs a MidiUniqueId with the specified bytes

Static Functions

Function Description
CreateBroadcast() Constructs a broadcast MidiUniqueId
CreateRandom() Constructs a random MidiUniqueId

MidiUniqueId IDL

\ No newline at end of file + MidiUniqueId | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiUniqueId

The MidiUniqueId class is used to provide formatting and data validation for MIDI-CI MUID types used in Function Blocks and MIDI CI transactions.

In the specification, Byte1 is the LSB and Byte4 is the MSB. We follow that convention here.

Properties

Property Description
Byte1 The data value for byte 1 of the MUID
Byte2 The data value for byte 2 of the MUID
Byte3 The data value for byte 3 of the MUID
Byte4 The data value for byte 4 of the MUID
As28BitInteger The data value converted to a 28 bit integer
IsBroadcast True if this is the broadcast MUID value
IsReserved True if this is the reserved MUID value

Static Properties

Static Property Description
LabelShort Returns the localized abbreviation.
LabelFull Returns the localized full name.

Functions

Function Description
MidiUniqueId() Constructs an empty MidiUniqueId
MidiUniqueId(integer28bit) Constructs the MidiUniqueId from the given 28 bit integer
MidiUniqueId(byte1, byte2, byte3, byte4) Constructs a MidiUniqueId with the specified bytes

Static Functions

Function Description
CreateBroadcast() Constructs a broadcast MidiUniqueId
CreateRandom() Constructs a random MidiUniqueId

MidiUniqueId IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/README.html index 35ac239a..54b3aabd 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/simple-types/README.html @@ -1 +1 @@ - Simple Types | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Simple Types

There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways.


Table of contents

\ No newline at end of file + Simple Types | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Simple Types

There are several simple or basic types used in Windows MIDI Services. These types provide formatting and validation to help ensure applications display data in similar ways.


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html index 6c38af14..e8e2ca25 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiStreamConfigurationRequestReceivedEventArgs.html @@ -1 +1 @@ - MidiStreamConfigurationRequestReceivedEventArgs | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiStreamConfigurationRequestReceivedEventArgs

(in development)

IDL

MidiStreamConfigurationRequestReceivedEventArgs IDL

\ No newline at end of file + MidiStreamConfigurationRequestReceivedEventArgs | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiStreamConfigurationRequestReceivedEventArgs

(in development)

IDL

MidiStreamConfigurationRequestReceivedEventArgs IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html index d1ecb436..d46b3b2a 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDevice.html @@ -1 +1 @@ - MidiVirtualEndpointDevice | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiVirtualEndpointDevice

The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint.

Properties

Property Description
DeviceDefinition The MidiVirtualEndpointDeviceDefinition used to create this device. This should be treated as read-only data.
FunctionBlocks Current list of function blocks for this device.
SuppressHandledMessages True if the protocol messages handled by this class should be filtered out of the incoming message stream

Functions

Function Description
UpdateFunctionBlock Update the properties of a single function block. The number of actual function blocks cannot change after creation (per the UMP specification) but blocks may be marked as active or inactive. Changes here will result in the MIDI 2.0 function block notification messages being sent out.
UpdateEndpointName Update the endpoint name, and send out the appropriate endpoint name notification messages.

Events

Event Description
StreamConfigurationRequestReceived(device, args) Raised when this device receives a Stream Configuration Request UMP message.

IDL

MidiVirtualEndpointDevice IDL

\ No newline at end of file + MidiVirtualEndpointDevice | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiVirtualEndpointDevice

The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint.

Properties

Property Description
DeviceDefinition The MidiVirtualEndpointDeviceDefinition used to create this device. This should be treated as read-only data.
FunctionBlocks Current list of function blocks for this device.
SuppressHandledMessages True if the protocol messages handled by this class should be filtered out of the incoming message stream

Functions

Function Description
UpdateFunctionBlock Update the properties of a single function block. The number of actual function blocks cannot change after creation (per the UMP specification) but blocks may be marked as active or inactive. Changes here will result in the MIDI 2.0 function block notification messages being sent out.
UpdateEndpointName Update the endpoint name, and send out the appropriate endpoint name notification messages.

Events

Event Description
StreamConfigurationRequestReceived(device, args) Raised when this device receives a Stream Configuration Request UMP message.

IDL

MidiVirtualEndpointDevice IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html index a647fab8..9b43d66f 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.html @@ -1 +1 @@ - MidiVirtualEndpointDeviceDefinition | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiVirtualEndpointDeviceDefinition

The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint.

Properties

Property Description
EndpointName Name of the endpoint used for both the device enumeration and for responding to the endpoint name request UMP message
EndpointProductInstanceId The unique identifier for this device. This value is used when creating the device Id, and is also used as the response for endpoint discovery when the id is requested. In general, this value should be kept to less than 32 characters and not include any special characters or symbols
SupportsMidi1ProtocolMessages For endpoint discovery. True if this endpoint supports MIDI 1.0 protocol messages over UMP
SupportsMidi2ProtocolMessages For endpoint discovery. True if this endpoint supports MIDI 2.0 protocol messages over UMP
SupportsReceivingJRTimestamps For endpoint discovery. True if this endpoint supports recieving JR timestamps (typically, you’ll want to set this to false)
SupportsSendingJRTimestamps For endpoint discovery. True if this endpoint supports sending JR timestamps (typically, you’ll want to set this to false)
DeviceManufacturerSystemExclusiveId MIDI 2.0 UMP Device Identity value
DeviceFamilyLsb MIDI 2.0 UMP Device Identity value
DeviceFamilyMsb MIDI 2.0 UMP Device Identity value
DeviceFamilyModelLsb MIDI 2.0 UMP Device Identity value
DeviceFamilyModelMsb MIDI 2.0 UMP Device Identity value
SoftwareRevisionLevel MIDI 2.0 UMP Device Identity value
AreFunctionBlocksStatic True if the function blocks will not change in any way
FunctionBlocks list of function blocks for this device

Functions

Function Description
MidiVirtualEndpointDeviceDefinition() Construct a new device definition

IDL

MidiVirtualEndpointDeviceDefinition IDL

\ No newline at end of file + MidiVirtualEndpointDeviceDefinition | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

MidiVirtualEndpointDeviceDefinition

The MidiVirtualEndpointDeviceDefinition class specifies, in an easy to use format, the responses for discovery and protocol negotiation, as well as the properties to use when constructing the device endpoint.

Properties

Property Description
EndpointName Name of the endpoint used for both the device enumeration and for responding to the endpoint name request UMP message
EndpointProductInstanceId The unique identifier for this device. This value is used when creating the device Id, and is also used as the response for endpoint discovery when the id is requested. In general, this value should be kept to less than 32 characters and not include any special characters or symbols
SupportsMidi1ProtocolMessages For endpoint discovery. True if this endpoint supports MIDI 1.0 protocol messages over UMP
SupportsMidi2ProtocolMessages For endpoint discovery. True if this endpoint supports MIDI 2.0 protocol messages over UMP
SupportsReceivingJRTimestamps For endpoint discovery. True if this endpoint supports recieving JR timestamps (typically, you’ll want to set this to false)
SupportsSendingJRTimestamps For endpoint discovery. True if this endpoint supports sending JR timestamps (typically, you’ll want to set this to false)
DeviceManufacturerSystemExclusiveId MIDI 2.0 UMP Device Identity value
DeviceFamilyLsb MIDI 2.0 UMP Device Identity value
DeviceFamilyMsb MIDI 2.0 UMP Device Identity value
DeviceFamilyModelLsb MIDI 2.0 UMP Device Identity value
DeviceFamilyModelMsb MIDI 2.0 UMP Device Identity value
SoftwareRevisionLevel MIDI 2.0 UMP Device Identity value
AreFunctionBlocksStatic True if the function blocks will not change in any way
FunctionBlocks list of function blocks for this device

Functions

Function Description
MidiVirtualEndpointDeviceDefinition() Construct a new device definition

IDL

MidiVirtualEndpointDeviceDefinition IDL

\ No newline at end of file diff --git a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/README.html b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/README.html index 8d0c2515..365fca62 100644 --- a/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/README.html +++ b/docs/_site/developer-docs/Windows.Devices.Midi2/virtual-device/README.html @@ -1 +1 @@ - Virtual Devices | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Virtual Devices

Fully-featured app-to-app MIDI in a MIDI 2.0 world involves connections to a virtual device which must participate in the full MIDI 2.0 protocol, from discovery through protocol negotiation. To support this scenario, the way app-to-app MIDI works in Windows MIDI Services is for an application to define a device and then using the MidiSession, construct that device’s endpoint. Once the device endpoint is opened, Windows MIDI Services will then construct a second application-visible multi-client endpoint which applications will use to talk to the device app.

During that conversation, the service will also handle discovery and protocol negotiation with the virtual device just like it would any physical device.

In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin


Table of contents

\ No newline at end of file + Virtual Devices | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Virtual Devices

Fully-featured app-to-app MIDI in a MIDI 2.0 world involves connections to a virtual device which must participate in the full MIDI 2.0 protocol, from discovery through protocol negotiation. To support this scenario, the way app-to-app MIDI works in Windows MIDI Services is for an application to define a device and then using the MidiSession, construct that device’s endpoint. Once the device endpoint is opened, Windows MIDI Services will then construct a second application-visible multi-client endpoint which applications will use to talk to the device app.

During that conversation, the service will also handle discovery and protocol negotiation with the virtual device just like it would any physical device.

In addition to the service component, it is implemented in the client API as a type of Client-SIde Processing Plugin


Table of contents

\ No newline at end of file diff --git a/docs/_site/developer-docs/best-practices.html b/docs/_site/developer-docs/best-practices.html index 4f8c6b1a..a3a43d67 100644 --- a/docs/_site/developer-docs/best-practices.html +++ b/docs/_site/developer-docs/best-practices.html @@ -1,4 +1,4 @@ - Best Practices | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Best Practices and Performance Optimizations

Here’s a list of best practices and performance optimizations for MIDI API-consuming applications.

Fast transmission of messages

For maximum compatibility across languages, and for safety, WinRT doesn’t allow pointers to be exposed by any properties or as parameters or return types for any function. In addition, the by-value and by-reference semantics for parameters are not always under the control of the API developer.

For those reasons, and to maximize ease of use across a number of languages and use-cases, we have multiple ways to send and receive messages.

You will want to do your own performance testing from your application and scenarios, but in general, the send/receives with the least overhead are those which send/receive individual 32 bit words, a single 128 bit structure, or the IMemoryBuffer. The word and struct methods do pass copies of data, but the amount of data, for most time critical messages, is still 64 bits or less (MIDI 1.0 channel voice messages are 32 bits, MIDI 2.0 channel voice messages are 64 bits).

The IMemoryBuffer approach is a more advanced way to transfer data to and from the API. This wraps a buffer of data which you can reuse between calls, including send/receive, as long as you manage and avoid any potential overlaps. Internally, the COM types used to access this ensures that only pointers are passed into the API. There’s a bit more ceremony to using this approach, so we recommend investing time there only if it better fits your app’s programming model. In addition, because IMemoryBuffer deals with bytes and not 32 bit words, you need to ensure you are correctly copying the data in, following the endianness rules for our internal MIDI 2.0 data representation.

The most flexible, but least performant approach, is to use the IMidiMessage interface and the methods which return strongly typed messages. These do involve additional type allocations either on the part of the caller or in the API code.

Data copies

In the underlying implementation, copying of data is unavoidable in places. Here are the main places where it happens.

When sending messages

  1. The individual WinRT projection for your language may enforce a copy or translation of the data going into the API. This varies. Arrays, in particular, vary here.
  2. The API copies the data (typically a memcpy), regardless of how it is provided, into the cross-process queue for that client endpoint connection. This is shared cross-process memory on Windows. It’s also a circular queue, so we can’t hold onto pointers for long, which is why 4 below operates how it does.
  3. On the service side, the pointers into the buffer are provided to the client connection and the plugins in that chain. No copying here.
  4. There will be copies of the data created if there are any processing plugins which must significantly manipulate the data (each plugin decides how it deals with the data), or if you schedule the message to be sent in the future (see 2 above).
  5. Finally, the messages may be copied when being supplied to the transport. In the case of USB, we make a call into a kernel driver, so have another cross process queue for that which requires we copy data into it to supply it to the driver. In the case of networking, we have to copy the data into the network buffers and transmit. In app-to-app / virtual MIDI, and also the built-in loopback endpoints, we typically just send the same message pointers through the entire process and do not copy any data in the transport.

This code is all quite efficient, and the amount of data in a single message is small, so these happen quite quickly. Nevertheless, we’re always looking at places where we can further optimize, but still retain the flexibility provided by having a Windows Service which processes the messages.

When receiving messages, the process is almost exactly the opposite of sending. There’s no in-bound message scheduling, but there may be data transformations that plugins perform. In addition, endpoints with multiple clients connected do require fanning out those messages into multiple queues, resulting in multiple copies across the different cross-process inbound client connection queues. That is a small price to pay for full multi-client MIDI support.

Displaying connections to your app users

Most apps need to display device and endpoint connection information to their users. Here are some details related to that.

Use the MidiEndpointDeviceWatcher to respond to device changes

MIDI devices come and go based on connecting/disconnecting USB cables, or new network endpoints coming online. In addition, properties like Function Blocks and Endpoint Name are subject to change at any time. Use the MidiEndpointDeviceWatcher class on a background thread to monitor these endpoints, and receive notifications when anything changes. This is a much more robust approach vs simply enumerating a snapshot of devices up-front.

There’s no API or service reason to require a customer to reboot or reload a MIDI DAW or other application to see newly added endpoints.

Don’t include diagnostics endpoints for most apps

Unless the app is a utility / testing app, we recommend you do not display the UMP Loopback Endpoints to the user. These are for diagnostics and testing only. By default, they are excluded during enumeration.

Enable drill-down into Groups (functions)

A single function block may exist on multiple groups, and multiple groups may overlap function blocks. That is the nature of the MIDI 2.0 specification. In most cases, you’ll find that a function is associated with one or more groups and those groups do not span other function blocks.

We recommend that, when displaying a connection to the user, you connect them to the UMP Endpoint, but then enable some sort of drill-down to show the function block names and their associated groups.

SynthCompany Foo Synth 5
+            Best Practices | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Best Practices and Performance Optimizations

Here’s a list of best practices and performance optimizations for MIDI API-consuming applications.

Fast transmission of messages

For maximum compatibility across languages, and for safety, WinRT doesn’t allow pointers to be exposed by any properties or as parameters or return types for any function. In addition, the by-value and by-reference semantics for parameters are not always under the control of the API developer.

For those reasons, and to maximize ease of use across a number of languages and use-cases, we have multiple ways to send and receive messages.

You will want to do your own performance testing from your application and scenarios, but in general, the send/receives with the least overhead are those which send/receive individual 32 bit words, a single 128 bit structure, or the IMemoryBuffer. The word and struct methods do pass copies of data, but the amount of data, for most time critical messages, is still 64 bits or less (MIDI 1.0 channel voice messages are 32 bits, MIDI 2.0 channel voice messages are 64 bits).

The IMemoryBuffer approach is a more advanced way to transfer data to and from the API. This wraps a buffer of data which you can reuse between calls, including send/receive, as long as you manage and avoid any potential overlaps. Internally, the COM types used to access this ensures that only pointers are passed into the API. There’s a bit more ceremony to using this approach, so we recommend investing time there only if it better fits your app’s programming model. In addition, because IMemoryBuffer deals with bytes and not 32 bit words, you need to ensure you are correctly copying the data in, following the endianness rules for our internal MIDI 2.0 data representation.

The most flexible, but least performant approach, is to use the IMidiMessage interface and the methods which return strongly typed messages. These do involve additional type allocations either on the part of the caller or in the API code.

Data copies

In the underlying implementation, copying of data is unavoidable in places. Here are the main places where it happens.

When sending messages

  1. The individual WinRT projection for your language may enforce a copy or translation of the data going into the API. This varies. Arrays, in particular, vary here.
  2. The API copies the data (typically a memcpy), regardless of how it is provided, into the cross-process queue for that client endpoint connection. This is shared cross-process memory on Windows. It’s also a circular queue, so we can’t hold onto pointers for long, which is why 4 below operates how it does.
  3. On the service side, the pointers into the buffer are provided to the client connection and the plugins in that chain. No copying here.
  4. There will be copies of the data created if there are any processing plugins which must significantly manipulate the data (each plugin decides how it deals with the data), or if you schedule the message to be sent in the future (see 2 above).
  5. Finally, the messages may be copied when being supplied to the transport. In the case of USB, we make a call into a kernel driver, so have another cross process queue for that which requires we copy data into it to supply it to the driver. In the case of networking, we have to copy the data into the network buffers and transmit. In app-to-app / virtual MIDI, and also the built-in loopback endpoints, we typically just send the same message pointers through the entire process and do not copy any data in the transport.

This code is all quite efficient, and the amount of data in a single message is small, so these happen quite quickly. Nevertheless, we’re always looking at places where we can further optimize, but still retain the flexibility provided by having a Windows Service which processes the messages.

When receiving messages, the process is almost exactly the opposite of sending. There’s no in-bound message scheduling, but there may be data transformations that plugins perform. In addition, endpoints with multiple clients connected do require fanning out those messages into multiple queues, resulting in multiple copies across the different cross-process inbound client connection queues. That is a small price to pay for full multi-client MIDI support.

Displaying connections to your app users

Most apps need to display device and endpoint connection information to their users. Here are some details related to that.

Use the MidiEndpointDeviceWatcher to respond to device changes

MIDI devices come and go based on connecting/disconnecting USB cables, or new network endpoints coming online. In addition, properties like Function Blocks and Endpoint Name are subject to change at any time. Use the MidiEndpointDeviceWatcher class on a background thread to monitor these endpoints, and receive notifications when anything changes. This is a much more robust approach vs simply enumerating a snapshot of devices up-front.

There’s no API or service reason to require a customer to reboot or reload a MIDI DAW or other application to see newly added endpoints.

Don’t include diagnostics endpoints for most apps

Unless the app is a utility / testing app, we recommend you do not display the UMP Loopback Endpoints to the user. These are for diagnostics and testing only. By default, they are excluded during enumeration.

Enable drill-down into Groups (functions)

A single function block may exist on multiple groups, and multiple groups may overlap function blocks. That is the nature of the MIDI 2.0 specification. In most cases, you’ll find that a function is associated with one or more groups and those groups do not span other function blocks.

We recommend that, when displaying a connection to the user, you connect them to the UMP Endpoint, but then enable some sort of drill-down to show the function block names and their associated groups.

SynthCompany Foo Synth 5
 - Synthesizer (Groups 1, 2, 3)
 - Sequencer (Groups 4, 5)
 - MIDI DIN Out (Group 6)
diff --git a/docs/_site/developer-docs/consuming-midi-api.html b/docs/_site/developer-docs/consuming-midi-api.html
index db2d680c..970567c6 100644
--- a/docs/_site/developer-docs/consuming-midi-api.html
+++ b/docs/_site/developer-docs/consuming-midi-api.html
@@ -1,4 +1,4 @@
-            Consuming the MIDI API | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Consuming the Windows MIDI Services API

The Windows MIDI Services API is built using C++/WinRT. WinRT, a requirement for modern APIs on Windows, enables desktop applications, regardless of language, to be able to use APIs, SDKs, etc. that we create. The older tools, C++/CX, are arguably simpler to implement in, but because they include proprietary extensions to C++, we decided to go with standards-based C++/WinRT instead.

Prerequisites

To use the API, your application language and tools must be able to work with WinRT metadata and libraries, or the generated projection header file.

  • Visual Studio 2022+ if you are using Visual Studio
  • Windows SDK 10.0.20348 (Install with Visual Studio)
  • Windows 10 22H2, or preferably, the latest version of Windows 11. Our development machines are all running Windows 11.
  • C++ 17 (C++ 20 may work, C++ 14 will not)
  • The NuGet package(s) from the release

Note that there are somewhat hacky ways to get traditional C to work with the COM interfaces, but it is a ton of work for you, and is not a scenario we support. If you find yourself in that situation, I recommend factoring out the MIDI code into its own lib and encapsulating all the C++ calls in there.

NOTE: In the period of time before Windows MIDI Services ships in Windows, you will also need to run the latest Windows 11 Insider Canary build of Windows in order to be able to use the USB MIDI 2.0 driver. Click here to learn more and join the Windows Insider Program.

CPU Architecture: The public GitHub releases currently support Intel/AMD x64 only. Our internal builds and in-box release support x64 as well as Arm64. There is no planned support for Arm(32) or x86. We only support 64 bit applications.

Consuming from C++ with Visual Studio

Add the C++/WinRT Nuget package to your C++ project in Visual Studio. This installs the required tools and build process. See the C++/WinRT FAQ link below for using LLVM/Clang. Note that the Windows MIDI Services team does not provide any support for LLVM/Clang, but we will take PRs as required if we need to change something reasonable to ensure you are successful with those tools, within what C++/WinRT can support.

In your project, set your target and minimum SDK versions to 10.0.20348.0

Download the NuGet package for the Core SDK

  • Until this is published on NuGet.org, you’ll need to set up a local package repository. This is easy to do inside the NuGet Package Manager in Visual Studio. You simply point to a folder. The structure I use in the local clone of the repo is a subfolder of the release folder for all NuGet packages. Specifically D:\peteb\Documents\GitHub\microsoft\midi\build\release\NuGet\

If needed, modify the project file as required (info in the C++/WinRT docs, and you can also look at the sample application code). If you are not using Visual Studio as your toolchain for your project, you may want to pull out the MIDI code into a library in your project which does. It’s not strictly required, but it’s much easier to use C++/WinRT. (If you do not want to do this, you’ll need to manually set up the cppwinrt tools as part of your build process to generate the required Windows.Devices.Midi2.h projection header. After that, you can develop using your normal flow.).

Read through this page, specifically the “If the API is implemented in a Windows Runtime component”.

After that, you reference the types as you would anything else in C++. Only the toolchain is an extra step. What it produces is standard C++. We’re considering what we can do here to possibly eliminate even that step in the future, but it’s required for now.

When in doubt, REbuild your project. C++/WinRT does a lot of code generation for the projections.

Consuming from C# Desktop App

Your project will currently need to target .NET 7 or above. We prefer .NET 8.

Releases will eventually be in the official NuGet.org package source. For now, you can create a local package source and place the NuGet package in there. Then add it to your package sources in the NuGet Package Manager in Visual Studio.

The package contains the .NET (C#) projection for .NET 7 and .NET 8. You will still need to install the C#/WinRT NuGet package in your project because we use other Windows SDK types from Windows.Foundation and more.

Note that other .NET languages (like Visual Basic) may work, but have not been tested.

Consuming from C# UWP

Support for this is not yet in place. We are evaluating the need for UWP support. Our top priority is desktop application support.

Consuming from Rust / RS WinRT

We will provide more information in the future. However, you will follow a similar approach to C++ using windows-rs instead of C++/WinRT. Note that the Rust WinRT tools are newer and are still in active development. Supporting non-Windows SDK winmd files is or will be supported, but is not intuitive at the moment. There is no existing crate for Windows MIDI Services right now.

Consuming from C++ without Visual Studio (using cmake or other tools)

The C++/WinRT tool cppwinrt.exe will generate a standard C++ 17 header file Windows.Devices.Midi2.h which you can pull in and include in your project. The header file projections for WinRT types outside of Windows::Devices::Midi2 are included with the Windows SDK. When we ship Windows MIDI Services in-box in Windows, this API will be projected in the same way as all the others in the Windows SDK.

First, install the Windows SDK. You can get the SDK from the Windows Dev Center

The SDK install includes the cppwinrt.exe tool. For the 10.0.22621.0 version of the SDK, it is found here on my PC: C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64 and C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\arm64 . Pick the version appropriate for your development PC architecture.

Normally, all SDK header files, on my PC with the 10.0.22621.0 version of the SDK installed, are located here C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\cppwinrt\winrt

Generating the Projection Headers

The tool produces the header files from from the .winmd file. This file can be found with the developer release of Windows MIDI Services either as a separate download in the release, or by opening the NuGet package (it’s just a zip file) and pulling it from there. The .winmd file is just metadata about the implementation dll.

C:\demos\cppwinrt>dir
+            Consuming the MIDI API | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Consuming the Windows MIDI Services API

The Windows MIDI Services API is built using C++/WinRT. WinRT, a requirement for modern APIs on Windows, enables desktop applications, regardless of language, to be able to use APIs, SDKs, etc. that we create. The older tools, C++/CX, are arguably simpler to implement in, but because they include proprietary extensions to C++, we decided to go with standards-based C++/WinRT instead.

Prerequisites

To use the API, your application language and tools must be able to work with WinRT metadata and libraries, or the generated projection header file.

  • Visual Studio 2022+ if you are using Visual Studio
  • Windows SDK 10.0.20348 (Install with Visual Studio)
  • Windows 10 22H2, or preferably, the latest version of Windows 11. Our development machines are all running Windows 11.
  • C++ 17 (C++ 20 may work, C++ 14 will not)
  • The NuGet package(s) from the release

Note that there are somewhat hacky ways to get traditional C to work with the COM interfaces, but it is a ton of work for you, and is not a scenario we support. If you find yourself in that situation, I recommend factoring out the MIDI code into its own lib and encapsulating all the C++ calls in there.

NOTE: In the period of time before Windows MIDI Services ships in Windows, you will also need to run the latest Windows 11 Insider Canary build of Windows in order to be able to use the USB MIDI 2.0 driver. Click here to learn more and join the Windows Insider Program.

CPU Architecture: The public GitHub releases currently support Intel/AMD x64 only. Our internal builds and in-box release support x64 as well as Arm64. There is no planned support for Arm(32) or x86. We only support 64 bit applications.

Consuming from C++ with Visual Studio

Add the C++/WinRT Nuget package to your C++ project in Visual Studio. This installs the required tools and build process. See the C++/WinRT FAQ link below for using LLVM/Clang. Note that the Windows MIDI Services team does not provide any support for LLVM/Clang, but we will take PRs as required if we need to change something reasonable to ensure you are successful with those tools, within what C++/WinRT can support.

In your project, set your target and minimum SDK versions to 10.0.20348.0

Download the NuGet package for the Core SDK

  • Until this is published on NuGet.org, you’ll need to set up a local package repository. This is easy to do inside the NuGet Package Manager in Visual Studio. You simply point to a folder. The structure I use in the local clone of the repo is a subfolder of the release folder for all NuGet packages. Specifically D:\peteb\Documents\GitHub\microsoft\midi\build\release\NuGet\

If needed, modify the project file as required (info in the C++/WinRT docs, and you can also look at the sample application code). If you are not using Visual Studio as your toolchain for your project, you may want to pull out the MIDI code into a library in your project which does. It’s not strictly required, but it’s much easier to use C++/WinRT. (If you do not want to do this, you’ll need to manually set up the cppwinrt tools as part of your build process to generate the required Windows.Devices.Midi2.h projection header. After that, you can develop using your normal flow.).

Read through this page, specifically the “If the API is implemented in a Windows Runtime component”.

After that, you reference the types as you would anything else in C++. Only the toolchain is an extra step. What it produces is standard C++. We’re considering what we can do here to possibly eliminate even that step in the future, but it’s required for now.

When in doubt, REbuild your project. C++/WinRT does a lot of code generation for the projections.

Consuming from C# Desktop App

Your project will currently need to target .NET 7 or above. We prefer .NET 8.

Releases will eventually be in the official NuGet.org package source. For now, you can create a local package source and place the NuGet package in there. Then add it to your package sources in the NuGet Package Manager in Visual Studio.

The package contains the .NET (C#) projection for .NET 7 and .NET 8. You will still need to install the C#/WinRT NuGet package in your project because we use other Windows SDK types from Windows.Foundation and more.

Note that other .NET languages (like Visual Basic) may work, but have not been tested.

Consuming from C# UWP

Support for this is not yet in place. We are evaluating the need for UWP support. Our top priority is desktop application support.

Consuming from Rust / RS WinRT

We will provide more information in the future. However, you will follow a similar approach to C++ using windows-rs instead of C++/WinRT. Note that the Rust WinRT tools are newer and are still in active development. Supporting non-Windows SDK winmd files is or will be supported, but is not intuitive at the moment. There is no existing crate for Windows MIDI Services right now.

Consuming from C++ without Visual Studio (using cmake or other tools)

The C++/WinRT tool cppwinrt.exe will generate a standard C++ 17 header file Windows.Devices.Midi2.h which you can pull in and include in your project. The header file projections for WinRT types outside of Windows::Devices::Midi2 are included with the Windows SDK. When we ship Windows MIDI Services in-box in Windows, this API will be projected in the same way as all the others in the Windows SDK.

First, install the Windows SDK. You can get the SDK from the Windows Dev Center

The SDK install includes the cppwinrt.exe tool. For the 10.0.22621.0 version of the SDK, it is found here on my PC: C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\x64 and C:\Program Files (x86)\Windows Kits\10\bin\10.0.22621.0\arm64 . Pick the version appropriate for your development PC architecture.

Normally, all SDK header files, on my PC with the 10.0.22621.0 version of the SDK installed, are located here C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\cppwinrt\winrt

Generating the Projection Headers

The tool produces the header files from from the .winmd file. This file can be found with the developer release of Windows MIDI Services either as a separate download in the release, or by opening the NuGet package (it’s just a zip file) and pulling it from there. The .winmd file is just metadata about the implementation dll.

C:\demos\cppwinrt>dir
  Volume in drive C has no label.
  Volume Serial Number is 0AEC-1038
 
diff --git a/docs/_site/developer-docs/diagnostic-endpoints.html b/docs/_site/developer-docs/diagnostic-endpoints.html
index eb7a5dfd..ebf76636 100644
--- a/docs/_site/developer-docs/diagnostic-endpoints.html
+++ b/docs/_site/developer-docs/diagnostic-endpoints.html
@@ -1,4 +1,4 @@
-            Diagnostics Endpoints | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MIDI Diagnostic Endpoints

Windows MIDI Services comes with three diagnostic endpoints, two of which are there for application development, testing, and debugging.

Loopbacks A and B

Windows MIDI Services comes with two loopback endpoints which are always present if the Windows service is running. These cannot be turned off by applications or configuration, and so may be relied upon by customer support, unit tests, and more.

The Endpoint Device Ids are available as static members of the MidiEndpointDeviceInformation class

winrt::hstring MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId();
+            Diagnostics Endpoints | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

MIDI Diagnostic Endpoints

Windows MIDI Services comes with three diagnostic endpoints, two of which are there for application development, testing, and debugging.

Loopbacks A and B

Windows MIDI Services comes with two loopback endpoints which are always present if the Windows service is running. These cannot be turned off by applications or configuration, and so may be relied upon by customer support, unit tests, and more.

The Endpoint Device Ids are available as static members of the MidiEndpointDeviceInformation class

winrt::hstring MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId();
 winrt::hstring MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId();
 

By default, these endpoints are not returned by enumeration calls, because most applications would not want to present them to the user. However, you can include them in the MidiEndpointDeviceInformation::FindAll and MidiEndpointDeviceWatcher::CreateWatcher device filters by using the MidiEndpointDeviceInformationFilter enum value IncludeDiagnosticLoopback if your application has a diagnostic need for them.

MidiEndpointDeviceInformationFilter::IncludeDiagnosticLoopback
 

Diagnostic Loopback Endpoints A and B are cross-wired so that any message sent out on loopback A will come in on loopback B, and any message sent out on B will come in on A. In this way, the loopbacks function as a global app-to-app MIDI implementation for testing.

Note that there is only one instance of each endpoint in the system, so if multiple applications use the loopback, the messages will get mixed together like any other endpoint.

TIP: The Diagnostic Loopback Endpoints are in place for testing and development only. Applications should not present them to users, or use them for communication outside of testing and debugging. Don’t expose the diagnostic loopback endpoints as part of the list of endpoints in a production DAW application.

Special Timestamp Behavior

Normally, an incoming MIDI message will receive a new timestamp when it first arrives from a remote endpoint. In this way, you know exactly when the Windows service first “saw” the message.

The loopback endpoints are special-cased so that they do not alter the original sent timestamp. The entire message and timestamp, is sent back exactly as it is received. If you send a message to a loopback with a timestamp of 0 (send immediately), it will come back with the same 0 timestamp. Similarly, if you specify an actual timestamp, that same timestamp will come back in the received message. The latter can be helpful in unit testing when you need to correlate a sent message with a received message, or you need to verify that the specific timestamp you sent was actually sent.

If you need the more typical timestamp behavior, you can set up app-to-app MIDI virtual endpoints.

Metadata Capture

The Loopback endpoints capture Endpoint and Function Block metadata just like any other endpoint. Because of this, you can change the name of the endpoint through in-protocol messages. If you do that, simply change it back later using the same type of message.

Note: We’re working to purge the endpoint metadata cache on device reconnection or service restart, which would reset those properties and names. Currently, it persists across service and Windows restarts.

Ping

The ping endpoint is not normally returned through any enumeration. It is for internal use only, and should not be used by any applications. It recognizes only one type of proprietary message.

Behavior and implementation of the Ping endpoint is subject to change and should not be relied upon by any code outside of the API.

\ No newline at end of file diff --git a/docs/_site/developer-docs/endpoint-ids.html b/docs/_site/developer-docs/endpoint-ids.html index 2cc2d94e..a90986ee 100644 --- a/docs/_site/developer-docs/endpoint-ids.html +++ b/docs/_site/developer-docs/endpoint-ids.html @@ -1 +1 @@ - Endpoint Device Ids | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Endpoint Device Ids

The Endpoint Device Id (also referred to as a Device Id) is the way we identify individual devices and interfaces in Windows.

Example for one of the built-in loopback endpoints:

\\?\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_A#{e7cce071-3c03-423f-88d3-f1045d02552b}

Part Description
SWD Software device. This is any device that is not a physical device connected to the PC, and which is created using the Software Device APIs. All MIDI endpoints are software devices and may or may not have a physical connected device as a parent.
MIDISRV The name of the enumerator. For Windows MIDI Services, this is the MidiSrv Windows Service
MIDIU Indicates a MIDI UMP interface.
DIAG Mnemonic for the transport which created this device interface.
LOOPBACK_A Arbitrary unique identification string provided by the transport. Typically includes a unique identifier like a serial number. It may also contain other information like the pin pairs used to provide the bidirectional communication.
MIDIU_DIAG_LOOPBACK_A The entire string here is controlled by the transport. By convention it breaks down into the fields mentioned above, but that is not something you should count on. In general, parsing these strings is not recommended.
GUID The interface Id. For Windows MIDI Services, every interface is a bidirectional interface, even if the connected device is MIDI 1.0 with a single unidirectional interface. For MIDI 1.0 devices, you can look at the group terminal blocks to identify active groups/directions. For MIDI 2.0 devices, you can look at the function blocks for the same information and more.

If you look at the device in Device Manager, and look at Details/Device Instance Path, you’ll see all of the information here except for the interface Id. When you enumerate devices through Windows::Devices::Enumeration or through Windows MIDI Services, the interface Id is included and required.

Tip: Although it was required in the past, we don’t recommend parsing these strings. If there’s information you need about the device which is not contained in the enumerated properties, please let us know and we’ll look into whether or not we can create a custom property to hold that.

\ No newline at end of file + Endpoint Device Ids | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Endpoint Device Ids

The Endpoint Device Id (also referred to as a Device Id) is the way we identify individual devices and interfaces in Windows.

Example for one of the built-in loopback endpoints:

\\?\SWD#MIDISRV#MIDIU_DIAG_LOOPBACK_A#{e7cce071-3c03-423f-88d3-f1045d02552b}

Part Description
SWD Software device. This is any device that is not a physical device connected to the PC, and which is created using the Software Device APIs. All MIDI endpoints are software devices and may or may not have a physical connected device as a parent.
MIDISRV The name of the enumerator. For Windows MIDI Services, this is the MidiSrv Windows Service
MIDIU Indicates a MIDI UMP interface.
DIAG Mnemonic for the transport which created this device interface.
LOOPBACK_A Arbitrary unique identification string provided by the transport. Typically includes a unique identifier like a serial number. It may also contain other information like the pin pairs used to provide the bidirectional communication.
MIDIU_DIAG_LOOPBACK_A The entire string here is controlled by the transport. By convention it breaks down into the fields mentioned above, but that is not something you should count on. In general, parsing these strings is not recommended.
GUID The interface Id. For Windows MIDI Services, every interface is a bidirectional interface, even if the connected device is MIDI 1.0 with a single unidirectional interface. For MIDI 1.0 devices, you can look at the group terminal blocks to identify active groups/directions. For MIDI 2.0 devices, you can look at the function blocks for the same information and more.

If you look at the device in Device Manager, and look at Details/Device Instance Path, you’ll see all of the information here except for the interface Id. When you enumerate devices through Windows::Devices::Enumeration or through Windows MIDI Services, the interface Id is included and required.

Tip: Although it was required in the past, we don’t recommend parsing these strings. If there’s information you need about the device which is not contained in the enumerated properties, please let us know and we’ll look into whether or not we can create a custom property to hold that.

\ No newline at end of file diff --git a/docs/_site/developer-docs/faq-programming-languages.html b/docs/_site/developer-docs/faq-programming-languages.html index 3d84eec5..21fa3fdc 100644 --- a/docs/_site/developer-docs/faq-programming-languages.html +++ b/docs/_site/developer-docs/faq-programming-languages.html @@ -1 +1 @@ - Programming Languages FAQ | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Programming Languages and App Models FAQ

This is a developer-focused FAQ.

WinRT

Q: Why is the API and SDK WinRT instead of a set of C headers like classic APIs? Why not use classic COM? A: New APIs for Windows are required to be WinRT, unless there are really good reasons not to be. WinRT is enhanced COM with a richer type system with better support for use by most of the languages and frameworks used to develop Windows applications.

Q: Does the fact that the API and SDK are WinRT mean they are sandboxed? A: No. WinRT is modern COM. The term has been overloaded in the past to also include an app model, Store requirements, and more. In this project, WinRT simply means the implementation flavor with support for projections. It does not impose any sandbox or other restrictions on consuming applications.

Q: Why does the service plugin model use COM instead of WinRT? A: For our runtime discovery-based plugin model, “Classic” COM makes more sense. WinRT components need to be known at compile time.

Q: Why do MIDI namespaces sometimes start with Microsoft instead of Windows? A: Anything targeted for delivery in-box can use Windows.Devices. Anything which is an additional component download for applications, like the SDK, use Microsoft as the top-level namespace as per our conventions.

Projections

Q: Which projections will this project deliver? A: We will start with the basic projections: C++, C# (current .net versions), and JavaScript. We will add more (Rust, for example) as we proceed in development. We want to be as inclusive here as we can reasonably be.

App Models

Q: What is the primary app model the API and SDK are targeting? A: Windows desktop apps of all types including C++, C#, Electron, and more.

Q: Do the API and SDK support UWP Applications? A: During the initial testing rollout, the API is not built into Windows, and so may not be completely compatible with UWP apps. TBD which functions are usable from the UWP sandbox in the future, but we want to support as much as is possible.

Project Implementation Languages

Q: Which languages are used in the project? A: Primarily, the project is C++ and C#.

Q: Why is the API and SDK C++ instead of Rust? A: Rust supports WinRT, including authoring, through the rs/WinRT project. However, Rust does not currently support Arm64EC, which means apps on Arm64 devices which need to load x64 plugins (that is, most DAWs) would not be able to load the SDK into their process. Additionally, modern C++ can be used quite safely, it’s just not “safe by default” like Rust is.

Q: Why is the API and SDK C++ instead of C#/.net? A: The majority of DAWs are written in C++ or similar languages. Although one can create WinRT components from C#, they carry along a runtime and garbage collection which most DAW developers do not want in their process. Additionally, C# does not support Arm64EC.

Q: Why are the apps in C# /.net? A: C# is a great language for applications. Additionally, we want to encourage contributions from our enormous C#/.net development community.

Q: Why is the Windows Service C++ instead of C#, Rust, or something else? A: Early prototypes of the service were in C#, which worked fine for most things, until you got into the kernel data transfer, integration with the PnP stack, and more. The implementation team already knows how to use those features and APIs, with great performance, in C++ based on their work with the audio services in Windows today, so the implementation is in C++.

Q: Why does the driver have reimplementations of features we see in the standard library? A: In kernel mode drivers, the standard library is largely unavailable.

\ No newline at end of file + Programming Languages FAQ | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Programming Languages and App Models FAQ

This is a developer-focused FAQ.

WinRT

Q: Why is the API and SDK WinRT instead of a set of C headers like classic APIs? Why not use classic COM? A: New APIs for Windows are required to be WinRT, unless there are really good reasons not to be. WinRT is enhanced COM with a richer type system with better support for use by most of the languages and frameworks used to develop Windows applications.

Q: Does the fact that the API and SDK are WinRT mean they are sandboxed? A: No. WinRT is modern COM. The term has been overloaded in the past to also include an app model, Store requirements, and more. In this project, WinRT simply means the implementation flavor with support for projections. It does not impose any sandbox or other restrictions on consuming applications.

Q: Why does the service plugin model use COM instead of WinRT? A: For our runtime discovery-based plugin model, “Classic” COM makes more sense. WinRT components need to be known at compile time.

Q: Why do MIDI namespaces sometimes start with Microsoft instead of Windows? A: Anything targeted for delivery in-box can use Windows.Devices. Anything which is an additional component download for applications, like the SDK, use Microsoft as the top-level namespace as per our conventions.

Projections

Q: Which projections will this project deliver? A: We will start with the basic projections: C++, C# (current .net versions), and JavaScript. We will add more (Rust, for example) as we proceed in development. We want to be as inclusive here as we can reasonably be.

App Models

Q: What is the primary app model the API and SDK are targeting? A: Windows desktop apps of all types including C++, C#, Electron, and more.

Q: Do the API and SDK support UWP Applications? A: During the initial testing rollout, the API is not built into Windows, and so may not be completely compatible with UWP apps. TBD which functions are usable from the UWP sandbox in the future, but we want to support as much as is possible.

Project Implementation Languages

Q: Which languages are used in the project? A: Primarily, the project is C++ and C#.

Q: Why is the API and SDK C++ instead of Rust? A: Rust supports WinRT, including authoring, through the rs/WinRT project. However, Rust does not currently support Arm64EC, which means apps on Arm64 devices which need to load x64 plugins (that is, most DAWs) would not be able to load the SDK into their process. Additionally, modern C++ can be used quite safely, it’s just not “safe by default” like Rust is.

Q: Why is the API and SDK C++ instead of C#/.net? A: The majority of DAWs are written in C++ or similar languages. Although one can create WinRT components from C#, they carry along a runtime and garbage collection which most DAW developers do not want in their process. Additionally, C# does not support Arm64EC.

Q: Why are the apps in C# /.net? A: C# is a great language for applications. Additionally, we want to encourage contributions from our enormous C#/.net development community.

Q: Why is the Windows Service C++ instead of C#, Rust, or something else? A: Early prototypes of the service were in C#, which worked fine for most things, until you got into the kernel data transfer, integration with the PnP stack, and more. The implementation team already knows how to use those features and APIs, with great performance, in C++ based on their work with the audio services in Windows today, so the implementation is in C++.

Q: Why does the driver have reimplementations of features we see in the standard library? A: In kernel mode drivers, the standard library is largely unavailable.

\ No newline at end of file diff --git a/docs/_site/developer-docs/midi2-implementation-details.html b/docs/_site/developer-docs/midi2-implementation-details.html index f633413e..01d15199 100644 --- a/docs/_site/developer-docs/midi2-implementation-details.html +++ b/docs/_site/developer-docs/midi2-implementation-details.html @@ -1 +1 @@ - MIDI 2.0 Implementation Details | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Implementation Details

Specifications can be funny. As much as the MIDI Association, and all of us in it, try to be very specific and crisp on wording, there’s often room for interpretation. Most of these we work out among the various OS companies under the umbrella of the MIDI Association. But there are others were an approach may just not make sense on one OS or the other. Here are the ones that are Windows-specific, that you should be aware of as a developer.

Of course, the full source code for Windows MIDI Services, including the USB MIDI 2.0 driver, is available in our repo, so you can review it at any time to better understand how a feature or function works.

Discovery and Protocol Negotiation

Windows MIDI Services supports only the UMP-based Endpoint Discovery and Protocol Negotiation. We do not implement the deprecated MIDI-CI equivalents.

In addition, declaring the use of JR Timestamps in a USB MIDI 2.0 Group Terminal Block does not enable JR Timestamps in Windows MIDI Services. Instead, these must be negotiated using UMP-based Endpoint Discovery end Protocol Negotiation

UMP Endpoint Names for native MIDI 2.0 UMP format devices

Although we make all the names available through the Enumeration API, we have an order of precedence we use when providing the recommended Name property value. In order from most preferred to least, we have:

  1. Any user-supplied endpoint name configured through the configuration files (these will be created by the MIDI Settings app in the future)
  2. The name supplied through in-protocol Endpoint Name Notification messages
  3. The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0.

When we create MIDI 1.0-compatible “ports” for these endpoints, we’ll use the Function Block Names if available and Group Terminal Block names if not.

UMP Endpoint Names for MIDI 1.0 byte stream format devices

The API also creates UMP endpoints for MIDI 1.0 devices. This happens two ways:

  1. If the device is assigned to the USB MIDI 2.0 driver (this is preferred) the driver creates Group Terminal Blocks for each “cable” (a “port” in MIDI 1.0 API speak). In the new driver, we use the iJack names, if provided, to name the Group Terminal Blocks. This is the best way to ensure your endpoint and Group Terminal Block names are correct.
  2. If the device is assigned a third-party driver or the legacy MIDI 1.0 driver (not preferred in most cases), the service creates the Group Terminal Blocks using the same algorithm. However, because much less information is available to the service from the legacy drivers, the name may not be identical.

The precedence for naming is the same as with MIDI 2.0 devices, with the exception of the Endpoint Name Notification, which doesn’t exist in MIDI 1.0.

  1. Any user-supplied endpoint name
  2. The name supplied through in-protocol Endpoint Name Notification messages
  3. The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0.

iSerialNumber Really Helps

If your device exposes a unique iSerialNumber, that will really help with retaining name and other information across physical USB connects and disconnects. We do our best to retain the correct information if you plug into the same physical port, but when you change ports, a device without an iSerialNumber essentially becomes a new device. This is not unique to Windows, but it’s important enough to mention here. More info and guidance in this blog post.

\ No newline at end of file + MIDI 2.0 Implementation Details | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Implementation Details

Specifications can be funny. As much as the MIDI Association, and all of us in it, try to be very specific and crisp on wording, there’s often room for interpretation. Most of these we work out among the various OS companies under the umbrella of the MIDI Association. But there are others were an approach may just not make sense on one OS or the other. Here are the ones that are Windows-specific, that you should be aware of as a developer.

Of course, the full source code for Windows MIDI Services, including the USB MIDI 2.0 driver, is available in our repo, so you can review it at any time to better understand how a feature or function works.

Discovery and Protocol Negotiation

Windows MIDI Services supports only the UMP-based Endpoint Discovery and Protocol Negotiation. We do not implement the deprecated MIDI-CI equivalents.

In addition, declaring the use of JR Timestamps in a USB MIDI 2.0 Group Terminal Block does not enable JR Timestamps in Windows MIDI Services. Instead, these must be negotiated using UMP-based Endpoint Discovery end Protocol Negotiation

UMP Endpoint Names for native MIDI 2.0 UMP format devices

Although we make all the names available through the Enumeration API, we have an order of precedence we use when providing the recommended Name property value. In order from most preferred to least, we have:

  1. Any user-supplied endpoint name configured through the configuration files (these will be created by the MIDI Settings app in the future)
  2. The name supplied through in-protocol Endpoint Name Notification messages
  3. The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0.

When we create MIDI 1.0-compatible “ports” for these endpoints, we’ll use the Function Block Names if available and Group Terminal Block names if not.

UMP Endpoint Names for MIDI 1.0 byte stream format devices

The API also creates UMP endpoints for MIDI 1.0 devices. This happens two ways:

  1. If the device is assigned to the USB MIDI 2.0 driver (this is preferred) the driver creates Group Terminal Blocks for each “cable” (a “port” in MIDI 1.0 API speak). In the new driver, we use the iJack names, if provided, to name the Group Terminal Blocks. This is the best way to ensure your endpoint and Group Terminal Block names are correct.
  2. If the device is assigned a third-party driver or the legacy MIDI 1.0 driver (not preferred in most cases), the service creates the Group Terminal Blocks using the same algorithm. However, because much less information is available to the service from the legacy drivers, the name may not be identical.

The precedence for naming is the same as with MIDI 2.0 devices, with the exception of the Endpoint Name Notification, which doesn’t exist in MIDI 1.0.

  1. Any user-supplied endpoint name
  2. The name supplied through in-protocol Endpoint Name Notification messages
  3. The name supplied by the transport plugin in the service. This is typically pulled from a device name supplied by the driver, or other transport-specific sources such as network advertising in the case of Network MIDI 2.0.

iSerialNumber Really Helps

If your device exposes a unique iSerialNumber, that will really help with retaining name and other information across physical USB connects and disconnects. We do our best to retain the correct information if you plug into the same physical port, but when you change ports, a device without an iSerialNumber essentially becomes a new device. This is not unique to Windows, but it’s important enough to mention here. More info and guidance in this blog post.

\ No newline at end of file diff --git a/docs/_site/index.html b/docs/_site/index.html index 7f1184ba..017c71f9 100644 --- a/docs/_site/index.html +++ b/docs/_site/index.html @@ -1 +1 @@ - Windows Midi Services | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Windows MIDI Services

Source repo and developer releases on GitHub

Discord Server for discussion about this project

Key Features

  • Multi-client by default. Unless an endpoint is configured to not allow shared connections, or there is some issue around multi-client in a third-party driver, any endpoint (including MIDI 1.0 devices) can be used by multiple applications at the same time. So far, in our testing, we haven’t found any USB devices or drivers which cannot be multi-client.
  • Faster. In our testing, we’ve found that the new infrastructure is much faster at sending and receiving messages compared to the older API, even with plugins configured in the service. There are no built-in speed caps or throttling in Windows MIDI Services, even for older USB MIDI 1.0 devices. The driver is not limited USB full-speed, and supports USB 3.x speeds.
  • Lower Jitter. Along with higher speed comes lower jitter. This will vary by transport type (USB vs Network vs Virtual), and the device Windows is talking to, but the jitter is in the low microsecond range even without any compensation.
  • More Deterministic. Speaking of latency compensation, the new API enables timestamp-based message scheduling for outbound messages, and also will soon support Jitter Reduction timestamps for MIDI 2.0 devices which can use them.
  • Extensible. The service has been designed to be extensible by Microsoft and third-parties. New types of transports can be added at any time, including during prototyping of a new transport specification. (We’re working on Network MIDI 2.0, Bluetooth MIDI 1.0 and considering RTP, all using this model.) Similarly, message processing plugins can also be developed by Microsoft or third-parties and used for production and/or prototyping. No kernel driver experience required in most cases.
  • Includes app-to-App and Virtual MIDI. Windows MIDI Services includes virtual / app-to-app MIDI 2.0 to enable lightning fast communication between apps on the PC. We’re also investigating flexible routing between any MIDI endpoints as a future feature.
  • Better tools. We supply the midi.exe Windows MIDI Services Console for developers and power users, or anyone comfortable with the command line. You can use it to monitor endpoints, send and receive messages, send/capture SysEx data and much more. We’ll deliver the MIDI Settings GUI app after our initial release. That app enables renaming devices, configuring your MIDI setup, testing, and more.
  • UMP-Centric. The new API fully embraces MIDI 2.0 and the Universal MIDI Packet format and handles all required translation in the service and driver. This makes the app model simple while ensuring all your existing devices continue to work.
  • Open Source. The source code is open and available to everyone under a permissive license. Not sure how something works? Want to create a transport but aren’t sure how we did it? Want to investigate a bug or contribute a feature? The code is there for you to explore.

Note: Additionally MIDI CI functionality, which does not technically require OS support, will be coming after version 1.0. We intend to add helpers for profiles, property exchange, MUID tracking, and more. In the meantime, applications can send and receive MIDI CI messages without anything in their way, using custom code or third-party libraries. MIDI CI is just MIDI 1.0-compatible SysEx.

Developer Samples

Additional Resources

These are the updated MIDI 2.0 specifications which apply to this project today.


Table of contents

\ No newline at end of file + Windows Midi Services | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Windows MIDI Services

Source repo and developer releases on GitHub

Discord Server for discussion about this project

Key Features

  • Multi-client by default. Unless an endpoint is configured to not allow shared connections, or there is some issue around multi-client in a third-party driver, any endpoint (including MIDI 1.0 devices) can be used by multiple applications at the same time. So far, in our testing, we haven’t found any USB devices or drivers which cannot be multi-client.
  • Faster. In our testing, we’ve found that the new infrastructure is much faster at sending and receiving messages compared to the older API, even with plugins configured in the service. There are no built-in speed caps or throttling in Windows MIDI Services, even for older USB MIDI 1.0 devices. The driver is not limited USB full-speed, and supports USB 3.x speeds.
  • Lower Jitter. Along with higher speed comes lower jitter. This will vary by transport type (USB vs Network vs Virtual), and the device Windows is talking to, but the jitter is in the low microsecond range even without any compensation.
  • More Deterministic. Speaking of latency compensation, the new API enables timestamp-based message scheduling for outbound messages, and also will soon support Jitter Reduction timestamps for MIDI 2.0 devices which can use them.
  • Extensible. The service has been designed to be extensible by Microsoft and third-parties. New types of transports can be added at any time, including during prototyping of a new transport specification. (We’re working on Network MIDI 2.0, Bluetooth MIDI 1.0 and considering RTP, all using this model.) Similarly, message processing plugins can also be developed by Microsoft or third-parties and used for production and/or prototyping. No kernel driver experience required in most cases.
  • Includes app-to-App and Virtual MIDI. Windows MIDI Services includes virtual / app-to-app MIDI 2.0 to enable lightning fast communication between apps on the PC. We’re also investigating flexible routing between any MIDI endpoints as a future feature.
  • Better tools. We supply the midi.exe Windows MIDI Services Console for developers and power users, or anyone comfortable with the command line. You can use it to monitor endpoints, send and receive messages, send/capture SysEx data and much more. We’ll deliver the MIDI Settings GUI app after our initial release. That app enables renaming devices, configuring your MIDI setup, testing, and more.
  • UMP-Centric. The new API fully embraces MIDI 2.0 and the Universal MIDI Packet format and handles all required translation in the service and driver. This makes the app model simple while ensuring all your existing devices continue to work.
  • Open Source. The source code is open and available to everyone under a permissive license. Not sure how something works? Want to create a transport but aren’t sure how we did it? Want to investigate a bug or contribute a feature? The code is there for you to explore.

Note: Additionally MIDI CI functionality, which does not technically require OS support, will be coming after version 1.0. We intend to add helpers for profiles, property exchange, MUID tracking, and more. In the meantime, applications can send and receive MIDI CI messages without anything in their way, using custom code or third-party libraries. MIDI CI is just MIDI 1.0-compatible SysEx.

Developer Samples

Additional Resources

These are the updated MIDI 2.0 specifications which apply to this project today.


Table of contents

\ No newline at end of file diff --git a/docs/_site/midi-console.html b/docs/_site/midi-console.html index ae8e1ce7..6f103a1b 100644 --- a/docs/_site/midi-console.html +++ b/docs/_site/midi-console.html @@ -1,4 +1,4 @@ - MIDI Console | Windows MIDI Services Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Windows MIDI Services Console

If you have the midi console installed, you can invoke it from any command prompt using midi. We recommend using Windows Terminal for the best experience.

General Information

Commands vs Options

MIDI Console commands are words with no symbol prefix. For example endpoint or send-message-file. Options are prefixed with two dashes if you use the full word, or a single dash if you use the single-letter abbreviation. For example --help or -h. There is no statement completion built in to the console, but there are some supported abbreviations for commands. These are not yet fully documented but are present in the Program.cs in the console source code.

“Ports” vs “Streams”

In MIDI 1.0, specifically USB MIDI 1.0, a connected device would have a single input and single output stream. Inside that stream are packets of data with virtual cable numbers. Those numbers (16 total at most) identify the “port” the data is going to. Operating systems would then translate those into input and output ports. Those cable numbers were hidden from users.

MIDI 2.0 does not have a concept of a port. Instead, you always work with the stream itself. The group number, which is in the MIDI message now, is the moral equivalent of that cable number.

So where you may have seen a device with 5 input and 5 output ports in the past, you will now see a single bidirectional UMP Endpoint stream with 5 input groups and 5 output groups. We know this can take some getting used to, but it enables us to use MIDI 1.0 devices as though they are MIDI 2.0 devices, and provide a unified API.

Help

Add the option --help or its short version -h to any command to get information and examples for that command.

midi --help
+            MIDI Console | Windows MIDI Services                Skip to main content   Link      Menu      Expand       (external link)    Document      Search       Copy       Copied        

Windows MIDI Services Console

If you have the midi console installed, you can invoke it from any command prompt using midi. We recommend using Windows Terminal for the best experience.

General Information

Commands vs Options

MIDI Console commands are words with no symbol prefix. For example endpoint or send-message-file. Options are prefixed with two dashes if you use the full word, or a single dash if you use the single-letter abbreviation. For example --help or -h. There is no statement completion built in to the console, but there are some supported abbreviations for commands. These are not yet fully documented but are present in the Program.cs in the console source code.

“Ports” vs “Streams”

In MIDI 1.0, specifically USB MIDI 1.0, a connected device would have a single input and single output stream. Inside that stream are packets of data with virtual cable numbers. Those numbers (16 total at most) identify the “port” the data is going to. Operating systems would then translate those into input and output ports. Those cable numbers were hidden from users.

MIDI 2.0 does not have a concept of a port. Instead, you always work with the stream itself. The group number, which is in the MIDI message now, is the moral equivalent of that cable number.

So where you may have seen a device with 5 input and 5 output ports in the past, you will now see a single bidirectional UMP Endpoint stream with 5 input groups and 5 output groups. We know this can take some getting used to, but it enables us to use MIDI 1.0 devices as though they are MIDI 2.0 devices, and provide a unified API.

Help

Add the option --help or its short version -h to any command to get information and examples for that command.

midi --help
 midi service --help
 midi enumerate --help
 midi enumerate endpoints --help
diff --git a/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.md b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.md
new file mode 100644
index 00000000..efa06381
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSettings.md
@@ -0,0 +1,22 @@
+---
+layout: api_page
+title: IMidiEndpointConnectionSettings
+parent: Connections
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# IMidiEndpointConnectionSettings
+
+Settings which are optionally provided when connecting to an endpoint. Typically, the implementation of the endpoint will come with a concrete settings class which implements this interface, and translates the settings into JSON which is sent up to the service and read by the abstraction.
+
+## Properties
+
+| Property | Description |
+| -------- | ----------- |
+| `SettingsJson` | The JSON representation of the settings. |
+
+## IDL
+
+[IMidiEndpointConnectionSettings IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/IMidiEndpointConnectionSettings.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.md b/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.md
index 4748eb62..c3054b06 100644
--- a/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.md
+++ b/docs/developer-docs/Windows.Devices.Midi2/connections/MidiEndpointConnection.md
@@ -14,6 +14,12 @@ Connections allocate resources including send/receive buffers, and processing th
 
 To ensure an application is able to wire up processing plugins and event handlers before the connection is active, the connection returned by the `MidiSession` is not yet open. Once the connection is acquired, the application should assign event handlers, and optionally assign any message processing plugins. Once complete, the application calls the `Open()` function to connect to the service, create the queues, and begin sending and receiving messages.
 
+## A note on sending messages
+
+All `SendMessageXX` functions send a single Universal MIDI Packet message at a time. The pluralized versions `SendMessagesXX` will send multiple packets, in order, with the same timestamp.
+
+Currently, in the implementation behind the scenes, the service receives each timestamped message one at a time. We have the functions for sending more than one message as a developer convenience for similarity with other platforms, and also to allow for possible future optimization in the service communication code.
+
 ## Properties
 
 | Property | Description |
@@ -22,7 +28,7 @@ To ensure an application is able to wire up processing plugins and event handler
 | `EndpointDeviceId` | The system-wide identifier for the device connection. This is returned through enumeration calls. |
 | `Tag` | You may use this `Tag` property to hold any additional information you wish to have associated with the connection. |
 | `IsOpen` | True if this connection is currently open. When first created, the connection is not open until the consuming code calls the `Open` method |
-| `Settings` | Settings used to create this connection. |
+| `Settings` | Settings used to create this connection. Treat this as read-only. |
 | `MessageProcessingPlugins` | Collection of all message processing plugins which will optionally handle incoming messages. |
 
 ## Static Member Functions
@@ -46,8 +52,10 @@ To ensure an application is able to wire up processing plugins and event handler
 | `SendMessageWords(timestamp, word0, word1, word2)` | Send a single 96-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message |
 | `SendMessageWords(timestamp, word0, word1, word2, word3)` | Send a single 128-bit Universal MIDI Packet as 32-bit words. This is often the most efficient way to send this type of message |
 | `SendMessageBuffer(timestamp, buffer, byteOffset, byteLength)` | Send a single Universal MIDI Packet as bytes from a buffer. The number of bytes sent must match the size read from the first 4 bits of the data starting at the specified offset, and must be laid out correctly with the first byte corresponding to the MSB of the first word of the UMP (the word which contains hte message type). If you want to manage a chunk of buffer memory, the `IMemoryBuffer` type is the acceptable WinRT approach, and is as close as you get to sending a pointer into a buffer. |
+| `SendMessagesWordList(timestamp,words)` | This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully. |
+| `SendMessagesWordArray(timestamp,words)` | This sends more than one message with the same timestamp. Message words must be ordered contiguously from word-0 to word-n for each message, and the message types must be valid for the number of words for each message. If an error is encountered when sending messages, the function stops processing the list at that point and returns a failure code, even if some messages were sent successfully.|
 | `AddEndpointProcessingPlugin(plugin)` | Add an endpoint processing plugin to this connection |
-| `RemoveEndpointProcessingPlugin(id)` | Remove an endpoint processing plugin |
+| `RemoveEndpointProcessingPlugin(id)` | Remove an endpoint processing plugin from this connection |
 
 > Tip: In all the functions which accept a timestamp to schedule the message, **you can send a timestamp of 0 (zero) to bypass the scheduler and send the message immediately**. Otherwise, the provided timestamp is treated as an absolute time for when the message should be sent from the service. Note that the service-based scheduler (currently based on a `std::priority_queue`) gets less efficient when there are thousands of messages in it, so it's recommended that you not schedule too many messages at a time or too far out into the future. 
 

From eed0d2fd599390ef004234470d829c25d0d08309 Mon Sep 17 00:00:00 2001
From: Pete Brown 
Date: Thu, 8 Feb 2024 01:58:54 -0500
Subject: [PATCH 2/6] More API cleanup, and sample + docs update

---
 build/staging/reg/WinRTActivationEntries.cs   |   3 -
 build/staging/reg/WinRTActivationEntries.xml  |  15 -----
 build/staging/version/BundleInfo.wxi          |   2 +-
 docs/developer-docs/internal-interfaces.md    |  16 ++++++
 docs/troubleshooting.md                       |  17 ++++++
 .../{MidiSample.AppToAppMidi => }/App.xaml    |   0
 .../{MidiSample.AppToAppMidi => }/App.xaml.cs |   0
 .../Assets/LockScreenLogo.scale-200.png       | Bin
 .../Assets/SplashScreen.scale-200.png         | Bin
 .../Assets/Square150x150Logo.scale-200.png    | Bin
 .../Assets/Square44x44Logo.scale-200.png      | Bin
 ...x44Logo.targetsize-24_altform-unplated.png | Bin
 .../Assets/StoreLogo.png                      | Bin
 .../Assets/Wide310x150Logo.scale-200.png      | Bin
 .../MainWindow.xaml                           |   0
 .../MainWindow.xaml.cs                        |   0
 .../MidiSample.AppToAppMidi.csproj            |   2 +-
 .../MidiSample.AppToAppMidi.sln               |   0
 .../{MidiSample.AppToAppMidi => }/Note.cs     |   0
 .../Package.appxmanifest                      |   0
 .../Properties/launchSettings.json            |   0
 .../app.manifest                              |   0
 .../Midi2.VirtualMidiBidi.cpp                 |  22 +-------
 .../Midi2.VirtualMidiEndpointManager.cpp      |  14 ++---
 .../MidiEndpointTable.cpp                     |   2 +-
 .../VirtualMidiAbstraction/swd_shared.cpp     |   6 +-
 .../nuget/Windows.Devices.Midi2.nuspec        |   2 +-
 ...dl => IMidiEndpointConnectionSettings.idl} |   6 +-
 .../IMidiTransportSettingsData.idl            |   2 -
 .../Midi2Client/MidiEndpointConnection.cpp    |  53 ++++++++++++++----
 .../Midi2Client/MidiEndpointConnection.h      |  26 ++++-----
 .../Midi2Client/MidiEndpointConnection.idl    |  12 ++--
 .../MidiEndpointConnectionOptions.cpp         |  17 ------
 .../MidiEndpointConnectionOptions.h           |  42 --------------
 .../MidiEndpointConnectionOptions.idl         |  30 ----------
 .../MidiEndpointConnectionSharingEnum.idl     |  22 --------
 ...ndpointConnectionSharingPreferenceEnum.idl |  25 ---------
 .../MidiEndpointDeviceInformation.cpp         |  51 ++---------------
 .../MidiEndpointDeviceInformation.h           |   8 +--
 .../Midi2Client/MidiGroupTerminalBlock.cpp    |   1 -
 .../Midi2Client/MidiGroupTerminalBlock.h      |   2 +-
 .../Midi2Client/MidiSendMessageResultEnum.idl |   5 ++
 src/api/Client/Midi2Client/MidiService.cpp    |   6 +-
 src/api/Client/Midi2Client/MidiSession.cpp    |  28 ++-------
 src/api/Client/Midi2Client/MidiSession.h      |   8 +--
 src/api/Client/Midi2Client/MidiSession.idl    |  19 ++-----
 .../MidiSessionConnectionInformation.cpp      |   2 +-
 .../Midi2Client/MidiStreamMessageBuilder.h    |   2 +-
 .../Midi2Client/MidiVirtualEndpointDevice.cpp |  20 ++-----
 .../Midi2Client/WinRTActivationEntries.txt    |   6 +-
 .../Midi2Client/Windows.Devices.Midi2.vcxproj |  18 +++---
 .../Windows.Devices.Midi2.vcxproj.filters     |  46 +++++----------
 src/api/Client/Midi2Client/pch.h              |   2 -
 src/api/Client/Midi2Client/trace_logging.cpp  |   4 --
 src/api/Inc/json_helpers.h                    |  12 +++-
 src/api/Inc/string_util.h                     |  40 ++++++++++---
 src/api/Service/Exe/MidiDeviceManager.cpp     |  10 ++--
 src/api/Service/Exe/MidiSessionTracker.cpp    |   4 +-
 src/api/Service/Inc/MidiPipe.h                |   2 +-
 .../MidiEndpointConnectionTests.cpp           |  18 ++----
 .../Endpoint/EndpointMonitorCommand.cs        |   2 +-
 .../Endpoint/EndpointSendMessageCommand.cs    |   6 +-
 .../EndpointSendMessagesFileCommand.cs        |   2 +-
 src/user-tools/midi-console/Midi/Midi.csproj  |   4 +-
 64 files changed, 232 insertions(+), 432 deletions(-)
 create mode 100644 docs/developer-docs/internal-interfaces.md
 create mode 100644 docs/troubleshooting.md
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/App.xaml (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/App.xaml.cs (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/LockScreenLogo.scale-200.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/SplashScreen.scale-200.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/Square150x150Logo.scale-200.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/Square44x44Logo.scale-200.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/Square44x44Logo.targetsize-24_altform-unplated.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/StoreLogo.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Assets/Wide310x150Logo.scale-200.png (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/MainWindow.xaml (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/MainWindow.xaml.cs (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/MidiSample.AppToAppMidi.csproj (98%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/MidiSample.AppToAppMidi.sln (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Note.cs (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Package.appxmanifest (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/Properties/launchSettings.json (100%)
 rename samples/csharp-net/app-to-app-midi-cs/{MidiSample.AppToAppMidi => }/app.manifest (100%)
 rename src/api/Client/Midi2Client/{IMidiEndpointDefinedConnectionSettings.idl => IMidiEndpointConnectionSettings.idl} (85%)
 delete mode 100644 src/api/Client/Midi2Client/MidiEndpointConnectionOptions.cpp
 delete mode 100644 src/api/Client/Midi2Client/MidiEndpointConnectionOptions.h
 delete mode 100644 src/api/Client/Midi2Client/MidiEndpointConnectionOptions.idl
 delete mode 100644 src/api/Client/Midi2Client/MidiEndpointConnectionSharingEnum.idl
 delete mode 100644 src/api/Client/Midi2Client/MidiEndpointConnectionSharingPreferenceEnum.idl

diff --git a/build/staging/reg/WinRTActivationEntries.cs b/build/staging/reg/WinRTActivationEntries.cs
index 7d4b1af0..2a7b2d9f 100644
--- a/build/staging/reg/WinRTActivationEntries.cs
+++ b/build/staging/reg/WinRTActivationEntries.cs
@@ -32,13 +32,10 @@ class RegistryEntries
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiChannelEndpointListener", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiGroupEndpointListener", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiMessageTypeEndpointListener", ActivationType=0, Threading=0, TrustLevel=0  },
-        new RegEntry{ ClassName="Windows.Devices.Midi2.MidiVirtualEndpointDevice", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiVirtualEndpointDeviceDefinition", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiMessageReceivedEventArgs", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiEndpointConnection", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.IMidiEndpointConnectionStatics", ActivationType=0, Threading=0, TrustLevel=0  },
-        new RegEntry{ ClassName="Windows.Devices.Midi2.MidiEndpointConnectionOptions", ActivationType=0, Threading=0, TrustLevel=0  },
-        new RegEntry{ ClassName="Windows.Devices.Midi2.MidiStreamConfigurationSettings", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiService", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.IMidiServiceStatics", ActivationType=0, Threading=0, TrustLevel=0  },
         new RegEntry{ ClassName="Windows.Devices.Midi2.MidiClock", ActivationType=0, Threading=0, TrustLevel=0  },
diff --git a/build/staging/reg/WinRTActivationEntries.xml b/build/staging/reg/WinRTActivationEntries.xml
index 6dbc0886..62882cb0 100644
--- a/build/staging/reg/WinRTActivationEntries.xml
+++ b/build/staging/reg/WinRTActivationEntries.xml
@@ -133,11 +133,6 @@
              threading="Both"
              trustLevel="Base"
              />
-          
           
-          
-          
           
   
-  
+  
 
diff --git a/docs/developer-docs/internal-interfaces.md b/docs/developer-docs/internal-interfaces.md
new file mode 100644
index 00000000..33555c5b
--- /dev/null
+++ b/docs/developer-docs/internal-interfaces.md
@@ -0,0 +1,16 @@
+---
+layout: page
+title: Internal Interfaces
+parent: Windows Midi Services
+has_children: false
+---
+
+# Internal Interfaces
+
+There are a number of interfaces which are internal to Windows MIDI Services and are not part of the public API contract. But because this is an open source project, you can of course see them in the source code.
+
+These interfaces shall not be used by any non-Microsoft-authored applications. In addition to not providing all the functionality expected, it's possible they will change from revision to revision. Examples include, but are not limited to, `IMidiBiDi`, `IMidiAbstraction`, `IMidiCallback` `IMidiIn`, `IMidiOut`, `IMidiEndpointManager`, `IMidiTransform`, `IMidiDataTransform`, `IMidiAbstractionConfigurationManager`, `IMidiSessionTracker` and others.
+
+Some of those interfaces may be used if you create various types of service plugins executing within the service process. That use is allowed within the defined plugin framework. See the sample MIDI Abstraction and MIDI Transforms for examples.
+
+For client applications, regardless of type, the only supported way to communicate with the Windows Service, plugins, and drivers, are in the WinRT `Windows.Devices.Midi2` namespace. Use of the internal interfaces is not permitted.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 00000000..69f1118e
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,17 @@
+---
+layout: page
+title: Troubleshooting
+parent: Windows Midi Services
+---
+
+# Troubleshooting
+
+## Errors
+
+
+### Type Initializer Error
+
+If you receive the error "The type initializer for `Windows.Devices.Midi2.` threw an exception", in the console app in particular, it usually means that the Windows MIDI Services API is not properly registered on the system. This can happen during development if you do run the installer which puts the appropriate activation entries into the registry.
+
+This should never appear in production when Windows MIDI Services is in the box, unless you are using a development build for which the newer types have not been properly registered.
+
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/App.xaml b/samples/csharp-net/app-to-app-midi-cs/App.xaml
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/App.xaml
rename to samples/csharp-net/app-to-app-midi-cs/App.xaml
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/App.xaml.cs b/samples/csharp-net/app-to-app-midi-cs/App.xaml.cs
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/App.xaml.cs
rename to samples/csharp-net/app-to-app-midi-cs/App.xaml.cs
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/LockScreenLogo.scale-200.png b/samples/csharp-net/app-to-app-midi-cs/Assets/LockScreenLogo.scale-200.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/LockScreenLogo.scale-200.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/LockScreenLogo.scale-200.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/SplashScreen.scale-200.png b/samples/csharp-net/app-to-app-midi-cs/Assets/SplashScreen.scale-200.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/SplashScreen.scale-200.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/SplashScreen.scale-200.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square150x150Logo.scale-200.png b/samples/csharp-net/app-to-app-midi-cs/Assets/Square150x150Logo.scale-200.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square150x150Logo.scale-200.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/Square150x150Logo.scale-200.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square44x44Logo.scale-200.png b/samples/csharp-net/app-to-app-midi-cs/Assets/Square44x44Logo.scale-200.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square44x44Logo.scale-200.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/Square44x44Logo.scale-200.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/samples/csharp-net/app-to-app-midi-cs/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/StoreLogo.png b/samples/csharp-net/app-to-app-midi-cs/Assets/StoreLogo.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/StoreLogo.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/StoreLogo.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Wide310x150Logo.scale-200.png b/samples/csharp-net/app-to-app-midi-cs/Assets/Wide310x150Logo.scale-200.png
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Assets/Wide310x150Logo.scale-200.png
rename to samples/csharp-net/app-to-app-midi-cs/Assets/Wide310x150Logo.scale-200.png
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MainWindow.xaml b/samples/csharp-net/app-to-app-midi-cs/MainWindow.xaml
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MainWindow.xaml
rename to samples/csharp-net/app-to-app-midi-cs/MainWindow.xaml
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MainWindow.xaml.cs b/samples/csharp-net/app-to-app-midi-cs/MainWindow.xaml.cs
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MainWindow.xaml.cs
rename to samples/csharp-net/app-to-app-midi-cs/MainWindow.xaml.cs
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MidiSample.AppToAppMidi.csproj b/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj
similarity index 98%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MidiSample.AppToAppMidi.csproj
rename to samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj
index 798b3796..57e4e2d2 100644
--- a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MidiSample.AppToAppMidi.csproj
+++ b/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.csproj
@@ -29,7 +29,7 @@
   
     
     
-    
+    
     
     
   
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MidiSample.AppToAppMidi.sln b/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.sln
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/MidiSample.AppToAppMidi.sln
rename to samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi.sln
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Note.cs b/samples/csharp-net/app-to-app-midi-cs/Note.cs
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Note.cs
rename to samples/csharp-net/app-to-app-midi-cs/Note.cs
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Package.appxmanifest b/samples/csharp-net/app-to-app-midi-cs/Package.appxmanifest
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Package.appxmanifest
rename to samples/csharp-net/app-to-app-midi-cs/Package.appxmanifest
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Properties/launchSettings.json b/samples/csharp-net/app-to-app-midi-cs/Properties/launchSettings.json
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/Properties/launchSettings.json
rename to samples/csharp-net/app-to-app-midi-cs/Properties/launchSettings.json
diff --git a/samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/app.manifest b/samples/csharp-net/app-to-app-midi-cs/app.manifest
similarity index 100%
rename from samples/csharp-net/app-to-app-midi-cs/MidiSample.AppToAppMidi/app.manifest
rename to samples/csharp-net/app-to-app-midi-cs/app.manifest
diff --git a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiBidi.cpp b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiBidi.cpp
index 86cb2d30..670ce893 100644
--- a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiBidi.cpp
+++ b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiBidi.cpp
@@ -33,38 +33,28 @@ CMidi2VirtualMidiBiDi::Initialize(
 
     m_callback = Callback;
     m_callbackContext = Context;
-    m_endpointId = internal::NormalizeEndpointInterfaceIdCopy(endpointId);
+    m_endpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(endpointId);
   
     //if (Context != MIDI_PROTOCOL_MANAGER_ENDPOINT_CREATION_CONTEXT)
     {
-        OutputDebugString(__FUNCTION__ L" Looking up Endpoint:");
-        OutputDebugString(m_endpointId.c_str());
-
         HRESULT hr = S_OK;
 
         // This should use SWD properties and not a string search
 
         if (internal::EndpointInterfaceIdContainsString(m_endpointId, MIDI_VIRT_INSTANCE_ID_DEVICE_PREFIX))
         {
-            OutputDebugString(__FUNCTION__ L" - endpoint id is a virtual device\n");
-
             m_isDeviceSide = true;
 
             LOG_IF_FAILED(hr = AbstractionState::Current().GetEndpointTable()->OnDeviceConnected(m_endpointId, this));
         }
         else if (internal::EndpointInterfaceIdContainsString(m_endpointId, MIDI_VIRT_INSTANCE_ID_CLIENT_PREFIX))
         {
-            OutputDebugString(__FUNCTION__ L" - endpoint id is a virtual client\n");
-
             m_isDeviceSide = false;
 
             LOG_IF_FAILED(hr = AbstractionState::Current().GetEndpointTable()->OnClientConnected(m_endpointId, this));
         }
         else
         {
-            OutputDebugString(__FUNCTION__ L" - endpoint id is unknown type\n");
-            OutputDebugString(m_endpointId.c_str());
-
             // we don't understand this endpoint id
 
             hr = E_FAIL;
@@ -83,8 +73,6 @@ CMidi2VirtualMidiBiDi::Initialize(
 HRESULT
 CMidi2VirtualMidiBiDi::Cleanup()
 {
-    OutputDebugString(__FUNCTION__ L" - enter\n");
-
     TraceLoggingWrite(
         MidiVirtualMidiAbstractionTelemetryProvider::Provider(),
         __FUNCTION__,
@@ -99,19 +87,11 @@ CMidi2VirtualMidiBiDi::Cleanup()
 
     if (m_isDeviceSide)
     {
-        OutputDebugString(__FUNCTION__ L" - this is the device BiDi, so calling OnDeviceDisconnected\n");
-
         LOG_IF_FAILED(AbstractionState::Current().GetEndpointTable()->OnDeviceDisconnected(m_endpointId));
     }
-    else
-    {
-        OutputDebugString(__FUNCTION__ L" - this is the client BiDi. Nothing needed here.\n");
-    }
 
     UnlinkAssociatedBiDi();
 
-    OutputDebugString(__FUNCTION__ L" - exit\n");
-
     return S_OK;
 }
 
diff --git a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp
index 9e168a42..9f0ab427 100644
--- a/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp
+++ b/src/api/Abstraction/VirtualMidiAbstraction/Midi2.VirtualMidiEndpointManager.cpp
@@ -106,7 +106,7 @@ CMidi2VirtualMidiEndpointManager::DeleteClientEndpoint(std::wstring clientShortI
     if (m_MidiDeviceManager != nullptr)
     {
         //auto instanceId = GetSwdPropertyInstanceId(clientEndpointInterfaceId);
-        auto instanceId = internal::NormalizeDeviceInstanceIdCopy(clientShortInstanceId);
+        auto instanceId = internal::NormalizeDeviceInstanceIdWStringCopy(clientShortInstanceId);
 
         if (instanceId != L"")
         {
@@ -134,7 +134,7 @@ CMidi2VirtualMidiEndpointManager::CreateParentDevice()
 
     // the parent device parameters are set by the transport (this)
     std::wstring parentDeviceName{ TRANSPORT_PARENT_DEVICE_NAME };
-    std::wstring parentDeviceId{ internal::NormalizeDeviceInstanceIdCopy(TRANSPORT_PARENT_ID) };
+    std::wstring parentDeviceId{ internal::NormalizeDeviceInstanceIdWStringCopy(TRANSPORT_PARENT_ID) };
 
     SW_DEVICE_CREATE_INFO createInfo = {};
     createInfo.cbSize = sizeof(createInfo);
@@ -154,7 +154,7 @@ CMidi2VirtualMidiEndpointManager::CreateParentDevice()
         deviceIdMaxSize
     ));
 
-    m_parentDeviceId = internal::NormalizeDeviceInstanceIdCopy(newDeviceId);
+    m_parentDeviceId = internal::NormalizeDeviceInstanceIdWStringCopy(newDeviceId);
 
     OutputDebugString(__FUNCTION__ L" New parent device instance id: ");
     OutputDebugString(newDeviceId);
@@ -263,7 +263,7 @@ CMidi2VirtualMidiEndpointManager::CreateClientVisibleEndpoint(
     createInfo.cbSize = sizeof(createInfo);
 
 
-    std::wstring instanceId = internal::NormalizeDeviceInstanceIdCopy(MIDI_VIRT_INSTANCE_ID_CLIENT_PREFIX + entry.ShortUniqueId);
+    std::wstring instanceId = internal::NormalizeDeviceInstanceIdWStringCopy(MIDI_VIRT_INSTANCE_ID_CLIENT_PREFIX + entry.ShortUniqueId);
 
 
 
@@ -301,7 +301,7 @@ CMidi2VirtualMidiEndpointManager::CreateClientVisibleEndpoint(
     // we need this for removal later
     entry.CreatedShortClientInstanceId = instanceId;
 
-    entry.CreatedClientEndpointId = internal::NormalizeEndpointInterfaceIdCopy(newDeviceInterfaceId);
+    entry.CreatedClientEndpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(newDeviceInterfaceId);
 
     //MidiEndpointTable::Current().AddCreatedEndpointDevice(entry);
     //MidiEndpointTable::Current().AddCreatedClient(entry.VirtualEndpointAssociationId, entry.CreatedClientEndpointId);
@@ -394,7 +394,7 @@ CMidi2VirtualMidiEndpointManager::CreateDeviceSideEndpoint(
     createInfo.cbSize = sizeof(createInfo);
 
 
-    std::wstring instanceId = internal::NormalizeDeviceInstanceIdCopy(MIDI_VIRT_INSTANCE_ID_DEVICE_PREFIX + entry.ShortUniqueId);
+    std::wstring instanceId = internal::NormalizeDeviceInstanceIdWStringCopy(MIDI_VIRT_INSTANCE_ID_DEVICE_PREFIX + entry.ShortUniqueId);
 
 
     createInfo.pszInstanceId = instanceId.c_str();
@@ -428,7 +428,7 @@ CMidi2VirtualMidiEndpointManager::CreateDeviceSideEndpoint(
     // loopback transport.
     m_MidiDeviceManager->DeleteAllEndpointInProtocolDiscoveredProperties(newDeviceInterfaceId);
 
-    entry.CreatedDeviceEndpointId = internal::NormalizeEndpointInterfaceIdCopy(newDeviceInterfaceId);
+    entry.CreatedDeviceEndpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(newDeviceInterfaceId);
 
     AbstractionState::Current().GetEndpointTable()->AddCreatedEndpointDevice(entry);
 
diff --git a/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp b/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp
index 70edc91f..c6a6b0d1 100644
--- a/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp
+++ b/src/api/Abstraction/VirtualMidiAbstraction/MidiEndpointTable.cpp
@@ -42,7 +42,7 @@ MidiEndpointTable::OnClientConnected(std::wstring clientEndpointInterfaceId, CMi
     {
         OutputDebugString(__FUNCTION__ L"");
 
-        std::wstring cleanId = internal::NormalizeEndpointInterfaceIdCopy(clientEndpointInterfaceId);
+        std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(clientEndpointInterfaceId);
 
         // look up the association ID in SWD properties
 
diff --git a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp b/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp
index c1eac76c..241723fe 100644
--- a/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp
+++ b/src/api/Abstraction/VirtualMidiAbstraction/swd_shared.cpp
@@ -47,7 +47,7 @@ std::wstring GetStringSwdProperty(std::wstring deviceInterfaceId, std::wstring p
 _Use_decl_annotations_
 std::wstring GetSwdPropertyVirtualEndpointAssociationId(std::wstring deviceInterfaceId)
 {
-    std::wstring cleanId = internal::NormalizeEndpointInterfaceIdCopy(deviceInterfaceId);
+    std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId);
 
     return internal::ToUpperTrimmedWStringCopy(GetStringSwdProperty(cleanId, STRING_PKEY_MIDI_VirtualMidiEndpointAssociator, L""));
 }
@@ -56,7 +56,7 @@ std::wstring GetSwdPropertyVirtualEndpointAssociationId(std::wstring deviceInter
 _Use_decl_annotations_
 std::wstring GetSwdPropertyInstanceId(std::wstring deviceInterfaceId)
 {
-    std::wstring cleanId = internal::NormalizeEndpointInterfaceIdCopy(deviceInterfaceId);
+    std::wstring cleanId = internal::NormalizeEndpointInterfaceIdWStringCopy(deviceInterfaceId);
 
-    return internal::NormalizeDeviceInstanceIdCopy(GetStringSwdProperty(cleanId, L"System.Devices.DeviceInstanceId", L""));
+    return internal::NormalizeDeviceInstanceIdWStringCopy(GetStringSwdProperty(cleanId, L"System.Devices.DeviceInstanceId", L""));
 }
diff --git a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
index 95fa84df..4faed135 100644
--- a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
+++ b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
@@ -2,7 +2,7 @@
 
 	
 		Windows.Devices.Midi2
-		1.0.0-preview.3-0144
+		1.0.0-preview.3-0146
 		Microsoft Corporation
 		Windows MIDI Services API. Minimum package necessary to use Windows MIDI Services from an app on a PC that has Windows MIDI Services installed.
 		MIT
diff --git a/src/api/Client/Midi2Client/IMidiEndpointDefinedConnectionSettings.idl b/src/api/Client/Midi2Client/IMidiEndpointConnectionSettings.idl
similarity index 85%
rename from src/api/Client/Midi2Client/IMidiEndpointDefinedConnectionSettings.idl
rename to src/api/Client/Midi2Client/IMidiEndpointConnectionSettings.idl
index 7cc1b93f..d6681ce6 100644
--- a/src/api/Client/Midi2Client/IMidiEndpointDefinedConnectionSettings.idl
+++ b/src/api/Client/Midi2Client/IMidiEndpointConnectionSettings.idl
@@ -17,10 +17,8 @@ namespace Windows.Devices.Midi2
 {
     [MIDI_API_CONTRACT(1)]
     [MIDI_INTERFACE_UUID("65736736-35f3-421c-a683-3a034ad0dcc2",1.0)]
-    interface IMidiEndpointDefinedConnectionSettings
+    interface IMidiEndpointConnectionSettings
     {
-        String SettingsJson { get; set; };
-
-        Boolean IsDirty{ get; set; };
+        String SettingsJson { get; };
     }
 }
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/IMidiTransportSettingsData.idl b/src/api/Client/Midi2Client/IMidiTransportSettingsData.idl
index 87943544..a19df44c 100644
--- a/src/api/Client/Midi2Client/IMidiTransportSettingsData.idl
+++ b/src/api/Client/Midi2Client/IMidiTransportSettingsData.idl
@@ -16,7 +16,5 @@ namespace Windows.Devices.Midi2
     interface IMidiTransportSettingsData
     {
         String SettingsJson { get; set; };
-
-        Boolean IsDirty{ get; set; };
     }
 }
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.cpp b/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
index 9126a57d..10984eeb 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.cpp
@@ -144,8 +144,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         winrt::guid sessionId,
         winrt::com_ptr serviceAbstraction,
         winrt::guid const connectionId,
-        winrt::hstring const endpointDeviceId, 
-        midi2::MidiEndpointConnectionOptions options
+        winrt::hstring const endpointDeviceId
     )
     {
         internal::LogInfo(__FUNCTION__, L"Internal Initialize ");
@@ -162,8 +161,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
             m_serviceAbstraction = serviceAbstraction;
             
-            m_options = options;
-
             return true;
         }
         catch (winrt::hresult_error const& ex)
@@ -185,8 +182,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
             // Activate the endpoint for this device. Will fail if the device is not a BiDi device
             if (!ActivateMidiStream(m_serviceAbstraction, __uuidof(IMidiBiDi), (void**)&m_endpointAbstraction))
             {
-                OutputDebugString(__FUNCTION__ L" coult not activate MIDI stream");
-
                 internal::LogGeneralError(__FUNCTION__, L"Could not activate MIDI Stream");
 
                 return false;
@@ -275,8 +270,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     MidiEndpointConnection::~MidiEndpointConnection()
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         if (!m_closeHasBeenCalled)
         {
             InternalClose();
@@ -288,8 +281,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     void MidiEndpointConnection::InitializePlugins() noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         internal::LogInfo(__FUNCTION__, L"Initializing message processing plugins");
 
         for (const auto& plugin : m_messageProcessingPlugins)
@@ -309,8 +300,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     void MidiEndpointConnection::CallOnConnectionOpenedOnPlugins() noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         internal::LogInfo(__FUNCTION__, L"Notifying message processing plugins that the connection is opened");
 
         for (const auto& plugin : m_messageProcessingPlugins)
@@ -874,6 +863,46 @@ namespace winrt::Windows::Devices::Midi2::implementation
     }
 
 
+
+
+
+    _Use_decl_annotations_
+    midi2::MidiSendMessageResult MidiEndpointConnection::SendMessagesWordList(
+        internal::MidiTimestamp timestamp,
+        collections::IVectorView const& words) noexcept
+    {
+        UNREFERENCED_PARAMETER(timestamp);
+        UNREFERENCED_PARAMETER(words);
+
+        // TODO: Implement SendMessagesWordList
+
+        return midi2::MidiSendMessageResult::Succeeded;
+    }
+
+
+
+
+    _Use_decl_annotations_
+    midi2::MidiSendMessageResult MidiEndpointConnection::SendMessagesWordArray(
+        internal::MidiTimestamp timestamp,
+        winrt::array_view words) noexcept
+    {
+        UNREFERENCED_PARAMETER(timestamp);
+        UNREFERENCED_PARAMETER(words);
+
+        // TODO: Implement SendMessagesWordArray
+
+        return midi2::MidiSendMessageResult::Succeeded;
+    }
+
+
+
+
+
+
+
+
+
     _Use_decl_annotations_
     bool MidiEndpointConnection::ActivateMidiStream(
         winrt::com_ptr serviceAbstraction,
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.h b/src/api/Client/Midi2Client/MidiEndpointConnection.h
index bece7b56..9d5d63c2 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.h
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.h
@@ -41,52 +41,44 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
 
         bool IsOpen() const noexcept { return m_isOpen; }
-        midi2::IMidiEndpointDefinedConnectionSettings Settings() const noexcept { return m_settings; }
+        midi2::IMidiEndpointConnectionSettings Settings() const noexcept { return m_settings; }
 
         foundation::IInspectable Tag() const noexcept { return m_tag; }
         void Tag(_In_ foundation::IInspectable value) noexcept { m_tag = value; }
 
 
-        _Success_(return == true)
         bool InternalInitialize(
             _In_ winrt::guid sessionId,
             _In_ winrt::com_ptr serviceAbstraction,
             _In_ winrt::guid const connectionId,
-            _In_ winrt::hstring const endpointDeviceId,
-            _In_ midi2::MidiEndpointConnectionOptions options);
+            _In_ winrt::hstring const endpointDeviceId);
 
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessagePacket(
             _In_ midi2::IMidiUniversalPacket const& ump) noexcept;
 
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageStruct(
             _In_ internal::MidiTimestamp timestamp,
             _In_ midi2::MidiMessageStruct const& message,
             _In_ uint8_t wordCount) noexcept;
 
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageWords(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ uint32_t const word0) noexcept;
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageWords(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ uint32_t const word0,
             _In_ uint32_t const word1) noexcept;
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageWords(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ uint32_t const word0,
             _In_ uint32_t const word1,
             _In_ uint32_t const word2) noexcept;
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageWords(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ uint32_t const word0,
@@ -94,14 +86,12 @@ namespace winrt::Windows::Devices::Midi2::implementation
             _In_ uint32_t const word2,
             _In_ uint32_t const word3) noexcept;
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageWordArray(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ winrt::array_view words,
             _In_ uint32_t const startIndex,
             _In_ uint8_t const wordCount) noexcept;
 
-        _Success_(return == true)
         midi2::MidiSendMessageResult SendMessageBuffer(
             _In_ internal::MidiTimestamp timestamp,
             _In_ foundation::IMemoryBuffer const& buffer,
@@ -109,6 +99,14 @@ namespace winrt::Windows::Devices::Midi2::implementation
             _In_ uint8_t byteLength) noexcept;
 
 
+        midi2::MidiSendMessageResult SendMessagesWordList(
+            _In_ internal::MidiTimestamp timestamp, 
+            _In_ collections::IVectorView const& words) noexcept;
+
+        midi2::MidiSendMessageResult SendMessagesWordArray(
+            _In_ internal::MidiTimestamp timestamp, 
+            _In_ winrt::array_view words) noexcept;
+
 
         _Success_(return == true)
         bool Open();
@@ -155,12 +153,12 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
         winrt::event> m_messageReceivedEvent;
 
-        midi2::MidiEndpointConnectionOptions m_options;
+        //midi2::MidiEndpointConnectionOptions m_options;
 
         foundation::Collections::IVector
             m_messageProcessingPlugins{ winrt::multi_threaded_vector() };
 
-        midi2::IMidiEndpointDefinedConnectionSettings m_settings{ nullptr };
+        midi2::IMidiEndpointConnectionSettings m_settings{ nullptr };
 
 
         bool ValidateUmp(_In_ uint32_t word0, _In_ uint8_t wordCount) noexcept;
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.idl b/src/api/Client/Midi2Client/MidiEndpointConnection.idl
index a29251b9..150ee608 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.idl
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.idl
@@ -16,12 +16,12 @@ MIDI_IDL_IMPORT
 
 import "IMidiMessageReceivedEventSource.idl";
 
-import "MidiStreamConfigurationRequestedSettings.idl";
+//import "MidiStreamConfigurationRequestedSettings.idl";
 
 import "IMidiEndpointMessageProcessingPlugin.idl";
 import "MidiSendMessageResultEnum.idl";
 
-import "IMidiEndpointDefinedConnectionSettings.idl";
+import "IMidiEndpointConnectionSettings.idl";
 
 import "IMidiEndpointConnectionSource.idl";
 
@@ -53,8 +53,8 @@ namespace Windows.Devices.Midi2
         // here for cases when the app holds on to an instance of this outside of the map
         Boolean IsOpen{ get; };
 
-
-        IMidiEndpointDefinedConnectionSettings Settings{ get; };
+        // read-only copy of the settings used to create this connection
+        IMidiEndpointConnectionSettings Settings{ get; };
 
         Boolean Open();
 
@@ -85,6 +85,10 @@ namespace Windows.Devices.Midi2
         // for sending a section of a pre-existing buffer. Used when a client app is maintaining its own memory       
         MidiSendMessageResult SendMessageBuffer(MIDI_TIMESTAMP timestamp, Windows.Foundation.IMemoryBuffer buffer, UInt32 byteOffset, UInt8 byteLength);
 
+        // These methods will send multiple messages. The words must be ordered correctly
+        // so they are in order from word0 to wordn for each message.
+        MidiSendMessageResult SendMessagesWordList(MIDI_TIMESTAMP timestamp, IVectorView words);
+        MidiSendMessageResult SendMessagesWordArray(MIDI_TIMESTAMP timestamp, UInt32[] words);
 
     }
 
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.cpp b/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.cpp
deleted file mode 100644
index 047ad215..00000000
--- a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License
-// ============================================================================
-// This is part of the Windows MIDI Services App API and should be used
-// in your Windows application via an official binary distribution.
-// Further information: https://github.com/microsoft/MIDI/
-// ============================================================================
-
-
-#include "pch.h"
-#include "MidiEndpointConnectionOptions.h"
-#include "MidiEndpointConnectionOptions.g.cpp"
-
-
-namespace winrt::Windows::Devices::Midi2::implementation
-{
-}
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.h b/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.h
deleted file mode 100644
index 86dd8f46..00000000
--- a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License
-// ============================================================================
-// This is part of the Windows MIDI Services App API and should be used
-// in your Windows application via an official binary distribution.
-// Further information: https://github.com/microsoft/MIDI/
-// ============================================================================
-
-
-#pragma once
-#include "MidiEndpointConnectionOptions.g.h"
-
-namespace winrt::Windows::Devices::Midi2::implementation
-{
-    struct MidiEndpointConnectionOptions : MidiEndpointConnectionOptionsT
-    {
-    public:
-        MidiEndpointConnectionOptions() = default;
-
-        midi2::MidiEndpointConnectionSharingPreference ConnectionSharingPreference() { return m_connectionSharingPreference; }
-        void ConnectionSharingPreference(_In_ midi2::MidiEndpointConnectionSharingPreference const& value) { m_connectionSharingPreference = value; }
-
-
-        midi2::MidiStreamConfigurationRequestedSettings RequestedStreamConfiguration() { return m_streamRequestedConfigurationSettings; }
-        void RequestedStreamConfiguration(_In_ midi2::MidiStreamConfigurationRequestedSettings const& value) { m_streamRequestedConfigurationSettings = value; }
-
-    private:
-        bool m_disableAutomaticEndpointMetadataHandling = false;
-        bool m_disableAutomaticFunctionBlockMetadataHandling = false;
-        bool m_disableAutomaticStreamConfiguration = false;
-
-        midi2::MidiStreamConfigurationRequestedSettings m_streamRequestedConfigurationSettings;
-
-        midi2::MidiEndpointConnectionSharingPreference m_connectionSharingPreference{ midi2::MidiEndpointConnectionSharingPreference::Default };
-    };
-}
-namespace winrt::Windows::Devices::Midi2::factory_implementation
-{
-    struct MidiEndpointConnectionOptions : MidiEndpointConnectionOptionsT
-    {
-    };
-}
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.idl b/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.idl
deleted file mode 100644
index e7d14c0e..00000000
--- a/src/api/Client/Midi2Client/MidiEndpointConnectionOptions.idl
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License
-// ============================================================================
-// This is part of the Windows MIDI Services App API and should be used
-// in your Windows application via an official binary distribution.
-// Further information: https://github.com/microsoft/MIDI/
-// ============================================================================
-
-#include "midl_defines.h"
-MIDI_IDL_IMPORT
-
-import "MidiEndpointConnectionSharingPreferenceEnum.idl";
-
-import "MidiStreamConfigurationRequestedSettings.idl";
-
-namespace Windows.Devices.Midi2
-{
-    [MIDI_API_CONTRACT(1)]
-    [default_interface]
-    runtimeclass MidiEndpointConnectionOptions
-    {
-        MidiEndpointConnectionOptions();
-
-        MidiEndpointConnectionSharingPreference ConnectionSharingPreference{ get; set; };
-
-        
-        // this has all the settings we use in stream configuration
-        MidiStreamConfigurationRequestedSettings RequestedStreamConfiguration{ get; set; };
-   }
-}
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnectionSharingEnum.idl b/src/api/Client/Midi2Client/MidiEndpointConnectionSharingEnum.idl
deleted file mode 100644
index 0bbf8318..00000000
--- a/src/api/Client/Midi2Client/MidiEndpointConnectionSharingEnum.idl
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License
-// ============================================================================
-// This is part of the Windows MIDI Services App API and should be used
-// in your Windows application via an official binary distribution.
-// Further information: https://github.com/microsoft/MIDI/
-// ============================================================================
-
-#include "midl_defines.h"
-MIDI_IDL_IMPORT
-
-namespace Windows.Devices.Midi2
-{
-    [MIDI_API_CONTRACT(1)]
-    enum MidiEndpointConnectionSharing
-    {
-        Unknown = 0x0,
-
-        MultiClient = 0x10,
-        Exclusive = 0x20,
-    };
-}
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnectionSharingPreferenceEnum.idl b/src/api/Client/Midi2Client/MidiEndpointConnectionSharingPreferenceEnum.idl
deleted file mode 100644
index badb08ab..00000000
--- a/src/api/Client/Midi2Client/MidiEndpointConnectionSharingPreferenceEnum.idl
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License
-// ============================================================================
-// This is part of the Windows MIDI Services App API and should be used
-// in your Windows application via an official binary distribution.
-// Further information: https://github.com/microsoft/MIDI/
-// ============================================================================
-
-#include "midl_defines.h"
-MIDI_IDL_IMPORT
-
-namespace Windows.Devices.Midi2
-{
-    [MIDI_API_CONTRACT(1)]
-    enum MidiEndpointConnectionSharingPreference
-    {
-        Default = 0x0,                  // This is what everyone should choose whenever possible
-
-        PreferMultiClient = 0x10,
-        RequireMultiClient = 0x11,
-
-        PreferExclusiveMode = 0x20,     // these two are really for app-to-app / virtual MIDI devices.
-        RequireExclusiveMode = 0x21,    // the "require" options will cause the connection to fail to open if condition is not met
-    };
-}
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
index 847acfb7..d93cc756 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
@@ -651,16 +651,12 @@ namespace winrt::Windows::Devices::Midi2::implementation
     void MidiEndpointDeviceInformation::InternalUpdateFromDeviceInformation(
         winrt::Windows::Devices::Enumeration::DeviceInformation const& deviceInformation) noexcept
     {
-        OutputDebugString(L"" __FUNCTION__);
-
         if (deviceInformation == nullptr) return;
 
         for (auto&& [key, value] : deviceInformation.Properties())
         {
             // insert does a replace if the key exists in the map
 
-        //    OutputDebugString(key.c_str());
-
             m_properties.Insert(key, value);
 
             if (key == STRING_PKEY_MIDI_IN_GroupTerminalBlocks)
@@ -677,7 +673,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
             //}
         }
 
-        m_id = deviceInformation.Id();
+        m_id = internal::NormalizeEndpointInterfaceIdHStringCopy(deviceInformation.Id().c_str());
         m_transportSuppliedEndpointName = deviceInformation.Name();
 
 
@@ -689,8 +685,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
             if (deviceInformation.Properties().HasKey(functionBlockProperty))
             {
-                OutputDebugString(__FUNCTION__ L" Update includes a function block property\n");
-
                 // update the function block
                 auto refArray = GetBinaryProperty(functionBlockProperty);
 
@@ -703,8 +697,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
             if (deviceInformation.Properties().HasKey(functionBlockNameProperty))
             {
-                OutputDebugString(__FUNCTION__ L" Update includes a function block Name property\n");
-
                 // update the function block property name
 
                 if (m_functionBlocks.HasKey(fb))
@@ -729,8 +721,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     bool MidiEndpointDeviceInformation::UpdateFromDeviceInformation(
         winrt::Windows::Devices::Enumeration::DeviceInformation const& deviceInformation) noexcept
     {
-    //    OutputDebugString(L"" __FUNCTION__);
-
         if (deviceInformation == nullptr) return false;
 
         // TODO: If an Id is present, check that the ids (after lowercasing) are the same before allowing this.
@@ -746,8 +736,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     bool MidiEndpointDeviceInformation::UpdateFromDeviceInformationUpdate(
         winrt::Windows::Devices::Enumeration::DeviceInformationUpdate const& deviceInformationUpdate) noexcept
     {
-        OutputDebugString(__FUNCTION__ L"\n");
-
         if (deviceInformationUpdate == nullptr) return false;
 
         // TODO: Check that the ids (after lowercasing) are the same before allowing this.
@@ -779,8 +767,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
             if (deviceInformationUpdate.Properties().HasKey(functionBlockProperty))
             {
-                OutputDebugString(__FUNCTION__ L" Update includes a function block property\n");
-
                 // update the function block
                 auto refArray = GetBinaryProperty(functionBlockProperty);
                 
@@ -792,8 +778,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
             if (deviceInformationUpdate.Properties().HasKey(functionBlockNameProperty))
             {
-                OutputDebugString(__FUNCTION__ L" Update includes a function block Name property\n");
-
                 // update the function block property name
 
                 if (m_functionBlocks.HasKey(fb))
@@ -822,8 +806,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     _Use_decl_annotations_
     void MidiEndpointDeviceInformation::AddOrUpdateFunctionBlock(foundation::IReferenceArray refArray)
     {
-        OutputDebugString(__FUNCTION__ L"\n");
-
         if (refArray != nullptr)
         {
             auto data = refArray.Value();
@@ -863,8 +845,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     void MidiEndpointDeviceInformation::ReadDeviceIdentity()
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         auto key = STRING_PKEY_MIDI_DeviceIdentity;
 
         auto refArray = GetBinaryProperty(key);
@@ -877,18 +857,12 @@ namespace winrt::Windows::Devices::Midi2::implementation
             if (arraySize == sizeof(m_deviceIdentity))
             {
                 memcpy(&m_deviceIdentity, data.data(), arraySize);
-
-            //    OutputDebugString(__FUNCTION__ L" Device identity values read");
             }
             else
             {
-                OutputDebugString(__FUNCTION__ L" Unable to read device identity. Size of array is incorrect.");
+                internal::LogGeneralError(__FUNCTION__, L"Unable to read device identity. Size of array is incorrect");
             }
         }
-        else
-        {
-        //    OutputDebugString(__FUNCTION__ L" Unable to read device identity. Value is null.");
-        }
     }
 
 
@@ -897,33 +871,27 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         if (m_properties.HasKey(key))
         {
-         //   OutputDebugString(__FUNCTION__ L" Key present.");
-
             auto value = m_properties.Lookup(key).as();
 
             if (value != nullptr)
             {
-           //     OutputDebugString(__FUNCTION__ L" Value != null.");
-
                 auto t = value.Type();
 
                 if (t == foundation::PropertyType::UInt8Array)
                 {
-                 //   OutputDebugString(__FUNCTION__ L" Value type is UInt8Array.");
-
                     auto refArray = winrt::unbox_value>(m_properties.Lookup(key));
 
                     return refArray;
                 }
                 else
                 {
-                    OutputDebugString(__FUNCTION__ L" Value type is something unexpected.");
+                    internal::LogGeneralError(__FUNCTION__, L"Value type is something unexpected");
                 }
             }
         }
         else
         {
-        //    OutputDebugString(__FUNCTION__ L" Key not present.");
+            internal::LogGeneralError(__FUNCTION__, L"Property key not present");
         }
 
         return nullptr;
@@ -935,8 +903,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         try
         {
-            //OutputDebugString(L"" __FUNCTION__);
-
             // in groups property
             // STRING_PKEY_MIDI_IN_GroupTerminalBlocks
 
@@ -949,9 +915,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
                     auto data = refArray.Value();
                     auto arraySize = data.size();
 
-                    //OutputDebugString(L"Array size is:");
-                    //OutputDebugString(std::to_wstring(data.size()).c_str());
-
                     uint32_t offset = 0;
 
                     // get the KS_MULTIPLE_ITEMS info. First is a ULONG of the total size, next is a ULONG of the count of items
@@ -968,9 +931,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
                         auto block = winrt::make_self();
 
 
-                        //OutputDebugString(L"Header reported size is:");
-                        //OutputDebugString(std::to_wstring(pheader->Size).c_str());
-
                         int charOffset = sizeof(UMP_GROUP_TERMINAL_BLOCK_HEADER);
 
                         std::wstring name{};
@@ -998,8 +958,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         }
         catch (...)
         {
-            // can't blow up.
-            OutputDebugString(L"Exception processing endpoint GTB property");
+            internal::LogGeneralError(__FUNCTION__, L"Exception processing endpoint GTB property");
         }
     }
 
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
index 77a530e1..92f9e1d5 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
@@ -20,9 +20,9 @@ namespace winrt::Windows::Devices::Midi2::implementation
         //static winrt::hstring UniversalMidiPacketBidirectionalInterfaceClassId() noexcept { return L"" /* STRING_DEVINTERFACE_UNIVERSALMIDIPACKET_BIDI */; }
 
         // these would be more robust if they did an enumeration lookup on the loopback/ping properties
-        static winrt::hstring DiagnosticsLoopbackAEndpointId() noexcept { return MIDI_DIAGNOSTICS_LOOPBACK_BIDI_ID_A; }
-        static winrt::hstring DiagnosticsLoopbackBEndpointId() noexcept { return MIDI_DIAGNOSTICS_LOOPBACK_BIDI_ID_B; }
-        static winrt::hstring DiagnosticsInternalPingEndpointId() noexcept { return MIDI_DIAGNOSTICS_PING_BIDI_ID; }
+        static winrt::hstring DiagnosticsLoopbackAEndpointId() noexcept { return internal::NormalizeEndpointInterfaceIdHStringCopy(MIDI_DIAGNOSTICS_LOOPBACK_BIDI_ID_A).c_str(); }
+        static winrt::hstring DiagnosticsLoopbackBEndpointId() noexcept { return internal::NormalizeEndpointInterfaceIdHStringCopy(MIDI_DIAGNOSTICS_LOOPBACK_BIDI_ID_B).c_str(); }
+        static winrt::hstring DiagnosticsInternalPingEndpointId() noexcept { return internal::NormalizeEndpointInterfaceIdHStringCopy(MIDI_DIAGNOSTICS_PING_BIDI_ID).c_str(); }
 
         static winrt::hstring EndpointInterfaceClass() noexcept { return STRING_DEVINTERFACE_UNIVERSALMIDIPACKET_BIDI; }
 
@@ -40,7 +40,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         static winrt::Windows::Devices::Enumeration::DeviceWatcher CreateWatcher(
             _In_ midi2::MidiEndpointDeviceInformationFilter const& endpointFilter) noexcept;
 
-        static bool MidiEndpointDeviceInformation::DeviceMatchesFilter(
+        static bool DeviceMatchesFilter(
             _In_ midi2::MidiEndpointDeviceInformation const& deviceInformation,
             _In_ midi2::MidiEndpointDeviceInformationFilter const& endpointFilter) noexcept;
 
diff --git a/src/api/Client/Midi2Client/MidiGroupTerminalBlock.cpp b/src/api/Client/Midi2Client/MidiGroupTerminalBlock.cpp
index 083330be..9544eb89 100644
--- a/src/api/Client/Midi2Client/MidiGroupTerminalBlock.cpp
+++ b/src/api/Client/Midi2Client/MidiGroupTerminalBlock.cpp
@@ -129,7 +129,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
         }
         else
         {
-            OutputDebugString(L"Header is null");
             return false;
         }
     }
diff --git a/src/api/Client/Midi2Client/MidiGroupTerminalBlock.h b/src/api/Client/Midi2Client/MidiGroupTerminalBlock.h
index 581cbb06..5ce191e0 100644
--- a/src/api/Client/Midi2Client/MidiGroupTerminalBlock.h
+++ b/src/api/Client/Midi2Client/MidiGroupTerminalBlock.h
@@ -51,7 +51,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         uint8_t m_firstGroupIndex{ 0 };
         uint8_t m_numberOfGroupsSpanned{ 0 };
 
-        uint32_t MidiGroupTerminalBlock::CalculateBandwidth(_In_ uint16_t gtbBandwidthValue);
+        uint32_t CalculateBandwidth(_In_ uint16_t gtbBandwidthValue);
 
     };
 }
diff --git a/src/api/Client/Midi2Client/MidiSendMessageResultEnum.idl b/src/api/Client/Midi2Client/MidiSendMessageResultEnum.idl
index 4bc83d8d..75598b26 100644
--- a/src/api/Client/Midi2Client/MidiSendMessageResultEnum.idl
+++ b/src/api/Client/Midi2Client/MidiSendMessageResultEnum.idl
@@ -42,6 +42,11 @@ namespace Windows.Devices.Midi2
         DataIndexOutOfRange =               0x00400000,
         TimestampOutOfRange =               0x00800000,
 
+        // multiple-message failure reasons -------------------------------------
+        MessageListPartiallyProcessed =     0x00A00000,
+
+
+
         Other =                             0x01000000,
     };
 }
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiService.cpp b/src/api/Client/Midi2Client/MidiService.cpp
index 6d1d9e65..ca403082 100644
--- a/src/api/Client/Midi2Client/MidiService.cpp
+++ b/src/api/Client/Midi2Client/MidiService.cpp
@@ -55,11 +55,9 @@ namespace winrt::Windows::Devices::Midi2::implementation
             return *responseSummary;
         }
 
-        auto options = winrt::make();
-        
         // This ID must be consistent with what the service is set up to use.
 
-        auto endpoint = session.CreateEndpointConnection(MIDI_DIAGNOSTICS_PING_BIDI_ID, options);
+        auto endpoint = session.CreateEndpointConnection(MIDI_DIAGNOSTICS_PING_BIDI_ID);
 
         if (endpoint == nullptr)
         {
@@ -251,7 +249,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
                     if (sessionListJson != nullptr && sessionListJson.Length() > 0)
                     {
-                        winrt::hstring hstr = sessionListJson;
+                        winrt::hstring hstr(sessionListJson, sessionListJson.Length());
 
                         // Parse the json, create the objects, throw them into the vector and return
 
diff --git a/src/api/Client/Midi2Client/MidiSession.cpp b/src/api/Client/Midi2Client/MidiSession.cpp
index df1fe7a0..2887f1a9 100644
--- a/src/api/Client/Midi2Client/MidiSession.cpp
+++ b/src/api/Client/Midi2Client/MidiSession.cpp
@@ -148,29 +148,20 @@ namespace winrt::Windows::Devices::Midi2::implementation
     _Use_decl_annotations_
     midi2::MidiEndpointConnection MidiSession::CreateEndpointConnection(
         winrt::hstring const& endpointDeviceId,
-        midi2::MidiEndpointConnectionOptions const& options,
-        midi2::IMidiEndpointDefinedConnectionSettings const& /*settings*/
+        midi2::IMidiEndpointConnectionSettings const& /*settings*/
         ) noexcept
     {
         internal::LogInfo(__FUNCTION__, L"Creating Endpoint Connection");
 
         try
         {
-            auto normalizedDeviceId = winrt::to_hstring(internal::NormalizeEndpointInterfaceIdCopy(endpointDeviceId.c_str()).c_str());
+            auto normalizedDeviceId = winrt::to_hstring(internal::NormalizeEndpointInterfaceIdHStringCopy(endpointDeviceId.c_str()).c_str());
             auto endpointConnection = winrt::make_self();
 
-            // default options
-            midi2::MidiEndpointConnectionOptions fixedOptions{ nullptr };
-
-            if (options != nullptr)
-            {
-                fixedOptions = options;
-            }
-
             // generate internal endpoint Id
             auto connectionInstanceId = foundation::GuidHelper::CreateNewGuid();
 
-            if (endpointConnection->InternalInitialize(m_id, m_serviceAbstraction, connectionInstanceId, normalizedDeviceId, fixedOptions))
+            if (endpointConnection->InternalInitialize(m_id, m_serviceAbstraction, connectionInstanceId, normalizedDeviceId))
             {
                 m_connections.Insert(connectionInstanceId, *endpointConnection);
 
@@ -193,21 +184,12 @@ namespace winrt::Windows::Devices::Midi2::implementation
         }
     }
 
-    _Use_decl_annotations_
-    midi2::MidiEndpointConnection MidiSession::CreateEndpointConnection(
-        winrt::hstring const& endpointDeviceId,
-        midi2::MidiEndpointConnectionOptions const& options
-        ) noexcept
-    {
-        return CreateEndpointConnection(endpointDeviceId, options, nullptr);
-    }
-
     _Use_decl_annotations_
     midi2::MidiEndpointConnection MidiSession::CreateEndpointConnection(
         winrt::hstring const& endpointDeviceId
         ) noexcept
     {
-        return CreateEndpointConnection(endpointDeviceId, nullptr, nullptr);
+        return CreateEndpointConnection(endpointDeviceId, nullptr);
     }
 
 
@@ -414,7 +396,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         internal::LogInfo(__FUNCTION__, L"Virtual device creation worked.");
 
         // Creating the device succeeded, so create the connection
-        auto connection = CreateEndpointConnection(endpointDeviceId, nullptr, nullptr);
+        auto connection = CreateEndpointConnection(endpointDeviceId, nullptr);
 
         internal::LogInfo(__FUNCTION__, L"Created endpoint connection");
 
diff --git a/src/api/Client/Midi2Client/MidiSession.h b/src/api/Client/Midi2Client/MidiSession.h
index 8c1568e8..eefd2861 100644
--- a/src/api/Client/Midi2Client/MidiSession.h
+++ b/src/api/Client/Midi2Client/MidiSession.h
@@ -44,13 +44,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
         winrt::Windows::Devices::Midi2::MidiEndpointConnection CreateEndpointConnection(
             _In_ winrt::hstring const& endpointDeviceId,
-            _In_ midi2::MidiEndpointConnectionOptions const& options
-        ) noexcept;
-
-        winrt::Windows::Devices::Midi2::MidiEndpointConnection CreateEndpointConnection(
-            _In_ winrt::hstring const& endpointDeviceId,
-            _In_ midi2::MidiEndpointConnectionOptions const& options,
-            _In_ midi2::IMidiEndpointDefinedConnectionSettings const& settings
+            _In_ midi2::IMidiEndpointConnectionSettings const& settings
         ) noexcept;
 
 
diff --git a/src/api/Client/Midi2Client/MidiSession.idl b/src/api/Client/Midi2Client/MidiSession.idl
index 3a30e233..5b1fcd49 100644
--- a/src/api/Client/Midi2Client/MidiSession.idl
+++ b/src/api/Client/Midi2Client/MidiSession.idl
@@ -10,9 +10,8 @@
 MIDI_IDL_IMPORT
 
 import "MidiEndpointConnection.idl";
-import "IMidiEndpointDefinedConnectionSettings.idl";
+import "IMidiEndpointConnectionSettings.idl";
 import "MidiSessionSettings.idl";
-import "MidiEndpointConnectionOptions.idl";
 import "MidiVirtualEndpointDeviceDefinition.idl";
 
 
@@ -37,19 +36,17 @@ namespace Windows.Devices.Midi2
         // consuming code to use this table.
         IMapView Connections{ get; };
 
+        // create an unopened connection to the specified endpoint
         MidiEndpointConnection CreateEndpointConnection(
             String endpointDeviceId
         );
 
+        // create an unopened connection to the specified endpoint,
+        // and supply the provided settings to the endpoint device
+        // manager in the service
         MidiEndpointConnection CreateEndpointConnection(
             String endpointDeviceId,
-            MidiEndpointConnectionOptions options
-        );
-
-        MidiEndpointConnection CreateEndpointConnection(
-            String endpointDeviceId,
-            MidiEndpointConnectionOptions options,
-            IMidiEndpointDefinedConnectionSettings settings
+            IMidiEndpointConnectionSettings settings
         );
 
         // creating it here helps ensure this is the only possible owner
@@ -62,10 +59,6 @@ namespace Windows.Devices.Midi2
         // This will close and remove a single endpoint connection instance.
         void DisconnectEndpointConnection(Guid endpointConnectionId);
 
-        // This is associated with the session so we can session-scoped
-        // lifetime / info as well as provide the session-level service interface
-//        MidiVirtualDeviceManager VirtualDeviceManager{ get; };
-
         // changes the session name in the service. Needed
         // for cases where the session name is a project name
         // or similar
diff --git a/src/api/Client/Midi2Client/MidiSessionConnectionInformation.cpp b/src/api/Client/Midi2Client/MidiSessionConnectionInformation.cpp
index 87b5c2f8..cb5f95b0 100644
--- a/src/api/Client/Midi2Client/MidiSessionConnectionInformation.cpp
+++ b/src/api/Client/Midi2Client/MidiSessionConnectionInformation.cpp
@@ -13,7 +13,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
         foundation::DateTime const earliestConnectionTime
         )
     {
-        m_endpointDeviceId = endpointDeviceId;
+        m_endpointDeviceId = internal::NormalizeEndpointInterfaceIdHStringCopy(endpointDeviceId);
         m_instanceCount = instanceCount;
         m_earliestConnectionTime = earliestConnectionTime;
     }
diff --git a/src/api/Client/Midi2Client/MidiStreamMessageBuilder.h b/src/api/Client/Midi2Client/MidiStreamMessageBuilder.h
index cecfe2f6..f5280ed6 100644
--- a/src/api/Client/Midi2Client/MidiStreamMessageBuilder.h
+++ b/src/api/Client/Midi2Client/MidiStreamMessageBuilder.h
@@ -121,7 +121,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     private:
 
-        static collections::IVector MidiStreamMessageBuilder::BuildSplitTextMessages(
+        static collections::IVector BuildSplitTextMessages(
             _In_ internal::MidiTimestamp const timestamp,
             _In_ uint8_t const status,
             _In_ uint16_t const word0Remainder,
diff --git a/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.cpp b/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.cpp
index 0af916ff..5c643179 100644
--- a/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.cpp
+++ b/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.cpp
@@ -21,7 +21,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         UNREFERENCED_PARAMETER(block);
 
-        //throw hresult_not_implemented();
+        // TODO
     }
 
     _Use_decl_annotations_
@@ -29,35 +29,29 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         UNREFERENCED_PARAMETER(name);
 
-        //throw hresult_not_implemented();
+        // TODO
     }
 
 
     _Use_decl_annotations_
     void MidiVirtualEndpointDevice::Initialize(midi2::IMidiEndpointConnectionSource const& endpointConnection) noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         m_endpointConnection = endpointConnection.as();
     }
 
     void MidiVirtualEndpointDevice::OnEndpointConnectionOpened() noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
-        //throw hresult_not_implemented();
+        // nothing to do here
     }
 
     void MidiVirtualEndpointDevice::Cleanup() noexcept
     {
-        //throw hresult_not_implemented();
+        // nothing to do here
     }
 
     _Use_decl_annotations_
     void MidiVirtualEndpointDevice::SendFunctionBlockInfoNotificationMessage(midi2::MidiFunctionBlock const& fb) noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         auto functionBlockNotification = midi2::MidiStreamMessageBuilder::BuildFunctionBlockInfoNotificationMessage(
             0,
             true,
@@ -78,8 +72,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     _Use_decl_annotations_
     void MidiVirtualEndpointDevice::SendFunctionBlockNameNotificationMessages(midi2::MidiFunctionBlock const& fb) noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         if (fb.Name() == L"") return;
 
         auto nameMessages = midi2::MidiStreamMessageBuilder::BuildFunctionBlockNameNotificationMessages(
@@ -102,8 +94,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
         bool& skipFurtherListeners,
         bool& skipMainMessageReceivedEvent)  noexcept
     {
-        OutputDebugString(__FUNCTION__ L"");
-
         bool handled = false;
 
         if (args.MessageType() == MidiMessageType::Stream128)
@@ -243,8 +233,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         try
         {
-            OutputDebugString(__FUNCTION__ L"");
-
             // populate all the views, properties, blocks, etc.
 
             m_areFunctionBlocksStatic = definition.AreFunctionBlocksStatic();
diff --git a/src/api/Client/Midi2Client/WinRTActivationEntries.txt b/src/api/Client/Midi2Client/WinRTActivationEntries.txt
index 5654d247..03f184d4 100644
--- a/src/api/Client/Midi2Client/WinRTActivationEntries.txt
+++ b/src/api/Client/Midi2Client/WinRTActivationEntries.txt
@@ -55,7 +55,7 @@ Windows.Devices.Midi2.MidiMessageTypeEndpointListener | 0 | 0 | 0
 
 # Virtual Device Message Processing Plugins
 
-Windows.Devices.Midi2.MidiVirtualEndpointDevice | 0 | 0 | 0
+#Windows.Devices.Midi2.MidiVirtualEndpointDevice | 0 | 0 | 0
 Windows.Devices.Midi2.MidiVirtualEndpointDeviceDefinition | 0 | 0 | 0
 
 # Events
@@ -69,8 +69,8 @@ Windows.Devices.Midi2.IMidiEndpointConnectionStatics | 0 | 0 | 0
 
 # Endpoint Open Options
 
-Windows.Devices.Midi2.MidiEndpointConnectionOptions | 0 | 0 | 0
-Windows.Devices.Midi2.MidiStreamConfigurationSettings | 0 | 0 | 0
+#Windows.Devices.Midi2.MidiEndpointConnectionOptions | 0 | 0 | 0
+#Windows.Devices.Midi2.MidiStreamConfigurationSettings | 0 | 0 | 0
 
 
 # Service
diff --git a/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj b/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj
index 4c897c80..f5c0d2aa 100644
--- a/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj
+++ b/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj
@@ -159,7 +159,7 @@
   
     
       _DEBUG;%(PreprocessorDefinitions);WINAPI_FAMILY=WINAPI_FAMILY_DESKTOP_APP
-      stdcpp17
+      stdcpp20
       false
       true
       true
@@ -167,6 +167,8 @@
       $(ProjectDir);$(GeneratedFilesDir);$(IntDir);$(SolutionDir)inc;$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration);$(SolutionDir)VSFiles\intermediate\midi2.midisrvabstraction\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories)
       $(ProjectDir);$(GeneratedFilesDir);$(IntDir);$(SolutionDir)inc;$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration);$(SolutionDir)VSFiles\intermediate\midi2.midisrvabstraction\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories)
       $(ProjectDir);$(GeneratedFilesDir);$(IntDir);$(SolutionDir)inc;$(SolutionDir)VSFiles\intermediate\idl\$(Platform)\$(Configuration);$(SolutionDir)VSFiles\intermediate\midi2.midisrvabstraction\$(Platform)\$(Configuration);%(AdditionalIncludeDirectories)
+      stdcpp20
+      stdcpp20
     
     
       false
@@ -211,6 +213,9 @@
       true
       true
       true
+      stdcpp20
+      stdcpp20
+      stdcpp20
     
     
       true
@@ -246,9 +251,6 @@
     
       MidiEndpointConnection.idl
     
-    
-      MidiEndpointConnectionOptions.idl
-    
     
       MidiEndpointDeviceInformation.idl
     
@@ -365,9 +367,6 @@
     
       MidiEndpointConnection.idl
     
-    
-      MidiEndpointConnectionOptions.idl
-    
     
       MidiEndpointDeviceInformation.idl
     
@@ -486,7 +485,6 @@
     
     
     
-    
     
     
     
@@ -500,8 +498,6 @@
     
     
     
-    
-    
     
     
     
@@ -514,7 +510,7 @@
     
     
     
-    
+    
     
     
     
diff --git a/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj.filters b/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj.filters
index 2da0b4b6..5751984b 100644
--- a/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj.filters
+++ b/src/api/Client/Midi2Client/Windows.Devices.Midi2.vcxproj.filters
@@ -13,9 +13,6 @@
     
       {6965e07f-f558-4fdb-821c-dcb0ae49819a}
     
-    
-      {6427be3d-78fd-4fff-9bf4-2353b462bfc3}
-    
     
       {7a309dc0-af6f-4fa7-8827-649ef97dcc9a}
     
@@ -40,24 +37,15 @@
     
       {bce3490a-eb00-4ae7-9e49-6e31e91d70d1}
     
-    
-      {3c7e0669-3b44-4eb6-803e-308b307a3474}
-    
     
       {f99f0bd4-c968-4322-a806-90aca0f9e73e}
     
-    
-      {b8034624-6df4-444b-8fe4-9bb28fe040c9}
-    
     
       {4bae9d9e-c02c-49f6-b4a6-b8d0a1a2551c}
     
     
       {577d9050-8eb1-416d-9d4f-17cbb58b9b47}
     
-    
-      {993227f1-9e5a-45f9-a830-bae5f7259b84}
-    
     
       {abf74add-24a7-428a-b6f0-738ae3fadd6a}
     
@@ -91,6 +79,9 @@
     
       {3360af9e-3363-4faf-861f-7d778c66bf70}
     
+    
+      {6427be3d-78fd-4fff-9bf4-2353b462bfc3}
+    
   
   
     
@@ -276,10 +267,10 @@
   
   
     
-      API\Session
+      API\Endpoints\Session
     
     
-      API\Session
+      API\Endpoints\Session
     
     
       API\Transports
@@ -302,27 +293,12 @@
     
       API\Endpoints\Metadata\Blocks
     
-    
-      API\Endpoints\Connections\Options
-    
-    
-      API\Endpoints\Connections\Options
-    
-    
-      API\Endpoints\Connections
-    
     
       API\Transports
     
-    
-      API\Endpoints\Connections\Connection Types
-    
     
       API\Endpoints\Events
     
-    
-      API\Endpoints\Connections\Interfaces
-    
     
       API\Service
     
@@ -446,9 +422,6 @@
     
       API\Service
     
-    
-      API\Endpoints\Connections\Interfaces
-    
     
       API\Enumeration
     
@@ -467,6 +440,15 @@
     
       API\Service
     
+    
+      API\Endpoints\Connections
+    
+    
+      API\Endpoints\Connections
+    
+    
+      API\Endpoints\Connections
+    
   
   
     
diff --git a/src/api/Client/Midi2Client/pch.h b/src/api/Client/Midi2Client/pch.h
index 3d1be262..9848be54 100644
--- a/src/api/Client/Midi2Client/pch.h
+++ b/src/api/Client/Midi2Client/pch.h
@@ -88,8 +88,6 @@ namespace midi2 = ::winrt::Windows::Devices::Midi2;
 
 #include "MidiEndpointConnection.h"
 
-#include "MidiEndpointConnectionOptions.h"
-
 #include "MidiMessageReceivedEventArgs.h"
 #include "MidiEndpointDeviceInformationUpdateEventArgs.h"
 
diff --git a/src/api/Client/Midi2Client/trace_logging.cpp b/src/api/Client/Midi2Client/trace_logging.cpp
index 05e889cd..d5834efa 100644
--- a/src/api/Client/Midi2Client/trace_logging.cpp
+++ b/src/api/Client/Midi2Client/trace_logging.cpp
@@ -41,8 +41,6 @@ namespace Windows::Devices::Midi2::Internal
     void RegisterTraceLogging()
     {
         // HRESULT hr = S_OK;
-        OutputDebugString(L"" __FUNCTION__);
-
         TraceLoggingRegisterEx(g_hLoggingProvider, LoggingProviderEnabledCallback, nullptr);
 
         ////Generate the ActivityId used to track the session
@@ -65,8 +63,6 @@ namespace Windows::Devices::Midi2::Internal
 
     void UnregisterTraceLogging()
     {
-        OutputDebugString(L"" __FUNCTION__);
-
         TraceLoggingUnregister(g_hLoggingProvider);
 
         g_traceLoggingRegistered = true;
diff --git a/src/api/Inc/json_helpers.h b/src/api/Inc/json_helpers.h
index 72d541e1..7fda7643 100644
--- a/src/api/Inc/json_helpers.h
+++ b/src/api/Inc/json_helpers.h
@@ -104,10 +104,18 @@ namespace Windows::Devices::Midi2::Internal
 
 
 
-    inline void JsonStringifyObjectToOutParam(_In_ json::JsonObject obj, _Out_ BSTR** outParam)
+    inline bool JsonStringifyObjectToOutParam(_In_ json::JsonObject obj, _Out_ BSTR** outParam)
     {
         ATL::CComBSTR responseString = obj.Stringify().c_str();
-        responseString.CopyTo(*outParam);
+        
+        auto hr = responseString.CopyTo(*outParam);
+
+        if (SUCCEEDED(hr))
+        {
+            return true;
+        }
+
+        return false;
     }
 
 
diff --git a/src/api/Inc/string_util.h b/src/api/Inc/string_util.h
index 0b787ca6..a8a5758e 100644
--- a/src/api/Inc/string_util.h
+++ b/src/api/Inc/string_util.h
@@ -97,11 +97,6 @@ namespace Windows::Devices::Midi2::Internal
         return winrt::hstring{ ws };
     }
 
-    inline winrt::hstring ToUpperTrimmedHStringCopy(_In_ winrt::hstring s)
-    {
-        return ToUpperHStringCopy(TrimmedHStringCopy(s));
-    }
-
     inline winrt::hstring ToLowerHStringCopy(_In_ winrt::hstring s)
     {
         std::wstring ws{ s };
@@ -110,6 +105,17 @@ namespace Windows::Devices::Midi2::Internal
         return winrt::hstring{ ws };
     }
 
+    inline winrt::hstring ToUpperTrimmedHStringCopy(_In_ winrt::hstring s)
+    {
+        return ToUpperHStringCopy(TrimmedHStringCopy(s));
+    }
+
+    inline winrt::hstring ToLowerTrimmedHStringCopy(_In_ winrt::hstring s)
+    {
+        return ToLowerHStringCopy(TrimmedHStringCopy(s));
+    }
+
+
 
 
 
@@ -121,13 +127,31 @@ namespace Windows::Devices::Midi2::Internal
     }
 
     // This is for the device instance id. Not to be confused with the interface id
-    inline std::wstring NormalizeDeviceInstanceIdCopy(_In_ std::wstring deviceInstanceId)
+    inline std::wstring NormalizeDeviceInstanceIdWStringCopy(_In_ std::wstring deviceInstanceId)
     {
         return ToUpperTrimmedWStringCopy(deviceInstanceId);
     }
+    // This is for the device instance id. Not to be confused with the interface id
+    inline winrt::hstring NormalizeDeviceInstanceIdHStringCopy(_In_ winrt::hstring deviceInstanceId)
+    {
+        return ToUpperTrimmedHStringCopy(deviceInstanceId);
+    }
+
+    //// This is for the endpoint device interface id (the long SWD id with the GUID)
+    //inline std::wstring NormalizeEndpointInterfaceIdCopy(_In_ std::wstring endpointInterfaceId)
+    //{
+    //    return ToLowerTrimmedWStringCopy(endpointInterfaceId);
+    //}
+
+
+    // This is for the endpoint device interface id (the long SWD id with the GUID)
+    inline winrt::hstring NormalizeEndpointInterfaceIdHStringCopy(_In_ winrt::hstring endpointInterfaceId)
+    {
+        return ToLowerTrimmedHStringCopy(endpointInterfaceId);
+    }
 
     // This is for the endpoint device interface id (the long SWD id with the GUID)
-    inline std::wstring NormalizeEndpointInterfaceIdCopy(_In_ std::wstring endpointInterfaceId)
+    inline std::wstring NormalizeEndpointInterfaceIdWStringCopy(_In_ std::wstring endpointInterfaceId)
     {
         return ToLowerTrimmedWStringCopy(endpointInterfaceId);
     }
@@ -136,7 +160,7 @@ namespace Windows::Devices::Midi2::Internal
     // what NormalizeEndpointInterfaceIdCopy produces
     inline bool EndpointInterfaceIdContainsString(_In_ std::wstring endpointInterfaceId, _In_ std::wstring searchFor)
     {
-        auto id = NormalizeEndpointInterfaceIdCopy(endpointInterfaceId);
+        auto id = NormalizeEndpointInterfaceIdWStringCopy(endpointInterfaceId);
         auto sub = ToLowerWStringCopy(searchFor);             // match case with NormalizeEndpointInterfaceIdCopy
 
         if (id == L"" || sub == L"")
diff --git a/src/api/Service/Exe/MidiDeviceManager.cpp b/src/api/Service/Exe/MidiDeviceManager.cpp
index 07b3b0e0..108b5729 100644
--- a/src/api/Service/Exe/MidiDeviceManager.cpp
+++ b/src/api/Service/Exe/MidiDeviceManager.cpp
@@ -483,7 +483,7 @@ CMidiDeviceManager::ActivateEndpointInternal
         DEVPROP_TYPE_BOOLEAN, static_cast(sizeof(devPropTrue)), &devPropTrue });
 
 
-    midiPort->InstanceId = internal::NormalizeDeviceInstanceIdCopy(CreateInfo->pszInstanceId);
+    midiPort->InstanceId = internal::NormalizeDeviceInstanceIdWStringCopy(CreateInfo->pszInstanceId);
     midiPort->MidiFlow = MidiFlow;
     midiPort->Enumerator = MidiOne?AUDIO_DEVICE_ENUMERATOR : MIDI_DEVICE_ENUMERATOR;
 
@@ -586,7 +586,7 @@ CMidiDeviceManager::ActivateEndpointInternal
 
     if (DeviceInterfaceId)
     {
-        *DeviceInterfaceId = internal::NormalizeEndpointInterfaceIdCopy(midiPort->DeviceInterfaceId.get()).c_str();
+        *DeviceInterfaceId = internal::NormalizeEndpointInterfaceIdWStringCopy(midiPort->DeviceInterfaceId.get()).c_str();
     }
 
     // success, transfer the midiPort to the list
@@ -616,7 +616,7 @@ CMidiDeviceManager::UpdateEndpointProperties
 
     OutputDebugString(L"\n" __FUNCTION__ " ");
 
-    auto requestedInterfaceId = internal::NormalizeEndpointInterfaceIdCopy(DeviceInterfaceId);
+    auto requestedInterfaceId = internal::NormalizeEndpointInterfaceIdWStringCopy(DeviceInterfaceId);
 
     //OutputDebugString(requestedInterfaceId.c_str());
     //OutputDebugString(L"\n");
@@ -624,7 +624,7 @@ CMidiDeviceManager::UpdateEndpointProperties
     // locate the MIDIPORT 
     auto item = std::find_if(m_MidiPorts.begin(), m_MidiPorts.end(), [&](const std::unique_ptr& Port)
         {
-            auto portInterfaceId = internal::NormalizeEndpointInterfaceIdCopy(Port->DeviceInterfaceId.get());
+            auto portInterfaceId = internal::NormalizeEndpointInterfaceIdWStringCopy(Port->DeviceInterfaceId.get());
 
 //            OutputDebugString((L" -- Checking " + portInterfaceId).c_str());
 
@@ -770,7 +770,7 @@ CMidiDeviceManager::DeactivateEndpoint
 
     OutputDebugString(__FUNCTION__ L" - enter. Cleaned instance id is: ");
 
-    auto cleanId = internal::NormalizeDeviceInstanceIdCopy(InstanceId);
+    auto cleanId = internal::NormalizeDeviceInstanceIdWStringCopy(InstanceId);
 
     OutputDebugString(cleanId.c_str());
 
diff --git a/src/api/Service/Exe/MidiSessionTracker.cpp b/src/api/Service/Exe/MidiSessionTracker.cpp
index b117d8ad..3fd00b3e 100644
--- a/src/api/Service/Exe/MidiSessionTracker.cpp
+++ b/src/api/Service/Exe/MidiSessionTracker.cpp
@@ -90,7 +90,7 @@ CMidiSessionTracker::AddClientEndpointConnection(
 
     MidiSessionConnectionEntry newConnection;
 
-    auto cleanEndpointId = internal::NormalizeEndpointInterfaceIdCopy(ConnectionEndpointInterfaceId);
+    auto cleanEndpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(ConnectionEndpointInterfaceId);
 
     newConnection.ConnectedEndpointInterfaceId = cleanEndpointId;
     newConnection.InstanceCount = 1;
@@ -135,7 +135,7 @@ CMidiSessionTracker::RemoveClientEndpointConnection(
         TraceLoggingWideString(ConnectionEndpointInterfaceId)
     );
 
-    auto cleanEndpointId = internal::NormalizeEndpointInterfaceIdCopy(ConnectionEndpointInterfaceId);
+    auto cleanEndpointId = internal::NormalizeEndpointInterfaceIdWStringCopy(ConnectionEndpointInterfaceId);
 
     if (auto sessionEntry = m_sessions.find(SessionId); sessionEntry != m_sessions.end())
     {
diff --git a/src/api/Service/Inc/MidiPipe.h b/src/api/Service/Inc/MidiPipe.h
index 7dcee967..e8f5f847 100644
--- a/src/api/Service/Inc/MidiPipe.h
+++ b/src/api/Service/Inc/MidiPipe.h
@@ -24,7 +24,7 @@ class CMidiPipe :
     virtual HRESULT Initialize(_In_ LPCWSTR Device,
         _In_ MidiFlow Flow)
     {
-        m_Device = internal::NormalizeEndpointInterfaceIdCopy(Device);
+        m_Device = internal::NormalizeEndpointInterfaceIdWStringCopy(Device);
         m_Flow = Flow;
 
         if (IsFlowSupported(MidiFlowIn))
diff --git a/src/api/Test/Midi2.Client.unittests/MidiEndpointConnectionTests.cpp b/src/api/Test/Midi2.Client.unittests/MidiEndpointConnectionTests.cpp
index c7f70f62..17410f20 100644
--- a/src/api/Test/Midi2.Client.unittests/MidiEndpointConnectionTests.cpp
+++ b/src/api/Test/Midi2.Client.unittests/MidiEndpointConnectionTests.cpp
@@ -190,10 +190,8 @@ void MidiEndpointConnectionTests::TestSendAndReceiveUmpStruct()
 
     LOG_OUTPUT(L"Connecting to both Loopback A and Loopback B");
 
-    MidiEndpointConnectionOptions options;
-
-    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId(), options);
-    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId(), options);
+    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId());
+    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId());
 
     VERIFY_IS_NOT_NULL(connSend);
     VERIFY_IS_NOT_NULL(connReceive);
@@ -276,10 +274,8 @@ void MidiEndpointConnectionTests::TestSendAndReceiveUmp32()
     std::cout << std::endl << "Connecting to both Loopback A and Loopback B" << std::endl;
 
 
-    MidiEndpointConnectionOptions options;
-
-    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId(), options);
-    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId(), options);
+    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId());
+    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId());
 
     VERIFY_IS_NOT_NULL(connSend);
     VERIFY_IS_NOT_NULL(connReceive);
@@ -378,10 +374,8 @@ void MidiEndpointConnectionTests::TestSendAndReceiveWords()
     LOG_OUTPUT(L"Connecting to BiDi loopback Endpoints A and B");
 
 
-    MidiEndpointConnectionOptions options;
-
-    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId(), options);
-    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId(), options);
+    auto connSend = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackAEndpointId());
+    auto connReceive = session.CreateEndpointConnection(MidiEndpointDeviceInformation::DiagnosticsLoopbackBEndpointId());
 
     VERIFY_IS_NOT_NULL(connSend);
     VERIFY_IS_NOT_NULL(connReceive);
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
index 587bcfba..e0412a32 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointMonitorCommand.cs
@@ -184,7 +184,7 @@ public override int Execute(CommandContext context, Settings settings)
             if (!string.IsNullOrEmpty(endpointId))
             {
 
-                AnsiConsole.MarkupLine(Strings.MonitorMonitoringOnEndpointLabel + ": " + AnsiMarkupFormatter.FormatDeviceInstanceId(endpointId));
+                AnsiConsole.MarkupLine(Strings.MonitorMonitoringOnEndpointLabel + ": " + AnsiMarkupFormatter.FormatFullEndpointInterfaceId(endpointId));
 
                 //var table = new Table();
 
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
index 2e182417..b5a1464b 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessageCommand.cs
@@ -110,7 +110,7 @@ public override int Execute(CommandContext context, Settings settings)
 
             if (!string.IsNullOrEmpty(endpointId))
             {
-                AnsiConsole.MarkupLine(Strings.SendMessageSendingThroughEndpointLabel + ": " + AnsiMarkupFormatter.FormatDeviceInstanceId(endpointId));
+                AnsiConsole.MarkupLine(Strings.SendMessageSendingThroughEndpointLabel + ": " + AnsiMarkupFormatter.FormatFullEndpointInterfaceId(endpointId));
                 AnsiConsole.WriteLine();
 
                 bool openSuccess = false;
@@ -118,15 +118,13 @@ public override int Execute(CommandContext context, Settings settings)
                 // when this goes out of scope, it will dispose of the session, which closes the connections
                 using var session = MidiSession.CreateSession($"{Strings.AppShortName} - {Strings.SendMessageSessionNameSuffix}");
 
-                var bidiOpenOptions = new MidiEndpointConnectionOptions();
-
                 if (session == null)
                 {
                     AnsiConsole.MarkupLine(AnsiMarkupFormatter.FormatError(Strings.ErrorUnableToCreateSession));
                     return (int)MidiConsoleReturnCode.ErrorCreatingSession;
                 }
 
-                var connection = session.CreateEndpointConnection(endpointId, bidiOpenOptions);
+                var connection = session.CreateEndpointConnection(endpointId);
                 if (connection != null)
                 {
                     openSuccess = connection.Open();
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessagesFileCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessagesFileCommand.cs
index d55a66f0..e9a8ee00 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessagesFileCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointSendMessagesFileCommand.cs
@@ -97,7 +97,7 @@ public override int Execute(CommandContext context, Settings settings)
             if (!string.IsNullOrEmpty(endpointId))
             {
                 // TODO: Update loc strings
-                AnsiConsole.MarkupLine(Strings.SendMessageSendingThroughEndpointLabel + ": " + AnsiMarkupFormatter.FormatDeviceInstanceId(endpointId));
+                AnsiConsole.MarkupLine(Strings.SendMessageSendingThroughEndpointLabel + ": " + AnsiMarkupFormatter.FormatFullEndpointInterfaceId(endpointId));
                 AnsiConsole.WriteLine();
 
                 AnsiConsole.MarkupLine("Temporary UI change: Only error lines will be displayed when sending messages.");
diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj
index cf52f3f1..4ce5ee50 100644
--- a/src/user-tools/midi-console/Midi/Midi.csproj
+++ b/src/user-tools/midi-console/Midi/Midi.csproj
@@ -26,12 +26,12 @@
   
 
   
-    
+    
     
     
     
     
-    
+    
   
 
   

From 361793f5f9dfba57809dbeea106c5cfda7bf4ab6 Mon Sep 17 00:00:00 2001
From: Pete Brown 
Date: Thu, 8 Feb 2024 18:31:06 -0500
Subject: [PATCH 3/6] API Updates and addition of the mididmp.exe utility

---
 build/build.cake                              |    4 +
 build/replace_running_service.bat             |    7 +
 build/staging/version/BundleInfo.wxi          |    2 +-
 .../MidiVirtualEndpointDeviceDefinition.md    |    1 +
 docs/midi-dump.md                             |   82 +
 .../Midi2.DiagnosticsEndpointManager.cpp      |    6 +-
 .../nuget/Windows.Devices.Midi2.nuspec        |    2 +-
 .../Midi2Client/MidiEndpointConnection.idl    |    5 -
 .../MidiEndpointDeviceInformation.cpp         |    2 +
 .../MidiEndpointDeviceInformation.h           |    7 +-
 .../MidiEndpointDeviceInformation.idl         |    9 +-
 src/api/Client/Midi2Client/MidiSession.cpp    |   15 +-
 .../Midi2Client/MidiVirtualEndpointDevice.idl |    4 -
 .../MidiVirtualEndpointDeviceDefinition.h     |    4 +
 .../MidiVirtualEndpointDeviceDefinition.idl   |    2 +
 src/api/InBoxApps/mididmp/PropertySheet.props |   16 +
 src/api/InBoxApps/mididmp/main.cpp            |  251 ++
 src/api/InBoxApps/mididmp/mididmp.vcxproj     |  155 ++
 .../InBoxApps/mididmp/mididmp.vcxproj.filters |   37 +
 src/api/InBoxApps/mididmp/packages.config     |    4 +
 src/api/InBoxApps/mididmp/pch.cpp             |   10 +
 src/api/InBoxApps/mididmp/pch.h               |   23 +
 src/api/InBoxApps/mididmp/readme.txt          |   30 +
 src/api/Inc/MidiDefs.h                        |    2 +
 src/api/Midi2.sln                             |  181 ++
 src/api/Midi2Setup/Midi2Setup.vdproj          | 2018 ++++++++++-------
 .../MidiEndpointDeviceWatcherTests.cpp        |    7 +-
 .../api-package/WindowsMidiServices.wxs       |   15 +-
 28 files changed, 1992 insertions(+), 909 deletions(-)
 create mode 100644 docs/midi-dump.md
 create mode 100644 src/api/InBoxApps/mididmp/PropertySheet.props
 create mode 100644 src/api/InBoxApps/mididmp/main.cpp
 create mode 100644 src/api/InBoxApps/mididmp/mididmp.vcxproj
 create mode 100644 src/api/InBoxApps/mididmp/mididmp.vcxproj.filters
 create mode 100644 src/api/InBoxApps/mididmp/packages.config
 create mode 100644 src/api/InBoxApps/mididmp/pch.cpp
 create mode 100644 src/api/InBoxApps/mididmp/pch.h
 create mode 100644 src/api/InBoxApps/mididmp/readme.txt

diff --git a/build/build.cake b/build/build.cake
index bf5f5144..8852955f 100644
--- a/build/build.cake
+++ b/build/build.cake
@@ -188,6 +188,10 @@ Task("SetupEnvironment")
     // copy the C++ header for the API
     CopyFiles(System.IO.Path.Combine(generatedFilesDir, "Windows.Devices.Midi2.h"), copyToDir); 
 
+    CopyFiles(System.IO.Path.Combine(outputDir, "mididmp.exe"), copyToDir); 
+
+
+
     // copy the API Header and the .winmd to the "API bare" folder
 
     var apiBareCopyToDir = System.IO.Path.Combine(releaseRootDir, "api");
diff --git a/build/replace_running_service.bat b/build/replace_running_service.bat
index eacec931..9a7d2a72 100644
--- a/build/replace_running_service.bat
+++ b/build/replace_running_service.bat
@@ -8,13 +8,20 @@ sc stop midisrv
 
 set servicepath="%ProgramFiles%\Windows MIDI Services\Service"
 set apipath="%ProgramFiles%\Windows MIDI Services\API"
+set dmppath="%ProgramFiles%\Windows MIDI Services\"
 set buildoutput="%midi_repo_root%src\api\VSFiles\x64\Release"
 
+echo mididmp.exe
+copy /Y %buildoutput%\mididmp.exe %dmppath%
+
+echo MidiSrv.exe
 copy /Y %buildoutput%\MidiSrv.exe %servicepath%
 copy /Y %buildoutput%\Midi2.*Abstraction.dll %servicepath%
 copy /Y %buildoutput%\Midi2.*Transform.dll %servicepath%
 
+echo Windows.Devices.Midi2.dll
 copy /Y %buildoutput%\Windows.Devices.Midi2.dll %apipath%
+echo Windows.Devices.Midi2.pri
 copy /Y %buildoutput%\Windows.Devices.Midi2.pri %apipath%
 
 
diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index b4ce4c8b..ca9614ba 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
 
   
-  
+  
 
diff --git a/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.md b/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.md
index 9b3b5321..5963582b 100644
--- a/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.md
+++ b/docs/developer-docs/Windows.Devices.Midi2/virtual-device/MidiVirtualEndpointDeviceDefinition.md
@@ -28,6 +28,7 @@ The `MidiVirtualEndpointDeviceDefinition` class specifies, in an easy to use for
 | `SoftwareRevisionLevel` | MIDI 2.0 UMP Device Identity value |
 | `AreFunctionBlocksStatic` | True if the function blocks will not change in any way |
 | `FunctionBlocks` | list of function blocks for this device |
+| `TransportSuppliedDescription` | The description for the endpoint. Optional. |
 
 ## Functions
 
diff --git a/docs/midi-dump.md b/docs/midi-dump.md
new file mode 100644
index 00000000..6c1c323f
--- /dev/null
+++ b/docs/midi-dump.md
@@ -0,0 +1,82 @@
+---
+layout: page
+title: MIDI Dump Utility
+parent: Windows Midi Services
+---
+
+# Windows Dump Utility
+
+Windows MIDI Services comes with a simple command-line utility `mididmp.exe`. This has been designed for use by DAWs and support applications which need to shell out to a known executable to capture health information about the system.
+
+The utility returns information only about MIDI. Here is example output:
+
+```
+C:\Users\peteb>mididmp
+Microsoft Windows MIDI Services
+2024-02-08 18:28:52
+
+
+===============================================================================
+Endpoints
+===============================================================================
+
+endpoint_device_id : \\?\swd#midisrv#midiu_diag_loopback_a#{e7cce071-3c03-423f-88d3-f1045d02552b}
+name : Diagnostics Loopback A
+transport_mnemonic : DIAG
+name_user_supplied :
+name_user_endpoint_supplied :
+name_user_transport_supplied : Diagnostics Loopback A
+description_transport_supplied :
+description_user_supplied : Diagnostics loopback endpoint. For testing purposes.
+parent_id : SWD\MIDISRV\MIDIU_DIAG_TRANSPORT
+parent_name : MIDI 2.0 Diagnostics Devices
+-------------------------------------------------------------------------------
+endpoint_device_id : \\?\swd#midisrv#midiu_diag_loopback_b#{e7cce071-3c03-423f-88d3-f1045d02552b}
+name : Diagnostics Loopback B
+transport_mnemonic : DIAG
+name_user_supplied :
+name_user_endpoint_supplied :
+name_user_transport_supplied : Diagnostics Loopback B
+description_transport_supplied :
+description_user_supplied : Diagnostics loopback endpoint. For testing purposes.
+parent_id : SWD\MIDISRV\MIDIU_DIAG_TRANSPORT
+parent_name : MIDI 2.0 Diagnostics Devices
+-------------------------------------------------------------------------------
+endpoint_device_id : \\?\swd#midisrv#midiu_diag_ping#{e7cce071-3c03-423f-88d3-f1045d02552b}
+name : Diagnostics Ping (Internal)
+transport_mnemonic : DIAG
+name_user_supplied :
+name_user_endpoint_supplied :
+name_user_transport_supplied : Diagnostics Ping (Internal)
+description_transport_supplied :
+description_user_supplied : Internal UMP Ping endpoint. Do not send messages to this endpoint.
+parent_id : SWD\MIDISRV\MIDIU_DIAG_TRANSPORT
+parent_name : MIDI 2.0 Diagnostics Devices
+-------------------------------------------------------------------------------
+endpoint_device_id : \\?\swd#midisrv#midiu_ks_bidi_16024944077548273316_outpin.0_inpin.2#{e7cce071-3c03-423f-88d3-f1045d02552b}
+name : Unnamed Awesome MIDI 2.0 Synth
+transport_mnemonic : KS
+name_user_supplied : Unnamed Awesome MIDI 2.0 Synth
+name_user_endpoint_supplied : Foo Synth Amazing
+name_user_transport_supplied : Foo Synth
+description_transport_supplied :
+description_user_supplied : I love this synthesizer, but can't name it in public.
+parent_id : USB\VID_6666&PID_7777&MI_03\9&1663efa2&0&0003
+parent_name : Foo Synth
+
+===============================================================================
+Ping Test
+===============================================================================
+
+ping_attempt_count : 10
+ping_return_count : 10
+ping_time_round_trip_total_ticks : 7954
+ping_time_round_trip_average_ticks : 795
+
+===============================================================================
+Clock
+===============================================================================
+
+clock_frequency : 10000000
+clock_now : 912988511667
+```
\ No newline at end of file
diff --git a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp
index f245af48..85ed8c2e 100644
--- a/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp
+++ b/src/api/Abstraction/DiagnosticsAbstraction/Midi2.DiagnosticsEndpointManager.cpp
@@ -119,7 +119,7 @@ CMidi2DiagnosticsEndpointManager::CreateLoopbackEndpoint(
     BYTE nativeDataFormat = MIDI_PROP_NATIVEDATAFORMAT_UMP;
     UINT32 supportedDataFormat = (UINT32)MidiDataFormat::MidiDataFormat_UMP;
 
-    std::wstring description = L"Diagnostics loopback endpoint. For testing purposes.";
+    std::wstring description = L"Diagnostics loopback endpoint. For testing and development purposes.";
 
     auto endpointPurpose = (uint32_t)MidiEndpointDevicePurposePropertyValue::DiagnosticLoopback;
 
@@ -145,7 +145,7 @@ CMidi2DiagnosticsEndpointManager::CreateLoopbackEndpoint(
 
         {{PKEY_MIDI_EndpointDevicePurpose, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_UINT32, static_cast(sizeof(endpointPurpose)),(PVOID)&endpointPurpose},
-        {{PKEY_MIDI_UserSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr},
+        {{PKEY_MIDI_TransportSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_STRING, static_cast((description.length() + 1) * sizeof(WCHAR)), (PVOID)description.c_str() },
         {{PKEY_MIDI_NativeDataFormat, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_BYTE, static_cast(sizeof(BYTE)), (PVOID)&nativeDataFormat},
@@ -259,7 +259,7 @@ CMidi2DiagnosticsEndpointManager::CreatePingEndpoint(
             DEVPROP_TYPE_GUID, static_cast(sizeof(GUID)), (PVOID)&AbstractionLayerGUID },        // essential to instantiate the right endpoint types
         {{PKEY_MIDI_EndpointDevicePurpose, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_UINT32, static_cast(sizeof(endpointPurpose)),(PVOID)&endpointPurpose},
-        {{PKEY_MIDI_UserSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr},
+        {{PKEY_MIDI_TransportSuppliedDescription, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_STRING, static_cast((description.length() + 1) * sizeof(WCHAR)), (PVOID)description.c_str() },
         {{PKEY_MIDI_NativeDataFormat, DEVPROP_STORE_SYSTEM, nullptr},
             DEVPROP_TYPE_BYTE, static_cast(sizeof(BYTE)), (PVOID)&nativeDataFormat},
diff --git a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
index 4faed135..157dcab2 100644
--- a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
+++ b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
@@ -2,7 +2,7 @@
 
 	
 		Windows.Devices.Midi2
-		1.0.0-preview.3-0146
+		1.0.0-preview.3-0148
 		Microsoft Corporation
 		Windows MIDI Services API. Minimum package necessary to use Windows MIDI Services from an app on a PC that has Windows MIDI Services installed.
 		MIT
diff --git a/src/api/Client/Midi2Client/MidiEndpointConnection.idl b/src/api/Client/Midi2Client/MidiEndpointConnection.idl
index 150ee608..1ea1e4ba 100644
--- a/src/api/Client/Midi2Client/MidiEndpointConnection.idl
+++ b/src/api/Client/Midi2Client/MidiEndpointConnection.idl
@@ -15,14 +15,9 @@ MIDI_IDL_IMPORT
 
 
 import "IMidiMessageReceivedEventSource.idl";
-
-//import "MidiStreamConfigurationRequestedSettings.idl";
-
 import "IMidiEndpointMessageProcessingPlugin.idl";
 import "MidiSendMessageResultEnum.idl";
-
 import "IMidiEndpointConnectionSettings.idl";
-
 import "IMidiEndpointConnectionSource.idl";
 
 namespace Windows.Devices.Midi2
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
index d93cc756..e22d6b2a 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
@@ -117,6 +117,8 @@ namespace winrt::Windows::Devices::Midi2::implementation
         additionalProperties.Append(STRING_PKEY_MIDI_TransportSuppliedEndpointName);
         additionalProperties.Append(STRING_PKEY_MIDI_GenerateIncomingTimestamp);
 
+        additionalProperties.Append(STRING_PKEY_MIDI_TransportSuppliedDescription);       
+
         // USB / KS Properties ===============================================================
         // TODO: Group Terminal Blocks will likely be a single property
         additionalProperties.Append(STRING_PKEY_MIDI_IN_GroupTerminalBlocks);
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
index 92f9e1d5..26d2a6b0 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.h
@@ -106,10 +106,11 @@ namespace winrt::Windows::Devices::Midi2::implementation
         bool SupportsMidiPolyphonicExpression() { return GetBoolProperty(STRING_PKEY_MIDI_SupportsMidiPolyphonicExpression, false); }
         uint16_t RecommendedCCAutomationIntervalMS() { return GetUInt16Property(STRING_PKEY_MIDI_RecommendedCCAutomationIntervalMS, 0); }
 
-        winrt::hstring Description() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedDescription, L""); }
-        winrt::hstring LargeImagePath() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedLargeImagePath, L""); }
-        winrt::hstring SmallImagePath() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedSmallImagePath, L""); }
+        winrt::hstring UserSuppliedDescription() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedDescription, L""); }
+        winrt::hstring UserSuppliedLargeImagePath() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedLargeImagePath, L""); }
+        winrt::hstring UserSuppliedSmallImagePath() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_UserSuppliedSmallImagePath, L""); }
 
+        winrt::hstring TransportSuppliedDescription() const noexcept { return GetStringProperty(STRING_PKEY_MIDI_TransportSuppliedDescription, L""); }
 
 
         collections::IMapView Properties() { return m_properties.GetView(); }
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.idl b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.idl
index 81af4d41..d611aa6e 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.idl
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.idl
@@ -91,6 +91,9 @@ namespace Windows.Devices.Midi2
         // iSerialNumber from USB. This is transport-specific, but super important
         String TransportSuppliedSerialNumber{ get; };
 
+        // endpoint description supplied by the transport. This may contain most anything that is useful to the user.
+        String TransportSuppliedDescription{ get; };
+
         // manufacturer when we can get that. Typically from USB
         String ManufacturerName{ get; };
 
@@ -114,11 +117,11 @@ namespace Windows.Devices.Midi2
         MidiEndpointDevicePurpose EndpointPurpose{ get; };
 
         // The settings app allows the user to add some metadata, like a description
-        String Description{ get; };
+        String UserSuppliedDescription{ get; };
 
         // png icon supplied by the user
-        String LargeImagePath{ get; };
-        String SmallImagePath{ get; };
+        String UserSuppliedLargeImagePath{ get; };
+        String UserSuppliedSmallImagePath{ get; };
 
 
 
diff --git a/src/api/Client/Midi2Client/MidiSession.cpp b/src/api/Client/Midi2Client/MidiSession.cpp
index 2887f1a9..74312aac 100644
--- a/src/api/Client/Midi2Client/MidiSession.cpp
+++ b/src/api/Client/Midi2Client/MidiSession.cpp
@@ -202,12 +202,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
     {
         internal::LogInfo(__FUNCTION__, L"");
 
-
-        //winrt::hstring endpointDeviceId = 
-        //    L"\\\\?\\SWD#MIDISRV#MIDIU_VIRTDEV_" + 
-        //    deviceDefinition.EndpointProductInstanceId() +
-        //    L"#" + midi2::MidiEndpointDeviceInformation::EndpointInterfaceClass();
-
         winrt::hstring endpointDeviceId{};
 
 
@@ -218,7 +212,6 @@ namespace winrt::Windows::Devices::Midi2::implementation
         winrt::hstring virtualDeviceAbstractionId = L"{8FEAAD91-70E1-4A19-997A-377720A719C1}";
 
 
-
         json::JsonObject topLevelTransportPluginSettingsObject;
         json::JsonObject wrapperObject;
         json::JsonObject abstractionObject;
@@ -250,10 +243,10 @@ namespace winrt::Windows::Devices::Midi2::implementation
             MIDI_CONFIG_JSON_ENDPOINT_COMMON_NAME_PROPERTY,
             deviceDefinition.EndpointName().c_str());
 
-        //internal::JsonSetWStringProperty(
-        //    endpointDefinitionObject,
-        //    MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY,
-        //    deviceDefinition.EndpointDescription().c_str());
+        internal::JsonSetWStringProperty(
+            endpointDefinitionObject,
+            MIDI_CONFIG_JSON_ENDPOINT_COMMON_DESCRIPTION_PROPERTY,
+            deviceDefinition.TransportSuppliedDescription().c_str());
         
 
         // TODO: Other props that have to be set at the service level and not in-protocol
diff --git a/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.idl b/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.idl
index 13a56cfc..586c8040 100644
--- a/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.idl
+++ b/src/api/Client/Midi2Client/MidiVirtualEndpointDevice.idl
@@ -25,10 +25,6 @@ namespace Windows.Devices.Midi2
     [default_interface]
     runtimeclass MidiVirtualEndpointDevice : IMidiEndpointMessageProcessingPlugin
     {
-        //MidiVirtualEndpointDevice();
-
-        //String EndpointDeviceId{ get; };
-
         MidiVirtualEndpointDeviceDefinition DeviceDefinition{ get; };
 
         // This is a view because all modifications require sending notifications
diff --git a/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.h b/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.h
index 3ad22356..9b34a683 100644
--- a/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.h
+++ b/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.h
@@ -19,6 +19,9 @@ namespace winrt::Windows::Devices::Midi2::implementation
         winrt::hstring EndpointName() { return m_endpointName; }
         void EndpointName(_In_ winrt::hstring const& value) { m_endpointName = internal::TrimmedHStringCopy(value); }
 
+        winrt::hstring TransportSuppliedDescription() { return m_description; }
+        void TransportSuppliedDescription(_In_ winrt::hstring const& value) { m_description = internal::TrimmedHStringCopy(value); }
+
         winrt::hstring EndpointProductInstanceId() { return m_endpointProductInstanceId; }
         void EndpointProductInstanceId(_In_ winrt::hstring const& value) { m_endpointProductInstanceId = internal::TrimmedHStringCopy(value); }
 
@@ -59,6 +62,7 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
     private:
         winrt::hstring m_endpointName{};
+        winrt::hstring m_description{};
         winrt::hstring m_endpointProductInstanceId{};
 
         bool m_supportsMidi1ProtocolMessages{ false };
diff --git a/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.idl b/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.idl
index c0404e31..7a713355 100644
--- a/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.idl
+++ b/src/api/Client/Midi2Client/MidiVirtualEndpointDeviceDefinition.idl
@@ -25,6 +25,8 @@ namespace Windows.Devices.Midi2
         String EndpointName{ get; set; };
         String EndpointProductInstanceId{ get; set; };  // we'll also use this when creating the SWD
 
+        String TransportSuppliedDescription{ get; set; };
+
         Boolean SupportsMidi1ProtocolMessages{ get; set; };
         Boolean SupportsMidi2ProtocolMessages{ get; set; };
         Boolean SupportsReceivingJRTimestamps{ get; set; };
diff --git a/src/api/InBoxApps/mididmp/PropertySheet.props b/src/api/InBoxApps/mididmp/PropertySheet.props
new file mode 100644
index 00000000..b0c62269
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/PropertySheet.props
@@ -0,0 +1,16 @@
+
+
+  
+  
+    
+  
+  
+
\ No newline at end of file
diff --git a/src/api/InBoxApps/mididmp/main.cpp b/src/api/InBoxApps/mididmp/main.cpp
new file mode 100644
index 00000000..2901b4fc
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/main.cpp
@@ -0,0 +1,251 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License
+// ============================================================================
+// This is part of the Windows MIDI Services App API and should be used
+// in your Windows application via an official binary distribution.
+// Further information: https://github.com/microsoft/MIDI/
+// ============================================================================
+
+
+#pragma once
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+
+#include "pch.h"
+
+using namespace winrt;
+using namespace Windows::Foundation;
+
+const std::wstring fieldSeparator = L" : ";
+
+void OutputBlankLine()
+{
+    std::wcout
+        << std::endl;
+}
+
+void OutputCurrentTime()
+{
+    auto const time = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
+
+    std::wcout
+        << std::format(L"{:%Y-%m-%d %X}", time)
+        << std::endl;
+}
+
+void OutputSectionHeader(_In_ std::wstring headerText)
+{
+    const std::wstring sectionHeaderSeparator = std::wstring(79, '=');
+
+    std::wcout
+        << std::endl
+        << sectionHeaderSeparator
+        << std::endl
+        << headerText
+        << std::endl
+        << sectionHeaderSeparator
+        << std::endl
+        << std::endl;
+}
+
+void OutputItemSeparator()
+{
+    const std::wstring itemSeparator = std::wstring(79, '-');
+
+    std::wcout
+        << itemSeparator
+        << std::endl;
+}
+
+void OutputHeader(_In_ std::wstring headerText)
+{
+    std::wcout
+        << headerText
+        << std::endl;
+}
+
+void OutputStringField(_In_ std::wstring fieldName, _In_ winrt::hstring value)
+{
+    std::wcout
+        << fieldName
+        << fieldSeparator
+        << value.c_str()
+        << std::endl;
+}
+
+void OutputTimestampField(_In_ std::wstring fieldName, _In_ uint64_t value)
+{
+    std::wcout
+        << fieldName
+        << fieldSeparator
+        << value
+        << std::endl;
+}
+
+void OutputNumericField(_In_ std::wstring fieldName, _In_ uint32_t value)
+{
+    std::wcout
+        << fieldName
+        << fieldSeparator
+        << value
+        << std::endl;
+}
+
+
+void OutputError(_In_ std::wstring errorMessage)
+{
+    const std::wstring errorLabel = L"ERROR";
+
+    std::wcout 
+        << errorLabel
+        << fieldSeparator
+        << errorMessage
+        << std::endl;
+}
+
+#define RETURN_SUCCESS return 0
+#define RETURN_FAIL return 1
+
+int main()
+{
+    winrt::init_apartment();
+
+    bool verbose = true;
+    bool pingTest = true;
+    bool midiClock = true;
+
+    OutputHeader(L"Microsoft Windows MIDI Services");
+    OutputCurrentTime();
+    OutputBlankLine();
+
+    try
+    {
+        OutputSectionHeader(L"Endpoints");
+
+        // list devices
+
+        collections::IVectorView devices{ nullptr };
+
+        try
+        {
+            // list all devices
+            devices = midi2::MidiEndpointDeviceInformation::FindAll(
+                midi2::MidiEndpointDeviceInformationSortOrder::Name,
+                midi2::MidiEndpointDeviceInformationFilter::IncludeClientByteStreamNative |
+                midi2::MidiEndpointDeviceInformationFilter::IncludeClientUmpNative |
+                midi2::MidiEndpointDeviceInformationFilter::IncludeDiagnosticLoopback |
+                midi2::MidiEndpointDeviceInformationFilter::IncludeDiagnosticPing |
+                midi2::MidiEndpointDeviceInformationFilter::IncludeVirtualDeviceResponder
+            );
+        }
+        catch (...)
+        {
+            OutputError(L"Unable to access Windows MIDI Services and enumerate devices.");
+
+            RETURN_FAIL;
+        }
+
+        if (devices != nullptr && devices.Size() > 0)
+        {
+            for (uint32_t i = 0; i < devices.Size(); i++)
+            {
+                auto device = devices.GetAt(i);
+
+                // These names should not be localized because customers may parse these output fields
+
+                OutputStringField(L"endpoint_device_id", device.Id());
+                OutputStringField(L"name", device.Name());
+                OutputStringField(L"transport_mnemonic", device.TransportMnemonic());
+
+                if (verbose)
+                {
+                    OutputStringField(L"name_user_supplied", device.UserSuppliedName());
+                    OutputStringField(L"name_user_endpoint_supplied", device.EndpointSuppliedName());
+                    OutputStringField(L"name_user_transport_supplied", device.TransportSuppliedName());
+                    OutputStringField(L"description_transport_supplied", device.TransportSuppliedDescription());
+                    OutputStringField(L"description_user_supplied", device.UserSuppliedDescription());
+                }
+
+                auto parent = device.GetParentDeviceInformation();
+
+                if (parent != nullptr)
+                {
+                    OutputStringField(L"parent_id", parent.Id());
+                    OutputStringField(L"parent_name", parent.Name());
+                }
+                else
+                {
+                    OutputError(L"Unable to find endpoint parent");
+                }
+
+                if (i != devices.Size() - 1)
+                {
+                    OutputItemSeparator();
+                }
+            }
+        }
+        else
+        {
+            OutputError(L"Enumerating devices returned no matches. This is not expected and indicates an installation problem or that the service is not running.");
+            RETURN_FAIL;
+        }
+
+
+        const uint8_t pingCount = 10;
+
+        // ping the service
+        if (pingTest)
+        {
+            OutputSectionHeader(L"Ping Test");
+
+            OutputTimestampField(L"ping_attempt_count", pingCount);
+
+            auto pingResult = midi2::MidiService::PingService(pingCount);
+
+            OutputNumericField(L"ping_return_count", pingResult.Responses().Size());
+
+            if (pingResult.Success())
+            {
+                OutputTimestampField(L"ping_time_round_trip_total_ticks", pingResult.TotalPingRoundTripMidiClock());
+                OutputTimestampField(L"ping_time_round_trip_average_ticks", pingResult.AveragePingRoundTripMidiClock());
+
+            }
+            else
+            {
+                OutputError(L"Ping test failed");
+                OutputStringField(L"Failure Reason", pingResult.FailureReason());
+            }
+        }
+
+        if (midiClock)
+        {
+            OutputSectionHeader(L"Clock");
+
+            OutputTimestampField(L"clock_frequency", midi2::MidiClock::TimestampFrequency());
+            OutputTimestampField(L"clock_now", midi2::MidiClock::Now());
+
+        }
+
+    }
+    catch (...)
+    {
+        OutputError(L"Exception attempting to gather MIDI information.");
+
+        RETURN_FAIL;
+    }
+
+
+    RETURN_SUCCESS;
+}
diff --git a/src/api/InBoxApps/mididmp/mididmp.vcxproj b/src/api/InBoxApps/mididmp/mididmp.vcxproj
new file mode 100644
index 00000000..8c907878
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/mididmp.vcxproj
@@ -0,0 +1,155 @@
+
+
+  
+  
+    true
+    true
+    true
+    true
+    15.0
+    {5ec6d5eb-53d4-4731-891e-f746f0201429}
+    Win32Proj
+    mididmp
+    10.0.20348.0
+    10.0.17134.0
+  
+  
+  
+    
+      Debug
+      Win32
+    
+    
+      Release
+      Win32
+    
+    
+      Debug
+      x64
+    
+    
+      Release
+      x64
+    
+  
+  
+    Application
+    v143
+    v142
+    v141
+    v140
+    Unicode
+  
+  
+    true
+    true
+  
+  
+    false
+    true
+    false
+  
+  
+  
+  
+  
+  
+  
+    
+  
+  
+    
+  
+  
+  
+    $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
+    $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
+  
+  
+    $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
+    $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
+  
+  
+    $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
+    $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
+  
+  
+    $(SolutionDir)VSFiles\intermediate\$(ProjectName)\$(Platform)\$(Configuration)\
+    $(SolutionDir)VSFiles\$(Platform)\$(Configuration)\
+  
+  
+    
+      Use
+      pch.h
+      $(IntDir)pch.pch
+      _CONSOLE;WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)
+      Level4
+      %(AdditionalOptions) /permissive- /bigobj
+    
+  
+  
+    
+      Disabled
+      _DEBUG;%(PreprocessorDefinitions)
+      stdcpp20
+    
+    
+      Console
+      false
+    
+  
+  
+    
+      WIN32;%(PreprocessorDefinitions)
+      stdcpp20
+    
+  
+  
+    
+      MaxSpeed
+      true
+      true
+      NDEBUG;%(PreprocessorDefinitions)
+      stdcpp20
+      stdcpp20
+    
+    
+      Console
+      true
+      true
+      false
+    
+  
+  
+    
+  
+  
+    
+    
+      Create
+    
+  
+  
+    
+    
+    
+      false
+    
+  
+  
+    
+      {9eaa3af3-7328-4f67-a011-e2dd8fbaa4c4}
+    
+  
+  
+  
+    
+  
+  
+    
+      This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+    
+    
+    
+  
+
\ No newline at end of file
diff --git a/src/api/InBoxApps/mididmp/mididmp.vcxproj.filters b/src/api/InBoxApps/mididmp/mididmp.vcxproj.filters
new file mode 100644
index 00000000..388ab2e2
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/mididmp.vcxproj.filters
@@ -0,0 +1,37 @@
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hh;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+      rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+    
+  
+  
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+  
+    
+    
+  
+  
+    
+  
+
\ No newline at end of file
diff --git a/src/api/InBoxApps/mididmp/packages.config b/src/api/InBoxApps/mididmp/packages.config
new file mode 100644
index 00000000..cbf6205e
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/packages.config
@@ -0,0 +1,4 @@
+
+
+  
+
\ No newline at end of file
diff --git a/src/api/InBoxApps/mididmp/pch.cpp b/src/api/InBoxApps/mididmp/pch.cpp
new file mode 100644
index 00000000..1cf47ae4
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/pch.cpp
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License
+// ============================================================================
+// This is part of the Windows MIDI Services App API and should be used
+// in your Windows application via an official binary distribution.
+// Further information: https://github.com/microsoft/MIDI/
+// ============================================================================
+
+
+#include "pch.h"
diff --git a/src/api/InBoxApps/mididmp/pch.h b/src/api/InBoxApps/mididmp/pch.h
new file mode 100644
index 00000000..f50e5fe2
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/pch.h
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License
+// ============================================================================
+// This is part of the Windows MIDI Services App API and should be used
+// in your Windows application via an official binary distribution.
+// Further information: https://github.com/microsoft/MIDI/
+// ============================================================================
+
+
+#pragma once
+
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+
+namespace midi2 = winrt::Windows::Devices::Midi2;
+namespace foundation = winrt::Windows::Foundation;
+namespace collections = winrt::Windows::Foundation::Collections;
\ No newline at end of file
diff --git a/src/api/InBoxApps/mididmp/readme.txt b/src/api/InBoxApps/mididmp/readme.txt
new file mode 100644
index 00000000..5dd28a08
--- /dev/null
+++ b/src/api/InBoxApps/mididmp/readme.txt
@@ -0,0 +1,30 @@
+========================================================================
+    C++/WinRT mididmp Project Overview
+========================================================================
+
+This project demonstrates how to get started consuming Windows Runtime 
+classes directly from standard C++, using platform projection headers
+generated from Windows SDK metadata files.
+
+Steps to generate and consume SDK platform projection:
+1. Build project initially to generate platform projection headers into
+    your Generated Files folder.
+2. Include a projection namespace header in your pch.h, such as 
+    .
+3. Consume winrt namespace and any Windows Runtime namespaces, such as 
+    winrt::Windows::Foundation, from source code.
+4. Initialize apartment via init_apartment() and consume winrt classes.
+
+Steps to generate and consume a projection from third party metadata:
+1. Add a WinMD reference by right-clicking the References project node
+    and selecting "Add Reference...".  In the Add References dialog, 
+    browse to the component WinMD you want to consume and add it.
+2. Build the project once to generate projection headers for the 
+    referenced WinMD file under the "Generated Files" subfolder.
+3. As above, include projection headers in pch or source code 
+    to consume projected Windows Runtime classes.
+
+========================================================================
+Learn more about C++/WinRT here:
+http://aka.ms/cppwinrt/
+========================================================================
diff --git a/src/api/Inc/MidiDefs.h b/src/api/Inc/MidiDefs.h
index dc69ddbe..b5923f3e 100644
--- a/src/api/Inc/MidiDefs.h
+++ b/src/api/Inc/MidiDefs.h
@@ -527,6 +527,8 @@ DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_MidiOutLatencyTicksUserOverride, 802);     // DE
 #define STRING_PKEY_MIDI_VirtualMidiEndpointAssociator MIDI_STRING_PKEY_GUID MIDI_STRING_PKEY_PID_SEPARATOR L"900"
 DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_VirtualMidiEndpointAssociator, 900);     // DEVPROP_TYPE_GUID
 
+#define STRING_PKEY_MIDI_TransportSuppliedDescription MIDI_STRING_PKEY_GUID MIDI_STRING_PKEY_PID_SEPARATOR L"901"
+DEFINE_MIDIDEVPROPKEY(PKEY_MIDI_TransportSuppliedDescription, 910);     // DEVPROP_TYPE_STRING
 
 
 
diff --git a/src/api/Midi2.sln b/src/api/Midi2.sln
index fdf30ae4..95c84015 100644
--- a/src/api/Midi2.sln
+++ b/src/api/Midi2.sln
@@ -215,16 +215,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Midi2.JitterReductionGenera
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Windows.Devices.Midi.shim", "Client\MidiRT\Windows.Devices.Midi.Shim\Windows.Devices.Midi.Shim.vcxproj", "{16F34756-0269-4CEB-8F1C-32D9C6441990}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mididmp", "InBoxApps\mididmp\mididmp.vcxproj", "{5EC6D5EB-53D4-4731-891E-F746F0201429}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "In-Box Apps", "In-Box Apps", "{67A42126-8502-4681-9ACC-B1417C527620}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Debug|ARM64 = Debug|ARM64
 		Debug|ARM64EC = Debug|ARM64EC
 		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
 		Release|Any CPU = Release|Any CPU
 		Release|ARM64 = Release|ARM64
 		Release|ARM64EC = Release|ARM64EC
 		Release|x64 = Release|x64
+		Release|x86 = Release|x86
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|Any CPU.ActiveCfg = Debug|x64
@@ -235,6 +241,8 @@ Global
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|x64.ActiveCfg = Debug|x64
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|x64.Build.0 = Debug|x64
+		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|x86.ActiveCfg = Debug|x64
+		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Debug|x86.Build.0 = Debug|x64
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|Any CPU.ActiveCfg = Release|x64
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|Any CPU.Build.0 = Release|x64
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -243,6 +251,8 @@ Global
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|x64.ActiveCfg = Release|x64
 		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|x64.Build.0 = Release|x64
+		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|x86.ActiveCfg = Release|x64
+		{22ABB513-5E77-474D-AA11-E56B8071EB4C}.Release|x86.Build.0 = Release|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|Any CPU.Build.0 = Debug|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|Any CPU.Deploy.0 = Debug|x64
@@ -251,6 +261,9 @@ Global
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|x64.ActiveCfg = Debug|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|x64.Build.0 = Debug|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|x86.ActiveCfg = Debug|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|x86.Build.0 = Debug|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Debug|x86.Deploy.0 = Debug|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|Any CPU.ActiveCfg = Release|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|Any CPU.Build.0 = Release|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|Any CPU.Deploy.0 = Release|x64
@@ -259,6 +272,9 @@ Global
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|ARM64EC.ActiveCfg = Release|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|x64.ActiveCfg = Release|x64
 		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|x64.Build.0 = Release|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|x86.ActiveCfg = Release|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|x86.Build.0 = Release|x64
+		{0ACC44A8-A2AE-449C-AABA-64A75277C5BD}.Release|x86.Deploy.0 = Release|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|Any CPU.Build.0 = Debug|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -266,6 +282,8 @@ Global
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|x64.ActiveCfg = Debug|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|x64.Build.0 = Debug|x64
+		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|x86.ActiveCfg = Debug|x64
+		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Debug|x86.Build.0 = Debug|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|Any CPU.ActiveCfg = Release|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|Any CPU.Build.0 = Release|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -273,6 +291,8 @@ Global
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|ARM64EC.ActiveCfg = Release|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|x64.ActiveCfg = Release|x64
 		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|x64.Build.0 = Release|x64
+		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|x86.ActiveCfg = Release|x64
+		{8EABA9B2-A718-4AA3-88F7-E264CF3CCC29}.Release|x86.Build.0 = Release|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|Any CPU.Build.0 = Debug|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -281,6 +301,8 @@ Global
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|x64.ActiveCfg = Debug|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|x64.Build.0 = Debug|x64
+		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|x86.ActiveCfg = Debug|x64
+		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Debug|x86.Build.0 = Debug|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|Any CPU.ActiveCfg = Release|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|Any CPU.Build.0 = Release|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -289,6 +311,8 @@ Global
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|x64.ActiveCfg = Release|x64
 		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|x64.Build.0 = Release|x64
+		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|x86.ActiveCfg = Release|x64
+		{EFB7CF90-7DEF-44CF-868A-191CA30E0FCF}.Release|x86.Build.0 = Release|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|Any CPU.Build.0 = Debug|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -297,6 +321,8 @@ Global
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|x64.ActiveCfg = Debug|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|x64.Build.0 = Debug|x64
+		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|x86.ActiveCfg = Debug|x64
+		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Debug|x86.Build.0 = Debug|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|Any CPU.ActiveCfg = Release|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|Any CPU.Build.0 = Release|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -305,6 +331,8 @@ Global
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|x64.ActiveCfg = Release|x64
 		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|x64.Build.0 = Release|x64
+		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|x86.ActiveCfg = Release|x64
+		{00B066CB-3F9F-4B31-B30A-48631B07D157}.Release|x86.Build.0 = Release|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|Any CPU.Build.0 = Debug|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -313,6 +341,8 @@ Global
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|x64.ActiveCfg = Debug|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|x64.Build.0 = Debug|x64
+		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|x86.ActiveCfg = Debug|x64
+		{0FB85768-237C-4A60-A824-E09884C3EB34}.Debug|x86.Build.0 = Debug|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|Any CPU.ActiveCfg = Release|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|Any CPU.Build.0 = Release|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -321,6 +351,8 @@ Global
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|x64.ActiveCfg = Release|x64
 		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|x64.Build.0 = Release|x64
+		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|x86.ActiveCfg = Release|x64
+		{0FB85768-237C-4A60-A824-E09884C3EB34}.Release|x86.Build.0 = Release|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|Any CPU.Build.0 = Debug|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -328,6 +360,8 @@ Global
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|x64.ActiveCfg = Debug|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|x64.Build.0 = Debug|x64
+		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|x86.ActiveCfg = Debug|x64
+		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Debug|x86.Build.0 = Debug|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|Any CPU.ActiveCfg = Release|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|Any CPU.Build.0 = Release|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -335,6 +369,8 @@ Global
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|ARM64EC.ActiveCfg = Release|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|x64.ActiveCfg = Release|x64
 		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|x64.Build.0 = Release|x64
+		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|x86.ActiveCfg = Release|x64
+		{A08D50A1-F83A-4B36-BC65-5E3E36C93050}.Release|x86.Build.0 = Release|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|Any CPU.Build.0 = Debug|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -342,6 +378,8 @@ Global
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|x64.ActiveCfg = Debug|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|x64.Build.0 = Debug|x64
+		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|x86.ActiveCfg = Debug|x64
+		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Debug|x86.Build.0 = Debug|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|Any CPU.ActiveCfg = Release|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|Any CPU.Build.0 = Release|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -349,6 +387,8 @@ Global
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|ARM64EC.ActiveCfg = Release|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|x64.ActiveCfg = Release|x64
 		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|x64.Build.0 = Release|x64
+		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|x86.ActiveCfg = Release|x64
+		{14F12F86-9BDE-4DA3-B295-7FD990080E57}.Release|x86.Build.0 = Release|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|Any CPU.Build.0 = Debug|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -356,6 +396,8 @@ Global
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|x64.ActiveCfg = Debug|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|x64.Build.0 = Debug|x64
+		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|x86.ActiveCfg = Debug|x64
+		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Debug|x86.Build.0 = Debug|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|Any CPU.ActiveCfg = Release|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|Any CPU.Build.0 = Release|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -363,6 +405,8 @@ Global
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|ARM64EC.ActiveCfg = Release|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|x64.ActiveCfg = Release|x64
 		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|x64.Build.0 = Release|x64
+		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|x86.ActiveCfg = Release|x64
+		{4C09E660-79C6-4BA1-B823-21A867A3A4A9}.Release|x86.Build.0 = Release|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|Any CPU.Build.0 = Debug|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -371,6 +415,8 @@ Global
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|x64.ActiveCfg = Debug|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|x64.Build.0 = Debug|x64
+		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|x86.ActiveCfg = Debug|x64
+		{4F48735C-9364-462C-B207-2262D4E62589}.Debug|x86.Build.0 = Debug|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|Any CPU.ActiveCfg = Release|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|Any CPU.Build.0 = Release|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -379,6 +425,8 @@ Global
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|x64.ActiveCfg = Release|x64
 		{4F48735C-9364-462C-B207-2262D4E62589}.Release|x64.Build.0 = Release|x64
+		{4F48735C-9364-462C-B207-2262D4E62589}.Release|x86.ActiveCfg = Release|x64
+		{4F48735C-9364-462C-B207-2262D4E62589}.Release|x86.Build.0 = Release|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|Any CPU.Build.0 = Debug|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -387,6 +435,8 @@ Global
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|x64.ActiveCfg = Debug|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|x64.Build.0 = Debug|x64
+		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|x86.ActiveCfg = Debug|x64
+		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Debug|x86.Build.0 = Debug|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|Any CPU.ActiveCfg = Release|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|Any CPU.Build.0 = Release|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -395,6 +445,8 @@ Global
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|x64.ActiveCfg = Release|x64
 		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|x64.Build.0 = Release|x64
+		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|x86.ActiveCfg = Release|x64
+		{9991FF5B-E0F0-4373-A7C2-20B1EFDE5F70}.Release|x86.Build.0 = Release|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|Any CPU.Build.0 = Debug|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -403,6 +455,8 @@ Global
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|x64.ActiveCfg = Debug|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|x64.Build.0 = Debug|x64
+		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|x86.ActiveCfg = Debug|x64
+		{3D391727-2A65-4BA6-A730-EC10406AF543}.Debug|x86.Build.0 = Debug|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|Any CPU.ActiveCfg = Release|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|Any CPU.Build.0 = Release|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -411,6 +465,8 @@ Global
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|x64.ActiveCfg = Release|x64
 		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|x64.Build.0 = Release|x64
+		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|x86.ActiveCfg = Release|x64
+		{3D391727-2A65-4BA6-A730-EC10406AF543}.Release|x86.Build.0 = Release|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|Any CPU.Build.0 = Debug|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -418,6 +474,8 @@ Global
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|ARM64EC.ActiveCfg = Debug|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|x64.ActiveCfg = Debug|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|x64.Build.0 = Debug|x64
+		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|x86.ActiveCfg = Debug|x64
+		{574447FB-B44C-403E-9617-092F08B0FB27}.Debug|x86.Build.0 = Debug|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|Any CPU.ActiveCfg = Release|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|Any CPU.Build.0 = Release|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -425,6 +483,8 @@ Global
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|ARM64EC.ActiveCfg = Release|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|x64.ActiveCfg = Release|x64
 		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|x64.Build.0 = Release|x64
+		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|x86.ActiveCfg = Release|x64
+		{574447FB-B44C-403E-9617-092F08B0FB27}.Release|x86.Build.0 = Release|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|Any CPU.Build.0 = Debug|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -433,6 +493,8 @@ Global
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|x64.ActiveCfg = Debug|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|x64.Build.0 = Debug|x64
+		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|x86.ActiveCfg = Debug|x64
+		{2480B077-46E5-42AE-9BDB-685AFF258529}.Debug|x86.Build.0 = Debug|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|Any CPU.ActiveCfg = Release|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|Any CPU.Build.0 = Release|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -441,6 +503,8 @@ Global
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|x64.ActiveCfg = Release|x64
 		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|x64.Build.0 = Release|x64
+		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|x86.ActiveCfg = Release|x64
+		{2480B077-46E5-42AE-9BDB-685AFF258529}.Release|x86.Build.0 = Release|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|Any CPU.Build.0 = Debug|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -448,6 +512,8 @@ Global
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|x64.ActiveCfg = Debug|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|x64.Build.0 = Debug|x64
+		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|x86.ActiveCfg = Debug|x64
+		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Debug|x86.Build.0 = Debug|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|Any CPU.ActiveCfg = Release|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|Any CPU.Build.0 = Release|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -455,6 +521,8 @@ Global
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|ARM64EC.ActiveCfg = Release|ARM64EC
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|x64.ActiveCfg = Release|x64
 		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|x64.Build.0 = Release|x64
+		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|x86.ActiveCfg = Release|x64
+		{9EAA3AF3-7328-4F67-A011-E2DD8FBAA4C4}.Release|x86.Build.0 = Release|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|Any CPU.Build.0 = Debug|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -463,6 +531,8 @@ Global
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|x64.ActiveCfg = Debug|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|x64.Build.0 = Debug|x64
+		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|x86.ActiveCfg = Debug|x64
+		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Debug|x86.Build.0 = Debug|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|Any CPU.ActiveCfg = Release|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|Any CPU.Build.0 = Release|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -471,6 +541,8 @@ Global
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|x64.ActiveCfg = Release|x64
 		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|x64.Build.0 = Release|x64
+		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|x86.ActiveCfg = Release|x64
+		{3BD492AD-A08C-4923-9486-138189CA4A0A}.Release|x86.Build.0 = Release|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|Any CPU.Build.0 = Debug|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -479,6 +551,8 @@ Global
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|x64.ActiveCfg = Debug|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|x64.Build.0 = Debug|x64
+		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|x86.ActiveCfg = Debug|x64
+		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Debug|x86.Build.0 = Debug|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|Any CPU.ActiveCfg = Release|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|Any CPU.Build.0 = Release|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -487,6 +561,8 @@ Global
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|x64.ActiveCfg = Release|x64
 		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|x64.Build.0 = Release|x64
+		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|x86.ActiveCfg = Release|x64
+		{F6ACF293-2612-4D01-AFA4-103282B84A36}.Release|x86.Build.0 = Release|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|Any CPU.Build.0 = Debug|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -495,6 +571,8 @@ Global
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|x64.ActiveCfg = Debug|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|x64.Build.0 = Debug|x64
+		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|x86.ActiveCfg = Debug|x64
+		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Debug|x86.Build.0 = Debug|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|Any CPU.ActiveCfg = Release|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|Any CPU.Build.0 = Release|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -503,6 +581,8 @@ Global
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|x64.ActiveCfg = Release|x64
 		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|x64.Build.0 = Release|x64
+		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|x86.ActiveCfg = Release|x64
+		{7E618284-6AA0-4FCE-9E4A-D895A5EE8E3C}.Release|x86.Build.0 = Release|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|Any CPU.Build.0 = Debug|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -511,6 +591,8 @@ Global
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|x64.ActiveCfg = Debug|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|x64.Build.0 = Debug|x64
+		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|x86.ActiveCfg = Debug|x64
+		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Debug|x86.Build.0 = Debug|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|Any CPU.ActiveCfg = Release|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|Any CPU.Build.0 = Release|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -519,6 +601,8 @@ Global
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|x64.ActiveCfg = Release|x64
 		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|x64.Build.0 = Release|x64
+		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|x86.ActiveCfg = Release|x64
+		{03009B2B-E3E8-49DC-A0D6-0FA90AE3B15B}.Release|x86.Build.0 = Release|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|Any CPU.Build.0 = Debug|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -527,6 +611,8 @@ Global
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|x64.ActiveCfg = Debug|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|x64.Build.0 = Debug|x64
+		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|x86.ActiveCfg = Debug|x64
+		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Debug|x86.Build.0 = Debug|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|Any CPU.ActiveCfg = Release|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|Any CPU.Build.0 = Release|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -535,6 +621,8 @@ Global
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|x64.ActiveCfg = Release|x64
 		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|x64.Build.0 = Release|x64
+		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|x86.ActiveCfg = Release|x64
+		{093852BE-32B8-4EB8-814E-91410FFDB4F6}.Release|x86.Build.0 = Release|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|Any CPU.Build.0 = Debug|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|Any CPU.Deploy.0 = Debug|x64
@@ -547,6 +635,9 @@ Global
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x64.ActiveCfg = Debug|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x64.Build.0 = Debug|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x64.Deploy.0 = Debug|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x86.ActiveCfg = Debug|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x86.Build.0 = Debug|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Debug|x86.Deploy.0 = Debug|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|Any CPU.ActiveCfg = Release|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|Any CPU.Build.0 = Release|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|Any CPU.Deploy.0 = Release|x64
@@ -559,6 +650,9 @@ Global
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x64.ActiveCfg = Release|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x64.Build.0 = Release|x64
 		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x64.Deploy.0 = Release|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x86.ActiveCfg = Release|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x86.Build.0 = Release|x64
+		{2AD0622B-D47A-4CC1-9493-459730F442BE}.Release|x86.Deploy.0 = Release|x64
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -567,6 +661,8 @@ Global
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|ARM64EC.Build.0 = Debug|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|x64.ActiveCfg = Debug|x64
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|x64.Build.0 = Debug|x64
+		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Debug|x86.Build.0 = Debug|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|Any CPU.Build.0 = Release|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -575,6 +671,8 @@ Global
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|ARM64EC.Build.0 = Release|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|x64.ActiveCfg = Release|Any CPU
 		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|x64.Build.0 = Release|Any CPU
+		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|x86.ActiveCfg = Release|Any CPU
+		{3BFD29F8-004E-4AF3-A135-F96E659BA376}.Release|x86.Build.0 = Release|Any CPU
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|Any CPU.ActiveCfg = Debug
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|Any CPU.Build.0 = Debug
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|ARM64.ActiveCfg = Debug
@@ -583,6 +681,8 @@ Global
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|ARM64EC.Build.0 = Debug
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|x64.ActiveCfg = Debug
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|x64.Build.0 = Debug
+		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|x86.ActiveCfg = Debug
+		{38A9F27A-13E3-49DF-920B-630B09C68105}.Debug|x86.Build.0 = Debug
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|Any CPU.ActiveCfg = Release
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|Any CPU.Build.0 = Release
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|ARM64.ActiveCfg = Release
@@ -591,6 +691,8 @@ Global
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|ARM64EC.Build.0 = Release
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|x64.ActiveCfg = Release
 		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|x64.Build.0 = Release
+		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|x86.ActiveCfg = Release
+		{38A9F27A-13E3-49DF-920B-630B09C68105}.Release|x86.Build.0 = Release
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|Any CPU.Build.0 = Debug|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -599,6 +701,8 @@ Global
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|x64.ActiveCfg = Debug|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|x64.Build.0 = Debug|x64
+		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|x86.ActiveCfg = Debug|x64
+		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Debug|x86.Build.0 = Debug|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|Any CPU.ActiveCfg = Release|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|Any CPU.Build.0 = Release|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -607,6 +711,8 @@ Global
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|x64.ActiveCfg = Release|x64
 		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|x64.Build.0 = Release|x64
+		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|x86.ActiveCfg = Release|x64
+		{7427BC7A-4247-42B0-AC9B-7DA10418AA9D}.Release|x86.Build.0 = Release|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|Any CPU.Build.0 = Debug|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -615,6 +721,8 @@ Global
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|x64.ActiveCfg = Debug|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|x64.Build.0 = Debug|x64
+		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|x86.ActiveCfg = Debug|x64
+		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Debug|x86.Build.0 = Debug|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|Any CPU.ActiveCfg = Release|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|Any CPU.Build.0 = Release|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -623,6 +731,8 @@ Global
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|x64.ActiveCfg = Release|x64
 		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|x64.Build.0 = Release|x64
+		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|x86.ActiveCfg = Release|x64
+		{8795821B-541D-4B9B-BF7F-50CA976FC54E}.Release|x86.Build.0 = Release|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|Any CPU.Build.0 = Debug|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -631,6 +741,8 @@ Global
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|x64.ActiveCfg = Debug|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|x64.Build.0 = Debug|x64
+		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|x86.ActiveCfg = Debug|x64
+		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Debug|x86.Build.0 = Debug|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|Any CPU.ActiveCfg = Release|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|Any CPU.Build.0 = Release|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -639,6 +751,8 @@ Global
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|x64.ActiveCfg = Release|x64
 		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|x64.Build.0 = Release|x64
+		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|x86.ActiveCfg = Release|x64
+		{36E99993-ABE3-44CC-A776-B4E835B5EEC6}.Release|x86.Build.0 = Release|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|Any CPU.Build.0 = Debug|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -647,6 +761,8 @@ Global
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|ARM64EC.Build.0 = Debug|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|x64.ActiveCfg = Debug|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|x64.Build.0 = Debug|x64
+		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|x86.ActiveCfg = Debug|x64
+		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Debug|x86.Build.0 = Debug|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|Any CPU.ActiveCfg = Release|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|Any CPU.Build.0 = Release|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -655,6 +771,8 @@ Global
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|ARM64EC.Build.0 = Release|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|x64.ActiveCfg = Release|x64
 		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|x64.Build.0 = Release|x64
+		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|x86.ActiveCfg = Release|x64
+		{4DABE157-7DD5-422A-8C77-B83EAC9987D0}.Release|x86.Build.0 = Release|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|Any CPU.Build.0 = Debug|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -663,6 +781,8 @@ Global
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|x64.ActiveCfg = Debug|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|x64.Build.0 = Debug|x64
+		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|x86.ActiveCfg = Debug|x64
+		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Debug|x86.Build.0 = Debug|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|Any CPU.ActiveCfg = Release|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|Any CPU.Build.0 = Release|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -671,6 +791,8 @@ Global
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|x64.ActiveCfg = Release|x64
 		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|x64.Build.0 = Release|x64
+		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|x86.ActiveCfg = Release|x64
+		{0DDD9961-7959-46B1-A11D-05BA8AF65297}.Release|x86.Build.0 = Release|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|Any CPU.Build.0 = Debug|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -679,6 +801,9 @@ Global
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|ARM64EC.Build.0 = Debug|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|x64.ActiveCfg = Debug|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|x64.Build.0 = Debug|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|x86.ActiveCfg = Debug|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|x86.Build.0 = Debug|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Debug|x86.Deploy.0 = Debug|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|Any CPU.ActiveCfg = Release|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|Any CPU.Build.0 = Release|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -687,6 +812,9 @@ Global
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|ARM64EC.Build.0 = Release|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|x64.ActiveCfg = Release|x64
 		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|x64.Build.0 = Release|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|x86.ActiveCfg = Release|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|x86.Build.0 = Release|x64
+		{1B5A1991-AD62-494F-AE3A-1A681914898D}.Release|x86.Deploy.0 = Release|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|Any CPU.Build.0 = Debug|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -695,6 +823,8 @@ Global
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|x64.ActiveCfg = Debug|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|x64.Build.0 = Debug|x64
+		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|x86.ActiveCfg = Debug|x64
+		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Debug|x86.Build.0 = Debug|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|Any CPU.ActiveCfg = Release|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|Any CPU.Build.0 = Release|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -703,6 +833,8 @@ Global
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|x64.ActiveCfg = Release|x64
 		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|x64.Build.0 = Release|x64
+		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|x86.ActiveCfg = Release|x64
+		{206CEDBF-6343-4171-87A8-1DDDE6E2ED60}.Release|x86.Build.0 = Release|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|Any CPU.Build.0 = Debug|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -711,6 +843,8 @@ Global
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|x64.ActiveCfg = Debug|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|x64.Build.0 = Debug|x64
+		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|x86.ActiveCfg = Debug|x64
+		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Debug|x86.Build.0 = Debug|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|Any CPU.ActiveCfg = Release|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|Any CPU.Build.0 = Release|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -719,6 +853,8 @@ Global
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|x64.ActiveCfg = Release|x64
 		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|x64.Build.0 = Release|x64
+		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|x86.ActiveCfg = Release|x64
+		{0E739771-0C0B-42EE-AADB-95E7E1E5A5ED}.Release|x86.Build.0 = Release|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|Any CPU.Build.0 = Debug|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -727,6 +863,8 @@ Global
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|x64.ActiveCfg = Debug|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|x64.Build.0 = Debug|x64
+		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|x86.ActiveCfg = Debug|x64
+		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Debug|x86.Build.0 = Debug|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|Any CPU.ActiveCfg = Release|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|Any CPU.Build.0 = Release|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -735,6 +873,8 @@ Global
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|x64.ActiveCfg = Release|x64
 		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|x64.Build.0 = Release|x64
+		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|x86.ActiveCfg = Release|x64
+		{35B356BF-276B-4D4E-83AA-CB3B98A92F42}.Release|x86.Build.0 = Release|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|Any CPU.Build.0 = Debug|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -743,6 +883,8 @@ Global
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|x64.ActiveCfg = Debug|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|x64.Build.0 = Debug|x64
+		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|x86.ActiveCfg = Debug|x64
+		{3CC19466-95AA-43CD-B327-4C53C026B965}.Debug|x86.Build.0 = Debug|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|Any CPU.ActiveCfg = Release|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|Any CPU.Build.0 = Release|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -751,6 +893,8 @@ Global
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|x64.ActiveCfg = Release|x64
 		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|x64.Build.0 = Release|x64
+		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|x86.ActiveCfg = Release|x64
+		{3CC19466-95AA-43CD-B327-4C53C026B965}.Release|x86.Build.0 = Release|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|Any CPU.Build.0 = Debug|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -759,6 +903,8 @@ Global
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|x64.ActiveCfg = Debug|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|x64.Build.0 = Debug|x64
+		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|x86.ActiveCfg = Debug|x64
+		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Debug|x86.Build.0 = Debug|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|Any CPU.ActiveCfg = Release|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|Any CPU.Build.0 = Release|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -767,6 +913,8 @@ Global
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|x64.ActiveCfg = Release|x64
 		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|x64.Build.0 = Release|x64
+		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|x86.ActiveCfg = Release|x64
+		{366FA284-D8C0-4CC5-B9A3-917EAB967173}.Release|x86.Build.0 = Release|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|Any CPU.Build.0 = Debug|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -775,6 +923,8 @@ Global
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|ARM64EC.Build.0 = Debug|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|x64.ActiveCfg = Debug|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|x64.Build.0 = Debug|x64
+		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|x86.ActiveCfg = Debug|x64
+		{1425218C-E6E6-40BB-B99B-052156749E2C}.Debug|x86.Build.0 = Debug|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|Any CPU.ActiveCfg = Release|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|Any CPU.Build.0 = Release|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -783,6 +933,8 @@ Global
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|ARM64EC.Build.0 = Release|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|x64.ActiveCfg = Release|x64
 		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|x64.Build.0 = Release|x64
+		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|x86.ActiveCfg = Release|x64
+		{1425218C-E6E6-40BB-B99B-052156749E2C}.Release|x86.Build.0 = Release|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|Any CPU.Build.0 = Debug|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -791,6 +943,8 @@ Global
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|ARM64EC.Build.0 = Debug|ARM64EC
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|x64.ActiveCfg = Debug|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|x64.Build.0 = Debug|x64
+		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|x86.ActiveCfg = Debug|x64
+		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Debug|x86.Build.0 = Debug|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|Any CPU.ActiveCfg = Release|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|Any CPU.Build.0 = Release|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -799,6 +953,8 @@ Global
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|ARM64EC.Build.0 = Release|ARM64EC
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|x64.ActiveCfg = Release|x64
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|x64.Build.0 = Release|x64
+		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|x86.ActiveCfg = Release|x64
+		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E}.Release|x86.Build.0 = Release|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|Any CPU.Build.0 = Debug|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|ARM64.ActiveCfg = Debug|ARM64
@@ -807,6 +963,8 @@ Global
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|ARM64EC.Build.0 = Debug|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|x64.ActiveCfg = Debug|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|x64.Build.0 = Debug|x64
+		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|x86.ActiveCfg = Debug|x64
+		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Debug|x86.Build.0 = Debug|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|Any CPU.ActiveCfg = Release|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|Any CPU.Build.0 = Release|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|ARM64.ActiveCfg = Release|ARM64
@@ -815,6 +973,28 @@ Global
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|ARM64EC.Build.0 = Release|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|x64.ActiveCfg = Release|x64
 		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|x64.Build.0 = Release|x64
+		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|x86.ActiveCfg = Release|x64
+		{16F34756-0269-4CEB-8F1C-32D9C6441990}.Release|x86.Build.0 = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|Any CPU.ActiveCfg = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|Any CPU.Build.0 = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|ARM64.ActiveCfg = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|ARM64.Build.0 = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|ARM64EC.ActiveCfg = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|ARM64EC.Build.0 = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|x64.ActiveCfg = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|x64.Build.0 = Debug|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|x86.ActiveCfg = Debug|Win32
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Debug|x86.Build.0 = Debug|Win32
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|Any CPU.ActiveCfg = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|Any CPU.Build.0 = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|ARM64.ActiveCfg = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|ARM64.Build.0 = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|ARM64EC.ActiveCfg = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|ARM64EC.Build.0 = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|x64.ActiveCfg = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|x64.Build.0 = Release|x64
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|x86.ActiveCfg = Release|Win32
+		{5EC6D5EB-53D4-4731-891E-F746F0201429}.Release|x86.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -860,6 +1040,7 @@ Global
 		{1425218C-E6E6-40BB-B99B-052156749E2C} = {3AB9D0BD-B6CA-4633-B6F2-4AC5A8A550C1}
 		{6D151BF5-40A2-4BD7-BB67-07D2741DA01E} = {23C1D0EF-10F0-464B-86C3-1FCD3F6BA20E}
 		{16F34756-0269-4CEB-8F1C-32D9C6441990} = {6DB1D424-53D4-488F-8053-EBBD7D1F2E49}
+		{5EC6D5EB-53D4-4731-891E-F746F0201429} = {67A42126-8502-4681-9ACC-B1417C527620}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {7F5A157F-9894-451D-B091-848921952166}
diff --git a/src/api/Midi2Setup/Midi2Setup.vdproj b/src/api/Midi2Setup/Midi2Setup.vdproj
index 0f059f97..e667836c 100644
--- a/src/api/Midi2Setup/Midi2Setup.vdproj
+++ b/src/api/Midi2Setup/Midi2Setup.vdproj
@@ -15,217 +15,229 @@
     {
         "Entry"
         {
-        "MsmKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "MsmKey" = "8:_0154D5B2B86828CA92F8831E54D8F6AC"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_0154D5B2B86828CA92F8831E54D8F6AC"
+        "MsmKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_0755F252C43C3A2DD5D20D9C102BD571"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "MsmKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -237,26 +249,32 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_1D3C83321B67411EA0904B305816D102"
+        "MsmKey" = "8:_0AA6EC5B722D4FDBA7D4F9D05F8643E3"
         "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "MsmKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_233E143DE3B73E4453F74EDD5B3ABEEC"
-        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
+        "MsmKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_1D3C83321B67411EA0904B305816D102"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_233E143DE3B73E4453F74EDD5B3ABEEC"
-        "OwnerKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
+        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -280,6 +298,12 @@
         "Entry"
         {
         "MsmKey" = "8:_233E143DE3B73E4453F74EDD5B3ABEEC"
+        "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_233E143DE3B73E4453F74EDD5B3ABEEC"
         "OwnerKey" = "8:_68E0B9A947AF439D85CA3BDFF2BBD167"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -327,6 +351,12 @@
         }
         "Entry"
         {
+        "MsmKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
         "MsmKey" = "8:_276951EB6BDD2CD6AB8AE7556C7D8689"
         "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
         "MsmSig" = "8:_UNDEFINED"
@@ -364,6 +394,12 @@
         "Entry"
         {
         "MsmKey" = "8:_276951EB6BDD2CD6AB8AE7556C7D8689"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_276951EB6BDD2CD6AB8AE7556C7D8689"
         "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -388,6 +424,12 @@
         "Entry"
         {
         "MsmKey" = "8:_276951EB6BDD2CD6AB8AE7556C7D8689"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_276951EB6BDD2CD6AB8AE7556C7D8689"
         "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -405,14 +447,14 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_2A289A46DDDCDB3C03EF153AF3B20740"
+        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_2A289A46DDDCDB3C03EF153AF3B20740"
-        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
+        "MsmKey" = "8:_2B6435411A4038953484EA387D0FA66C"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -454,6 +496,12 @@
         "Entry"
         {
         "MsmKey" = "8:_2F5C424CFDE592C6779DC96C50DE92D5"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_2F5C424CFDE592C6779DC96C50DE92D5"
         "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -478,6 +526,12 @@
         "Entry"
         {
         "MsmKey" = "8:_2F5C424CFDE592C6779DC96C50DE92D5"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_2F5C424CFDE592C6779DC96C50DE92D5"
         "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -496,720 +550,660 @@
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_302A67F584DEEBFE64CA6A95052A5DC3"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_34543395AD4FF04123A4792FE90CD38F"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_382F643D576543949E3A3257F6CBB94C"
-        "OwnerKey" = "8:_UNDEFINED"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
-        "OwnerKey" = "8:_UNDEFINED"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_68E0B9A947AF439D85CA3BDFF2BBD167"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_5B95BDBA834E45B6BA7B73AC8260C86C"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_4CBC0561CDF04E49AE2734EE3CD2C07D"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
-        "OwnerKey" = "8:_1D3C83321B67411EA0904B305816D102"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "MsmKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "MsmKey" = "8:_37D162CB28E849F754916FDCB08AF7DF"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "MsmKey" = "8:_382F643D576543949E3A3257F6CBB94C"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "MsmKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "MsmKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_68E0B9A947AF439D85CA3BDFF2BBD167"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_5B95BDBA834E45B6BA7B73AC8260C86C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_4CBC0561CDF04E49AE2734EE3CD2C07D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_428935DEDF4C98BB73B5D79781950553"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_3B1DFF32830E639F0B2FEA8C1093F913"
+        "OwnerKey" = "8:_1D3C83321B67411EA0904B305816D102"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "MsmKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1221,12 +1215,6 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_4A8575366038813B2621B79F6A0DE09D"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
         "MsmKey" = "8:_4C05A796E0EA1385250413DDDB39A8A0"
         "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
         "MsmSig" = "8:_UNDEFINED"
@@ -1258,199 +1246,199 @@
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D4B61818D0EAEA95F9B52F98429C00"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -1474,19 +1462,19 @@
         "Entry"
         {
         "MsmKey" = "8:_50D875E42CEF6E0475EAB4384E4C79E1"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D875E42CEF6E0475EAB4384E4C79E1"
-        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
+        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_50D875E42CEF6E0475EAB4384E4C79E1"
-        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -1516,6 +1504,12 @@
         "Entry"
         {
         "MsmKey" = "8:_50D875E42CEF6E0475EAB4384E4C79E1"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_50D875E42CEF6E0475EAB4384E4C79E1"
         "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1533,7 +1527,7 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "MsmKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1545,13 +1539,19 @@
         }
         "Entry"
         {
+        "MsmKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
         "MsmKey" = "8:_5B95BDBA834E45B6BA7B73AC8260C86C"
         "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "MsmKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1569,25 +1569,13 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
         "MsmKey" = "8:_6AFCA391A88D2B1D8428D24510B3A04B"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_6F5D8E3B5217A7443623E462BC72D72E"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "MsmSig" = "8:_UNDEFINED"
-        }
-        "Entry"
-        {
-        "MsmKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "MsmKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1605,37 +1593,37 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_7C283ADD0DBBDD14EB43B37B6D5547C7"
+        "MsmKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "MsmKey" = "8:_7C283ADD0DBBDD14EB43B37B6D5547C7"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "MsmKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "MsmKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "MsmKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "MsmKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1684,6 +1672,12 @@
         "Entry"
         {
         "MsmKey" = "8:_95A010555EE939A8528D490FA44410C9"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_95A010555EE939A8528D490FA44410C9"
         "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1708,6 +1702,12 @@
         "Entry"
         {
         "MsmKey" = "8:_95A010555EE939A8528D490FA44410C9"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_95A010555EE939A8528D490FA44410C9"
         "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
         "MsmSig" = "8:_UNDEFINED"
         }
@@ -1725,588 +1725,690 @@
         }
         "Entry"
         {
-        "MsmKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "MsmKey" = "8:_96D39F2AE655138BDB27309D9592F394"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "MsmKey" = "8:_9A9676306B9D38430ABF0D0D8A8925CC"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "MsmKey" = "8:_9D159DB4D8B2DBC39225922575C0F718"
+        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "MsmKey" = "8:_9D159DB4D8B2DBC39225922575C0F718"
+        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "MsmKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "MsmKey" = "8:_A5E8A2AF57F2DF96E596B54E05C01B40"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "MsmKey" = "8:_A7EA42DD9965ABA4797E07FA38A68200"
+        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "MsmKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "MsmKey" = "8:_AF44815B3AED37759493B1D5BDF77009"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "MsmKey" = "8:_AF44815B3AED37759493B1D5BDF77009"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "MsmKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "MsmKey" = "8:_B4987357771E9650BFC1A82AE19BBDE5"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "MsmKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9D159DB4D8B2DBC39225922575C0F718"
-        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_9D159DB4D8B2DBC39225922575C0F718"
-        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_A5E8A2AF57F2DF96E596B54E05C01B40"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_A7EA42DD9965ABA4797E07FA38A68200"
-        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_AF44815B3AED37759493B1D5BDF77009"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_AF44815B3AED37759493B1D5BDF77009"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "MsmKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "MsmKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "MsmKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "MsmKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "MsmKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "MsmKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "MsmKey" = "8:_C7E6605211AB403584AC29C785C545BC"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "MsmKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "MsmKey" = "8:_C9587D5C62934F63133676A301B6E124"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "MsmKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "MsmKey" = "8:_CCD3C7F368C1012EF9CFD11D4F7F92E9"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "MsmKey" = "8:_CFF36ED096DFDD032B4618FCFBC718D8"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "MsmKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "MsmKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "MsmKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
-        "OwnerKey" = "8:_UNDEFINED"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_7556BB3FD66143ECB6D6F80CDA1BE7C6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
-        "OwnerKey" = "8:_UNDEFINED"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_68E0B9A947AF439D85CA3BDFF2BBD167"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
-        "OwnerKey" = "8:_UNDEFINED"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_5B95BDBA834E45B6BA7B73AC8260C86C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_CCD3C7F368C1012EF9CFD11D4F7F92E9"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_4CBC0561CDF04E49AE2734EE3CD2C07D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
-        "OwnerKey" = "8:_UNDEFINED"
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_3AAD30AFFF014FE89217F6CE7DCF3B59"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
+        "OwnerKey" = "8:_1D3C83321B67411EA0904B305816D102"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "MsmKey" = "8:_E79216D0CC017651664FC4ADDF83D73C"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_D762B338818C929E6CE965017865C458"
+        "MsmKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "MsmKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "MsmKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_09DF22DDCC3840BB876AD6FD96805A45"
+        "MsmKey" = "8:_EF1F0DBB74DD0C65F6C8D5C61FF5566E"
+        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
+        "MsmKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
+        "OwnerKey" = "8:_UNDEFINED"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_D0D96875B57D4EBEA944BD965D96E49F"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_C6A35D2DD48E420BB1F3FCA3D80AC851"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_BEC36957B0E941E2B1B4D6498BD81706"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_693A1D6836AF48149FB14FEAC557010F"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_68E0B9A947AF439D85CA3BDFF2BBD167"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_5B95BDBA834E45B6BA7B73AC8260C86C"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_4CBC0561CDF04E49AE2734EE3CD2C07D"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_382F643D576543949E3A3257F6CBB94C"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_254D9D387B8B48048714FDBA6F6E7E9C"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E386CA0AE72FBD122562EAE2A9B23CC9"
-        "OwnerKey" = "8:_1D3C83321B67411EA0904B305816D102"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EF1F0DBB74DD0C65F6C8D5C61FF5566E"
-        "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_EF73BDE238574EA1B9C0A604958811F1"
-        "OwnerKey" = "8:_UNDEFINED"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
-        "MsmKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
+        "MsmKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
+        "MsmSig" = "8:_UNDEFINED"
+        }
+        "Entry"
+        {
         "MsmKey" = "8:_F28DD8FA20DAFAFE1191E4F2791F0AF3"
         "OwnerKey" = "8:_C8C0732FDB5E4B6F8DE78F03F1D63BF6"
         "MsmSig" = "8:_UNDEFINED"
@@ -2326,187 +2428,187 @@
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_91AB7DADCD76FA202CD61355BDB9B896"
+        "OwnerKey" = "8:_8D6FBD48B17D0272D3A4C42D2086DCFC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_28CE7CFAF1F76E97F61908293882D3AA"
+        "OwnerKey" = "8:_BDD80E4C59C9F64435279C9F49D61ECE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_E9E2A0F5BFC130A2768BDCEB58203218"
+        "OwnerKey" = "8:_B47D5CF19A53FFBCBB50D25C2F352C71"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_EBD30E60C62F816F92EC2452F5201741"
+        "OwnerKey" = "8:_DEFCB29661F2C15E3937D67BC4C0FAFE"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_C6A2F213414C1114F9CDDD85C706267E"
+        "OwnerKey" = "8:_7E96439C50F901B66BD91AA4F59B4E61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+        "OwnerKey" = "8:_B62F13A5DAB496EE006E2DE11D16556F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+        "OwnerKey" = "8:_01A146111C552A7E27F1EDAEAA5EB7C1"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_357DEC8E3C7BEC12355AA4AFE1981480"
+        "OwnerKey" = "8:_EBD56ACE56C7F5313FC8CFA4315DE750"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_64D134B4F98C3FF2612FD66039526D01"
+        "OwnerKey" = "8:_51770B36E8A1A5AAECA5BC492FBEE9C2"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_7D7DEF71947AFBFD9830D49C0EF7C318"
+        "OwnerKey" = "8:_1A95ADA589FD8D992FC111F1D96D5CA0"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_07FDABE693A5BC695381F14C6DFCB32B"
+        "OwnerKey" = "8:_CB9FD6789732F4275D1DFCFCDCF7656B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_1FFC97B29DF5F3AFA840AD3712E209EF"
+        "OwnerKey" = "8:_7FDA3F28832E05DEB9C812C10EC0CE64"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_46A940C5147ABB55F5A2E61986BCE5A2"
+        "OwnerKey" = "8:_393D5E32D33C232883DB08EB84F6CC20"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_D2EF09C4CC31207D8F9109344D81E36D"
+        "OwnerKey" = "8:_A2E78BFE511CC4D22FC5809832B07764"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_8ED8C44232F9629B10B7E81811DDAF51"
+        "OwnerKey" = "8:_EA9CB4BFE2C4CD07261F98B5CF64B701"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_72BB161928F3CEA39EF9264409A2388D"
+        "OwnerKey" = "8:_7A6270EC10358F48DC73868B20FC53BC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+        "OwnerKey" = "8:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_00721FCC4A8536F0E791A93392E1A676"
+        "OwnerKey" = "8:_27123CA2CE0BB900334C1D2D1C795D61"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_D7A3807909C77FD0139A9D58EA6A958B"
+        "OwnerKey" = "8:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_6A85F419D4F9DDA0B85EE639B074456E"
+        "OwnerKey" = "8:_8FD21B762DD38FE7546F650989F107AC"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_49428703B010864FE37630D7FF2406D6"
+        "OwnerKey" = "8:_2B6435411A4038953484EA387D0FA66C"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_405698B6556593B0790A193D4B2A1487"
+        "OwnerKey" = "8:_1756D3C85847CC73E289C7CBA23B7E66"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_8AC07ED954F3A9355818A81E725216E9"
+        "OwnerKey" = "8:_C458435F5C063853AE7C9DB499B248D8"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_D762B338818C929E6CE965017865C458"
+        "OwnerKey" = "8:_EADBD849A98B1FB69FEA7AF364A7FA6F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_EAC5264CF2A86908C662E55D5585C79C"
+        "OwnerKey" = "8:_60474879E569BC83FB3CCD93E8BD8125"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_A985B244FAFAEEDEF43258C077C8AAD0"
+        "OwnerKey" = "8:_DBB530A394CAE32F6C6508C9AA7136D3"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_968389A48A2B7ED7F0DF9D77E8A0D929"
+        "OwnerKey" = "8:_3C94E07D85C3D8875D7B59DD77F9FC8B"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_F05F117885DFAFCBC78FF7F18A26C4B5"
+        "OwnerKey" = "8:_07ADCD38A57541FC180069DDE02A3F31"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_367E7B3EF8AC32F2637A4A15230F4752"
+        "OwnerKey" = "8:_585438A68DC498FAE9BF8E26E062B99D"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+        "OwnerKey" = "8:_AA2B6C447612269CEF481FAA418DCF9E"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_9B6FD1B75C4A0338D0AC92F747A45531"
+        "OwnerKey" = "8:_362B97FBFB5AFACB174970DABAAA2024"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -2518,13 +2620,13 @@
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_EDA07A9BBC93339C52ABE94570919DCA"
+        "OwnerKey" = "8:_084170B05F1E9E4D5D51895730801F0F"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
         {
         "MsmKey" = "8:_UNDEFINED"
-        "OwnerKey" = "8:_428935DEDF4C98BB73B5D79781950553"
+        "OwnerKey" = "8:_F0CF5A2114F5CA5056B633FE5D9D6A94"
         "MsmSig" = "8:_UNDEFINED"
         }
         "Entry"
@@ -2676,21 +2778,10 @@
         }
         "File"
         {
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_00721FCC4A8536F0E791A93392E1A676"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0154D5B2B86828CA92F8831E54D8F6AC"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract, Version=3.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_00721FCC4A8536F0E791A93392E1A676"
-                    {
-                    "Name" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-core-errorhandling-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-errorhandling-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -2707,10 +2798,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0154D5B2B86828CA92F8831E54D8F6AC"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_01A146111C552A7E27F1EDAEAA5EB7C1"
             {
-            "SourcePath" = "8:api-ms-win-core-errorhandling-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-errorhandling-l1-1-0.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileRetailInfoContract, Version=1.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_01A146111C552A7E27F1EDAEAA5EB7C1"
+                    {
+                    "Name" = "8:Windows.System.Profile.ProfileRetailInfoContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.System.Profile.ProfileRetailInfoContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -2758,20 +2860,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_07FDABE693A5BC695381F14C6DFCB32B"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_07ADCD38A57541FC180069DDE02A3F31"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Services.Store.StoreContract, Version=4.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_07FDABE693A5BC695381F14C6DFCB32B"
+                    "_07ADCD38A57541FC180069DDE02A3F31"
                     {
-                    "Name" = "8:Windows.Services.Store.StoreContract.winmd"
+                    "Name" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Services.Store.StoreContract.winmd"
+            "SourcePath" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -2789,20 +2891,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_1FFC97B29DF5F3AFA840AD3712E209EF"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_084170B05F1E9E4D5D51895730801F0F"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Services.Maps.LocalSearchContract, Version=4.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Networking.Connectivity.WwanContract, Version=2.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_1FFC97B29DF5F3AFA840AD3712E209EF"
+                    "_084170B05F1E9E4D5D51895730801F0F"
                     {
-                    "Name" = "8:Windows.Services.Maps.LocalSearchContract.winmd"
+                    "Name" = "8:Windows.Networking.Connectivity.WwanContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Services.Maps.LocalSearchContract.winmd"
+            "SourcePath" = "8:Windows.Networking.Connectivity.WwanContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -2820,10 +2922,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_233E143DE3B73E4453F74EDD5B3ABEEC"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_1756D3C85847CC73E289C7CBA23B7E66"
             {
-            "SourcePath" = "8:MSVCP140.dll"
-            "TargetName" = "8:MSVCP140.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.Devices.Custom.CustomDeviceContract, Version=1.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_1756D3C85847CC73E289C7CBA23B7E66"
+                    {
+                    "Name" = "8:Windows.Devices.Custom.CustomDeviceContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.Devices.Custom.CustomDeviceContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -2836,23 +2949,34 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:FALSE"
+            "Exclude" = "11:TRUE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_24B054AA53ABF04589027F14F505DEA0"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_1A95ADA589FD8D992FC111F1D96D5CA0"
             {
-            "SourcePath" = "8:api-ms-win-core-synch-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-synch-l1-1-0.dll"
-            "Tag" = "8:"
-            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
-            "Condition" = "8:"
-            "Transitive" = "11:FALSE"
-            "Vital" = "11:TRUE"
-            "ReadOnly" = "11:FALSE"
-            "Hidden" = "11:FALSE"
-            "System" = "11:FALSE"
-            "Permanent" = "11:FALSE"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.Services.TargetedContent.TargetedContentContract, Version=1.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_1A95ADA589FD8D992FC111F1D96D5CA0"
+                    {
+                    "Name" = "8:Windows.Services.TargetedContent.TargetedContentContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.Services.TargetedContent.TargetedContentContract.winmd"
+            "TargetName" = "8:"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
@@ -2860,10 +2984,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_276951EB6BDD2CD6AB8AE7556C7D8689"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_233E143DE3B73E4453F74EDD5B3ABEEC"
             {
-            "SourcePath" = "8:VCRUNTIME140_1.dll"
-            "TargetName" = "8:VCRUNTIME140_1.dll"
+            "SourcePath" = "8:MSVCP140.dll"
+            "TargetName" = "8:MSVCP140.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -2880,20 +3004,40 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_28CE7CFAF1F76E97F61908293882D3AA"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_24B054AA53ABF04589027F14F505DEA0"
+            {
+            "SourcePath" = "8:api-ms-win-core-synch-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-synch-l1-1-0.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:TRUE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_27123CA2CE0BB900334C1D2D1C795D61"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_28CE7CFAF1F76E97F61908293882D3AA"
+                    "_27123CA2CE0BB900334C1D2D1C795D61"
                     {
-                    "Name" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd"
+                    "Name" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd"
+            "SourcePath" = "8:Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -2911,6 +3055,26 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_276951EB6BDD2CD6AB8AE7556C7D8689"
+            {
+            "SourcePath" = "8:VCRUNTIME140_1.dll"
+            "TargetName" = "8:VCRUNTIME140_1.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
             "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2A289A46DDDCDB3C03EF153AF3B20740"
             {
             "SourcePath" = "8:api-ms-win-crt-locale-l1-1-0.dll"
@@ -2931,6 +3095,37 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_2B6435411A4038953484EA387D0FA66C"
+            {
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.Devices.DevicesLowLevelContract, Version=3.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_2B6435411A4038953484EA387D0FA66C"
+                    {
+                    "Name" = "8:Windows.Devices.DevicesLowLevelContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.Devices.DevicesLowLevelContract.winmd"
+            "TargetName" = "8:"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:TRUE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
             "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_2F5C424CFDE592C6779DC96C50DE92D5"
             {
             "SourcePath" = "8:api-ms-win-crt-heap-l1-1-0.dll"
@@ -3013,20 +3208,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_357DEC8E3C7BEC12355AA4AFE1981480"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_362B97FBFB5AFACB174970DABAAA2024"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileHardwareTokenContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Foundation.UniversalApiContract, Version=12.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_357DEC8E3C7BEC12355AA4AFE1981480"
+                    "_362B97FBFB5AFACB174970DABAAA2024"
                     {
-                    "Name" = "8:Windows.System.Profile.ProfileHardwareTokenContract.winmd"
+                    "Name" = "8:Windows.Foundation.UniversalApiContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.System.Profile.ProfileHardwareTokenContract.winmd"
+            "SourcePath" = "8:Windows.Foundation.UniversalApiContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3044,21 +3239,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_367E7B3EF8AC32F2637A4A15230F4752"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_37D162CB28E849F754916FDCB08AF7DF"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract, Version=2.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_367E7B3EF8AC32F2637A4A15230F4752"
-                    {
-                    "Name" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-crt-runtime-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-runtime-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3071,24 +3255,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_36A94C5F965A72DAA4EC55E74E7E5DB6"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_393D5E32D33C232883DB08EB84F6CC20"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileRetailInfoContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Services.Maps.GuidanceContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_36A94C5F965A72DAA4EC55E74E7E5DB6"
+                    "_393D5E32D33C232883DB08EB84F6CC20"
                     {
-                    "Name" = "8:Windows.System.Profile.ProfileRetailInfoContract.winmd"
+                    "Name" = "8:Windows.Services.Maps.GuidanceContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.System.Profile.ProfileRetailInfoContract.winmd"
+            "SourcePath" = "8:Windows.Services.Maps.GuidanceContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3126,20 +3310,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_405698B6556593B0790A193D4B2A1487"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_3C94E07D85C3D8875D7B59DD77F9FC8B"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Devices.Custom.CustomDeviceContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract, Version=6.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_405698B6556593B0790A193D4B2A1487"
+                    "_3C94E07D85C3D8875D7B59DD77F9FC8B"
                     {
-                    "Name" = "8:Windows.Devices.Custom.CustomDeviceContract.winmd"
+                    "Name" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Devices.Custom.CustomDeviceContract.winmd"
+            "SourcePath" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3157,21 +3341,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_428935DEDF4C98BB73B5D79781950553"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4A8575366038813B2621B79F6A0DE09D"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Foundation.FoundationContract, Version=4.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_428935DEDF4C98BB73B5D79781950553"
-                    {
-                    "Name" = "8:Windows.Foundation.FoundationContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.Foundation.FoundationContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-core-synch-l1-2-0.dll"
+            "TargetName" = "8:api-ms-win-core-synch-l1-2-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3188,20 +3361,40 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_46A940C5147ABB55F5A2E61986BCE5A2"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4C05A796E0EA1385250413DDDB39A8A0"
+            {
+            "SourcePath" = "8:AVRT.dll"
+            "TargetName" = "8:AVRT.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:TRUE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_50D4B61818D0EAEA95F9B52F98429C00"
             {
             "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Services.Maps.GuidanceContract, Version=3.0.0.0, Culture=neutral"
+            "AssemblyIsInGAC" = "11:TRUE"
+            "AssemblyAsmDisplayName" = "8:System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
                 "ScatterAssemblies"
                 {
-                    "_46A940C5147ABB55F5A2E61986BCE5A2"
+                    "_50D4B61818D0EAEA95F9B52F98429C00"
                     {
-                    "Name" = "8:Windows.Services.Maps.GuidanceContract.winmd"
+                    "Name" = "8:System.Runtime.WindowsRuntime.dll"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Services.Maps.GuidanceContract.winmd"
+            "SourcePath" = "8:System.Runtime.WindowsRuntime.dll"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3219,20 +3412,40 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_49428703B010864FE37630D7FF2406D6"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_50D875E42CEF6E0475EAB4384E4C79E1"
+            {
+            "SourcePath" = "8:api-ms-win-crt-string-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-string-l1-1-0.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_51770B36E8A1A5AAECA5BC492FBEE9C2"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Devices.DevicesLowLevelContract, Version=3.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Storage.Provider.CloudFilesContract, Version=6.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_49428703B010864FE37630D7FF2406D6"
+                    "_51770B36E8A1A5AAECA5BC492FBEE9C2"
                     {
-                    "Name" = "8:Windows.Devices.DevicesLowLevelContract.winmd"
+                    "Name" = "8:Windows.Storage.Provider.CloudFilesContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Devices.DevicesLowLevelContract.winmd"
+            "SourcePath" = "8:Windows.Storage.Provider.CloudFilesContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3250,10 +3463,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4A8575366038813B2621B79F6A0DE09D"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_51E17CB7FBBD905EE7F5AC8AEBFAC949"
             {
-            "SourcePath" = "8:api-ms-win-core-synch-l1-2-0.dll"
-            "TargetName" = "8:api-ms-win-core-synch-l1-2-0.dll"
+            "SourcePath" = "8:api-ms-win-crt-math-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-math-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3266,14 +3479,25 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_4C05A796E0EA1385250413DDDB39A8A0"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_585438A68DC498FAE9BF8E26E062B99D"
             {
-            "SourcePath" = "8:AVRT.dll"
-            "TargetName" = "8:AVRT.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract, Version=2.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_585438A68DC498FAE9BF8E26E062B99D"
+                    {
+                    "Name" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3290,20 +3514,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_50D4B61818D0EAEA95F9B52F98429C00"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_60474879E569BC83FB3CCD93E8BD8125"
             {
             "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:TRUE"
-            "AssemblyAsmDisplayName" = "8:System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract, Version=2.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_50D4B61818D0EAEA95F9B52F98429C00"
+                    "_60474879E569BC83FB3CCD93E8BD8125"
                     {
-                    "Name" = "8:System.Runtime.WindowsRuntime.dll"
+                    "Name" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:System.Runtime.WindowsRuntime.dll"
+            "SourcePath" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3321,10 +3545,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_50D875E42CEF6E0475EAB4384E4C79E1"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6AFCA391A88D2B1D8428D24510B3A04B"
             {
-            "SourcePath" = "8:api-ms-win-crt-string-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-crt-string-l1-1-0.dll"
+            "SourcePath" = "8:api-ms-win-core-util-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-util-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3337,24 +3561,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:FALSE"
+            "Exclude" = "11:TRUE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_51AC9A8259C4EDAFB6EE5842C4FB5736"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_6C0FC2CA0DEDF657DF20D393C7B9DA60"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileSharedModeContract, Version=2.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Gaming.XboxLive.StorageApiContract, Version=1.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_51AC9A8259C4EDAFB6EE5842C4FB5736"
+                    "_6C0FC2CA0DEDF657DF20D393C7B9DA60"
                     {
-                    "Name" = "8:Windows.System.Profile.ProfileSharedModeContract.winmd"
+                    "Name" = "8:Windows.Gaming.XboxLive.StorageApiContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.System.Profile.ProfileSharedModeContract.winmd"
+            "SourcePath" = "8:Windows.Gaming.XboxLive.StorageApiContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3372,10 +3596,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_51E17CB7FBBD905EE7F5AC8AEBFAC949"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_74AF18A1F5E848E1AD7C9BBA67EA0C9B"
             {
-            "SourcePath" = "8:api-ms-win-crt-math-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-crt-math-l1-1-0.dll"
+            "SourcePath" = "8:api-ms-win-eventing-provider-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-eventing-provider-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3388,24 +3612,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:FALSE"
+            "Exclude" = "11:TRUE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_64D134B4F98C3FF2612FD66039526D01"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_7A6270EC10358F48DC73868B20FC53BC"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Storage.Provider.CloudFilesContract, Version=7.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Graphics.Printing3D.Printing3DContract, Version=4.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_64D134B4F98C3FF2612FD66039526D01"
+                    "_7A6270EC10358F48DC73868B20FC53BC"
                     {
-                    "Name" = "8:Windows.Storage.Provider.CloudFilesContract.winmd"
+                    "Name" = "8:Windows.Graphics.Printing3D.Printing3DContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Storage.Provider.CloudFilesContract.winmd"
+            "SourcePath" = "8:Windows.Graphics.Printing3D.Printing3DContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3423,20 +3647,40 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_6A85F419D4F9DDA0B85EE639B074456E"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7C283ADD0DBBDD14EB43B37B6D5547C7"
+            {
+            "SourcePath" = "8:api-ms-win-core-string-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-string-l1-1-0.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_7E96439C50F901B66BD91AA4F59B4E61"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Devices.Printers.PrintersContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_6A85F419D4F9DDA0B85EE639B074456E"
+                    "_7E96439C50F901B66BD91AA4F59B4E61"
                     {
-                    "Name" = "8:Windows.Devices.Printers.PrintersContract.winmd"
+                    "Name" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Devices.Printers.PrintersContract.winmd"
+            "SourcePath" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3454,10 +3698,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6AFCA391A88D2B1D8428D24510B3A04B"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_7FDA3F28832E05DEB9C812C10EC0CE64"
             {
-            "SourcePath" = "8:api-ms-win-core-util-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-util-l1-1-0.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.Services.Maps.LocalSearchContract, Version=4.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_7FDA3F28832E05DEB9C812C10EC0CE64"
+                    {
+                    "Name" = "8:Windows.Services.Maps.LocalSearchContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.Services.Maps.LocalSearchContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3474,10 +3729,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6F5D8E3B5217A7443623E462BC72D72E"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8D6FBD48B17D0272D3A4C42D2086DCFC"
             {
-            "SourcePath" = "8:api-ms-win-core-localization-l1-2-0.dll"
-            "TargetName" = "8:api-ms-win-core-localization-l1-2-0.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract, Version=3.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_8D6FBD48B17D0272D3A4C42D2086DCFC"
+                    {
+                    "Name" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3494,20 +3760,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_72BB161928F3CEA39EF9264409A2388D"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8FD21B762DD38FE7546F650989F107AC"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Graphics.Printing3D.Printing3DContract, Version=4.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Devices.Printers.PrintersContract, Version=1.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_72BB161928F3CEA39EF9264409A2388D"
+                    "_8FD21B762DD38FE7546F650989F107AC"
                     {
-                    "Name" = "8:Windows.Graphics.Printing3D.Printing3DContract.winmd"
+                    "Name" = "8:Windows.Devices.Printers.PrintersContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Graphics.Printing3D.Printing3DContract.winmd"
+            "SourcePath" = "8:Windows.Devices.Printers.PrintersContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3525,10 +3791,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_74AF18A1F5E848E1AD7C9BBA67EA0C9B"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93CD0DA651F6774F190E1411E90600D6"
             {
-            "SourcePath" = "8:api-ms-win-eventing-provider-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-eventing-provider-l1-1-0.dll"
+            "SourcePath" = "8:api-ms-win-core-processthreads-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-processthreads-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3545,10 +3811,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7C283ADD0DBBDD14EB43B37B6D5547C7"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_95A010555EE939A8528D490FA44410C9"
             {
-            "SourcePath" = "8:api-ms-win-core-string-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-string-l1-1-0.dll"
+            "SourcePath" = "8:VCRUNTIME140.dll"
+            "TargetName" = "8:VCRUNTIME140.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3565,21 +3831,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_7D7DEF71947AFBFD9830D49C0EF7C318"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_96D39F2AE655138BDB27309D9592F394"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Services.TargetedContent.TargetedContentContract, Version=1.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_7D7DEF71947AFBFD9830D49C0EF7C318"
-                    {
-                    "Name" = "8:Windows.Services.TargetedContent.TargetedContentContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.Services.TargetedContent.TargetedContentContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-core-processthreads-l1-1-1.dll"
+            "TargetName" = "8:api-ms-win-core-processthreads-l1-1-1.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3592,25 +3847,14 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8AC07ED954F3A9355818A81E725216E9"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9A9676306B9D38430ABF0D0D8A8925CC"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.StartupTaskContract, Version=3.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_8AC07ED954F3A9355818A81E725216E9"
-                    {
-                    "Name" = "8:Windows.ApplicationModel.StartupTaskContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.ApplicationModel.StartupTaskContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-core-sysinfo-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-sysinfo-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3623,25 +3867,14 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8C62DA280D86C03C1C6FCD579D2AEC3D"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9D159DB4D8B2DBC39225922575C0F718"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.AI.MachineLearning.MachineLearningContract, Version=5.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_8C62DA280D86C03C1C6FCD579D2AEC3D"
-                    {
-                    "Name" = "8:Windows.AI.MachineLearning.MachineLearningContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.AI.MachineLearning.MachineLearningContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:RPCRT4.dll"
+            "TargetName" = "8:RPCRT4.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3658,20 +3891,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_8ED8C44232F9629B10B7E81811DDAF51"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_A2E78BFE511CC4D22FC5809832B07764"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract, Version=3.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Security.Isolation.IsolatedWindowsEnvironmentContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_8ED8C44232F9629B10B7E81811DDAF51"
+                    "_A2E78BFE511CC4D22FC5809832B07764"
                     {
-                    "Name" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract.winmd"
+                    "Name" = "8:Windows.Security.Isolation.Isolatedwindowsenvironmentcontract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract.winmd"
+            "SourcePath" = "8:Windows.Security.Isolation.Isolatedwindowsenvironmentcontract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3689,21 +3922,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_91AB7DADCD76FA202CD61355BDB9B896"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A5E8A2AF57F2DF96E596B54E05C01B40"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract, Version=5.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_91AB7DADCD76FA202CD61355BDB9B896"
-                    {
-                    "Name" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-core-heap-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-heap-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3720,10 +3942,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_93CD0DA651F6774F190E1411E90600D6"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A7EA42DD9965ABA4797E07FA38A68200"
             {
-            "SourcePath" = "8:api-ms-win-core-processthreads-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-processthreads-l1-1-0.dll"
+            "SourcePath" = "8:ksuser.dll"
+            "TargetName" = "8:ksuser.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3740,10 +3962,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_95A010555EE939A8528D490FA44410C9"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_AA2B6C447612269CEF481FAA418DCF9E"
             {
-            "SourcePath" = "8:VCRUNTIME140.dll"
-            "TargetName" = "8:VCRUNTIME140.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.AI.MachineLearning.MachineLearningContract, Version=4.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_AA2B6C447612269CEF481FAA418DCF9E"
+                    {
+                    "Name" = "8:Windows.AI.MachineLearning.MachineLearningContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.AI.MachineLearning.MachineLearningContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3756,24 +3989,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:FALSE"
+            "Exclude" = "11:TRUE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_968389A48A2B7ED7F0DF9D77E8A0D929"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_AF44815B3AED37759493B1D5BDF77009"
             {
             "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract, Version=7.0.0.0, Culture=neutral"
+            "AssemblyIsInGAC" = "11:TRUE"
+            "AssemblyAsmDisplayName" = "8:System.Numerics.Vectors, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
                 "ScatterAssemblies"
                 {
-                    "_968389A48A2B7ED7F0DF9D77E8A0D929"
+                    "_AF44815B3AED37759493B1D5BDF77009"
                     {
-                    "Name" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract.winmd"
+                    "Name" = "8:System.Numerics.Vectors.dll"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.ApplicationModel.Calls.CallsPhoneContract.winmd"
+            "SourcePath" = "8:System.Numerics.Vectors.dll"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3791,20 +4024,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_9B6FD1B75C4A0338D0AC92F747A45531"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B47D5CF19A53FFBCBB50D25C2F352C71"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Foundation.UniversalApiContract, Version=15.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.UI.UIAutomation.UIAutomationContract, Version=1.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_9B6FD1B75C4A0338D0AC92F747A45531"
+                    "_B47D5CF19A53FFBCBB50D25C2F352C71"
                     {
-                    "Name" = "8:Windows.Foundation.UniversalApiContract.winmd"
+                    "Name" = "8:Windows.UI.UIAutomation.UIAutomationContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Foundation.UniversalApiContract.winmd"
+            "SourcePath" = "8:Windows.UI.UIAutomation.UIAutomationContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3822,10 +4055,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9D159DB4D8B2DBC39225922575C0F718"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B4987357771E9650BFC1A82AE19BBDE5"
             {
-            "SourcePath" = "8:RPCRT4.dll"
-            "TargetName" = "8:RPCRT4.dll"
+            "SourcePath" = "8:api-ms-win-core-rtlsupport-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-core-rtlsupport-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3838,14 +4071,25 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A5E8A2AF57F2DF96E596B54E05C01B40"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B62F13A5DAB496EE006E2DE11D16556F"
             {
-            "SourcePath" = "8:api-ms-win-core-heap-l1-1-0.dll"
-            "TargetName" = "8:api-ms-win-core-heap-l1-1-0.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileSharedModeContract, Version=2.0.0.0, Culture=neutral"
+                "ScatterAssemblies"
+                {
+                    "_B62F13A5DAB496EE006E2DE11D16556F"
+                    {
+                    "Name" = "8:Windows.System.Profile.ProfileSharedModeContract.winmd"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:Windows.System.Profile.ProfileSharedModeContract.winmd"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3862,10 +4106,21 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A7EA42DD9965ABA4797E07FA38A68200"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
             {
-            "SourcePath" = "8:ksuser.dll"
-            "TargetName" = "8:ksuser.dll"
+            "AssemblyRegister" = "3:1"
+            "AssemblyIsInGAC" = "11:TRUE"
+            "AssemblyAsmDisplayName" = "8:System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
+                "ScatterAssemblies"
+                {
+                    "_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+                    {
+                    "Name" = "8:System.Runtime.dll"
+                    "Attributes" = "3:512"
+                    }
+                }
+            "SourcePath" = "8:System.Runtime.dll"
+            "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -3882,20 +4137,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_A985B244FAFAEEDEF43258C077C8AAD0"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_BBCC1A4F548A09D97B2B0B1BF0A4C437"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.CallsVoipContract, Version=4.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract, Version=6.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_A985B244FAFAEEDEF43258C077C8AAD0"
+                    "_BBCC1A4F548A09D97B2B0B1BF0A4C437"
                     {
-                    "Name" = "8:Windows.ApplicationModel.Calls.CallsVoipContract.winmd"
+                    "Name" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.ApplicationModel.Calls.CallsVoipContract.winmd"
+            "SourcePath" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3913,20 +4168,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_AF44815B3AED37759493B1D5BDF77009"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_BDD80E4C59C9F64435279C9F49D61ECE"
             {
             "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:TRUE"
-            "AssemblyAsmDisplayName" = "8:System.Numerics.Vectors, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
+            "AssemblyIsInGAC" = "11:FALSE"
+            "AssemblyAsmDisplayName" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract, Version=1.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_AF44815B3AED37759493B1D5BDF77009"
+                    "_BDD80E4C59C9F64435279C9F49D61ECE"
                     {
-                    "Name" = "8:System.Numerics.Vectors.dll"
+                    "Name" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:System.Numerics.Vectors.dll"
+            "SourcePath" = "8:Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3944,20 +4199,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_C458435F5C063853AE7C9DB499B248D8"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Gaming.XboxLive.StorageApiContract, Version=1.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.StartupTaskContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_B494A2A1DE5B64E0DE3CEFD99A7DBC26"
+                    "_C458435F5C063853AE7C9DB499B248D8"
                     {
-                    "Name" = "8:Windows.Gaming.XboxLive.StorageApiContract.winmd"
+                    "Name" = "8:Windows.ApplicationModel.StartupTaskContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Gaming.XboxLive.StorageApiContract.winmd"
+            "SourcePath" = "8:Windows.ApplicationModel.StartupTaskContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -3975,21 +4230,30 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C7E6605211AB403584AC29C785C545BC"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:TRUE"
-            "AssemblyAsmDisplayName" = "8:System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"
-                "ScatterAssemblies"
-                {
-                    "_B964C8C7A3D3DC0A0C5DF9DFF7F2FACA"
-                    {
-                    "Name" = "8:System.Runtime.dll"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:System.Runtime.dll"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-crt-convert-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-convert-l1-1-0.dll"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:TRUE"
+            "IsolateTo" = "8:"
+            }
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C9587D5C62934F63133676A301B6E124"
+            {
+            "SourcePath" = "8:api-ms-win-core-localization-l1-2-0.dll"
+            "TargetName" = "8:api-ms-win-core-localization-l1-2-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -4006,20 +4270,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_C6A2F213414C1114F9CDDD85C706267E"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_CB9FD6789732F4275D1DFCFCDCF7656B"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract, Version=3.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Services.Store.StoreContract, Version=4.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_C6A2F213414C1114F9CDDD85C706267E"
+                    "_CB9FD6789732F4275D1DFCFCDCF7656B"
                     {
-                    "Name" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd"
+                    "Name" = "8:Windows.Services.Store.StoreContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd"
+            "SourcePath" = "8:Windows.Services.Store.StoreContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4057,21 +4321,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_D2EF09C4CC31207D8F9109344D81E36D"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CFF36ED096DFDD032B4618FCFBC718D8"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Security.Isolation.IsolatedWindowsEnvironmentContract, Version=4.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_D2EF09C4CC31207D8F9109344D81E36D"
-                    {
-                    "Name" = "8:Windows.Security.Isolation.Isolatedwindowsenvironmentcontract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.Security.Isolation.Isolatedwindowsenvironmentcontract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-crt-utility-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-utility-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -4084,24 +4337,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_D762B338818C929E6CE965017865C458"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_DBB530A394CAE32F6C6508C9AA7136D3"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract, Version=2.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.CallsVoipContract, Version=4.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_D762B338818C929E6CE965017865C458"
+                    "_DBB530A394CAE32F6C6508C9AA7136D3"
                     {
-                    "Name" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd"
+                    "Name" = "8:Windows.ApplicationModel.Calls.CallsVoipContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd"
+            "SourcePath" = "8:Windows.ApplicationModel.Calls.CallsVoipContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4119,20 +4372,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_D7A3807909C77FD0139A9D58EA6A958B"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_DEFCB29661F2C15E3937D67BC4C0FAFE"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract, Version=6.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.System.SystemManagementContract, Version=7.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_D7A3807909C77FD0139A9D58EA6A958B"
+                    "_DEFCB29661F2C15E3937D67BC4C0FAFE"
                     {
-                    "Name" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd"
+                    "Name" = "8:Windows.System.SystemManagementContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd"
+            "SourcePath" = "8:Windows.System.SystemManagementContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4170,21 +4423,10 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_E9E2A0F5BFC130A2768BDCEB58203218"
+            "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E79216D0CC017651664FC4ADDF83D73C"
             {
-            "AssemblyRegister" = "3:1"
-            "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.UI.UIAutomation.UIAutomationContract, Version=2.0.0.0, Culture=neutral"
-                "ScatterAssemblies"
-                {
-                    "_E9E2A0F5BFC130A2768BDCEB58203218"
-                    {
-                    "Name" = "8:Windows.UI.UIAutomation.UIAutomationContract.winmd"
-                    "Attributes" = "3:512"
-                    }
-                }
-            "SourcePath" = "8:Windows.UI.UIAutomation.UIAutomationContract.winmd"
-            "TargetName" = "8:"
+            "SourcePath" = "8:api-ms-win-crt-string-l1-1-0.dll"
+            "TargetName" = "8:api-ms-win-crt-string-l1-1-0.dll"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
             "Condition" = "8:"
@@ -4197,24 +4439,24 @@
             "SharedLegacy" = "11:FALSE"
             "PackageAs" = "3:1"
             "Register" = "3:1"
-            "Exclude" = "11:TRUE"
+            "Exclude" = "11:FALSE"
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EAC5264CF2A86908C662E55D5585C79C"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EA9CB4BFE2C4CD07261F98B5CF64B701"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract, Version=2.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract, Version=3.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_EAC5264CF2A86908C662E55D5585C79C"
+                    "_EA9CB4BFE2C4CD07261F98B5CF64B701"
                     {
-                    "Name" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd"
+                    "Name" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd"
+            "SourcePath" = "8:Windows.Networking.Sockets.ControlChannelTriggerContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4232,20 +4474,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EBD30E60C62F816F92EC2452F5201741"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EADBD849A98B1FB69FEA7AF364A7FA6F"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.System.SystemManagementContract, Version=7.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract, Version=2.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_EBD30E60C62F816F92EC2452F5201741"
+                    "_EADBD849A98B1FB69FEA7AF364A7FA6F"
                     {
-                    "Name" = "8:Windows.System.SystemManagementContract.winmd"
+                    "Name" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.System.SystemManagementContract.winmd"
+            "SourcePath" = "8:Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4263,20 +4505,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EDA07A9BBC93339C52ABE94570919DCA"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_EBD56ACE56C7F5313FC8CFA4315DE750"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.Networking.Connectivity.WwanContract, Version=2.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.System.Profile.ProfileHardwareTokenContract, Version=1.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_EDA07A9BBC93339C52ABE94570919DCA"
+                    "_EBD56ACE56C7F5313FC8CFA4315DE750"
                     {
-                    "Name" = "8:Windows.Networking.Connectivity.WwanContract.winmd"
+                    "Name" = "8:Windows.System.Profile.ProfileHardwareTokenContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.Networking.Connectivity.WwanContract.winmd"
+            "SourcePath" = "8:Windows.System.Profile.ProfileHardwareTokenContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4314,20 +4556,20 @@
             "IsDependency" = "11:TRUE"
             "IsolateTo" = "8:"
             }
-            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_F05F117885DFAFCBC78FF7F18A26C4B5"
+            "{9F6F8455-1EF1-4B85-886A-4223BCC8E7F7}:_F0CF5A2114F5CA5056B633FE5D9D6A94"
             {
             "AssemblyRegister" = "3:1"
             "AssemblyIsInGAC" = "11:FALSE"
-            "AssemblyAsmDisplayName" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract, Version=4.0.0.0, Culture=neutral"
+            "AssemblyAsmDisplayName" = "8:Windows.Foundation.FoundationContract, Version=4.0.0.0, Culture=neutral"
                 "ScatterAssemblies"
                 {
-                    "_F05F117885DFAFCBC78FF7F18A26C4B5"
+                    "_F0CF5A2114F5CA5056B633FE5D9D6A94"
                     {
-                    "Name" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd"
+                    "Name" = "8:Windows.Foundation.FoundationContract.winmd"
                     "Attributes" = "3:512"
                     }
                 }
-            "SourcePath" = "8:Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd"
+            "SourcePath" = "8:Windows.Foundation.FoundationContract.winmd"
             "TargetName" = "8:"
             "Tag" = "8:"
             "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
@@ -4442,7 +4684,7 @@
         "Name" = "8:Microsoft Visual Studio"
         "ProductName" = "8:Midi 2.0"
         "ProductCode" = "8:{66FE638B-F86B-4592-B5A0-21701F9D3D6B}"
-        "PackageCode" = "8:{19135813-C749-4931-AA2F-134B008E5DEB}"
+        "PackageCode" = "8:{95948475-BA25-4B03-99D4-23BFD64BC986}"
         "UpgradeCode" = "8:{05A49F02-230E-4CCE-AEE5-4179B0172736}"
         "AspNetVersion" = "8:"
         "RestartWWWService" = "11:FALSE"
@@ -5105,6 +5347,34 @@
                 {
                 }
             }
+            "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_0AA6EC5B722D4FDBA7D4F9D05F8643E3"
+            {
+            "SourcePath" = "8:..\\x64\\Release\\mididmp.exe"
+            "TargetName" = "8:"
+            "Tag" = "8:"
+            "Folder" = "8:_1DC960FE630C406E9A1F93C99C1E099A"
+            "Condition" = "8:"
+            "Transitive" = "11:FALSE"
+            "Vital" = "11:TRUE"
+            "ReadOnly" = "11:FALSE"
+            "Hidden" = "11:FALSE"
+            "System" = "11:FALSE"
+            "Permanent" = "11:FALSE"
+            "SharedLegacy" = "11:FALSE"
+            "PackageAs" = "3:1"
+            "Register" = "3:1"
+            "Exclude" = "11:FALSE"
+            "IsDependency" = "11:FALSE"
+            "IsolateTo" = "8:"
+            "ProjectOutputGroupRegister" = "3:1"
+            "OutputConfiguration" = "8:"
+            "OutputGroupCanonicalName" = "8:Built"
+            "OutputProjectGuid" = "8:{5EC6D5EB-53D4-4731-891E-F746F0201429}"
+            "ShowKeyOutput" = "11:TRUE"
+                "ExcludeFilters"
+                {
+                }
+            }
             "{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_1D3C83321B67411EA0904B305816D102"
             {
             "SourcePath" = "8:..\\VSFiles\\x64\\Release\\Midi2.VirtualMidiAbstraction.dll"
diff --git a/src/api/Test/Midi2.Client.unittests/MidiEndpointDeviceWatcherTests.cpp b/src/api/Test/Midi2.Client.unittests/MidiEndpointDeviceWatcherTests.cpp
index 6e4bbab0..105a5fa8 100644
--- a/src/api/Test/Midi2.Client.unittests/MidiEndpointDeviceWatcherTests.cpp
+++ b/src/api/Test/Midi2.Client.unittests/MidiEndpointDeviceWatcherTests.cpp
@@ -44,9 +44,10 @@ void MidiEndpointDeviceWatcherTests::TestWatcherEnumeration(MidiEndpointDeviceIn
     auto EndpointDeviceAddedHandler = [&](MidiEndpointDeviceWatcher const& /*sender*/, MidiEndpointDeviceInformation const& addedDevice)
         {
             std::cout << "Device Added event raised." << std::endl;
-            std::cout << "Id:   " << winrt::to_string(addedDevice.Id()) << std::endl;
-            std::cout << "Name: " << winrt::to_string(addedDevice.Name()) << std::endl;
-            std::cout << "Desc: " << winrt::to_string(addedDevice.Description()) << std::endl;
+            std::cout << "Id:             " << winrt::to_string(addedDevice.Id()) << std::endl;
+            std::cout << "Name:           " << winrt::to_string(addedDevice.Name()) << std::endl;
+            std::cout << "Transport Desc: " << winrt::to_string(addedDevice.TransportSuppliedDescription()) << std::endl;
+            std::cout << "User Desc:      " << winrt::to_string(addedDevice.UserSuppliedDescription()) << std::endl;
             std::cout << std::endl;
 
             numEndpointsActual++;
diff --git a/src/oob-setup/api-package/WindowsMidiServices.wxs b/src/oob-setup/api-package/WindowsMidiServices.wxs
index c7553da5..3220a39e 100644
--- a/src/oob-setup/api-package/WindowsMidiServices.wxs
+++ b/src/oob-setup/api-package/WindowsMidiServices.wxs
@@ -164,7 +164,19 @@
                    >
         
         
-
+        
+       
+            
+       
+            
+                    
+                   
+            
         
         
             
 
+            
         
 
 

From 11e497013885459d4d2ffda42f97cd87a8c8c1ba Mon Sep 17 00:00:00 2001
From: Pete Brown 
Date: Thu, 8 Feb 2024 18:50:34 -0500
Subject: [PATCH 4/6] mididmp.exe formatting and documentation

---
 build/staging/version/BundleInfo.wxi |  2 +-
 docs/midi-dump.md                    | 37 +++++++++++++++++++++----
 src/api/InBoxApps/mididmp/main.cpp   | 41 ++++++++++++++++++----------
 3 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index ca9614ba..07ac4219 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
 
   
-  
+  
 
diff --git a/docs/midi-dump.md b/docs/midi-dump.md
index 6c1c323f..72aee8d9 100644
--- a/docs/midi-dump.md
+++ b/docs/midi-dump.md
@@ -13,11 +13,15 @@ The utility returns information only about MIDI. Here is example output:
 ```
 C:\Users\peteb>mididmp
 Microsoft Windows MIDI Services
-2024-02-08 18:28:52
 
+===============================================================================
+header
+===============================================================================
+
+current_time : 2024-02-08 18:44:31
 
 ===============================================================================
-Endpoints
+enum_endpoints
 ===============================================================================
 
 endpoint_device_id : \\?\swd#midisrv#midiu_diag_loopback_a#{e7cce071-3c03-423f-88d3-f1045d02552b}
@@ -65,7 +69,7 @@ parent_id : USB\VID_6666&PID_7777&MI_03\9&1663efa2&0&0003
 parent_name : Foo Synth
 
 ===============================================================================
-Ping Test
+ping_test
 ===============================================================================
 
 ping_attempt_count : 10
@@ -74,9 +78,32 @@ ping_time_round_trip_total_ticks : 7954
 ping_time_round_trip_average_ticks : 795
 
 ===============================================================================
-Clock
+midi_clock
 ===============================================================================
 
 clock_frequency : 10000000
 clock_now : 912988511667
-```
\ No newline at end of file
+```
+
+If the MIDI Service is not running or not installed, you'll get output like this:
+
+```
+C:\Users\peteb>mididmp
+===============================================================================
+header
+===============================================================================
+
+current_time : 2024-02-08 18:47:14
+
+===============================================================================
+enum_endpoints
+===============================================================================
+
+ERROR : Enumerating devices returned no matches. This is not expected and indicates an installation problem or that the service is not running.
+```
+
+We may add more fields or sections in the future. If you are machine parsing this file, do not rely on the order of fields or sections. The actual names of fields shown and the section headers will remain static and can be used in machine parsing, however. The tokens are not localized.
+
+The date at the top of the file is in YYYY-MM-DD format. Time is in 24-hour format.
+
+The executable returns 0 when succeeded, and non-zero when failed.
diff --git a/src/api/InBoxApps/mididmp/main.cpp b/src/api/InBoxApps/mididmp/main.cpp
index 2901b4fc..61524939 100644
--- a/src/api/InBoxApps/mididmp/main.cpp
+++ b/src/api/InBoxApps/mididmp/main.cpp
@@ -36,15 +36,6 @@ void OutputBlankLine()
         << std::endl;
 }
 
-void OutputCurrentTime()
-{
-    auto const time = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
-
-    std::wcout
-        << std::format(L"{:%Y-%m-%d %X}", time)
-        << std::endl;
-}
-
 void OutputSectionHeader(_In_ std::wstring headerText)
 {
     const std::wstring sectionHeaderSeparator = std::wstring(79, '=');
@@ -85,6 +76,26 @@ void OutputStringField(_In_ std::wstring fieldName, _In_ winrt::hstring value)
         << std::endl;
 }
 
+void OutputStringField(_In_ std::wstring fieldName, _In_ std::wstring value)
+{
+    std::wcout
+        << fieldName
+        << fieldSeparator
+        << value
+        << std::endl;
+}
+
+
+void OutputCurrentTime()
+{
+    auto const time = std::chrono::current_zone()->to_local(std::chrono::system_clock::now());
+
+    OutputStringField(L"current_time", std::format(L"{:%Y-%m-%d %X}", time));
+
+}
+
+
+
 void OutputTimestampField(_In_ std::wstring fieldName, _In_ uint64_t value)
 {
     std::wcout
@@ -127,12 +138,15 @@ int main()
     bool midiClock = true;
 
     OutputHeader(L"Microsoft Windows MIDI Services");
+
+    OutputSectionHeader(L"header");
+
     OutputCurrentTime();
     OutputBlankLine();
 
     try
     {
-        OutputSectionHeader(L"Endpoints");
+        OutputSectionHeader(L"enum_endpoints");
 
         // list devices
 
@@ -208,7 +222,7 @@ int main()
         // ping the service
         if (pingTest)
         {
-            OutputSectionHeader(L"Ping Test");
+            OutputSectionHeader(L"ping_test");
 
             OutputTimestampField(L"ping_attempt_count", pingCount);
 
@@ -225,17 +239,16 @@ int main()
             else
             {
                 OutputError(L"Ping test failed");
-                OutputStringField(L"Failure Reason", pingResult.FailureReason());
+                OutputStringField(L"ping_failure_reason", pingResult.FailureReason());
             }
         }
 
         if (midiClock)
         {
-            OutputSectionHeader(L"Clock");
+            OutputSectionHeader(L"midi_clock");
 
             OutputTimestampField(L"clock_frequency", midi2::MidiClock::TimestampFrequency());
             OutputTimestampField(L"clock_now", midi2::MidiClock::Now());
-
         }
 
     }

From 31e79773af99737bbc31dc9f8b57295b4dcaf7c0 Mon Sep 17 00:00:00 2001
From: Pete Brown 
Date: Thu, 8 Feb 2024 19:35:28 -0500
Subject: [PATCH 5/6] Finished mididmp #59

Completes issue #59
---
 build/staging/version/BundleInfo.wxi                     | 2 +-
 src/api/InBoxApps/mididmp/main.cpp                       | 1 -
 .../Midi/Commands/Endpoint/EndpointPropertiesCommand.cs  | 6 +++---
 .../Midi/Commands/Enumerate/EnumEndpointsCommand.cs      | 9 +++++++--
 src/user-tools/midi-console/Midi/Midi.csproj             | 2 +-
 5 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index 07ac4219..c236a3e5 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
 
   
-  
+  
 
diff --git a/src/api/InBoxApps/mididmp/main.cpp b/src/api/InBoxApps/mididmp/main.cpp
index 61524939..b7af3893 100644
--- a/src/api/InBoxApps/mididmp/main.cpp
+++ b/src/api/InBoxApps/mididmp/main.cpp
@@ -142,7 +142,6 @@ int main()
     OutputSectionHeader(L"header");
 
     OutputCurrentTime();
-    OutputBlankLine();
 
     try
     {
diff --git a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointPropertiesCommand.cs b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointPropertiesCommand.cs
index 17c64a16..25714953 100644
--- a/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointPropertiesCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Endpoint/EndpointPropertiesCommand.cs
@@ -108,9 +108,9 @@ public override int Execute(CommandContext context, Settings settings)
                 table.AddEmptyRow();
                 table.AddRow(AnsiMarkupFormatter.FormatTableColumnHeading(Resources.Strings.PropertiesTableSectionHeaderUserData), "");
                 table.AddRow(Resources.Strings.PropertiesTablePropertyLabelUserSuppliedName, AnsiMarkupFormatter.FormatEndpointName(di.UserSuppliedName));
-                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelDescription, AnsiMarkupFormatter.EscapeString(di.Description));
-                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelSmallImagePath, AnsiMarkupFormatter.EscapeString(di.SmallImagePath));
-                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelLargeImagePath, AnsiMarkupFormatter.EscapeString(di.LargeImagePath));
+                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelDescription, AnsiMarkupFormatter.EscapeString(di.UserSuppliedDescription));
+                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelSmallImagePath, AnsiMarkupFormatter.EscapeString(di.UserSuppliedSmallImagePath));
+                table.AddRow(Resources.Strings.PropertiesTablePropertyLabelLargeImagePath, AnsiMarkupFormatter.EscapeString(di.UserSuppliedLargeImagePath));
 
 
 
diff --git a/src/user-tools/midi-console/Midi/Commands/Enumerate/EnumEndpointsCommand.cs b/src/user-tools/midi-console/Midi/Commands/Enumerate/EnumEndpointsCommand.cs
index 36d3ab04..ff516e21 100644
--- a/src/user-tools/midi-console/Midi/Commands/Enumerate/EnumEndpointsCommand.cs
+++ b/src/user-tools/midi-console/Midi/Commands/Enumerate/EnumEndpointsCommand.cs
@@ -139,9 +139,14 @@ private void DisplayEndpointInformationFormatted(Table table, Settings settings,
 
             if (settings.Verbose)
             {
-                if (!string.IsNullOrEmpty(endpointInfo.Description))
+                if (!string.IsNullOrEmpty(endpointInfo.TransportSuppliedDescription))
                 {
-                    table.AddRow(new Markup(AnsiMarkupFormatter.EscapeString(endpointInfo.Description)));
+                    table.AddRow(new Markup(AnsiMarkupFormatter.EscapeString(endpointInfo.TransportSuppliedDescription)));
+                }
+
+                if (!string.IsNullOrEmpty(endpointInfo.UserSuppliedDescription))
+                {
+                    table.AddRow(new Markup(AnsiMarkupFormatter.EscapeString(endpointInfo.UserSuppliedDescription)));
                 }
 
             }
diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj
index 4ce5ee50..2bd42f01 100644
--- a/src/user-tools/midi-console/Midi/Midi.csproj
+++ b/src/user-tools/midi-console/Midi/Midi.csproj
@@ -31,7 +31,7 @@
     
     
     
-    
+    
   
 
   

From d5d2ca211559d28dbc2bf894bdc647d76dbd3ec1 Mon Sep 17 00:00:00 2001
From: Pete Brown 
Date: Thu, 8 Feb 2024 21:45:22 -0500
Subject: [PATCH 6/6] Additional documentation and a few more API updates while
 I was at it.

---
 build/staging/version/BundleInfo.wxi          |  2 +-
 .../Windows.Devices.Midi2/clock/MidiClock.md  |  1 +
 .../IMidiEndpointConnectionSource.md          | 16 ++++++
 .../IMidiMessageReceivedEventSource.md        | 22 ++++++++
 .../connections/MidiSendMessageResultEnum.md  | 47 ++++++++++++++++
 ...MidiEndpointDeviceInformationFilterEnum.md | 27 ++++++++++
 ...iEndpointDeviceInformationSortOrderEnum.md | 31 +++++++++++
 .../MidiEndpointDevicePurposeEnum.md          | 26 +++++++++
 .../Midi1ChannelVoiceMessageStatusEnum.md     | 27 ++++++++++
 .../Midi2ChannelVoiceMessageStatusEnum.md     | 35 ++++++++++++
 .../MidiEndpointDiscoveryFilterFlagsEnum.md   | 27 ++++++++++
 ...diFunctionBlockDiscoveryFilterFlagsEnum.md | 23 ++++++++
 .../MidiSystemExclusive8StatusEnum.md         | 24 +++++++++
 .../MidiFunctionBlockDirectionEnum.md         | 24 +++++++++
 .../metadata/MidiFunctionBlockMidi10Enum.md   | 24 +++++++++
 .../metadata/MidiFunctionBlockUIHintEnum.md   | 26 +++++++++
 .../MidiGroupTerminalBlockDirectionEnum.md    | 23 ++++++++
 .../MidiGroupTerminalBlockProtocolEnum.md     | 29 ++++++++++
 .../nuget/Windows.Devices.Midi2.nuspec        |  2 +-
 src/api/Client/Midi2Client/MidiClock.h        |  2 +
 src/api/Client/Midi2Client/MidiClock.idl      |  3 ++
 .../MidiEndpointDeviceInformation.cpp         | 53 +++++++++++++++++++
 ...idiEndpointDeviceInformationFilterEnum.idl | 11 ++--
 ...EndpointDeviceInformationSortOrderEnum.idl | 13 ++++-
 .../MidiSystemExclusive8StatusEnum.idl        |  8 +--
 src/api/Inc/MidiDefs.h                        |  2 +
 src/user-tools/midi-console/Midi/Midi.csproj  |  2 +-
 27 files changed, 518 insertions(+), 12 deletions(-)
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSource.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/connections/IMidiMessageReceivedEventSource.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/connections/MidiSendMessageResultEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationFilterEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationSortOrderEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDevicePurposeEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/messages/Midi1ChannelVoiceMessageStatusEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/messages/Midi2ChannelVoiceMessageStatusEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/messages/MidiEndpointDiscoveryFilterFlagsEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/messages/MidiFunctionBlockDiscoveryFilterFlagsEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/messages/MidiSystemExclusive8StatusEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockDirectionEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockMidi10Enum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockUIHintEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockDirectionEnum.md
 create mode 100644 docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockProtocolEnum.md

diff --git a/build/staging/version/BundleInfo.wxi b/build/staging/version/BundleInfo.wxi
index c236a3e5..7a5df408 100644
--- a/build/staging/version/BundleInfo.wxi
+++ b/build/staging/version/BundleInfo.wxi
@@ -1,4 +1,4 @@
 
   
-  
+  
 
diff --git a/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.md b/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.md
index 65970cad..d537fe68 100644
--- a/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.md
+++ b/docs/developer-docs/Windows.Devices.Midi2/clock/MidiClock.md
@@ -21,6 +21,7 @@ You can learn more about high-resolution timestamps in Windows at [https://aka.m
 | --------------- | ----------- |
 | `Now` | Returns the current timestamp |
 | `TimestampFrequency` | Returns the number of timestamp ticks per second. This is calculated the first time it is called, and then cached for future calls. |
+| `TimestampConstantSendImmediately` | Returns the constant to use when you want to send messages immediately and bypass outgoing message scheduling. Developers may use this value or simply provide `0` in place of the timestamp when sending messages.  |
 
 ## Static Functions
 
diff --git a/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSource.md b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSource.md
new file mode 100644
index 00000000..62eecd4d
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiEndpointConnectionSource.md
@@ -0,0 +1,16 @@
+---
+layout: api_page
+title: IMidiEndpointConnectionSource
+parent: Connections
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# IMidiEndpointConnectionSource
+
+Marker interface which is used to prevent circular references in the API, specifically with message processing plugins. This interface is only supported when used by the `MidiEndpointConnection` class.
+
+## IDL
+
+[IMidiEndpointConnectionSource IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/IMidiEndpointConnectionSource.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiMessageReceivedEventSource.md b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiMessageReceivedEventSource.md
new file mode 100644
index 00000000..dc87f73e
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/connections/IMidiMessageReceivedEventSource.md
@@ -0,0 +1,22 @@
+---
+layout: api_page
+title: IMidiMessageReceivedEventSource
+parent: Connections
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# IMidiMessageReceivedEventSource
+
+Interface which contains the event definition used by any class which raises the `MessageReceived` event. This is defined in an interface so that message processing plugins and the `MidiEndpointConnection` type can be used interchangeably in an event handler.
+
+## Events
+
+| Event | Description |
+| -------- | ----------- |
+| `MessageReceived(source, args)` | The main message received event definition. |
+
+## IDL
+
+[IMidiMessageReceivedEventSource IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/IMidiMessageReceivedEventSource.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/connections/MidiSendMessageResultEnum.md b/docs/developer-docs/Windows.Devices.Midi2/connections/MidiSendMessageResultEnum.md
new file mode 100644
index 00000000..7dcef5fb
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/connections/MidiSendMessageResultEnum.md
@@ -0,0 +1,47 @@
+---
+layout: api_page
+title: MidiSendMessageResult
+parent: Connections
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiSendMessageResult
+
+When an application sends a message, it should check the result of sending to ensure that the message was transmitted. Each of the message sending functions returns a `MidiSendMessageResult` flags enum. Values in this enum are OR'd together to indicate success or failure, and in the case of failure, the reason.
+
+The `MidiEndpointConnection` type includes static helper functions to process the `MidiSendMessageResult` and determine success or failure. The application may then optionally look at the remaining data to see which failure reason(s) apply. 
+
+```cpp
+auto sendResult = myConnection.SendMessageWords(MidiClock::TimestampConstantSendImmediately(), 0x28675309);
+
+if (MidiEndpointConnection::SendMessageSucceeded(sendResult))
+{
+    // do something in the case of success
+}
+else
+{
+    // one or more failure reasons in the result. Use bitwise AND `&` operator to decipher.
+}
+
+```
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ----- | ----------- |
+| `Succeeded` | `0x80000000` | Indicates success. |
+| `Failed` | `0x10000000` | Indicates failure. The actual failure reason will be combined with the result. |
+| `BufferFull` | `0x00010000` | The message could not be sent because the outgoing buffer to the service was full |
+| `EndpointConnectionClosedOrInvalid` | `0x00040000` | The endpoint connection was closed or invalidated before the message could be sent. |
+| `InvalidMessageTypeForWordCount` | `0x00100000` | The number of words sent does not match the message type of the first word. |
+| `InvalidMessageOther` | `0x00200000` | The message sent was invalid for another reason. |
+| `DataIndexOutOfRange` | `0x00400000` | Reading a full message would result in overrunning the provided array, collection, or buffer. |
+| `TimestampOutOfRange` | `0x00800000` | The provided timestamp is too far in the future to be scheduled. |
+| `MessageListPartiallyProcessed` | `0x00A00000` | The message list was only partially processed. Not all messages were sent. |
+| `Other` | `0x01000000` | Other reason that cannot be determined. |
+
+## IDL
+
+[MidiSendMessageResult IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiSendMessageResult.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationFilterEnum.md b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationFilterEnum.md
new file mode 100644
index 00000000..e2d18c53
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationFilterEnum.md
@@ -0,0 +1,27 @@
+---
+layout: api_page
+title: MidiEndpointDeviceInformationFilter
+parent: Endpoint Enumeration
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiEndpointDeviceInformationFilter Enumeration
+
+When enumerating devices, it is helpful to be able to filter for different types of devices. For example, an application providing diagnostic or development services may want to enumerate the diagnostic loopback endpoints. A Digital Audio Workstation, on the other hand, would only want to enumerate the normal UMP and Byte Stream native endpoints.
+
+## Properties
+
+| Property | Value | Description |
+| --------------- | ---------- | ----------- |
+| `IncludeClientUmpNative` | `0x00000001` | Include endpoints which are MIDI UMP endpoints natively. These are typically considered MIDI 2.0 devices even if they only send MIDI 1.0 messages in UMP. |
+| `IncludeClientByteStreamNative` | `0x00000002` | Include endpoints which are MIDI 1.0 byte stream endpoints natively. These are converted to UMP internally in Windows MIDI Services. |
+| `IncludeVirtualDeviceResponder` | `0x00000100` | Include endpoints which are virtual devices. Note that this is the device side of the endpoint, not the side available to other applications. Typically, you would not use this. |
+| `IncludeDiagnosticLoopback` | `0x00010000` | Use this value only when providing development, test, or diagnostic services for MIDI. |
+| `IncludeDiagnosticPing` | `0x00020000` | You would not normally include this in an enumeration. This endpoint is internal. |
+| `AllTypicalEndpoints` | `IncludeClientUmpNative | IncludeClientByteStreamNative` | This is the value most applications should use, and is the default. |
+
+## IDL
+
+[MidiEndpointDeviceInformationFilterEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiEndpointDeviceInformationFilterEnum.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationSortOrderEnum.md b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationSortOrderEnum.md
new file mode 100644
index 00000000..c89f1a31
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDeviceInformationSortOrderEnum.md
@@ -0,0 +1,31 @@
+---
+layout: api_page
+title: MidiEndpointDeviceInformationSortOrder
+parent: Endpoint Enumeration
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiEndpointDeviceInformationSortOrder Enumeration
+
+Specifies the sort order to use when enumerating a static list of devices.
+
+## Properties
+
+| Property | Value | Description |
+| --------------- | ---------- | ----------- |
+| `None` | `0` | No sort. Return in default order |
+| `Name` | `1` | Sort by the name of the endpoint |
+| `EndpointDeviceId` | `2` | Sort by the id of the endpoint (the SWD id) |
+| `DeviceInstanceId` | `3` | Sort by the device instance id |
+| `ContainerThenName` | `11` | Sort by the container and then by name. This is helpful when you want endpoints grouped by parent. |
+| `ContainerThenEndpointDeviceId` | `12` | Sort by the container and then by the endpoint id |
+| `ContainerThenDeviceInstanceId` | `13` | Sort by the container and then by the device instance id |
+| `TransportMnemonicThenName` | `21` | Sort by the transport mnemonic (example: "DIAG") and then by the device instance id |
+| `TransportMnemonicThenEndpointDeviceId` | `22` | Sort by the transport mnemonic and then by the endpoint id |
+| `TransportMnemonicThenDeviceInstanceId` | `23` | Sort by the transport mnemonic and then by the device instance id |
+
+## IDL
+
+[MidiEndpointDeviceInformationSortOrderEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiEndpointDeviceInformationSortOrderEnum.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDevicePurposeEnum.md b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDevicePurposeEnum.md
new file mode 100644
index 00000000..4a003e14
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/enumeration/MidiEndpointDevicePurposeEnum.md
@@ -0,0 +1,26 @@
+---
+layout: api_page
+title: MidiEndpointDevicePurpose
+parent: Endpoint Enumeration
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiEndpointDevicePurpose Enumeration
+
+Indicates the intended purpose of the endpoint. Use this to help classify endpoints you show to users in your application. This value is also used internally when filtering endpoints per the `MidiEndpointDeviceInformationFilter` enumeration.
+
+## Properties
+
+| Property | Value | Description |
+| --------------- | ---------- | ----------- |
+| `NormalMessageEndpoint` | `0` | The endpoint is any number of normal messaging endpoint types. |
+| `VirtualDeviceResponder` | `100` | The endpoint is the device-side of an app-to-app MIDI connection. Only the device app should use this endpoint. |
+| `InBoxGeneralMidiSynth` | `400` | The endpoint represents the internal General MIDI Synthesizer  |
+| `DiagnosticLoopback` | `500` | The endpoint is one of the static system-wide diagnostics loopback endpoints. These are not normally used in applications  |
+| `DiagnosticPing` | `510` | The endpoint is the internal diagnostics ping endpoint. This endpoint should never be used by applications as it is reserved for the `MidiService` ping feature.  |
+
+## IDL
+
+[MidiEndpointDevicePurposeEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiEndpointDevicePurposeEnum.idl)
+
diff --git a/docs/developer-docs/Windows.Devices.Midi2/messages/Midi1ChannelVoiceMessageStatusEnum.md b/docs/developer-docs/Windows.Devices.Midi2/messages/Midi1ChannelVoiceMessageStatusEnum.md
new file mode 100644
index 00000000..563eca64
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/messages/Midi1ChannelVoiceMessageStatusEnum.md
@@ -0,0 +1,27 @@
+---
+layout: api_page
+title: Midi1ChannelVoiceMessageStatus
+parent: Messages
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# Midi1ChannelVoiceMessageStatus Enumeration
+
+Status to use for MIDI 1.0 Channel Voice messages. Note that not all MIDI 1.0 messages are channel voice messages, so this is not an exhaustive list of MIDI 1.0 messages. However, this is the total set of MIDI 1.0 messages which can be used in a MIDI Universal MIDI Packet Message type 2.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `NoteOff` | `0x8` | MIDI 1.0 Note Off message |
+| `NoteOn` | `0x9` | MIDI 1.0 Note On message |
+| `PolyPressure` | `0xA` | MIDI 1.0 polyphonic pressure message |
+| `ControlChange` | `0xB` | MIDI 1.0 control change message |
+| `ProgramChange` | `0xC` | MIDI 1.0 program change message |
+| `ChannelPressure` | `0xD` | MIDI 1.0 channel pressure message |
+| `PitchBend` | `0xE` | MIDI 1.0 pitch bend message |
+
+## IDL
+
+[Midi1ChannelVoiceMessageStatusEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/Midi1ChannelVoiceMessageStatusEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/messages/Midi2ChannelVoiceMessageStatusEnum.md b/docs/developer-docs/Windows.Devices.Midi2/messages/Midi2ChannelVoiceMessageStatusEnum.md
new file mode 100644
index 00000000..6d86282a
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/messages/Midi2ChannelVoiceMessageStatusEnum.md
@@ -0,0 +1,35 @@
+---
+layout: api_page
+title: Midi2ChannelVoiceMessageStatus
+parent: Messages
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# Midi2ChannelVoiceMessageStatus Enumeration
+
+Status to use for MIDI 2.0 Channel Voice messages. These are message type 4 messages.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `RegisteredPerNoteController` | `0x0` | MIDI 2.0 Registered per-note controller message |
+| `AssignablePerNoteController` | `0x1` | MIDI 2.0 Assignable per-note controller message |
+| `RegisteredController` | `0x2` | MIDI 2.0 Registered controller message |
+| `AssignableController` | `0x3` | MIDI 2.0 Assignable controller message |
+| `RelativeRegisteredController` | `0x4` | MIDI 2.0 Relative registered controller message |
+| `RelativeAssignableController` | `0x5` | MIDI 2.0 Relative assignable controller message |
+| `PerNotePitchBend` | `0x6` | MIDI 2.0 per-note pitch bend message |
+| `NoteOff` | `0x8` | MIDI 2.0 Note Off message |
+| `NoteOn` | `0x9` | MIDI 2.0 Note On message |
+| `PolyPressure` | `0xA` | MIDI 2.0 polyphonic pressure message |
+| `ControlChange` | `0xB` | MIDI 2.0 control change message |
+| `ProgramChange` | `0xC` | MIDI 2.0 program change message |
+| `ChannelPressure` | `0xD` | MIDI 2.0 channel pressure message |
+| `PitchBend` | `0xE` | MIDI 2.0 pitch bend message |
+| `PerNoteManagement` | `0xF` | MIDI 2.0 per-note management message |
+
+## IDL
+
+[Midi2ChannelVoiceMessageStatusEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/Midi2ChannelVoiceMessageStatusEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/messages/MidiEndpointDiscoveryFilterFlagsEnum.md b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiEndpointDiscoveryFilterFlagsEnum.md
new file mode 100644
index 00000000..26ce1b96
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiEndpointDiscoveryFilterFlagsEnum.md
@@ -0,0 +1,27 @@
+---
+layout: api_page
+title: MidiEndpointDiscoveryFilterFlags
+parent: Messages
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiEndpointDiscoveryFilterFlags Enumeration
+
+Used to indicate which endpoint discovery messages you want to receive when you query an endpoint.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `None` | `0x00000000` | Request nothing. |
+| `RequestEndpointInformation` | `0x00000001` | Request the details of the endpoint. |
+| `RequestDeviceIdentity` | `0x00000002` | Request identity information including System Exclusive Ids and version information |
+| `RequestEndpointName` | `0x00000004` | Request endpoint name messages |
+| `RequestProductInstanceId` | `0x00000008` | Request product instance id messages |
+| `RequestStreamConfiguration` | `0x00000010` | Request the stream configuration |
+
+
+## IDL
+
+[MidiEndpointDiscoveryFilterFlagsEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiEndpointDiscoveryFilterFlagsEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/messages/MidiFunctionBlockDiscoveryFilterFlagsEnum.md b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiFunctionBlockDiscoveryFilterFlagsEnum.md
new file mode 100644
index 00000000..331cb8d9
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiFunctionBlockDiscoveryFilterFlagsEnum.md
@@ -0,0 +1,23 @@
+---
+layout: api_page
+title: MidiFunctionBlockDiscoveryFilterFlags
+parent: Messages
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiFunctionBlockDiscoveryFilterFlags Enumeration
+
+Used to indicate which function block messages you want to receive when you request function blocks.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `None` | `0x00000000` | No information requested |
+| `RequestFunctionBlockInformation` | `0x00000001` | Request the core function block information |
+| `RequestFunctionBlockName` | `0x00000002` | Request a set of function block name messages |
+
+## IDL
+
+[MidiFunctionBlockDiscoveryFilterFlagsEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiFunctionBlockDiscoveryFilterFlagsEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/messages/MidiSystemExclusive8StatusEnum.md b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiSystemExclusive8StatusEnum.md
new file mode 100644
index 00000000..23545c55
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/messages/MidiSystemExclusive8StatusEnum.md
@@ -0,0 +1,24 @@
+---
+layout: api_page
+title: MidiSystemExclusive8Status
+parent: Messages
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiSystemExclusive8Status Enumeration
+
+Used to indicate the type of System Exclusive 8 Universal MIDI Packet (UMP) as per the MIDI 2.0 UMP specification.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `CompleteMessageInSingleMessagePacket` | `0x0` |  |
+| `StartMessagePacket` | `0x1` |  |
+| `ContinueMessagePacket` | `0x2` |  |
+| `EndMessagePacket` | `0x3` |  |
+
+## IDL
+
+[MidiSystemExclusive8StatusEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiSystemExclusive8StatusEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockDirectionEnum.md b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockDirectionEnum.md
new file mode 100644
index 00000000..34a348c6
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockDirectionEnum.md
@@ -0,0 +1,24 @@
+---
+layout: api_page
+title: MidiFunctionBlockDirection
+parent: Metadata
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiFunctionBlockDirection Enumeration
+
+Indicates the message flow for a function block. Note that this is, per the specification, from the function block's point of view. So, for example, a function block specifying `BlockOutput` would be a sender of messages, and therefore used as an input in the API.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `Undefined` | `0x0` | Unknown or undefined |
+| `BlockInput` | `0x1` | This block represents an input function, from the block's point of view. |
+| `BlockOutput` | `0x2` | This block represents an output function, from the block's point of view. |
+| `Bidirectional` | `0x3` | This block represents a bidirectional function. |
+
+## IDL
+
+MidiFunctionBlockDirectionEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiFunctionBlockDirectionEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockMidi10Enum.md b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockMidi10Enum.md
new file mode 100644
index 00000000..2a9189f2
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockMidi10Enum.md
@@ -0,0 +1,24 @@
+---
+layout: api_page
+title: MidiFunctionBlockMidi10
+parent: Metadata
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiFunctionBlockMidi10 Enumeration
+
+Indicates the MIDI 1.0 capability restrictions for a function block. Note that Windows MIDI Services does not currently throttle the speed of outbound messages, even if the block indicates it has restricted bandwidth.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `Not10` | `0x0` | This function block is not a MIDI 1.0 function. |
+| `YesBandwidthUnrestricted` | `0x1` | This block represents a MIDI 1.0 function, but has the ability to receive messages faster than the original MIDI 1.0 protocol speed. |
+| `YesBandwidthRestricted` | `0x2` | This block represents a MIDI 1.0 function, and applications should take care to send messages to it at the normal MIDI 1.0 protocol speed. |
+| `Reserved` | `0x3` | Reserved for future use. |
+
+## IDL
+
+MidiFunctionBlockMidi10Enum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiFunctionBlockMidi10Enum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockUIHintEnum.md b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockUIHintEnum.md
new file mode 100644
index 00000000..f7d2ac96
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiFunctionBlockUIHintEnum.md
@@ -0,0 +1,26 @@
+---
+layout: api_page
+title: MidiFunctionBlockUIHint
+parent: Metadata
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiFunctionBlockUIHint Enumeration
+
+The MIDI 2.0 protocol is bi-directional in nature, but individual function blocks may be primarily an input or an output from the user's point of view. The UI hint enumeration (the values of which are described in the MIDI 2.0 Universal MIDI Packet specification) helps provide an indicator fro how to present the function to the user. For example, a tone generator may support bi-directional communication so it can indicate which patch is playing, but it would be primarily a receiver of MIDI note information, from the user's point of view.
+
+In general, these values should not restrict completely what you enable a user to do with the groups in a function block, but they should help in how you present the information to the user. You may, for example, present a list of receiver functions and groups to the user initially, but provide a "show all" to show the remaining functions and groups.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `Unknown` | `0x0` | Unknown or undefined. |
+| `Receiver` | `0x1` | This block is primarily a receiver of MIDI data. For example, a tone generator. |
+| `Sender` | `0x2` | This block is primarily a sender of MIDI data. For example, a keyboard or grid of touch pads. |
+| `Bidirectional` | `0x3` | This block is bidirectional. For example, a sequencer which can both record and play notes. |
+
+## IDL
+
+MidiFunctionBlockUIHintEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiFunctionBlockUIHintEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockDirectionEnum.md b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockDirectionEnum.md
new file mode 100644
index 00000000..966b85b1
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockDirectionEnum.md
@@ -0,0 +1,23 @@
+---
+layout: api_page
+title: MidiGroupTerminalBlockDirection
+parent: Metadata
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiGroupTerminalBlockDirection Enumeration
+
+Indicates the message flow for a group terminal block. Note that this is, per the specification, from the group terminal block's point of view. So, for example, a group terminal block specifying `BlockOutput` would be a sender of messages, and therefore used as an input in the API.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `Bidirectional` | `0x0` | This block represents a bidirectional function. |
+| `BlockInput` | `0x1` | This block represents an input function, from the block's point of view. |
+| `BlockOutput` | `0x2` | This block represents an output function, from the block's point of view. |
+
+## IDL
+
+MidiGroupTerminalBlockDirectionEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiGroupTerminalBlockDirectionEnum.idl)
diff --git a/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockProtocolEnum.md b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockProtocolEnum.md
new file mode 100644
index 00000000..53a467b6
--- /dev/null
+++ b/docs/developer-docs/Windows.Devices.Midi2/metadata/MidiGroupTerminalBlockProtocolEnum.md
@@ -0,0 +1,29 @@
+---
+layout: api_page
+title: MidiGroupTerminalBlockProtocol
+parent: Metadata
+grand_parent: Windows.Devices.Midi2 API
+has_children: false
+---
+
+# MidiGroupTerminalBlockProtocol Enumeration
+
+Indicates the protocol specifics for the Group Terminal Block. Group terminal blocks are still available, but are generally deprecated by the MIDI Association in favor of function blocks, endpoint discovery and protocol negotiation, when available.
+
+## Properties
+
+| Property | Value | Description |
+| -------- | ------- | ------ |
+| `Unknown` | `0x00` | Unknown or undefined |
+| `Midi1Message64` | `0x01` | Supports MIDI 1.0 messages, including 64 bit System Exclusive messages  |
+| `Midi1Message64WithJitterReduction` | `0x02` | Supports MIDI 1.0 messages, including 64 bit System Exclusive messages * |
+| `Midi1Message128` | `0x03` | Supports MIDI 1.0 messages, including 128 bit System Exclusive messages |
+| `Midi1Message128WithJitterReduction` | `0x04` | Supports MIDI 1.0 messages, including 128 bit System Exclusive messages * |
+| `Midi2` | `0x11` | Supports MIDI 2.0 messages |
+| `Midi2WithJitterReduction` | `0x12` | Supports MIDI 2.0 messages, including 128 bit System Exclusive messages * |
+
+\* Note. Jitter Reduction indicators in group terminal blocks should be ignored. These are now specified through endpoint discovery and protocol negotiation, and are handled completely in the MIDI service. Do not send jitter reduction messages from your application.
+
+## IDL
+
+MidiGroupTerminalBlockProtocolEnum IDL](https://github.com/microsoft/MIDI/blob/main/src/api/Client/Midi2Client/MidiGroupTerminalBlockProtocolEnum.idl)
diff --git a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
index 157dcab2..6814eb36 100644
--- a/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
+++ b/src/api/Client/Midi2Client-Projection/nuget/Windows.Devices.Midi2.nuspec
@@ -2,7 +2,7 @@
 
 	
 		Windows.Devices.Midi2
-		1.0.0-preview.3-0148
+		1.0.0-preview.3-0150
 		Microsoft Corporation
 		Windows MIDI Services API. Minimum package necessary to use Windows MIDI Services from an app on a PC that has Windows MIDI Services installed.
 		MIT
diff --git a/src/api/Client/Midi2Client/MidiClock.h b/src/api/Client/Midi2Client/MidiClock.h
index 676f3746..9c3bc3c8 100644
--- a/src/api/Client/Midi2Client/MidiClock.h
+++ b/src/api/Client/Midi2Client/MidiClock.h
@@ -19,6 +19,8 @@ namespace winrt::Windows::Devices::Midi2::implementation
 
         static internal::MidiTimestamp Now();
 
+        static internal::MidiTimestamp TimestampConstantSendImmediately() { return MIDI_TIMESTAMP_SEND_IMMEDIATELY; }
+
         static uint64_t TimestampFrequency();
 
         static internal::MidiTimestamp OffsetTimestampByTicks(
diff --git a/src/api/Client/Midi2Client/MidiClock.idl b/src/api/Client/Midi2Client/MidiClock.idl
index 93f79b8e..0265c409 100644
--- a/src/api/Client/Midi2Client/MidiClock.idl
+++ b/src/api/Client/Midi2Client/MidiClock.idl
@@ -19,6 +19,9 @@ namespace Windows.Devices.Midi2
         // gets the current MIDI timestamp
         static MIDI_TIMESTAMP Now{ get; };
 
+        // gets the current MIDI timestamp
+        static MIDI_TIMESTAMP TimestampConstantSendImmediately{ get; };
+
         // returns the units per second for the timestamp
         static UInt64 TimestampFrequency{ get; };
 
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
index e22d6b2a..0373faff 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformation.cpp
@@ -305,6 +305,14 @@ namespace winrt::Windows::Devices::Midi2::implementation
                 });
             break;
 
+        case MidiEndpointDeviceInformationSortOrder::EndpointDeviceId:
+            std::sort(begin(midiDevices), end(midiDevices),
+                [](_In_ const auto& device1, _In_ const auto& device2)
+                {
+                    return device1.Id() < device2.Id();
+                });
+            break;
+
         case MidiEndpointDeviceInformationSortOrder::ContainerThenName:
             std::sort(begin(midiDevices), end(midiDevices),
                 [](_In_ const auto& device1, _In_ const auto& device2)
@@ -327,6 +335,51 @@ namespace winrt::Windows::Devices::Midi2::implementation
                 });
             break;
 
+        case MidiEndpointDeviceInformationSortOrder::ContainerThenEndpointDeviceId:
+            std::sort(begin(midiDevices), end(midiDevices),
+                [](_In_ const auto& device1, _In_ const auto& device2)
+                {
+                    if (device1.ContainerId() == device2.ContainerId())
+                        return device1.Id() < device2.Id();
+
+                    return device1.ContainerId() < device2.ContainerId();
+                });
+            break;
+
+        case MidiEndpointDeviceInformationSortOrder::TransportMnemonicThenName:
+            std::sort(begin(midiDevices), end(midiDevices),
+                [](_In_ const auto& device1, _In_ const auto& device2)
+                {
+                    if (device1.TransportMnemonic() == device2.TransportMnemonic())
+                        return device1.Name() < device2.Name();
+
+                    return device1.TransportMnemonic() < device2.TransportMnemonic();
+                });
+            break;
+
+        case MidiEndpointDeviceInformationSortOrder::TransportMnemonicThenEndpointDeviceId:
+            std::sort(begin(midiDevices), end(midiDevices),
+                [](_In_ const auto& device1, _In_ const auto& device2)
+                {
+                    if (device1.TransportMnemonic() == device2.TransportMnemonic())
+                        return device1.Id() < device2.Id();
+
+                    return device1.TransportMnemonic() < device2.TransportMnemonic();
+                });
+            break;
+
+        case MidiEndpointDeviceInformationSortOrder::TransportMnemonicThenDeviceInstanceId:
+            std::sort(begin(midiDevices), end(midiDevices),
+                [](_In_ const auto& device1, _In_ const auto& device2)
+                {
+                    if (device1.TransportMnemonic() == device2.TransportMnemonic())
+                        return device1.DeviceInstanceId() < device2.DeviceInstanceId();
+
+                    return device1.TransportMnemonic() < device2.TransportMnemonic();
+                });
+            break;
+
+
         case MidiEndpointDeviceInformationSortOrder::None:
             // do nothing
             break;
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformationFilterEnum.idl b/src/api/Client/Midi2Client/MidiEndpointDeviceInformationFilterEnum.idl
index 71adf53a..da0807ec 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformationFilterEnum.idl
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformationFilterEnum.idl
@@ -17,7 +17,7 @@ namespace Windows.Devices.Midi2
     {
         // Normal client devices to connect to to send/receive. 
         // These two are all most apps need
-        IncludeClientUmpNative =        0x00000001,
+        IncludeClientUmpNative = 0x00000001,
         IncludeClientByteStreamNative = 0x00000002,
 
         // this is for the *source* data, not the client connection. 
@@ -27,8 +27,13 @@ namespace Windows.Devices.Midi2
 
         // the diagnostics loopback devices. I've included Ping to be 
         // inclusive, but no app should ever use it
-        IncludeDiagnosticLoopback =     0x00010000,
-        IncludeDiagnosticPing =         0x00020000,
+        IncludeDiagnosticLoopback = 0x00010000,
+        IncludeDiagnosticPing = 0x00020000,
+
+
+
+
+        AllTypicalEndpoints = IncludeClientUmpNative | IncludeClientByteStreamNative,
 
     };
 }
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiEndpointDeviceInformationSortOrderEnum.idl b/src/api/Client/Midi2Client/MidiEndpointDeviceInformationSortOrderEnum.idl
index db63bec5..8959d7c2 100644
--- a/src/api/Client/Midi2Client/MidiEndpointDeviceInformationSortOrderEnum.idl
+++ b/src/api/Client/Midi2Client/MidiEndpointDeviceInformationSortOrderEnum.idl
@@ -15,10 +15,19 @@ namespace Windows.Devices.Midi2
     enum MidiEndpointDeviceInformationSortOrder
     {
         None = 0,
+
         Name = 1,
-        DeviceInstanceId = 2,
+        EndpointDeviceId = 2,
+        DeviceInstanceId = 3,
+
 
         ContainerThenName = 11,
-        ContainerThenDeviceInstanceId = 12
+        ContainerThenEndpointDeviceId = 12,
+        ContainerThenDeviceInstanceId = 13,
+
+        TransportMnemonicThenName = 21,
+        TransportMnemonicThenEndpointDeviceId = 22,
+        TransportMnemonicThenDeviceInstanceId = 23,
+
     };
 }
\ No newline at end of file
diff --git a/src/api/Client/Midi2Client/MidiSystemExclusive8StatusEnum.idl b/src/api/Client/Midi2Client/MidiSystemExclusive8StatusEnum.idl
index fa4d094b..ed6208fc 100644
--- a/src/api/Client/Midi2Client/MidiSystemExclusive8StatusEnum.idl
+++ b/src/api/Client/Midi2Client/MidiSystemExclusive8StatusEnum.idl
@@ -14,9 +14,9 @@ namespace Windows.Devices.Midi2
     [MIDI_API_CONTRACT(1)]
     enum MidiSystemExclusive8Status
     {
-        CompleteMessageInSingleUmp = 0x0,
-        StartUmp = 0x1,
-        ContinueUmp = 0x2,
-        EndUmp = 0x3,
+        CompleteMessageInSingleMessagePacket = 0x0,
+        StartMessagePacket = 0x1,
+        ContinueMessagePacket = 0x2,
+        EndMessagePacket = 0x3,
     };
 }
\ No newline at end of file
diff --git a/src/api/Inc/MidiDefs.h b/src/api/Inc/MidiDefs.h
index b5923f3e..8edd8f98 100644
--- a/src/api/Inc/MidiDefs.h
+++ b/src/api/Inc/MidiDefs.h
@@ -16,6 +16,8 @@
 #define MAXIMUM_LOOPED_DATASIZE 16
 
 
+#define MIDI_TIMESTAMP_SEND_IMMEDIATELY 0
+
 // we can't let the memory usage run away. This many messages is a 
 // lot, and performance will suffer above 5000 or so. This number is
 // used by the scheduler and then also by the client API
diff --git a/src/user-tools/midi-console/Midi/Midi.csproj b/src/user-tools/midi-console/Midi/Midi.csproj
index 2bd42f01..b4b4a30c 100644
--- a/src/user-tools/midi-console/Midi/Midi.csproj
+++ b/src/user-tools/midi-console/Midi/Midi.csproj
@@ -31,7 +31,7 @@
     
     
     
-    
+