working on win32 uwp! and libremidi update

This commit is contained in:
Sebastian @ HfG
2024-10-28 19:24:18 +01:00
parent 06cb6d8319
commit 1e3755148c
106 changed files with 8474 additions and 2198 deletions
@@ -16,6 +16,7 @@ typedef UInt32 MIDIObjectRef;
typedef MIDIObjectRef MIDIClientRef;
#else
using MIDIClientRef = uint32_t;
using MIDIObjectRef = uint32_t;
#endif
namespace libremidi
{
@@ -0,0 +1,72 @@
#pragma once
#include <libremidi/error.hpp>
#include <CoreMIDI/CoreMIDI.h>
namespace libremidi
{
struct coremidi_error_domain : public stdx::error_domain
{
public:
constexpr coremidi_error_domain() noexcept
: error_domain{{0xa32b080ac770514eULL, 0xef59a407f921da43ULL}}
{
}
stdx::string_ref name() const noexcept override { return "coremidi"; }
bool equivalent(const stdx::error& lhs, const stdx::error& rhs) const noexcept override
{
if (lhs.domain() == rhs.domain())
return error_cast<std::errc>(lhs) == error_cast<std::errc>(rhs);
return false;
}
stdx::string_ref message(const stdx::error& e) const noexcept override
{
switch (error_cast<OSStatus>(e))
{
case kMIDIInvalidClient:
return "Invalid Client";
case kMIDIInvalidPort:
return "Invalid Port";
case kMIDIWrongEndpointType:
return "Wrong EndpointT ype";
case kMIDINoConnection:
return "No Connection";
case kMIDIUnknownEndpoint:
return "Unknown Endpoint";
case kMIDIUnknownProperty:
return "Unknown Property";
case kMIDIWrongPropertyType:
return "Wrong Property Type";
case kMIDINoCurrentSetup:
return "No Current Setup";
case kMIDIMessageSendErr:
return "Message Send Error";
case kMIDIServerStartErr:
return "Server Start Error";
case kMIDISetupFormatErr:
return "Setup Format Error";
case kMIDIWrongThread:
return "Wrong Thread";
case kMIDIObjectNotFound:
return "Object Not Found";
case kMIDIIDNotUnique:
return "ID Not Unique";
case kMIDINotPermitted:
return "Not Permitted";
case kMIDIUnknownError:
return "Unknown Error";
}
return "Unknown error code";
}
};
inline stdx::error from_osstatus(OSStatus ret) noexcept
{
static constexpr coremidi_error_domain domain{};
return {ret, domain};
}
}
@@ -1,7 +1,9 @@
#pragma once
#include <libremidi/detail/memory.hpp>
#include <libremidi/detail/midi_api.hpp>
#include <libremidi/error_handler.hpp>
#include <libremidi/input_configuration.hpp>
#include <libremidi/backends/coremidi/error_domain.hpp>
#include <CoreMIDI/CoreMIDI.h>
#include <CoreServices/CoreServices.h>
@@ -28,7 +30,8 @@ namespace
static inline std::string get_string_property(MIDIObjectRef object, CFStringRef property) noexcept
{
CFStringRef res;
MIDIObjectGetStringProperty(object, property, &res);
if (MIDIObjectGetStringProperty(object, property, &res) || !res)
return {};
char name[256];
CFStringGetCString(res, name, sizeof(name), kCFStringEncodingUTF8);
@@ -215,15 +218,15 @@ locate_object(auto& self, const port_information& info, MIDIObjectType requested
auto ret = MIDIObjectFindByUniqueID(uid, &object, &type);
if (ret != noErr)
{
self.template error<invalid_parameter_error>(
self.configuration, "coremidi::locate_object: cannot find port: " + info.port_name);
self.libremidi_handle_error(
self.configuration, "cannot find port: " + info.port_name);
return 0;
}
if (type != requested_type || object == 0)
{
self.template error<invalid_parameter_error>(
self.configuration, "coremidi::locate_object: invalid object: " + info.port_name + " : "
self.libremidi_handle_error(
self.configuration, "invalid object: " + info.port_name + " : "
+ std::to_string(object));
return 0;
}
@@ -255,6 +258,13 @@ struct coremidi_data
}
}
void close_client(auto& self)
{
self.client_open_ = std::errc::not_connected;
if (!self.configuration.context)
MIDIClientDispose(self.client);
}
static uint64_t time_in_nanos(MIDITimeStamp tp) noexcept
{
if (tp == 0)
@@ -319,6 +329,23 @@ struct coremidi_data
}
}
}
stdx::error close_port()
{
if (this->endpoint)
{
MIDIEndpointDispose(this->endpoint);
this->endpoint = 0;
}
if (this->port)
{
MIDIPortDispose(this->port);
this->port = 0;
}
return stdx::error{};
}
};
}
+31 -55
View File
@@ -8,10 +8,11 @@ namespace libremidi
{
class midi_in_core final
: public midi1::in_api
, private coremidi_data
, public coremidi_data
, public error_handler
{
public:
using midi_api::client_open_;
struct
: input_configuration
, coremidi_input_configuration
@@ -23,11 +24,14 @@ public:
{
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_core() override
@@ -38,33 +42,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; }
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;
@@ -73,29 +62,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;
@@ -104,31 +93,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
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();
}
timestamp absolute_timestamp() const noexcept override
@@ -158,17 +137,14 @@ public:
// MIDIPacketLists, they must be handled by multiple calls to this
// function.
if (packet->length == 0)
if (packet->length > 0)
{
packet = MIDIPacketNext(packet);
continue;
auto to_ns = [packet] { return time_in_nanos(packet->timeStamp); };
self.m_processing.on_bytes_multi(
{packet->data, packet->data + packet->length},
self.m_processing.timestamp<timestamp_info>(to_ns, 0));
}
auto to_ns = [packet] { return time_in_nanos(packet->timeStamp); };
self.m_processing.on_bytes_multi(
{packet->data, packet->data + packet->length},
self.m_processing.timestamp<timestamp_info>(to_ns, 0));
packet = MIDIPacketNext(packet);
}
}
@@ -7,10 +7,11 @@ namespace libremidi
{
class midi_out_core final
: public midi1::out_api
, private coremidi_data
, public coremidi_data
, public error_handler
{
public:
using midi_api::client_open_;
struct
: output_configuration
, coremidi_output_configuration
@@ -22,11 +23,14 @@ public:
{
if (auto result = init_client(configuration); result != noErr)
{
error<driver_error>(
libremidi_handle_error(
this->configuration,
"midi_out_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_out_core()
@@ -36,112 +40,79 @@ 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_core: set_client_name unsupported");
}
void set_port_name(std::string_view) override
{
warning(configuration, "midi_out_core: set_port_name unsupported");
close_client(*this);
}
libremidi::API get_current_api() const noexcept override { return libremidi::API::COREMIDI; }
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_core::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_core::open_virtual_port: a virtual output port already "
"exists!");
return false;
}
// Create a virtual MIDI output source.
MIDIEndpointRef endpoint;
OSStatus result = MIDISourceCreate(this->client, toCFString(portName).get(), &endpoint);
if (result != noErr)
{
error<driver_error>(
libremidi_handle_error(
this->configuration,
"midi_out_core::initialize: error creating macOS virtual MIDI source.");
return false;
"error creating macOS virtual MIDI source.");
return from_osstatus(result);
}
// Save our api-specific connection information.
this->endpoint = endpoint;
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_message(const unsigned char* message, size_t size) override
stdx::error send_message(const unsigned char* message, size_t size) override
{
unsigned int nBytes = static_cast<unsigned int>(size);
if (nBytes == 0)
{
warning(configuration, "midi_out_core::send_message: no data in message argument!");
return;
libremidi_handle_warning(configuration, "no data in message argument!");
return std::errc::invalid_argument;
}
if (message[0] != 0xF0 && nBytes > 3)
{
warning(
libremidi_handle_warning(
configuration,
"midi_out_core::send_message: message format problem ... not sysex but "
"message format problem ... not sysex but "
"> 3 bytes?");
return;
return std::errc::bad_message;
}
const MIDITimeStamp timestamp = LIBREMIDI_AUDIO_GET_CURRENT_HOST_TIME();
@@ -166,9 +137,10 @@ public:
if (!packet)
{
error<driver_error>(
this->configuration, "midi_out_core::send_message: could not allocate packet list");
return;
libremidi_handle_error(
this->configuration, "could not allocate packet list");
return std::errc::message_size;
}
// Send to any destinations that may have connected to us.
@@ -177,10 +149,11 @@ public:
auto result = MIDIReceived(this->endpoint, packetList);
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;
}
}
@@ -190,12 +163,14 @@ public:
auto result = MIDISend(this->port, this->destinationId, packetList);
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{};
@@ -38,9 +38,9 @@ public:
if (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));
return;
}
@@ -69,11 +69,11 @@ public:
MIDIEndpointGetEntity(obj, &e);
bool physical = bool(e);
bool ok = false;
bool ok = this->configuration.track_any;
if (physical && this->configuration.track_hardware)
ok = true;
ok |= true;
else if ((!physical) && this->configuration.track_virtual)
ok = true;
ok |= true;
if (!ok)
return {};