very, very simple WP with midi CC out

This commit is contained in:
Sebastian
2024-10-09 02:01:23 +02:00
commit 3d6fc151f1
126 changed files with 19539 additions and 0 deletions
+459
View File
@@ -0,0 +1,459 @@
#pragma once
#include <libremidi/backends/linux/dylib_loader.hpp>
#include <alsa/asoundlib.h>
#if defined(SND_LIB_VERSION)
#if __has_include(<alsa/rawmidi.h>) && SND_LIB_VERSION >= ((1 << 16) | (2 << 8) | 6)
#define LIBREMIDI_ALSA_HAS_RAMWIDI 1
#define LIBREMIDI_ALSA_HAS_RAWMIDI_TREAD 1
#endif
#if __has_include(<alsa/ump.h>) && SND_LIB_VERSION >= ((1 << 16) | (2 << 8) | 10)
#define LIBREMIDI_ALSA_HAS_UMP 1
#endif
#endif
namespace libremidi
{
struct libasound
{
// Useful one-liner:
// nm -A * | grep ' snd_' | grep -v '@' | cut -f 2 -d 'U' | sort | uniq | sed 's/ snd_//' | sed 's/_/, /' | awk ' { print "LIBREMIDI_SYMBOL_DEF(snd_"$1 " " $2 ");" }'
explicit libasound()
: library{"libasound.so.2"}
{
if (!library)
{
available = false;
return;
}
strerror = library.symbol<decltype(&::snd_strerror)>("snd_strerror");
if (!strerror)
available = false;
}
static const libasound& instance()
{
static const libasound self;
return self;
}
dylib_loader library;
decltype(&::snd_strerror) strerror{};
bool available{true};
struct card_t
{
explicit card_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_card, get_name);
LIBREMIDI_SYMBOL_INIT(snd_card, next);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_card, get_name);
LIBREMIDI_SYMBOL_DEF(snd_card, next);
} card{library};
struct ctl_t
{
explicit ctl_t(const dylib_loader& library)
: rawmidi{library}
#if LIBREMIDI_ALSA_HAS_UMP
, ump{library}
#endif
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_ctl, close);
LIBREMIDI_SYMBOL_INIT(snd_ctl, open);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_ctl, close);
LIBREMIDI_SYMBOL_DEF(snd_ctl, open);
struct rawmidi_t
{
explicit rawmidi_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_ctl_rawmidi, info);
LIBREMIDI_SYMBOL_INIT(snd_ctl_rawmidi, next_device);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_ctl_rawmidi, info);
LIBREMIDI_SYMBOL_DEF(snd_ctl_rawmidi, next_device);
} rawmidi;
#if LIBREMIDI_ALSA_HAS_UMP
struct ump_t
{
explicit ump_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_ctl_ump, block_info);
LIBREMIDI_SYMBOL_INIT(snd_ctl_ump, endpoint_info);
LIBREMIDI_SYMBOL_INIT(snd_ctl_ump, next_device);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_ctl_ump, block_info);
LIBREMIDI_SYMBOL_DEF(snd_ctl_ump, endpoint_info);
LIBREMIDI_SYMBOL_DEF(snd_ctl_ump, next_device);
} ump;
#endif
} ctl{library};
struct midi_t
{
explicit midi_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_midi, event_decode);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_encode);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_free);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_init);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_new);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_no_status);
LIBREMIDI_SYMBOL_INIT(snd_midi, event_resize_buffer);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_midi, event_decode);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_encode);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_free);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_init);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_new);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_no_status);
LIBREMIDI_SYMBOL_DEF(snd_midi, event_resize_buffer);
} midi{library};
#if LIBREMIDI_ALSA_HAS_RAMWIDI
struct rawmidi_t
{
explicit rawmidi_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, close);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_get_name);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_get_subdevice_name);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_get_subdevices_count);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_set_device);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_set_stream);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_set_subdevice);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, info_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, open);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_current);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_get_buffer_size);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_set_clock_type);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_set_no_active_sensing);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_set_read_mode);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, params_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, poll_descriptors);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, poll_descriptors_count);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, poll_descriptors_revents);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, read);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, status);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, status_get_avail);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, status_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, tread);
LIBREMIDI_SYMBOL_INIT(snd_rawmidi, write);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, close);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_get_name);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_get_subdevice_name);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_get_subdevices_count);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_set_device);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_set_stream);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_set_subdevice);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, info_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, open);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_current);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_get_buffer_size);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_set_clock_type);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_set_no_active_sensing);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_set_read_mode);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, params_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, poll_descriptors);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, poll_descriptors_count);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, poll_descriptors_revents);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, read);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, status);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, status_get_avail);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, status_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, tread);
LIBREMIDI_SYMBOL_DEF(snd_rawmidi, write);
} rawmidi{library};
#endif
struct seq_t
{
explicit seq_t(const dylib_loader& library)
#if LIBREMIDI_ALSA_HAS_UMP
: ump{library}
#endif
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_seq, alloc_queue);
LIBREMIDI_SYMBOL_INIT(snd_seq, client_id);
LIBREMIDI_SYMBOL_INIT(snd_seq, client_info_get_client);
LIBREMIDI_SYMBOL_INIT(snd_seq, client_info_get_name);
LIBREMIDI_SYMBOL_INIT(snd_seq, client_info_set_client);
LIBREMIDI_SYMBOL_INIT(snd_seq, client_info_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_seq, close);
LIBREMIDI_SYMBOL_INIT(snd_seq, connect_from);
LIBREMIDI_SYMBOL_INIT(snd_seq, control_queue);
LIBREMIDI_SYMBOL_INIT(snd_seq, create_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, delete_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, drain_output);
LIBREMIDI_SYMBOL_INIT(snd_seq, event_input);
LIBREMIDI_SYMBOL_INIT(snd_seq, event_input_pending);
LIBREMIDI_SYMBOL_INIT(snd_seq, event_output);
LIBREMIDI_SYMBOL_INIT(snd_seq, free_event);
LIBREMIDI_SYMBOL_INIT(snd_seq, free_queue);
LIBREMIDI_SYMBOL_INIT(snd_seq, get_any_client_info);
LIBREMIDI_SYMBOL_INIT(snd_seq, get_any_port_info);
LIBREMIDI_SYMBOL_INIT(snd_seq, get_port_info);
LIBREMIDI_SYMBOL_INIT(snd_seq, open);
LIBREMIDI_SYMBOL_INIT(snd_seq, poll_descriptors);
LIBREMIDI_SYMBOL_INIT(snd_seq, poll_descriptors_count);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_get_addr);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_get_capability);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_get_name);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_get_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_get_type);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_capability);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_client);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_midi_channels);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_name);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_timestamping);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_timestamp_queue);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_timestamp_real);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_set_type);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_info_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_free);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_malloc);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_set_dest);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_set_sender);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_set_time_real);
LIBREMIDI_SYMBOL_INIT(snd_seq, port_subscribe_set_time_update);
LIBREMIDI_SYMBOL_INIT(snd_seq, query_next_client);
LIBREMIDI_SYMBOL_INIT(snd_seq, query_next_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, queue_tempo_set_ppq);
LIBREMIDI_SYMBOL_INIT(snd_seq, queue_tempo_set_tempo);
LIBREMIDI_SYMBOL_INIT(snd_seq, queue_tempo_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_seq, set_client_name);
LIBREMIDI_SYMBOL_INIT(snd_seq, set_port_info);
LIBREMIDI_SYMBOL_INIT(snd_seq, set_queue_tempo);
LIBREMIDI_SYMBOL_INIT(snd_seq, subscribe_port);
LIBREMIDI_SYMBOL_INIT(snd_seq, unsubscribe_port);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_seq, alloc_queue);
LIBREMIDI_SYMBOL_DEF(snd_seq, client_id);
LIBREMIDI_SYMBOL_DEF(snd_seq, client_info_get_client);
LIBREMIDI_SYMBOL_DEF(snd_seq, client_info_get_name);
LIBREMIDI_SYMBOL_DEF(snd_seq, client_info_set_client);
LIBREMIDI_SYMBOL_DEF(snd_seq, client_info_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_seq, close);
LIBREMIDI_SYMBOL_DEF(snd_seq, connect_from);
LIBREMIDI_SYMBOL_DEF(snd_seq, control_queue);
LIBREMIDI_SYMBOL_DEF(snd_seq, create_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, delete_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, drain_output);
LIBREMIDI_SYMBOL_DEF(snd_seq, event_input);
LIBREMIDI_SYMBOL_DEF(snd_seq, event_input_pending);
LIBREMIDI_SYMBOL_DEF(snd_seq, event_output);
LIBREMIDI_SYMBOL_DEF(snd_seq, free_event);
LIBREMIDI_SYMBOL_DEF(snd_seq, free_queue);
LIBREMIDI_SYMBOL_DEF(snd_seq, get_any_client_info);
LIBREMIDI_SYMBOL_DEF(snd_seq, get_any_port_info);
LIBREMIDI_SYMBOL_DEF(snd_seq, get_port_info);
LIBREMIDI_SYMBOL_DEF(snd_seq, open);
LIBREMIDI_SYMBOL_DEF(snd_seq, poll_descriptors);
LIBREMIDI_SYMBOL_DEF(snd_seq, poll_descriptors_count);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_get_addr);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_get_capability);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_get_name);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_get_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_get_type);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_capability);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_client);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_midi_channels);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_name);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_timestamping);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_timestamp_queue);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_timestamp_real);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_set_type);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_info_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_free);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_malloc);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_set_dest);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_set_sender);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_set_time_real);
LIBREMIDI_SYMBOL_DEF(snd_seq, port_subscribe_set_time_update);
LIBREMIDI_SYMBOL_DEF(snd_seq, query_next_client);
LIBREMIDI_SYMBOL_DEF(snd_seq, query_next_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, queue_tempo_set_ppq);
LIBREMIDI_SYMBOL_DEF(snd_seq, queue_tempo_set_tempo);
LIBREMIDI_SYMBOL_DEF(snd_seq, queue_tempo_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_seq, set_client_name);
LIBREMIDI_SYMBOL_DEF(snd_seq, set_port_info);
LIBREMIDI_SYMBOL_DEF(snd_seq, set_queue_tempo);
LIBREMIDI_SYMBOL_DEF(snd_seq, subscribe_port);
LIBREMIDI_SYMBOL_DEF(snd_seq, unsubscribe_port);
#if LIBREMIDI_ALSA_HAS_UMP
struct ump_t
{
explicit ump_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_seq, set_client_midi_version);
LIBREMIDI_SYMBOL_INIT(snd_seq_ump, event_input);
LIBREMIDI_SYMBOL_INIT(snd_seq_ump, event_output);
LIBREMIDI_SYMBOL_INIT(snd_seq_ump, event_output_direct);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_seq, set_client_midi_version);
LIBREMIDI_SYMBOL_DEF(snd_seq_ump, event_input);
LIBREMIDI_SYMBOL_DEF(snd_seq_ump, event_output);
LIBREMIDI_SYMBOL_DEF(snd_seq_ump, event_output_direct);
} ump;
#endif
} seq{library};
#if LIBREMIDI_ALSA_HAS_UMP
struct ump_t
{
explicit ump_t(const dylib_loader& library)
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(snd_ump, block_info_get_name);
LIBREMIDI_SYMBOL_INIT(snd_ump, block_info_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_ump, close);
LIBREMIDI_SYMBOL_INIT(snd_ump, endpoint_info_get_name);
LIBREMIDI_SYMBOL_INIT(snd_ump, endpoint_info_sizeof);
LIBREMIDI_SYMBOL_INIT(snd_ump, open);
LIBREMIDI_SYMBOL_INIT(snd_ump, poll_descriptors);
LIBREMIDI_SYMBOL_INIT(snd_ump, poll_descriptors_count);
LIBREMIDI_SYMBOL_INIT(snd_ump, poll_descriptors_revents);
LIBREMIDI_SYMBOL_INIT(snd_ump, rawmidi);
LIBREMIDI_SYMBOL_INIT(snd_ump, rawmidi_params);
LIBREMIDI_SYMBOL_INIT(snd_ump, rawmidi_params_current);
LIBREMIDI_SYMBOL_INIT(snd_ump, read);
LIBREMIDI_SYMBOL_INIT(snd_ump, tread);
LIBREMIDI_SYMBOL_INIT(snd_ump, write);
}
bool available{true};
LIBREMIDI_SYMBOL_DEF(snd_ump, block_info_get_name);
LIBREMIDI_SYMBOL_DEF(snd_ump, block_info_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_ump, close);
LIBREMIDI_SYMBOL_DEF(snd_ump, endpoint_info_get_name);
LIBREMIDI_SYMBOL_DEF(snd_ump, endpoint_info_sizeof);
LIBREMIDI_SYMBOL_DEF(snd_ump, open);
LIBREMIDI_SYMBOL_DEF(snd_ump, poll_descriptors);
LIBREMIDI_SYMBOL_DEF(snd_ump, poll_descriptors_count);
LIBREMIDI_SYMBOL_DEF(snd_ump, poll_descriptors_revents);
LIBREMIDI_SYMBOL_DEF(snd_ump, rawmidi);
LIBREMIDI_SYMBOL_DEF(snd_ump, rawmidi_params);
LIBREMIDI_SYMBOL_DEF(snd_ump, rawmidi_params_current);
LIBREMIDI_SYMBOL_DEF(snd_ump, read);
LIBREMIDI_SYMBOL_DEF(snd_ump, tread);
LIBREMIDI_SYMBOL_DEF(snd_ump, write);
} ump{library};
#endif
};
#undef snd_dylib_alloca
#define snd_dylib_alloca(ptr, access, type) \
{ \
*ptr = (snd_##access##_##type##_t*)alloca(snd.access.type##_sizeof()); \
memset(*ptr, 0, snd.access.type##_sizeof()); \
}
#define snd_dylib_alloca2(ptr, access1, access2, type) \
{ \
*ptr = (snd_##access1##_access2##_##type##_t*)alloca(snd.access1.access2.type##_sizeof()); \
memset(*ptr, 0, snd.access1.access2.type##_sizeof()); \
}
#undef snd_rawmidi_info_alloca
#define snd_rawmidi_info_alloca(ptr) snd_dylib_alloca(ptr, rawmidi, info)
#undef snd_rawmidi_params_alloca
#define snd_rawmidi_params_alloca(ptr) snd_dylib_alloca(ptr, rawmidi, params)
#undef snd_rawmidi_status_alloca
#define snd_rawmidi_status_alloca(ptr) snd_dylib_alloca(ptr, rawmidi, status)
#undef snd_seq_client_info_alloca
#define snd_seq_client_info_alloca(ptr) snd_dylib_alloca(ptr, seq, client_info)
#undef snd_seq_port_info_alloca
#define snd_seq_port_info_alloca(ptr) snd_dylib_alloca(ptr, seq, port_info)
#undef snd_seq_queue_tempo_alloca
#define snd_seq_queue_tempo_alloca(ptr) snd_dylib_alloca(ptr, seq, queue_tempo)
#if LIBREMIDI_ALSA_HAS_UMP
#undef snd_ump_block_info_alloca
#define snd_ump_block_info_alloca(ptr) snd_dylib_alloca(ptr, ump, block_info)
#undef snd_ump_endpoint_info_alloca
#define snd_ump_endpoint_info_alloca(ptr) snd_dylib_alloca(ptr, ump, endpoint_info)
#endif
}
@@ -0,0 +1,85 @@
#pragma once
#if __has_include(<dlfcn.h>)
#include <dlfcn.h>
#include <cassert>
namespace libremidi
{
class dylib_loader
{
public:
explicit dylib_loader(const char* const so)
{
impl = dlopen(so, RTLD_LAZY | RTLD_LOCAL | RTLD_NODELETE);
}
dylib_loader(const dylib_loader&) noexcept = delete;
dylib_loader& operator=(const dylib_loader&) noexcept = delete;
dylib_loader(dylib_loader&& other) noexcept
{
impl = other.impl;
other.impl = nullptr;
}
dylib_loader& operator=(dylib_loader&& other) noexcept
{
impl = other.impl;
other.impl = nullptr;
return *this;
}
~dylib_loader()
{
if (impl)
{
dlclose(impl);
}
}
template <typename T>
T symbol(const char* const sym) const noexcept
{
assert(impl);
return reinterpret_cast<T>(dlsym(impl, sym));
}
operator bool() const noexcept { return bool(impl); }
private:
void* impl{};
};
}
#define LIBREMIDI_SYMBOL_NAME_S(prefix, name) #prefix "_" #name
#define LIBREMIDI_SYMBOL_NAME(prefix, name) prefix##_##name
#define LIBREMIDI_SYMBOL_DEF(prefix, name) \
decltype(&::LIBREMIDI_SYMBOL_NAME(prefix, name)) name{};
#define LIBREMIDI_SYMBOL_INIT(prefix, name) \
{ \
name = library.symbol<decltype(&::LIBREMIDI_SYMBOL_NAME(prefix, name))>( \
LIBREMIDI_SYMBOL_NAME_S(prefix, name)); \
if (!name) \
{ \
available = false; \
return; \
} \
}
// Because some libs have names that are C++ keywords, e.g. udev_new:
#define LIBREMIDI_SYMBOL_NAME2_S(prefix, name, varname) #prefix "_" #name
#define LIBREMIDI_SYMBOL_NAME2(prefix, name, varname) prefix##_##name
#define LIBREMIDI_SYMBOL_DEF2(prefix, name, varname) \
decltype(&::LIBREMIDI_SYMBOL_NAME2(prefix, name, varname)) varname{};
#define LIBREMIDI_SYMBOL_INIT2(prefix, name, varname) \
{ \
varname = library.symbol<decltype(&::LIBREMIDI_SYMBOL_NAME2(prefix, name, varname))>( \
LIBREMIDI_SYMBOL_NAME2_S(prefix, name, varname)); \
if (!varname) \
{ \
available = false; \
return; \
} \
}
#endif
@@ -0,0 +1,77 @@
#pragma once
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <poll.h>
#include <unistd.h>
#include <iostream>
namespace libremidi
{
struct eventfd_notifier
{
eventfd_notifier(bool semaphore = true)
{
if (semaphore)
this->fd = eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK);
else
this->fd = eventfd(0, EFD_NONBLOCK);
}
~eventfd_notifier() { close(this->fd); }
eventfd_notifier(const eventfd_notifier&) = delete;
eventfd_notifier(eventfd_notifier&&) = delete;
eventfd_notifier& operator=(const eventfd_notifier&) = delete;
eventfd_notifier& operator=(eventfd_notifier&&) = delete;
void notify() noexcept { eventfd_write(fd, 1); }
static bool ready(pollfd res) noexcept { return res.revents & POLLIN; }
eventfd_t consume() noexcept
{
eventfd_t val;
eventfd_read(fd, &val);
return val;
}
operator int() const noexcept { return fd; }
operator pollfd() const noexcept { return {.fd = fd, .events = POLLIN, .revents = 0}; }
int fd{-1};
};
struct timerfd_timer
{
timerfd_timer() { this->fd = timerfd_create(CLOCK_MONOTONIC, 0); }
~timerfd_timer() { close(this->fd); }
timerfd_timer(const timerfd_timer&) = delete;
timerfd_timer(timerfd_timer&&) = delete;
timerfd_timer& operator=(const timerfd_timer&) = delete;
timerfd_timer& operator=(timerfd_timer&&) = delete;
void oneshot(int64_t nsec)
{
itimerspec t{};
t.it_value.tv_nsec = nsec;
timerfd_settime(this->fd, 0, &t, nullptr);
}
void restart(int64_t nsec)
{
itimerspec t{};
t.it_value.tv_nsec = nsec;
t.it_interval.tv_nsec = nsec;
timerfd_settime(this->fd, 0, &t, nullptr);
}
void cancel()
{
itimerspec t{};
timerfd_settime(this->fd, 0, &t, nullptr);
}
operator int() const noexcept { return fd; }
operator pollfd() const noexcept { return {.fd = fd, .events = POLLIN, .revents = 0}; }
int fd{-1};
};
}
@@ -0,0 +1,169 @@
#pragma once
#include <libremidi/backends/linux/dylib_loader.hpp>
#include <pipewire/pipewire.h>
namespace libremidi
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
class libpipewire
{
public:
decltype(&::pw_init) init{};
decltype(&::pw_deinit) deinit{};
decltype(&::pw_context_new) context_new{};
decltype(&::pw_context_connect) context_connect{};
decltype(&::pw_context_destroy) context_destroy{};
decltype(&::pw_core_disconnect) core_disconnect{};
decltype(&::pw_proxy_add_listener) proxy_add_listener{};
decltype(&::pw_proxy_destroy) proxy_destroy{};
decltype(&::pw_main_loop_new) main_loop_new{};
decltype(&::pw_main_loop_destroy) main_loop_destroy{};
decltype(&::pw_main_loop_quit) main_loop_quit{};
decltype(&::pw_main_loop_run) main_loop_run{};
decltype(&::pw_main_loop_get_loop) main_loop_get_loop{};
/*
decltype(&::pw_thread_loop_new) thread_loop_new{};
decltype(&::pw_thread_loop_destroy) thread_loop_destroy{};
decltype(&::pw_thread_loop_wait) thread_loop_wait{};
decltype(&::pw_thread_loop_start) thread_loop_start{};
decltype(&::pw_thread_loop_stop) thread_loop_stop;
decltype(&::pw_thread_loop_lock) thread_loop_lock{};
decltype(&::pw_thread_loop_unlock) thread_loop_unlock;
decltype(&::pw_thread_loop_get_loop) thread_loop_get_loop{};
*/
decltype(&::pw_properties_new) properties_new{};
decltype(&::pw_properties_free) properties_free{};
decltype(&::pw_properties_get) properties_get{};
decltype(&::pw_filter_new_simple) filter_new_simple{};
decltype(&::pw_filter_get_node_id) filter_get_node_id{};
decltype(&::pw_filter_get_properties) filter_get_properties{};
decltype(&::pw_filter_add_port) filter_add_port{};
decltype(&::pw_filter_remove_port) filter_remove_port{};
decltype(&::pw_filter_update_properties) filter_update_properties{};
decltype(&::pw_filter_update_params) filter_update_params{};
decltype(&::pw_filter_get_time) filter_get_time{};
decltype(&::pw_filter_destroy) filter_destroy{};
decltype(&::pw_filter_connect) filter_connect{};
decltype(&::pw_filter_get_dsp_buffer) filter_get_dsp_buffer{};
decltype(&::pw_filter_queue_buffer) filter_queue_buffer{};
decltype(&::pw_filter_dequeue_buffer) filter_dequeue_buffer{};
decltype(&::pw_filter_flush) filter_flush{};
static const libpipewire& instance()
{
static const libpipewire self;
return self;
}
bool available{true};
private:
dylib_loader library;
libpipewire()
: library("libpipewire-0.3.so.0")
{
if (!library)
{
available = false;
return;
}
// in terms of regex:
// decltype\(&::([a-z_]+)\) [a-z_]+{};
// \1 = library.symbol<decltype(&::\1)>("\1");
init = library.symbol<decltype(&::pw_init)>("pw_init");
deinit = library.symbol<decltype(&::pw_deinit)>("pw_deinit");
context_new = library.symbol<decltype(&::pw_context_new)>("pw_context_new");
context_connect = library.symbol<decltype(&::pw_context_connect)>("pw_context_connect");
context_destroy = library.symbol<decltype(&::pw_context_destroy)>("pw_context_destroy");
core_disconnect = library.symbol<decltype(&::pw_core_disconnect)>("pw_core_disconnect");
proxy_add_listener
= library.symbol<decltype(&::pw_proxy_add_listener)>("pw_proxy_add_listener");
proxy_destroy = library.symbol<decltype(&::pw_proxy_destroy)>("pw_proxy_destroy");
main_loop_new = library.symbol<decltype(&::pw_main_loop_new)>("pw_main_loop_new");
main_loop_destroy = library.symbol<decltype(&::pw_main_loop_destroy)>("pw_main_loop_destroy");
main_loop_quit = library.symbol<decltype(&::pw_main_loop_quit)>("pw_main_loop_quit");
main_loop_run = library.symbol<decltype(&::pw_main_loop_run)>("pw_main_loop_run");
main_loop_get_loop
= library.symbol<decltype(&::pw_main_loop_get_loop)>("pw_main_loop_get_loop");
properties_new = library.symbol<decltype(&::pw_properties_new)>("pw_properties_new");
properties_free = library.symbol<decltype(&::pw_properties_free)>("pw_properties_free");
properties_get = library.symbol<decltype(&::pw_properties_get)>("pw_properties_get");
filter_new_simple = library.symbol<decltype(&::pw_filter_new_simple)>("pw_filter_new_simple");
filter_get_node_id
= library.symbol<decltype(&::pw_filter_get_node_id)>("pw_filter_get_node_id");
filter_get_properties
= library.symbol<decltype(&::pw_filter_get_properties)>("pw_filter_get_properties");
filter_add_port = library.symbol<decltype(&::pw_filter_add_port)>("pw_filter_add_port");
filter_remove_port
= library.symbol<decltype(&::pw_filter_remove_port)>("pw_filter_remove_port");
filter_update_properties
= library.symbol<decltype(&::pw_filter_update_properties)>("pw_filter_update_properties");
filter_update_params
= library.symbol<decltype(&::pw_filter_update_params)>("pw_filter_update_params");
filter_get_time = library.symbol<decltype(&::pw_filter_get_time)>("pw_filter_get_time");
filter_destroy = library.symbol<decltype(&::pw_filter_destroy)>("pw_filter_destroy");
filter_connect = library.symbol<decltype(&::pw_filter_connect)>("pw_filter_connect");
filter_get_dsp_buffer
= library.symbol<decltype(&::pw_filter_get_dsp_buffer)>("pw_filter_get_dsp_buffer");
filter_dequeue_buffer
= library.symbol<decltype(&::pw_filter_dequeue_buffer)>("pw_filter_dequeue_buffer");
filter_queue_buffer
= library.symbol<decltype(&::pw_filter_queue_buffer)>("pw_filter_queue_buffer");
filter_flush = library.symbol<decltype(&::pw_filter_flush)>("pw_filter_flush");
assert(init);
assert(deinit);
assert(context_new);
assert(context_connect);
assert(context_destroy);
assert(core_disconnect);
assert(proxy_destroy);
assert(main_loop_new);
assert(main_loop_destroy);
assert(main_loop_quit);
assert(main_loop_run);
assert(main_loop_get_loop);
assert(properties_new);
assert(properties_free);
assert(properties_get);
assert(filter_new_simple);
assert(filter_get_node_id);
assert(filter_get_properties);
assert(filter_add_port);
assert(filter_remove_port);
assert(filter_update_properties);
assert(filter_update_params);
assert(filter_get_time);
assert(filter_destroy);
assert(filter_connect);
assert(filter_get_dsp_buffer);
assert(filter_dequeue_buffer);
assert(filter_queue_buffer);
assert(filter_flush);
}
};
#pragma GCC diagnostic pop
}
+92
View File
@@ -0,0 +1,92 @@
#pragma once
#include <libremidi/backends/linux/dylib_loader.hpp>
#include <libremidi/backends/linux/helpers.hpp>
#include <libudev.h>
#include <cassert>
namespace libremidi
{
struct libudev
{
// Useful one-liner:
// nm -A * | grep ' udev_' | grep -v '@' | cut -f 2 -d 'U' | sort | uniq | sed 's/ udev_//'| awk ' { print "LIBREMIDI_SYMBOL_DEF(udev, "$1");" }'
explicit libudev()
: library{"libudev.so.1"}
{
if (!library)
{
available = false;
return;
}
LIBREMIDI_SYMBOL_INIT(udev, device_get_action);
LIBREMIDI_SYMBOL_INIT(udev, device_get_subsystem);
LIBREMIDI_SYMBOL_INIT(udev, device_unref);
LIBREMIDI_SYMBOL_INIT(udev, monitor_enable_receiving);
LIBREMIDI_SYMBOL_INIT(udev, monitor_get_fd);
LIBREMIDI_SYMBOL_INIT(udev, monitor_new_from_netlink);
LIBREMIDI_SYMBOL_INIT(udev, monitor_receive_device);
LIBREMIDI_SYMBOL_INIT(udev, monitor_unref);
LIBREMIDI_SYMBOL_INIT2(udev, new, create);
LIBREMIDI_SYMBOL_INIT(udev, unref);
}
static const libudev& instance()
{
static const libudev self;
return self;
}
dylib_loader library;
bool available{true};
LIBREMIDI_SYMBOL_DEF(udev, device_get_action);
LIBREMIDI_SYMBOL_DEF(udev, device_get_subsystem);
LIBREMIDI_SYMBOL_DEF(udev, device_unref);
LIBREMIDI_SYMBOL_DEF(udev, monitor_enable_receiving);
LIBREMIDI_SYMBOL_DEF(udev, monitor_get_fd);
LIBREMIDI_SYMBOL_DEF(udev, monitor_new_from_netlink);
LIBREMIDI_SYMBOL_DEF(udev, monitor_receive_device);
LIBREMIDI_SYMBOL_DEF(udev, monitor_unref);
LIBREMIDI_SYMBOL_DEF2(udev, new, create);
LIBREMIDI_SYMBOL_DEF(udev, unref);
};
struct udev_helper
{
udev_helper()
{
instance = udev.create();
assert(instance);
monitor = udev.monitor_new_from_netlink(instance, "udev");
assert(monitor);
udev.monitor_enable_receiving(monitor);
}
~udev_helper()
{
udev.monitor_unref(monitor);
udev.unref(instance);
}
udev_helper(const udev_helper&) = delete;
udev_helper(udev_helper&&) = delete;
udev_helper& operator=(const udev_helper&) = delete;
udev_helper& operator=(udev_helper&&) = delete;
operator pollfd() const noexcept
{
return {.fd = udev.monitor_get_fd(monitor), .events = POLLIN, .revents = 0};
}
const libudev& udev = libudev::instance();
struct udev* instance{};
udev_monitor* monitor{};
};
}