Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build_cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
name: "Windows (MSVC)",
os: windows-latest,
generator: "",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0 -DCMAKE_GENERATOR_PLATFORM=version=10.0.22621.0",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0",
test_target: "RUN_TESTS",
tests: 1,
examples: 1
Expand All @@ -33,7 +33,7 @@ jobs:
name: "Windows (MSVC, arm64)",
os: windows-11-arm,
generator: "",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0 -DCMAKE_GENERATOR_PLATFORM=version=10.0.22621.0",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0",
test_target: "RUN_TESTS",
tests: 1,
examples: 1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
name: "Windows (MSVC)",
os: windows-latest,
generator: "",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0 -DCMAKE_GENERATOR_PLATFORM=version=10.0.22621.0",
cmakeflags: "-DLIBREMIDI_NO_WINUWP=0 -DBOOST_ROOT=$PWD/boost_1_86_0",
environment: ""
}
- {
Expand Down
5 changes: 4 additions & 1 deletion cmake/libremidi.winmidi.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ endif()
if(LIBREMIDI_DOWNLOAD_CPPWINRT)
if(NOT EXISTS "${CMAKE_BINARY_DIR}/winmidi-headers.zip")
file(DOWNLOAD
https://github.com/microsoft/MIDI/releases/download/dev-preview-9-namm-4/Microsoft.Windows.Devices.Midi2.1.0.2-preview-9.250121-1820.nupkg
https://github.com/microsoft/MIDI/releases/download/rc-1/Microsoft.Windows.Devices.Midi2.1.0.14-rc.1.209.nupkg
"${CMAKE_BINARY_DIR}/winmidi-headers.zip"
)
endif()
Expand Down Expand Up @@ -52,6 +52,9 @@ if(CPPWINRT_TOOL)
file(
COPY
"${CMAKE_BINARY_DIR}/winmidi-headers/build/native/include/winmidi/init"
"${CMAKE_BINARY_DIR}/winmidi-headers/build/native/include/winmidi/WindowsMidiServicesAppSdkComExtensions.h"
"${CMAKE_BINARY_DIR}/winmidi-headers/build/native/include/winmidi/WindowsMidiServicesAppSdkComExtensions_i.c"
"${CMAKE_BINARY_DIR}/winmidi-headers/build/native/include/winmidi/WindowsMidiServicesAppSdkComExtensions_p.c"
DESTINATION
"${CMAKE_BINARY_DIR}/cppwinrt-winmidi/"
)
Expand Down
14 changes: 14 additions & 0 deletions include/libremidi/backends/winmidi/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,27 @@
#include <cctype>
#include <string>
#include <guiddef.h>
#include <unknwn.h>

#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Microsoft.Windows.Devices.Midi2.h>
#include <libremidi/cmidi2.hpp>

#if __has_include(<WindowsMidiServicesAppSdkComExtensions.h>)
#include <WindowsMidiServicesAppSdkComExtensions.h>
#define LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS 1

#define LIBREMIDI_DEFINE_GUID_CONSTEXPR(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
static constexpr const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}

namespace libremidi {
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionMessagesReceivedCallback,0x8087b303,0x0519,0x31d1,0x31,0xd1,0x00,0x00,0x00,0x00,0x00,0x10);
LIBREMIDI_DEFINE_GUID_CONSTEXPR(IID, IID_IMidiEndpointConnectionRaw,0x8087b303,0x0519,0x31d1,0x31,0xd1,0x00,0x00,0x00,0x00,0x00,0x20);
}
#endif

// MinGW support
#if !defined(_MSC_VER)
namespace Microsoft::Windows::Devices::Midi2::Initialization
Expand Down
95 changes: 95 additions & 0 deletions include/libremidi/backends/winmidi/midi_in.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,56 @@ class midi_in_impl final
{
} configuration;

#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
struct raw_callback_type final : IMidiEndpointConnectionMessagesReceivedCallback
{
explicit raw_callback_type(midi_in_impl& self)
: self{self}
{

}

midi_in_impl& self;
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override
{
if (!ppvObject)
return E_POINTER;

if (riid == __uuidof(IUnknown) ||
riid == libremidi::IID_IMidiEndpointConnectionMessagesReceivedCallback)
{
*ppvObject = static_cast<IMidiEndpointConnectionMessagesReceivedCallback*>(this);
AddRef();
return S_OK;
}

*ppvObject = nullptr;
return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE AddRef() override
{
return 1;
}

ULONG STDMETHODCALLTYPE Release() override
{
return 1;
}

HRESULT STDMETHODCALLTYPE MessagesReceived(
GUID sessionId,
GUID connectionId,
UINT64 timestamp,
UINT32 wordCount,
UINT32 *messages) override {
HRESULT res{};
self.process_message(sessionId, connectionId, timestamp, wordCount, messages);
return res;
}
} raw_callback{*this};
#endif

explicit midi_in_impl(
libremidi::ump_input_configuration&& conf, winmidi::input_configuration&& apiconf)
: configuration{std::move(conf), std::move(apiconf)}
Expand Down Expand Up @@ -55,12 +105,20 @@ class midi_in_impl final
// TODO use a MidiGroupEndpointListener for the filtering
m_endpoint = m_session.CreateEndpointConnection(ep.EndpointDeviceId());

#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
m_revoke_token = m_endpoint.MessageReceived(
[this](
const winrt::Microsoft::Windows::Devices::Midi2::IMidiMessageReceivedEventSource&,
const winrt::Microsoft::Windows::Devices::Midi2::MidiMessageReceivedEventArgs& args) {
process_message(args);
});
#else
m_endpoint.as(libremidi::IID_IMidiEndpointConnectionRaw, m_raw_endpoint.put_void());

m_raw_endpoint->SetMessagesReceivedCallback(
&raw_callback
);
#endif

m_endpoint.Open();

Expand Down Expand Up @@ -96,9 +154,43 @@ class midi_in_impl final
{ump_space, ump_space + b.Size()}, m_processing.timestamp<timestamp_info>(to_ns, 0));
}

