libremidi update to v5.4.3 and added virtual midi out as default
This commit is contained in:
@@ -18,7 +18,7 @@ typedef MIDIObjectRef MIDIClientRef;
|
||||
using MIDIClientRef = uint32_t;
|
||||
using MIDIObjectRef = uint32_t;
|
||||
#endif
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
|
||||
struct coremidi_input_configuration
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <CoreMIDI/CoreMIDI.h>
|
||||
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
struct coremidi_error_domain : public stdx::error_domain
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include <libremidi/backends/coremidi/error_domain.hpp>
|
||||
#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>
|
||||
@@ -21,13 +21,12 @@
|
||||
#define LIBREMIDI_AUDIO_GET_CURRENT_HOST_TIME AudioGetCurrentHostTime
|
||||
#endif
|
||||
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
using CFString_handle = unique_handle<const __CFString, CFRelease>;
|
||||
using CFStringMutable_handle = unique_handle<__CFString, CFRelease>;
|
||||
namespace
|
||||
{
|
||||
static inline std::string get_string_property(MIDIObjectRef object, CFStringRef property) noexcept
|
||||
|
||||
LIBREMIDI_STATIC std::string get_string_property(MIDIObjectRef object, CFStringRef property) noexcept
|
||||
{
|
||||
CFStringRef res;
|
||||
if (MIDIObjectGetStringProperty(object, property, &res) || !res)
|
||||
@@ -39,14 +38,14 @@ static inline std::string get_string_property(MIDIObjectRef object, CFStringRef
|
||||
return name;
|
||||
}
|
||||
|
||||
static inline int32_t get_int_property(MIDIObjectRef object, CFStringRef property) noexcept
|
||||
LIBREMIDI_STATIC int32_t get_int_property(MIDIObjectRef object, CFStringRef property) noexcept
|
||||
{
|
||||
SInt32 res;
|
||||
MIDIObjectGetIntegerProperty(object, property, &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline CFString_handle toCFString(std::string_view str) noexcept
|
||||
LIBREMIDI_STATIC CFString_handle toCFString(std::string_view str) noexcept
|
||||
{
|
||||
return CFString_handle{CFStringCreateWithCString(nullptr, str.data(), kCFStringEncodingASCII)};
|
||||
}
|
||||
@@ -71,20 +70,22 @@ inline uint64_t AudioConvertHostTimeToNanos(uint64_t hostTime)
|
||||
return static_cast<uint64_t>(res);
|
||||
}
|
||||
#endif
|
||||
|
||||
LIBREMIDI_STATIC auto get_cfstring_property(MIDIObjectRef prop, CFStringRef name)
|
||||
{
|
||||
CFStringRef str = nullptr;
|
||||
MIDIObjectGetStringProperty(prop, name, &str);
|
||||
return CFString_handle{str};
|
||||
}
|
||||
|
||||
// This function was submitted by Douglas Casey Tucker and apparently
|
||||
// derived largely from PortMidi.
|
||||
inline CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
|
||||
{
|
||||
CFMutableStringRef result = CFStringCreateMutable(nullptr, 0);
|
||||
|
||||
static constexpr auto getProp = [](MIDIObjectRef prop) {
|
||||
CFStringRef str = nullptr;
|
||||
MIDIObjectGetStringProperty(prop, kMIDIPropertyName, &str);
|
||||
return CFString_handle{str};
|
||||
};
|
||||
|
||||
// Begin with the endpoint's name.
|
||||
if (auto endpoint_name = getProp(endpoint))
|
||||
if (auto endpoint_name = get_cfstring_property(endpoint, kMIDIPropertyName))
|
||||
{
|
||||
CFStringAppend(result, endpoint_name.get());
|
||||
}
|
||||
@@ -101,7 +102,7 @@ inline CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
|
||||
if (CFStringGetLength(result) == 0)
|
||||
{
|
||||
// endpoint name has zero length -- try the entity
|
||||
if (auto entity_name = getProp(entity))
|
||||
if (auto entity_name = get_cfstring_property(entity, kMIDIPropertyName))
|
||||
{
|
||||
CFStringAppend(result, entity_name.get());
|
||||
}
|
||||
@@ -112,7 +113,7 @@ inline CFStringRef EndpointName(MIDIEndpointRef endpoint, bool isExternal)
|
||||
if (device == 0)
|
||||
goto finish;
|
||||
|
||||
if (auto dev_name = getProp(device))
|
||||
if (auto dev_name = get_cfstring_property(device, kMIDIPropertyName))
|
||||
{
|
||||
const auto dev_strlen = CFStringGetLength(dev_name.get());
|
||||
|
||||
@@ -218,22 +219,19 @@ locate_object(auto& self, const port_information& info, MIDIObjectType requested
|
||||
auto ret = MIDIObjectFindByUniqueID(uid, &object, &type);
|
||||
if (ret != noErr)
|
||||
{
|
||||
self.libremidi_handle_error(
|
||||
self.configuration, "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.libremidi_handle_error(
|
||||
self.configuration, "invalid object: " + info.port_name + " : "
|
||||
+ std::to_string(object));
|
||||
self.configuration, "invalid object: " + info.port_name + " : " + std::to_string(object));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
// A structure to hold variables related to the CoreMIDI API
|
||||
// implementation.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <libremidi/detail/midi_in.hpp>
|
||||
#include <libremidi/detail/midi_stream_decoder.hpp>
|
||||
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
class midi_in_core final
|
||||
: public midi1::in_api
|
||||
@@ -25,8 +25,7 @@ public:
|
||||
if (auto result = init_client(configuration); result != noErr)
|
||||
{
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"error creating MIDI client object: " + std::to_string(result));
|
||||
this->configuration, "error creating MIDI client object: " + std::to_string(result));
|
||||
client_open_ = from_osstatus(result);
|
||||
return;
|
||||
}
|
||||
@@ -64,8 +63,7 @@ public:
|
||||
{
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error creating macOS MIDI input port: "
|
||||
+ std::to_string(result));
|
||||
this->configuration, "error creating macOS MIDI input port: " + std::to_string(result));
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
@@ -74,8 +72,7 @@ public:
|
||||
{
|
||||
MIDIPortDispose(port);
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error connecting macOS MIDI input port.");
|
||||
libremidi_handle_error(this->configuration, "error connecting macOS MIDI input port.");
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
@@ -105,10 +102,7 @@ public:
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
stdx::error close_port() override
|
||||
{
|
||||
return coremidi_data::close_port();
|
||||
}
|
||||
stdx::error close_port() override { return coremidi_data::close_port(); }
|
||||
|
||||
timestamp absolute_timestamp() const noexcept override
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <libremidi/backends/coremidi/helpers.hpp>
|
||||
#include <libremidi/detail/midi_out.hpp>
|
||||
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
class midi_out_core final
|
||||
: public midi1::out_api
|
||||
@@ -24,8 +24,7 @@ public:
|
||||
if (auto result = init_client(configuration); result != noErr)
|
||||
{
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"error creating MIDI client object: " + std::to_string(result));
|
||||
this->configuration, "error creating MIDI client object: " + std::to_string(result));
|
||||
client_open_ = from_osstatus(result);
|
||||
return;
|
||||
}
|
||||
@@ -60,8 +59,7 @@ public:
|
||||
if (result != noErr)
|
||||
{
|
||||
close_client(*this);
|
||||
libremidi_handle_error(
|
||||
this->configuration, "error creating macOS MIDI output port.");
|
||||
libremidi_handle_error(this->configuration, "error creating macOS MIDI output port.");
|
||||
return from_osstatus(result);
|
||||
}
|
||||
|
||||
@@ -80,9 +78,7 @@ public:
|
||||
|
||||
if (result != noErr)
|
||||
{
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"error creating macOS virtual MIDI source.");
|
||||
libremidi_handle_error(this->configuration, "error creating macOS virtual MIDI source.");
|
||||
|
||||
return from_osstatus(result);
|
||||
}
|
||||
@@ -92,10 +88,7 @@ public:
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
stdx::error close_port() override
|
||||
{
|
||||
return coremidi_data::close_port();
|
||||
}
|
||||
stdx::error close_port() override { return coremidi_data::close_port(); }
|
||||
|
||||
stdx::error send_message(const unsigned char* message, size_t size) override
|
||||
{
|
||||
@@ -118,8 +111,8 @@ public:
|
||||
const MIDITimeStamp timestamp = LIBREMIDI_AUDIO_GET_CURRENT_HOST_TIME();
|
||||
|
||||
const ByteCount bufsize = nBytes > 65535 ? 65535 : nBytes;
|
||||
Byte buffer[bufsize + 16]; // pad for other struct members
|
||||
ByteCount listSize = sizeof(buffer);
|
||||
Byte* buffer = (Byte*)alloca(bufsize + 16); // pad for other struct members
|
||||
ByteCount listSize = bufsize + 16;
|
||||
MIDIPacketList* packetList = (MIDIPacketList*)buffer;
|
||||
|
||||
ByteCount remainingBytes = nBytes;
|
||||
@@ -137,8 +130,7 @@ public:
|
||||
|
||||
if (!packet)
|
||||
{
|
||||
libremidi_handle_error(
|
||||
this->configuration, "could not allocate packet list");
|
||||
libremidi_handle_error(this->configuration, "could not allocate packet list");
|
||||
|
||||
return std::errc::message_size;
|
||||
}
|
||||
@@ -163,9 +155,7 @@ public:
|
||||
auto result = MIDISend(this->port, this->destinationId, packetList);
|
||||
if (result != noErr)
|
||||
{
|
||||
libremidi_handle_warning(
|
||||
this->configuration,
|
||||
"error sending MIDI message to port.");
|
||||
libremidi_handle_warning(this->configuration, "error sending MIDI message to port.");
|
||||
return std::errc::io_error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <bit>
|
||||
|
||||
namespace libremidi
|
||||
NAMESPACE_LIBREMIDI
|
||||
{
|
||||
class observer_core
|
||||
: public observer_api
|
||||
@@ -22,6 +22,10 @@ public:
|
||||
|
||||
explicit observer_core(observer_configuration&& conf, coremidi_observer_configuration&& apiconf)
|
||||
: configuration{std::move(conf), std::move(apiconf)}
|
||||
{
|
||||
}
|
||||
|
||||
void finish_init()
|
||||
{
|
||||
if (configuration.client_name.empty())
|
||||
configuration.client_name = "libremidi observer";
|
||||
@@ -32,15 +36,13 @@ public:
|
||||
auto result = MIDIClientCreate(
|
||||
toCFString(configuration.client_name).get(),
|
||||
+[](const MIDINotification* message, void* ctx) {
|
||||
((observer_core*)ctx)->notify(message);
|
||||
},
|
||||
this, &client);
|
||||
((observer_core*)ctx)->notify(message);
|
||||
}, this, &client);
|
||||
|
||||
if (result != noErr)
|
||||
{
|
||||
libremidi_handle_error(
|
||||
this->configuration,
|
||||
"error creating MIDI client object: " + std::to_string(result));
|
||||
this->configuration, "error creating MIDI client object: " + std::to_string(result));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -78,13 +80,56 @@ public:
|
||||
if (!ok)
|
||||
return {};
|
||||
|
||||
// Get the MIDI device from the entity
|
||||
libremidi::transport_type type{};
|
||||
libremidi::container_identifier usb_location_id{};
|
||||
libremidi::device_identifier usb_vendor_product{};
|
||||
{
|
||||
MIDIDeviceRef device{};
|
||||
if (MIDIEntityGetDevice(e, &device) == noErr)
|
||||
{
|
||||
if (device)
|
||||
{
|
||||
using enum libremidi::transport_type;
|
||||
SInt32 devid_res{};
|
||||
if (MIDIObjectGetIntegerProperty(device, CFSTR("USBLocationID"), &devid_res) == noErr)
|
||||
{
|
||||
type = (libremidi::transport_type)(hardware | usb);
|
||||
usb_location_id = (uint64_t)devid_res;
|
||||
}
|
||||
|
||||
SInt32 vendor_res{};
|
||||
if (MIDIObjectGetIntegerProperty(device, CFSTR("USBVendorProduct"), &vendor_res)
|
||||
== noErr)
|
||||
{
|
||||
type = (libremidi::transport_type)(hardware | usb);
|
||||
usb_vendor_product = (uint64_t)vendor_res;
|
||||
}
|
||||
|
||||
const auto driver = get_string_property(device, kMIDIPropertyDriverOwner);
|
||||
if (driver == "com.apple.AppleMIDIUSBDriver")
|
||||
type = (libremidi::transport_type)(hardware | usb);
|
||||
if (driver == "com.apple.AppleMIDIBluetoothDriver")
|
||||
type = (libremidi::transport_type)(hardware | bluetooth);
|
||||
if (driver == "com.apple.AppleMIDIIACDriver")
|
||||
type = (libremidi::transport_type)(software);
|
||||
if (driver == "com.apple.AppleMIDIRTPDriver")
|
||||
type = (libremidi::transport_type)(network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::conditional_t<Input, input_port, output_port>{
|
||||
{.client = (std::uintptr_t)this->client,
|
||||
{.api = get_current_api(),
|
||||
.client = (std::uintptr_t)this->client,
|
||||
.container = usb_location_id,
|
||||
.device = usb_vendor_product,
|
||||
.port = std::bit_cast<uint32_t>(get_int_property(obj, kMIDIPropertyUniqueID)),
|
||||
.manufacturer = get_string_property(obj, kMIDIPropertyManufacturer),
|
||||
.device_name = get_string_property(obj, kMIDIPropertyModel),
|
||||
.port_name = get_string_property(obj, kMIDIPropertyName),
|
||||
.display_name = get_string_property(obj, kMIDIPropertyDisplayName)}};
|
||||
.display_name = get_string_property(obj, kMIDIPropertyDisplayName),
|
||||
.type = type}};
|
||||
}
|
||||
|
||||
std::vector<libremidi::input_port> get_input_ports() const noexcept override
|
||||
@@ -173,3 +218,17 @@ private:
|
||||
MIDIClientRef client{};
|
||||
};
|
||||
}
|
||||
|
||||
NAMESPACE_LIBREMIDI::coremidi
|
||||
{
|
||||
struct observer_impl : observer_core
|
||||
{
|
||||
observer_impl(observer_configuration&& conf, coremidi_observer_configuration&& apiconf)
|
||||
: observer_core{std::move(conf), std::move(apiconf)}
|
||||
{
|
||||
finish_init();
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::COREMIDI; }
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user