2024-10-09 02:01:23 +02:00
|
|
|
#pragma once
|
|
|
|
|
#include <libremidi/config.hpp>
|
|
|
|
|
#include <libremidi/error.hpp>
|
|
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
#include <array>
|
2024-10-09 02:01:23 +02:00
|
|
|
#include <compare>
|
|
|
|
|
#include <string>
|
2025-06-13 19:16:35 +02:00
|
|
|
#include <variant>
|
2024-10-09 02:01:23 +02:00
|
|
|
|
|
|
|
|
namespace libremidi
|
|
|
|
|
{
|
|
|
|
|
using client_handle = std::uint64_t;
|
|
|
|
|
using port_handle = std::uint64_t;
|
|
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
struct uuid
|
|
|
|
|
{
|
|
|
|
|
std::array<uint8_t, 16> bytes;
|
|
|
|
|
|
|
|
|
|
bool operator==(const uuid& other) const noexcept = default;
|
|
|
|
|
std::strong_ordering operator<=>(const uuid& other) const noexcept = default;
|
|
|
|
|
};
|
|
|
|
|
using container_identifier = std::variant<std::monostate, uuid, std::string, std::uint64_t>;
|
|
|
|
|
using device_identifier = std::variant<std::monostate, std::string, std::uint64_t>;
|
|
|
|
|
|
2024-10-09 02:01:23 +02:00
|
|
|
struct LIBREMIDI_EXPORT port_information
|
|
|
|
|
{
|
2025-06-13 19:16:35 +02:00
|
|
|
enum port_type : uint8_t
|
|
|
|
|
{
|
|
|
|
|
unknown = 0,
|
|
|
|
|
|
|
|
|
|
software = (1 << 1),
|
|
|
|
|
loopback = (1 << 2),
|
|
|
|
|
|
|
|
|
|
hardware = (1 << 3),
|
|
|
|
|
usb = (1 << 4),
|
|
|
|
|
bluetooth = (1 << 5),
|
|
|
|
|
pci = (1 << 6),
|
|
|
|
|
|
|
|
|
|
network = (1 << 7),
|
|
|
|
|
};
|
2024-10-09 02:01:23 +02:00
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
/// Handle to the API client object if the API provides one
|
2024-10-09 02:01:23 +02:00
|
|
|
// ALSA Raw: unused
|
|
|
|
|
// ALSA Seq: snd_seq_t*
|
|
|
|
|
// CoreMIDI: MidiClientRef
|
|
|
|
|
// WebMIDI: unused
|
|
|
|
|
// JACK: jack_client_t*
|
2025-06-13 19:16:35 +02:00
|
|
|
// PipeWire: unused // FIXME: pw_context? pw_main_loop?
|
2024-10-09 02:01:23 +02:00
|
|
|
// WinMM: unused
|
|
|
|
|
// WinUWP: unused
|
2024-10-28 19:24:18 +01:00
|
|
|
client_handle client = static_cast<client_handle>(-1);
|
2024-10-09 02:01:23 +02:00
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
/// Container identifier if the API provides one
|
|
|
|
|
// WinMIDI: ContainerID GUID (bit_cast to a winapi or winrt::GUID ;
|
|
|
|
|
// this is not the string but the binary representation).
|
|
|
|
|
// ALSA: device id (std::string), e.g. ID_PATH as returned by udev: "pci-0000:00:14.0-usb-0:12:1.0"
|
|
|
|
|
// CoreMIDI: USBLocationID (int32_t)
|
|
|
|
|
container_identifier container = std::monostate{};
|
|
|
|
|
|
|
|
|
|
/// Device identifier if the API provides one
|
|
|
|
|
// WinMM: { uint16_t manufacturer_id, uint16_t product_id; }
|
|
|
|
|
// WinMIDI: EndpointDeviceId (std::string), e.g. "\\?\swd#midisrv#midiu_ksa..."
|
|
|
|
|
// ALSA: sysfs path (std::string), e.g. "/sys/devices/pci0000:00/0000:00:02.2/0000:02:00.0/sound/card0/controlC0"
|
|
|
|
|
// CoreMIDI: USBVendorProduct (int32_t)
|
|
|
|
|
device_identifier device = std::monostate{};
|
|
|
|
|
|
|
|
|
|
/// Handle to the port identifier if the API provides one
|
|
|
|
|
// ALSA Raw: bit_cast to struct { uint16_t card, device, sub, padding; }.
|
|
|
|
|
// ALSA Seq: bit_cast to struct { uint32_t client, port; }
|
2024-10-28 19:24:18 +01:00
|
|
|
// CoreMIDI: MidiObjectRef's kMIDIPropertyUniqueID (uint32_t)
|
2024-10-09 02:01:23 +02:00
|
|
|
// WebMIDI: unused
|
|
|
|
|
// JACK: jack_port_id_t
|
|
|
|
|
// PipeWire: port.id
|
2025-06-13 19:16:35 +02:00
|
|
|
// WinMIDI: uint64_t terminal_block_number; (MidiGroupTerminalBlock::Number(), index is 1-based)
|
|
|
|
|
// WinMM: port index between 0 and midi{In,Out}GetNumDevs()
|
2024-10-09 02:01:23 +02:00
|
|
|
// WinUWP: unused
|
2024-10-28 19:24:18 +01:00
|
|
|
port_handle port = static_cast<port_handle>(-1);
|
2024-10-09 02:01:23 +02:00
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
/// User-readable information
|
|
|
|
|
// CoreMIDI: kMIDIPropertyManufacturer
|
|
|
|
|
// WinMIDI: MidiEndpointDeviceInformation::GetTransportSuppliedInfo().ManufacturerName
|
|
|
|
|
// WinMM: unavailable
|
2024-10-28 19:24:18 +01:00
|
|
|
std::string manufacturer{};
|
2025-06-13 19:16:35 +02:00
|
|
|
|
|
|
|
|
// CoreMIDI: kMIDIPropertyModel
|
|
|
|
|
// WinMIDI: MidiEndpointDeviceInformation::Name
|
|
|
|
|
// WinMM: unavailable
|
2024-10-28 19:24:18 +01:00
|
|
|
std::string device_name{};
|
2025-06-13 19:16:35 +02:00
|
|
|
|
|
|
|
|
// CoreMIDI: kMIDIPropertyName
|
|
|
|
|
// WinMIDI: MidiGroupTerminalBlock::Name
|
|
|
|
|
// WinMM: szPname
|
2024-10-28 19:24:18 +01:00
|
|
|
std::string port_name{};
|
2025-06-13 19:16:35 +02:00
|
|
|
|
|
|
|
|
// CoreMIDI: kMIDIPropertyDisplayName
|
|
|
|
|
// Otherwise: the closest to a unique name we can get
|
2024-10-28 19:24:18 +01:00
|
|
|
std::string display_name{};
|
2024-10-09 02:01:23 +02:00
|
|
|
|
2025-06-13 19:16:35 +02:00
|
|
|
/// Port type
|
|
|
|
|
// CoreMIDI: available
|
|
|
|
|
// WinMM: unavailable
|
|
|
|
|
// WinMIDI: available
|
|
|
|
|
port_type type = port_type::unknown;
|
|
|
|
|
|
2024-10-09 02:01:23 +02:00
|
|
|
bool operator==(const port_information& other) const noexcept = default;
|
|
|
|
|
std::strong_ordering operator<=>(const port_information& other) const noexcept = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct input_port : port_information
|
|
|
|
|
{
|
|
|
|
|
bool operator==(const input_port& other) const noexcept = default;
|
|
|
|
|
std::strong_ordering operator<=>(const input_port& other) const noexcept = default;
|
|
|
|
|
};
|
|
|
|
|
struct output_port : port_information
|
|
|
|
|
{
|
|
|
|
|
bool operator==(const output_port& other) const noexcept = default;
|
|
|
|
|
std::strong_ordering operator<=>(const output_port& other) const noexcept = default;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using input_port_callback = std::function<void(const input_port&)>;
|
|
|
|
|
using output_port_callback = std::function<void(const output_port&)>;
|
|
|
|
|
struct observer_configuration
|
|
|
|
|
{
|
|
|
|
|
midi_error_callback on_error{};
|
2024-10-28 19:24:18 +01:00
|
|
|
midi_warning_callback on_warning{};
|
2024-10-09 02:01:23 +02:00
|
|
|
|
2024-10-28 19:24:18 +01:00
|
|
|
input_port_callback input_added{};
|
|
|
|
|
input_port_callback input_removed{};
|
|
|
|
|
output_port_callback output_added{};
|
|
|
|
|
output_port_callback output_removed{};
|
2024-10-09 02:01:23 +02:00
|
|
|
|
|
|
|
|
// Observe hardware ports
|
|
|
|
|
uint32_t track_hardware : 1 = true;
|
|
|
|
|
|
|
|
|
|
// Observe software (virtual) ports if the API provides it
|
|
|
|
|
uint32_t track_virtual : 1 = false;
|
|
|
|
|
|
|
|
|
|
// Observe any port - some systems have other weird port types than hw / sw, this covers them
|
|
|
|
|
uint32_t track_any : 1 = false;
|
|
|
|
|
|
|
|
|
|
// Notify of the existing ports in the observer constructor
|
|
|
|
|
uint32_t notify_in_constructor : 1 = true;
|
|
|
|
|
|
|
|
|
|
bool has_callbacks() const noexcept
|
|
|
|
|
{
|
|
|
|
|
return input_added || input_removed || output_added || output_removed;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|