#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
void process_message(
const GUID& /* sessionId */,
const GUID& /* connectionId */,
UINT64 timestamp,
UINT32 wordCount,
UINT32 *ump)
{
static constexpr timestamp_backend_info timestamp_info{
.has_absolute_timestamps = true,
.absolute_is_monotonic = false,
.has_samples = false,
};

if(wordCount == 0)
return;

if (m_group_filter >= 0)
{
int group = cmidi2_ump_get_group(ump);
if (group != m_group_filter)
return;
}

auto to_ns = [t = timestamp] { return t; };
m_processing.on_bytes(
{ump, ump + wordCount}, m_processing.timestamp<timestamp_info>(to_ns, 0));
}
#endif

stdx::error close_port() override
{
#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
m_endpoint.MessageReceived(m_revoke_token);
#else
m_raw_endpoint->RemoveMessagesReceivedCallback();
#endif
m_session.DisconnectEndpointConnection(m_endpoint.ConnectionId());
return stdx::error{};
}
Expand All @@ -109,6 +201,9 @@ class midi_in_impl final
MidiSession m_session;
winrt::event_token m_revoke_token{};
winrt::Microsoft::Windows::Devices::Midi2::MidiEndpointConnection m_endpoint{nullptr};
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
winrt::impl::com_ref<IMidiEndpointConnectionRaw> m_raw_endpoint{};
#endif
midi2::input_state_machine m_processing{this->configuration};
int m_group_filter = -1;
};
Expand Down
35 changes: 34 additions & 1 deletion include/libremidi/backends/winmidi/midi_out.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class midi_out_impl final
return std::errc::address_not_available;

m_endpoint = m_session.CreateEndpointConnection(ep.EndpointDeviceId());
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
m_endpoint.as(libremidi::IID_IMidiEndpointConnectionRaw, m_raw_endpoint.put_void());
#endif
m_endpoint.Open();

return stdx::error{};
Expand All @@ -61,6 +64,8 @@ class midi_out_impl final
stdx::error send_ump(const uint32_t* message, size_t size) override
{
auto write_func = [this](const uint32_t* ump, int64_t bytes) -> std::errc {

#if !LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
MidiSendMessageResults ret{};
switch (bytes / 4)
{
Expand All @@ -80,9 +85,34 @@ class midi_out_impl final
default:
return std::errc::bad_message;
}

if (ret != MidiSendMessageResults::Succeeded)
return std::errc::bad_message;
#else
HRESULT ret{};
switch (bytes / 4)
{
case 1:
assert( m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(1, (UINT32*)ump));
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 1, (UINT32*)ump);
break;
case 2:
assert( m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(2, (UINT32*)ump));
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 2, (UINT32*)ump);
break;
case 3:
assert( m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(3, (UINT32*)ump));
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 3, (UINT32*)ump);
break;
case 4:
assert( m_raw_endpoint->ValidateBufferHasOnlyCompleteUmps(4, (UINT32*)ump));
ret = m_raw_endpoint->SendMidiMessagesRaw(0, 4, (UINT32*)ump);
break;
default:
return std::errc::bad_message;
}
#endif
if(ret < 0)
return std::errc::io_error;
return std::errc{0};
};

Expand All @@ -92,6 +122,9 @@ class midi_out_impl final
private:
MidiSession m_session;
winrt::Microsoft::Windows::Devices::Midi2::MidiEndpointConnection m_endpoint{nullptr};
#if LIBREMIDI_WINMIDI_HAS_COM_EXTENSIONS
winrt::impl::com_ref<IMidiEndpointConnectionRaw> m_raw_endpoint{};
#endif
};

}
1 change: 1 addition & 0 deletions include/libremidi/backends/winuwp/helpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string>
#include <thread>
#include <vector>
#include <unknwn.h>

#include <winrt/Windows.Devices.Enumeration.h>
#include <winrt/Windows.Devices.Midi.h>
Expand Down
2 changes: 2 additions & 0 deletions include/libremidi/cmidi2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
#include <stdbool.h>
#include <stdint.h>

#if !defined(_MSC_VER)
#pragma GCC system_header
#pragma clang system_header
#endif

#define CMIDI2_MIDI_2_0_RESERVED 0
#define CMIDI2_JR_TIMESTAMP_TICKS_PER_SECOND 31250
Expand Down
4 changes: 4 additions & 0 deletions include/libremidi/error.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
#pragma once
#include <libremidi/config.hpp>

#if !defined(_MSC_VER)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
#include <libremidi/system_error2.hpp>
#if !defined(_MSC_VER)
#pragma GCC diagnostic pop
#endif

#include <functional>
#include <string_view>
Expand Down