Skip to content

Commit

Permalink
Merge pull request #268 from microsoft/pete-dev
Browse files Browse the repository at this point in the history
Endpoint documentation + start of user-defined loopbacks
  • Loading branch information
Psychlist1972 authored Feb 10, 2024
2 parents d90e8ac + e50b3d0 commit 0cf4de7
Show file tree
Hide file tree
Showing 39 changed files with 8,273 additions and 1,338 deletions.
2 changes: 1 addition & 1 deletion build/staging/version/BundleInfo.wxi
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Include>
<?define SetupVersionName="Developer Preview 5" ?>
<?define SetupVersionNumber="1.0.24040.2018" ?>
<?define SetupVersionNumber="1.0.24041.0202" ?>
</Include>
11 changes: 11 additions & 0 deletions docs/endpoints/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
layout: page
title: Transport Types
has_children: true
---

# Transport Types

Windows MIDI Services supports a number of types of MIDI transports, with more coming in the future.

In addition to the ones already in the box (listed below) we are working on Bluetooth MIDI 1.0 and Network MIDI 2.0.
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
---
layout: page
title: Diagnostics Endpoints
parent: Windows Midi Services
parent: Transport Types
grandparent: Windows Midi Services
has_children: false
---

# MIDI Diagnostic Endpoints

Windows MIDI Services comes with three diagnostic endpoints, two of which are there for application development, testing, and debugging.
| Property | Value |
| -------- | ----- |
| Abstraction Id | `{ac9b5417-3fe0-4e62-960f-034ee4235a1a}` |
| Mnemonic | `DIAG` |

(Note: This transport cannot be disabled and is not listed in the registry. Its activation is hard-coded into the Windows service. Settings for this transport are not read from the configuration file and cannot be changed.)

Windows MIDI Services comes with three diagnostic endpoints, two of which are there for application development, testing, and debugging. These will not normally be used by musicians or displayed through music-creation applications.

## Loopbacks A and B

Expand Down
48 changes: 48 additions & 0 deletions docs/endpoints/kernel-streaming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
layout: page
title: Kernel Streaming
parent: Transport Types
grandparent: Windows MIDI Services
has_children: true
---

# Kernel Streaming

| Property | Value |
| -------- | ----- |
| Abstraction Id | `{26FA740D-469C-4D33-BEB1-3885DE7D6DF1}` |
| Mnemonic | `KS` |

## Overview

Kernel Streaming is the mechanism through which most USB and other MIDI 1.0 drivers are used in Windows MIDI Services. In addition to USB MIDI 1.0, this provides access to many third-party drivers including BLE MIDI 1.0 and more.

In addition to MIDI 1.0 drivers, the Kernel Streaming transport is also the interface to the MIDI 2.0 class driver.

## Suggested Uses

Although this transport is primarily recommended for USB devices, it may be used for access to most other existing MIDI 1.0 devices on Windows.

## Configuration

Endpoints for this transport are not created through the configuration file, but certain properties, such as the name and description, are updatable through it.

```json
"endpointTransportPluginSettings":
{
"{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}":
{
"_comment" : "Native Instruments Kontrol S61",
"userSuppliedName" : "Pete's Kontrol S61",
"userSuppliedDescription" : "This is my Kontrol S61. There are many like it, but this one is mine. My Kontrol S61 is my best friend. It is my life. I must master it as I must master my life. Without me, my S61 is useless. Without my S61, I am useless."
}
}
}
```


## Implementation

32 changes: 32 additions & 0 deletions docs/endpoints/virtual-device-app.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
layout: page
title: Virtual Device App
parent: Transport Types
grandparent: Windows MIDI Services
has_children: true
---

# Virtual Device App

| Property | Value |
| -------- | ----- |
| Abstraction Id | `{8FEAAD91-70E1-4A19-997A-377720A719C1}` |
| Mnemonic | `APP` |

## Overview

One way to have app-to-app MIDI on Windows is to use a simple loopback. That is typically created ahead of time, and is available for any applications to use to communicate with each other. The lifetime of these loopback endpoints are not tied to any one application.

Another approach is to allow applications to create and publish an endpoint which is declared through settings inside the application itself. When the application closes, the endpoint closes. That is the model the Virtual Device App feature implements. (If you want the simple pre-created loopback, see the Virtual Loopback transport)

In addition, MIDI 2.0 has additional requirements for endpoints. They need to be able to participate in the MIDI Endpoint Discovery process, and respond with appropriate endpoint capabilities and preferred settings. The Virtual Device App makes that configuration simple for application developers and musicians.

## Suggested Uses

This is the right kind of endpoint to create if you have an application which operates as a synthesizer, tone generator, or an input device, and you want the app to act and be seen in the same way a piece of MIDI hardware would be seen.

Today, the API provides support for MIDI 2.0 / UMP protocol. In the future, we'll add MIDI CI and other capabilities to these virtual devices (today, those need to be done manually or through a third-party library).

## Configuration

Because this type of endpoint is tied to the runtime of an application, it can be created only through the API by creating a `MidiVirtualDeviceDefinition` and calling the appropriate `MidiSession` methods to create and open the endpoint. This is not something that a MIDI user will pre-create in the settings app or configuration file.
39 changes: 39 additions & 0 deletions docs/endpoints/virtual-loopback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
layout: page
title: Virtual Loopback
parent: Transport Types
grandparent: Windows MIDI Services
has_children: true
---

# Virtual Loopback

