working on win32 uwp! and libremidi update
This commit is contained in:
@@ -0,0 +1,507 @@
|
||||
// clang-format off
|
||||
#include <libremidi/libremidi-c.h>
|
||||
#include <libremidi/libremidi.hpp>
|
||||
#include <libremidi/backends.hpp>
|
||||
// clang-format on
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
struct libremidi_midi_observer_handle
|
||||
{
|
||||
libremidi::observer self;
|
||||
};
|
||||
|
||||
struct libremidi_midi_in_handle
|
||||
{
|
||||
libremidi::midi_in self;
|
||||
};
|
||||
|
||||
struct libremidi_midi_out_handle
|
||||
{
|
||||
libremidi::midi_out self;
|
||||
};
|
||||
|
||||
namespace libremidi
|
||||
{
|
||||
|
||||
static void assign_error_callback(const auto& src, auto& dst)
|
||||
{
|
||||
if (src.callback)
|
||||
{
|
||||
dst = [src](std::string_view errorText, const source_location& loc) {
|
||||
src.callback(src.context, errorText.data(), errorText.size(), &loc);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
const char* libremidi_get_version(void)
|
||||
{
|
||||
return LIBREMIDI_VERSION;
|
||||
}
|
||||
|
||||
void libremidi_available_midi1_apis(void* ctx, void (*cb)(void* ctx, libremidi_api))
|
||||
{
|
||||
if (!cb)
|
||||
return;
|
||||
libremidi::midi1::for_all_backends([=](auto b) { cb(ctx, b.API); });
|
||||
}
|
||||
|
||||
void libremidi_available_midi2_apis(void* ctx, void (*cb)(void* ctx, libremidi_api))
|
||||
{
|
||||
if (!cb)
|
||||
return;
|
||||
libremidi::midi2::for_all_backends([=](auto b) { cb(ctx, b.API); });
|
||||
}
|
||||
|
||||
const char* libremidi_api_identifier(libremidi_api api)
|
||||
{
|
||||
return libremidi::get_api_name(api).data();
|
||||
}
|
||||
|
||||
const char* libremidi_api_display_name(libremidi_api api)
|
||||
{
|
||||
return libremidi::get_api_display_name(api).data();
|
||||
}
|
||||
|
||||
libremidi_api libremidi_get_compiled_api_by_identifier(const char* name)
|
||||
{
|
||||
libremidi_api ret = libremidi_api::UNSPECIFIED;
|
||||
libremidi::midi_any::for_all_backends([&](auto& b) {
|
||||
if (name == b.name)
|
||||
ret = b.API;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
int libremidi_midi_api_configuration_init(libremidi_api_configuration* conf)
|
||||
{
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_observer_configuration_init(libremidi_observer_configuration* conf)
|
||||
{
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_configuration_init(libremidi_midi_configuration* conf)
|
||||
{
|
||||
memset(conf, 0, sizeof(*conf));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_in_port_clone(const libremidi_midi_in_port* port, libremidi_midi_in_port** dst)
|
||||
{
|
||||
if (!port || !dst)
|
||||
return -EINVAL;
|
||||
|
||||
auto copied = new libremidi::input_port{*reinterpret_cast<const libremidi::input_port*>(port)};
|
||||
*dst = reinterpret_cast<libremidi_midi_in_port*>(copied);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_in_port_free(libremidi_midi_in_port* port)
|
||||
{
|
||||
delete reinterpret_cast<libremidi::input_port*>(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_in_port_name(const libremidi_midi_in_port* port, const char** name, size_t* len)
|
||||
{
|
||||
if (!port || !name || !len)
|
||||
return -EINVAL;
|
||||
|
||||
auto& p = *reinterpret_cast<const libremidi::input_port*>(port);
|
||||
*name = p.port_name.data();
|
||||
*len = p.port_name.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_port_clone(
|
||||
const libremidi_midi_out_port* port, libremidi_midi_out_port** dst)
|
||||
{
|
||||
if (!port || !dst)
|
||||
return -EINVAL;
|
||||
|
||||
auto copied = new libremidi::output_port{*reinterpret_cast<const libremidi::output_port*>(port)};
|
||||
*dst = reinterpret_cast<libremidi_midi_out_port*>(copied);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_port_free(libremidi_midi_out_port* port)
|
||||
{
|
||||
delete reinterpret_cast<libremidi::output_port*>(port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_port_name(
|
||||
const libremidi_midi_out_port* port, const char** name, size_t* len)
|
||||
{
|
||||
if (!port || !name || !len)
|
||||
return -EINVAL;
|
||||
|
||||
auto& p = *reinterpret_cast<const libremidi::output_port*>(port);
|
||||
*name = p.port_name.data();
|
||||
*len = p.port_name.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_observer_new(
|
||||
const libremidi_observer_configuration* c, libremidi_api_configuration* api,
|
||||
libremidi_midi_observer_handle** out)
|
||||
{
|
||||
if (!out || !c)
|
||||
return -EINVAL;
|
||||
|
||||
libremidi::observer_configuration conf;
|
||||
libremidi::assign_error_callback(c->on_error, conf.on_error);
|
||||
libremidi::assign_error_callback(c->on_warning, conf.on_warning);
|
||||
|
||||
conf.track_hardware = c->track_hardware;
|
||||
conf.track_virtual = c->track_virtual;
|
||||
conf.track_any = c->track_any;
|
||||
conf.notify_in_constructor = c->notify_in_constructor;
|
||||
|
||||
auto api_conf = libremidi::observer_configuration_for(static_cast<libremidi::API>(api->api));
|
||||
|
||||
if (c->input_added.callback)
|
||||
{
|
||||
conf.input_added = [cb = c->input_added](const auto& port) {
|
||||
cb.callback(cb.context, reinterpret_cast<const libremidi_midi_in_port*>(&port));
|
||||
};
|
||||
}
|
||||
if (c->input_removed.callback)
|
||||
{
|
||||
conf.input_removed = [cb = c->input_removed](const auto& port) {
|
||||
cb.callback(cb.context, reinterpret_cast<const libremidi_midi_in_port*>(&port));
|
||||
};
|
||||
}
|
||||
if (c->output_added.callback)
|
||||
{
|
||||
conf.output_added = [cb = c->output_added](const auto& port) {
|
||||
cb.callback(cb.context, reinterpret_cast<const libremidi_midi_out_port*>(&port));
|
||||
};
|
||||
}
|
||||
if (c->output_removed.callback)
|
||||
{
|
||||
conf.output_removed = [cb = c->output_removed](const auto& port) {
|
||||
cb.callback(cb.context, reinterpret_cast<const libremidi_midi_out_port*>(&port));
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto ptr = new libremidi_midi_observer_handle{
|
||||
libremidi::observer{std::move(conf), std::move(api_conf)}};
|
||||
*out = ptr;
|
||||
return 0;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
int libremidi_midi_observer_enumerate_input_ports(
|
||||
libremidi_midi_observer_handle* ptr, void* context,
|
||||
void (*cb)(void* ctx, const libremidi_midi_in_port*))
|
||||
{
|
||||
if (!ptr || !cb)
|
||||
return -EINVAL;
|
||||
|
||||
for (const auto& port : ptr->self.get_input_ports())
|
||||
{
|
||||
cb(context, reinterpret_cast<const libremidi_midi_in_port*>(&port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_observer_enumerate_output_ports(
|
||||
libremidi_midi_observer_handle* ptr, void* context,
|
||||
void (*cb)(void* ctx, const libremidi_midi_out_port*))
|
||||
{
|
||||
if (!ptr || !cb)
|
||||
return -EINVAL;
|
||||
|
||||
for (const auto& port : ptr->self.get_output_ports())
|
||||
{
|
||||
cb(context, reinterpret_cast<const libremidi_midi_out_port*>(&port));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_observer_free(libremidi_midi_observer_handle* ptr)
|
||||
{
|
||||
delete ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_in_new(
|
||||
const libremidi_midi_configuration* c, const libremidi_api_configuration* api,
|
||||
libremidi_midi_in_handle** out)
|
||||
{
|
||||
if (!out || !c)
|
||||
return -EINVAL;
|
||||
if (!c->virtual_port && !c->in_port)
|
||||
return -EINVAL;
|
||||
|
||||
*out = nullptr;
|
||||
|
||||
auto api_conf = libremidi::midi_in_configuration_for(static_cast<libremidi::API>(api->api));
|
||||
|
||||
// Create the MIDI object
|
||||
switch (c->version)
|
||||
{
|
||||
case libremidi_midi_configuration::MIDI1:
|
||||
case libremidi_midi_configuration::MIDI1_RAW: {
|
||||
libremidi::input_configuration conf;
|
||||
libremidi::assign_error_callback(c->on_error, conf.on_error);
|
||||
libremidi::assign_error_callback(c->on_warning, conf.on_warning);
|
||||
conf.ignore_sensing = c->ignore_sensing;
|
||||
conf.ignore_sysex = c->ignore_sysex;
|
||||
conf.ignore_timing = c->ignore_timing;
|
||||
conf.timestamps = c->timestamps;
|
||||
|
||||
if (c->get_timestamp.callback)
|
||||
{
|
||||
conf.get_timestamp
|
||||
= [cb = c->get_timestamp](int64_t msg) { return cb.callback(cb.context, msg); };
|
||||
}
|
||||
|
||||
if (c->on_midi1_message.callback)
|
||||
conf.on_message = [cb = c->on_midi1_message](const libremidi::message& msg) {
|
||||
cb.callback(cb.context, msg.timestamp, msg.bytes.data(), msg.size());
|
||||
};
|
||||
else if (c->on_midi1_raw_data.callback)
|
||||
{
|
||||
conf.on_raw_data = [cb = c->on_midi1_raw_data](std::span<const uint8_t> msg, int64_t ts) {
|
||||
cb.callback(cb.context, ts, msg.data(), msg.size());
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto ptr = new libremidi_midi_in_handle{
|
||||
libremidi::midi_in{std::move(conf), std::move(api_conf)}};
|
||||
*out = ptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case libremidi_midi_configuration::MIDI2:
|
||||
case libremidi_midi_configuration::MIDI2_RAW: {
|
||||
libremidi::ump_input_configuration conf;
|
||||
libremidi::assign_error_callback(c->on_error, conf.on_error);
|
||||
libremidi::assign_error_callback(c->on_warning, conf.on_warning);
|
||||
conf.ignore_sensing = c->ignore_sensing;
|
||||
conf.ignore_sysex = c->ignore_sysex;
|
||||
conf.ignore_timing = c->ignore_timing;
|
||||
conf.timestamps = c->timestamps;
|
||||
|
||||
if (c->get_timestamp.callback)
|
||||
{
|
||||
conf.get_timestamp
|
||||
= [cb = c->get_timestamp](int64_t msg) { return cb.callback(cb.context, msg); };
|
||||
}
|
||||
|
||||
if (c->on_midi2_message.callback)
|
||||
conf.on_message = [cb = c->on_midi2_message](const libremidi::ump& msg) {
|
||||
cb.callback(cb.context, msg.timestamp, msg.data, msg.size());
|
||||
};
|
||||
else if (c->on_midi2_raw_data.callback)
|
||||
{
|
||||
conf.on_raw_data = [cb = c->on_midi2_raw_data](std::span<const uint32_t> msg, int64_t ts) {
|
||||
cb.callback(cb.context, ts, msg.data(), msg.size());
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
auto ptr = new libremidi_midi_in_handle{
|
||||
libremidi::midi_in{std::move(conf), std::move(api_conf)}};
|
||||
*out = ptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Open the port
|
||||
auto ptr = *out;
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
|
||||
if (c->virtual_port)
|
||||
{
|
||||
if (auto ret = ptr->self.open_virtual_port(c->port_name); ret != stdx::error{})
|
||||
{
|
||||
*out = nullptr;
|
||||
delete ptr;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto port = reinterpret_cast<const libremidi::input_port*>(c->in_port);
|
||||
if (auto ret = ptr->self.open_port(*port); ret != stdx::error{})
|
||||
{
|
||||
*out = nullptr;
|
||||
delete ptr;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
int libremidi_midi_in_is_connected(const libremidi_midi_in_handle* in)
|
||||
{
|
||||
if (!in)
|
||||
return -EINVAL;
|
||||
return in->self.is_port_connected() ? 1 : 0;
|
||||
}
|
||||
|
||||
libremidi_timestamp libremidi_midi_in_absolute_timestamp(libremidi_midi_in_handle* in)
|
||||
{
|
||||
if (!in)
|
||||
return -EINVAL;
|
||||
return in->self.absolute_timestamp();
|
||||
}
|
||||
|
||||
int libremidi_midi_in_free(libremidi_midi_in_handle* ptr)
|
||||
{
|
||||
delete ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_new(
|
||||
const libremidi_midi_configuration* c, const libremidi_api_configuration* api,
|
||||
libremidi_midi_out_handle** out)
|
||||
{
|
||||
if (!out || !c)
|
||||
return -EINVAL;
|
||||
if (!c->virtual_port && !c->out_port)
|
||||
return -EINVAL;
|
||||
|
||||
*out = nullptr;
|
||||
|
||||
auto api_conf = libremidi::midi_out_configuration_for(static_cast<libremidi::API>(api->api));
|
||||
|
||||
// Create the MIDI object
|
||||
libremidi::output_configuration conf;
|
||||
libremidi::assign_error_callback(c->on_error, conf.on_error);
|
||||
libremidi::assign_error_callback(c->on_warning, conf.on_warning);
|
||||
conf.timestamps = c->timestamps;
|
||||
try
|
||||
{
|
||||
auto ptr
|
||||
= new libremidi_midi_out_handle{libremidi::midi_out{std::move(conf), std::move(api_conf)}};
|
||||
*out = ptr;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
// Open the port
|
||||
auto ptr = *out;
|
||||
if (!ptr)
|
||||
return -EINVAL;
|
||||
|
||||
if (c->virtual_port)
|
||||
{
|
||||
if (auto ret = ptr->self.open_virtual_port(c->port_name); ret != stdx::error{})
|
||||
{
|
||||
*out = nullptr;
|
||||
delete ptr;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto port = reinterpret_cast<const libremidi::output_port*>(c->in_port);
|
||||
if (auto ret = ptr->self.open_port(*port); ret != stdx::error{})
|
||||
{
|
||||
*out = nullptr;
|
||||
delete ptr;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_is_connected(const libremidi_midi_out_handle* out)
|
||||
{
|
||||
if (!out)
|
||||
return -EINVAL;
|
||||
return out->self.is_port_connected() ? 1 : 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_send_message(
|
||||
libremidi_midi_out_handle* out, const libremidi_midi1_symbol* msg, size_t sz)
|
||||
{
|
||||
if (!out || !msg || sz > std::numeric_limits<int32_t>::max())
|
||||
return -EINVAL;
|
||||
|
||||
auto res = out->self.send_message(msg, sz);
|
||||
return res != stdx::error{} ? -EIO : 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_send_ump(libremidi_midi_out_handle* out, const libremidi_midi2_symbol* msg, size_t sz)
|
||||
{
|
||||
if (!out || !msg || sz > std::numeric_limits<int32_t>::max())
|
||||
return -EINVAL;
|
||||
|
||||
auto res = out->self.send_ump(msg, sz);
|
||||
return res != stdx::error{} ? -EIO : 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_schedule_message(
|
||||
libremidi_midi_out_handle* out, int64_t ts, const libremidi_midi1_symbol* msg, size_t sz)
|
||||
{
|
||||
if (!out || !msg || sz > std::numeric_limits<int32_t>::max())
|
||||
return -EINVAL;
|
||||
|
||||
auto res = out->self.schedule_message(ts, msg, sz);
|
||||
return res != stdx::error{} ? -EIO : 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_schedule_ump(
|
||||
libremidi_midi_out_handle* out, int64_t ts, const libremidi_midi2_symbol* msg, size_t sz)
|
||||
{
|
||||
if (!out || !msg || sz > std::numeric_limits<int32_t>::max())
|
||||
return -EINVAL;
|
||||
|
||||
auto res = out->self.schedule_ump(ts, msg, sz);
|
||||
return res != stdx::error{} ? -EIO : 0;
|
||||
}
|
||||
|
||||
int libremidi_midi_out_free(libremidi_midi_out_handle* ptr)
|
||||
{
|
||||
delete ptr;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user