working on win32 uwp! and libremidi update
This commit is contained in:
@@ -3,7 +3,21 @@
|
||||
|
||||
namespace libremidi::coremidi_ump
|
||||
{
|
||||
using input_configuration = coremidi_input_configuration;
|
||||
using output_configuration = coremidi_output_configuration;
|
||||
using observer_configuration = coremidi_observer_configuration;
|
||||
struct input_configuration
|
||||
{
|
||||
std::string client_name = "libremidi client";
|
||||
std::optional<MIDIClientRef> context{};
|
||||
};
|
||||
|
||||
struct output_configuration
|
||||
{
|
||||
std::string client_name = "libremidi client";
|
||||
std::optional<MIDIClientRef> context{};
|
||||
};
|
||||
|
||||
struct observer_configuration
|
||||
{
|
||||
std::string client_name = "libremidi client";
|
||||
std::function<void(MIDIClientRef)> on_create_context{};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,32 +2,37 @@
|
||||
#include <libremidi/backends/coremidi_ump/config.hpp>
|
||||
#include <libremidi/backends/coremidi_ump/helpers.hpp>
|
||||
#include <libremidi/detail/midi_in.hpp>
|
||||
#include <libremidi/detail/midi_stream_decoder.hpp>
|
||||
|
||||
namespace libremidi::coremidi_ump
|
||||
{
|
||||
|
||||
class midi_in_impl final
|
||||
: public midi2::in_api
|
||||
, private coremidi_data
|
||||
, public coremidi_data
|
||||
, public error_handler
|
||||
{
|
||||
public:
|
||||
using midi_api::client_open_;
|
||||
struct
|
||||
: ump_input_configuration
|
||||
, coremidi_ump::input_configuration
|
||||
{
|
||||
} configuration;
|
||||
|
||||
midi_in_impl(ump_input_configuration&& conf, coremidi_input_configuration&& apiconf)
|
||||
midi_in_impl(ump_input_configuration&& conf, coremidi_ump::input_configuration&& apiconf)
|
||||
: configuration{std::move(conf), std::move(apiconf)}
|
||||
{
|
||||
if (auto result = init_client(configuration); result != noErr)
|
||||
{
|
||||
error<driver_error>(
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"midi_in_core: error creating MIDI client object: " + std::to_string(result));
|
||||
"error creating MIDI client object: " + std::to_string(result));
|
||||
client_open_ = from_osstatus(result);
|
||||
return;
|
||||
}
|
||||
|
||||
client_open_ = stdx::error{};
|
||||
}
|
||||
|
||||
~midi_in_impl() override
|
||||
@@ -38,33 +43,18 @@ public:
|
||||
if (this->endpoint)
|
||||
MIDIEndpointDispose(this->endpoint);
|
||||
|
||||
close_client();
|
||||
}
|
||||
|
||||
void close_client()
|
||||
{
|
||||
if (!configuration.context)
|
||||
MIDIClientDispose(this->client);
|
||||
}
|
||||
|
||||
void set_client_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_in_core: set_client_name unsupported");
|
||||
}
|
||||
void set_port_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_in_core: set_port_name unsupported");
|
||||
close_client(*this);
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::COREMIDI_UMP; }
|
||||
|
||||
bool open_port(const input_port& info, std::string_view portName) override
|
||||
stdx::error open_port(const input_port& info, std::string_view portName) override
|
||||
{
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
|
||||
auto source = locate_object(*this, info, kMIDIObjectType_Source);
|
||||
if (source == 0)
|
||||
return false;
|
||||
return std::errc::invalid_argument;
|
||||
|
||||
// Create our local sink
|
||||
MIDIPortRef port;
|
||||
@@ -77,29 +67,29 @@ public:
|
||||
|
||||
if (result != noErr)
|
||||
{
|
||||
close_client();
|
||||
error<driver_error>(
|
||||
this->configuration, "midi_in_core::open_port: error creating macOS MIDI input port: "
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error creating macOS MIDI input port: "
|
||||
+ std::to_string(result));
|
||||
return false;
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
// Make the connection.
|
||||
if (result = MIDIPortConnectSource(port, source, nullptr); result != noErr)
|
||||
{
|
||||
MIDIPortDispose(port);
|
||||
close_client();
|
||||
error<driver_error>(
|
||||
this->configuration, "midi_in_core::open_port: error connecting macOS MIDI input port.");
|
||||
return false;
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error connecting macOS MIDI input port.");
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
// Save our api-specific port information.
|
||||
this->port = port;
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
bool open_virtual_port(std::string_view portName) override
|
||||
stdx::error open_virtual_port(std::string_view portName) override
|
||||
{
|
||||
// Create a virtual MIDI input destination.
|
||||
MIDIEndpointRef endpoint;
|
||||
@@ -111,37 +101,21 @@ public:
|
||||
|
||||
if (result != noErr)
|
||||
{
|
||||
error<driver_error>(
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"midi_in_core::open_virtual_port: error creating virtual macOS MIDI "
|
||||
"error creating virtual macOS MIDI "
|
||||
"destination.");
|
||||
return false;
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
// Save our api-specific connection information.
|
||||
this->endpoint = endpoint;
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
void close_port() override
|
||||
{
|
||||
if (this->endpoint)
|
||||
{
|
||||
MIDIEndpointDispose(this->endpoint);
|
||||
this->endpoint = 0;
|
||||
}
|
||||
|
||||
if (this->port)
|
||||
{
|
||||
MIDIPortDispose(this->port);
|
||||
this->port = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void set_timestamp(
|
||||
[[maybe_unused]] const MIDIEventPacket& packet,
|
||||
[[maybe_unused]] libremidi::ump& msg) noexcept
|
||||
stdx::error close_port() override
|
||||
{
|
||||
return coremidi_data::close_port();
|
||||
}
|
||||
|
||||
timestamp absolute_timestamp() const noexcept override
|
||||
@@ -151,33 +125,28 @@ public:
|
||||
|
||||
void midiInputCallback(const MIDIEventList* list, void* /*srcRef*/)
|
||||
{
|
||||
unsigned short nBytes{};
|
||||
static constexpr timestamp_backend_info timestamp_info{
|
||||
.has_absolute_timestamps = true,
|
||||
.absolute_is_monotonic = false,
|
||||
.has_samples = false,
|
||||
};
|
||||
|
||||
const MIDIEventPacket* packet = &list->packet[0];
|
||||
for (unsigned int i = 0; i < list->numPackets; ++i)
|
||||
{
|
||||
nBytes = packet->wordCount;
|
||||
if (nBytes == 0)
|
||||
if (packet->wordCount > 0)
|
||||
{
|
||||
packet = MIDIEventPacketNext(packet);
|
||||
continue;
|
||||
auto to_ns = [packet] { return time_in_nanos(packet->timeStamp); };
|
||||
m_processing.on_bytes_multi(
|
||||
{packet->words, packet->words + packet->wordCount},
|
||||
m_processing.timestamp<timestamp_info>(to_ns, 0));
|
||||
}
|
||||
|
||||
libremidi::ump msg;
|
||||
coremidi_data::set_timestamp(*this, packet->timeStamp, msg.timestamp);
|
||||
|
||||
if (packet->wordCount <= 4)
|
||||
{
|
||||
std::copy_n(packet->words, packet->wordCount, msg.data);
|
||||
configuration.on_message(std::move(msg));
|
||||
}
|
||||
last_time = time_in_nanos(packet->timeStamp);
|
||||
|
||||
packet = MIDIEventPacketNext(packet);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long long last_time{};
|
||||
midi2::input_state_machine m_processing{this->configuration};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,10 +9,11 @@ namespace libremidi::coremidi_ump
|
||||
{
|
||||
class midi_out_impl final
|
||||
: public midi2::out_api
|
||||
, private coremidi_data
|
||||
, public coremidi_data
|
||||
, public error_handler
|
||||
{
|
||||
public:
|
||||
using midi_api::client_open_;
|
||||
struct
|
||||
: libremidi::output_configuration
|
||||
, coremidi_ump::output_configuration
|
||||
@@ -25,11 +26,14 @@ public:
|
||||
{
|
||||
if (auto result = init_client(configuration); result != noErr)
|
||||
{
|
||||
error<driver_error>(
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"midi_out_impl: error creating MIDI client object: " + std::to_string(result));
|
||||
"error creating MIDI client object: " + std::to_string(result));
|
||||
client_open_ = from_osstatus(result);
|
||||
return;
|
||||
}
|
||||
|
||||
client_open_ = stdx::error{};
|
||||
}
|
||||
|
||||
~midi_out_impl()
|
||||
@@ -39,64 +43,40 @@ public:
|
||||
if (this->endpoint)
|
||||
MIDIEndpointDispose(this->endpoint);
|
||||
|
||||
close_client();
|
||||
}
|
||||
|
||||
void close_client()
|
||||
{
|
||||
if (!configuration.context)
|
||||
MIDIClientDispose(this->client);
|
||||
}
|
||||
|
||||
void set_client_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_out_impl: set_client_name unsupported");
|
||||
}
|
||||
void set_port_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_out_impl: set_port_name unsupported");
|
||||
close_client(*this);
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::COREMIDI_UMP; }
|
||||
|
||||
bool open_port(const output_port& info, std::string_view portName) override
|
||||
stdx::error open_port(const output_port& info, std::string_view portName) override
|
||||
{
|
||||
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, false);
|
||||
|
||||
// Find where we want to send
|
||||
auto destination = locate_object(*this, info, kMIDIObjectType_Destination);
|
||||
if (destination == 0)
|
||||
return false;
|
||||
return std::errc::invalid_argument;
|
||||
|
||||
// Create our local source
|
||||
MIDIPortRef port;
|
||||
OSStatus result = MIDIOutputPortCreate(this->client, toCFString(portName).get(), &port);
|
||||
if (result != noErr)
|
||||
{
|
||||
close_client();
|
||||
error<driver_error>(
|
||||
this->configuration, "midi_out_impl::open_port: error creating macOS MIDI output port.");
|
||||
return false;
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error creating macOS MIDI output port.");
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
// Save our api-specific connection information.
|
||||
this->port = port;
|
||||
this->destinationId = destination;
|
||||
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
bool open_virtual_port(std::string_view portName) override
|
||||
stdx::error open_virtual_port(std::string_view portName) override
|
||||
{
|
||||
if (this->endpoint)
|
||||
{
|
||||
warning(
|
||||
configuration,
|
||||
"midi_out_impl::open_virtual_port: a virtual output port already "
|
||||
"exists!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a virtual MIDI output source.
|
||||
OSStatus result = MIDISourceCreateWithProtocol(
|
||||
this->client, toCFString(portName).get(), kMIDIProtocol_2_0, &this->endpoint);
|
||||
@@ -104,42 +84,33 @@ public:
|
||||
if (result != noErr)
|
||||
{
|
||||
this->endpoint = 0;
|
||||
error<driver_error>(
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"midi_out_impl::initialize: error creating macOS virtual MIDI source.");
|
||||
return false;
|
||||
"error creating macOS virtual MIDI source.");
|
||||
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
void close_port() override
|
||||
stdx::error close_port() override
|
||||
{
|
||||
if (this->endpoint)
|
||||
{
|
||||
MIDIEndpointDispose(this->endpoint);
|
||||
this->endpoint = 0;
|
||||
}
|
||||
|
||||
if (this->port)
|
||||
{
|
||||
MIDIPortDispose(this->port);
|
||||
this->port = 0;
|
||||
}
|
||||
return coremidi_data::close_port();
|
||||
}
|
||||
|
||||
void send_ump(const uint32_t* ump_stream, std::size_t count) override
|
||||
stdx::error send_ump(const uint32_t* ump_stream, std::size_t count) override
|
||||
{
|
||||
MIDIEventList* eventList = reinterpret_cast<MIDIEventList*>(m_eventListBuffer);
|
||||
MIDIEventPacket* packet = MIDIEventListInit(eventList, kMIDIProtocol_2_0);
|
||||
const MIDITimeStamp ts = LIBREMIDI_AUDIO_GET_CURRENT_HOST_TIME();
|
||||
|
||||
auto write_fun = [ts, &packet, &eventList](const uint32_t* ump, int bytes) {
|
||||
auto write_fun = [ts, &packet, &eventList](const uint32_t* ump, int bytes) -> std::errc {
|
||||
packet = MIDIEventListAdd(eventList, event_list_max_size, packet, ts, bytes / 4, ump);
|
||||
if (packet)
|
||||
return segmentation_error::no_error;
|
||||
return std::errc{0};
|
||||
else
|
||||
return segmentation_error::need_space;
|
||||
return std::errc::not_enough_memory;
|
||||
};
|
||||
|
||||
auto realloc_fun = [this, &packet, &eventList] {
|
||||
@@ -148,20 +119,21 @@ public:
|
||||
};
|
||||
|
||||
segment_ump_stream(ump_stream, count, write_fun, realloc_fun);
|
||||
push_event_list(eventList);
|
||||
return push_event_list(eventList);
|
||||
}
|
||||
|
||||
void push_event_list(MIDIEventList* eventList)
|
||||
stdx::error push_event_list(MIDIEventList* eventList)
|
||||
{
|
||||
if (this->endpoint)
|
||||
{
|
||||
auto result = MIDIReceivedEventList(this->endpoint, eventList);
|
||||
if (result != noErr)
|
||||
{
|
||||
warning(
|
||||
libremidi_handle_warning(
|
||||
this->configuration,
|
||||
"midi_out_core::send_message: error sending MIDI to virtual "
|
||||
"error sending MIDI to virtual "
|
||||
"destinations.");
|
||||
return std::errc::io_error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,11 +142,13 @@ public:
|
||||
auto result = MIDISendEventList(this->port, this->destinationId, eventList);
|
||||
if (result != noErr)
|
||||
{
|
||||
warning(
|
||||
libremidi_handle_warning(
|
||||
this->configuration,
|
||||
"midi_out_core::send_message: error sending MIDI message to port.");
|
||||
"error sending MIDI message to port.");
|
||||
return std::errc::io_error;
|
||||
}
|
||||
}
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
MIDIEndpointRef destinationId{};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include <libremidi/backends/coremidi_ump/config.hpp>
|
||||
#include <libremidi/backends/coremidi/observer.hpp>
|
||||
|
||||
namespace libremidi::coremidi_ump
|
||||
@@ -6,7 +7,13 @@ namespace libremidi::coremidi_ump
|
||||
|
||||
class observer_impl final : public libremidi::observer_core
|
||||
{
|
||||
using observer_core::observer_core;
|
||||
public:
|
||||
explicit observer_impl(libremidi::observer_configuration&& conf, coremidi_ump::observer_configuration&& apiconf)
|
||||
: observer_core{std::move(conf), coremidi_observer_configuration{apiconf.client_name, apiconf.on_create_context}}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::COREMIDI_UMP; }
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user