| Property | Value |
| -------- | ----- |
| Abstraction Id | `{942BF02D-93C0-4EA8-B03E-D51156CA75E1}` |
| Mnemonic | `LOOP` |

## Overview

A Virtual Loopback is a mechanism for two or more applications to communicate with each other over MIDI.

## Suggested Uses

If you want to have loopback endpoints which are always available for routing between applications, but do not want them to be controlled by the applications themselves, this is the right kind of endpoint to set up.

## Configuration

As with all configuration file changes, we recommend using the Windows MIDI Services Settings application, once we make that available. For now, you may edit the JSON directly. But please note that JSON is quite unforgiving: the format is specific, and all keys (including the GUIDs and property names) are case-sensitive. In addition, there's no usable provision for comments in a JSON file, so we can't include examples in the file itself.

That out of the way, here's the configuration section for the Virtual Loopback MIDI endpoints.

```json

todo

```

# Implementation

Internally, the Virtual Loopback is implemented as two endpoints which are cross-wired, so anything sent to Loopback A arrives on the input of Loopback B, and vice versa. Each declared pair has an exclusive relationship, and there's no practical limit to the number of loopback pairs you can define.

41 changes: 41 additions & 0 deletions src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// 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"


AbstractionState::AbstractionState() = default;
AbstractionState::~AbstractionState() = default;

AbstractionState& AbstractionState::Current()
{
// explanation: http://www.modernescpp.com/index.php/thread-safe-initialization-of-data/

static AbstractionState current;

return current;
}



HRESULT
AbstractionState::ConstructEndpointManager()
{
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2LoopbackMidiEndpointManager>(&m_endpointManager));

return S_OK;
}


HRESULT
AbstractionState::ConstructConfigurationManager()
{
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2LoopbackMidiConfigurationManager>(&m_configurationManager));

return S_OK;
}
62 changes: 62 additions & 0 deletions src/api/Abstraction/LoopbackMidiAbstraction/AbstractionState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// 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

// singleton
class AbstractionState
{

public:
static AbstractionState& Current();

// no copying
AbstractionState(_In_ const AbstractionState&) = delete;
AbstractionState& operator=(_In_ const AbstractionState&) = delete;


wil::com_ptr<CMidi2LoopbackMidiEndpointManager> GetEndpointManager()
{
return m_endpointManager;
}

wil::com_ptr<CMidi2LoopbackMidiConfigurationManager> GetConfigurationManager()
{
return m_configurationManager;
}

std::shared_ptr<MidiEndpointTable> GetEndpointTable()
{
return m_endpointTable;
}


HRESULT Cleanup()
{
m_endpointManager.reset();
m_configurationManager.reset();

return S_OK;
}


HRESULT ConstructEndpointManager();
HRESULT ConstructConfigurationManager();


private:
AbstractionState();
~AbstractionState();


wil::com_ptr<CMidi2LoopbackMidiEndpointManager> m_endpointManager;
wil::com_ptr<CMidi2LoopbackMidiConfigurationManager> m_configurationManager;

std::shared_ptr<MidiEndpointTable> m_endpointTable = std::make_shared<MidiEndpointTable>();
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// 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"

_Use_decl_annotations_
HRESULT
CMidi2LoopbackMidiAbstraction::Activate(
REFIID Riid,
void **Interface
)
{
OutputDebugString(L"" __FUNCTION__ " Enter");

RETURN_HR_IF(E_INVALIDARG, nullptr == Interface);

if (__uuidof(IMidiBiDi) == Riid)
{
OutputDebugString(L"" __FUNCTION__ " Activating IMidiBiDi");

TraceLoggingWrite(
MidiLoopbackMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__ "- IMidiBiDi",
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this")
);


wil::com_ptr_nothrow<IMidiBiDi> midiBiDi;
RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize<CMidi2LoopbackMidiBiDi>(&midiBiDi));
*Interface = midiBiDi.detach();
}



else if (__uuidof(IMidiEndpointManager) == Riid)
{
TraceLoggingWrite(
MidiLoopbackMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__ "- IMidiEndpointManager",
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this")
);

// check to see if this is the first time we're creating the endpoint manager. If so, create it.
if (AbstractionState::Current().GetEndpointManager() == nullptr)
{
AbstractionState::Current().ConstructEndpointManager();
}

RETURN_IF_FAILED(AbstractionState::Current().GetEndpointManager()->QueryInterface(Riid, Interface));
}
else if (__uuidof(IMidiAbstractionConfigurationManager) == Riid)
{
TraceLoggingWrite(
MidiLoopbackMidiAbstractionTelemetryProvider::Provider(),
__FUNCTION__ "- IMidiAbstractionConfigurationManager",
TraceLoggingLevel(WINEVENT_LEVEL_INFO),
TraceLoggingPointer(this, "this")
);

// check to see if this is the first time we're creating the endpoint manager. If so, create it.
if (AbstractionState::Current().GetConfigurationManager() == nullptr)
{
AbstractionState::Current().ConstructConfigurationManager();
}

RETURN_IF_FAILED(AbstractionState::Current().GetConfigurationManager()->QueryInterface(Riid, Interface));
}

else
{
return E_NOINTERFACE;
}

return S_OK;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
; Copyright (c) Microsoft Corporation. All rights reserved.

LIBRARY

EXPORTS
DllCanUnloadNow PRIVATE
DllGetClassObject PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
DllInstall PRIVATE
Loading

0 comments on commit 0cf4de7

Please sign in to comment.