Skip to content

Commit

Permalink
[c] API improvements and fixes, add timestamps and API info getters
Browse files Browse the repository at this point in the history
  • Loading branch information
jcelerier committed Sep 7, 2024
1 parent f71ee67 commit b495928
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 82 deletions.
1 change: 1 addition & 0 deletions cmake/libremidi.sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ target_sources(libremidi PRIVATE
include/libremidi/reader.cpp
include/libremidi/writer.cpp

include/libremidi/api-c.h
include/libremidi/libremidi-c.h
include/libremidi/libremidi-c.cpp
)
6 changes: 4 additions & 2 deletions examples/c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,15 @@ void on_output_port_found(void* ctx, const libremidi_midi_out_port* port)
e->out_port_count++;
}

void on_midi1_message(void* ctx, const midi1_symbol* msg, size_t len)
void on_midi1_message(
void* ctx, libremidi_timestamp ts, const libremidi_midi1_symbol* msg, size_t len)
{
printf("%#02x %#02x %#02x \n", (int)msg[0], (int)msg[1], (int)msg[2]);
fflush(stdout);
}

void on_midi2_message(void* ctx, const midi2_symbol* msg, size_t len)
void on_midi2_message(
void* ctx, libremidi_timestamp ts, const libremidi_midi2_symbol* msg, size_t len)
{
printf("%#02x %#02x %#02x\n", (int)msg[0], (int)msg[1], (int)msg[2]);
fflush(stdout);
Expand Down
37 changes: 37 additions & 0 deletions include/libremidi/api-c.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#pragma once

#if __cplusplus
extern "C" {
#endif

//! MIDI API specifier arguments.
//! To get information on which feature is supported by each back-end, check their backend file
//! in e.g. backends/winmm.hpp, etc.
typedef enum libremidi_api
{
UNSPECIFIED = 0x0, /*!< Search for a working compiled API. */

// MIDI 1.0 APIs
COREMIDI = 0x1, /*!< macOS CoreMidi API. */
ALSA_SEQ, /*!< Linux ALSA Sequencer API. */
ALSA_RAW, /*!< Linux Raw ALSA API. */
JACK_MIDI, /*!< JACK Low-Latency MIDI Server API. */
WINDOWS_MM, /*!< Microsoft Multimedia MIDI API. */
WINDOWS_UWP, /*!< Microsoft WinRT MIDI API. */
WEBMIDI, /*!< Web MIDI API through Emscripten */
PIPEWIRE, /*!< PipeWire */
KEYBOARD, /*!< Computer keyboard input */

// MIDI 2.0 APIs
ALSA_RAW_UMP = 0x1000, /*!< Raw ALSA API for MIDI 2.0 */
ALSA_SEQ_UMP, /*!< Linux ALSA Sequencer API for MIDI 2.0 */
COREMIDI_UMP, /*!< macOS CoreMidi API for MIDI 2.0. Requires macOS 11+ */
WINDOWS_MIDI_SERVICES, /*!< Windows API for MIDI 2.0. Requires Windows 11 */
KEYBOARD_UMP, /*!< Computer keyboard input */

DUMMY /*!< A compilable but non-functional API. */
} libremidi_api;

#if __cplusplus
}
#endif
26 changes: 2 additions & 24 deletions include/libremidi/api.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include <libremidi/api-c.h>
#include <libremidi/config.hpp>

#include <string_view>
Expand All @@ -9,30 +10,7 @@ namespace libremidi
//! MIDI API specifier arguments.
//! To get information on which feature is supported by each back-end, check their backend file
//! in e.g. backends/winmm.hpp, etc.
enum class API
{
UNSPECIFIED = 0x0, /*!< Search for a working compiled API. */

// MIDI 1.0 APIs
COREMIDI = 0x1, /*!< macOS CoreMidi API. */
ALSA_SEQ, /*!< Linux ALSA Sequencer API. */
ALSA_RAW, /*!< Linux Raw ALSA API. */
JACK_MIDI, /*!< JACK Low-Latency MIDI Server API. */
WINDOWS_MM, /*!< Microsoft Multimedia MIDI API. */
WINDOWS_UWP, /*!< Microsoft WinRT MIDI API. */
WEBMIDI, /*!< Web MIDI API through Emscripten */
PIPEWIRE, /*!< PipeWire */
KEYBOARD, /*!< Computer keyboard input */

// MIDI 2.0 APIs
ALSA_RAW_UMP = 0x1000, /*!< Raw ALSA API for MIDI 2.0 */
ALSA_SEQ_UMP, /*!< Linux ALSA Sequencer API for MIDI 2.0 */
COREMIDI_UMP, /*!< macOS CoreMidi API for MIDI 2.0. Requires macOS 11+ */
WINDOWS_MIDI_SERVICES, /*!< Windows API for MIDI 2.0. Requires Windows 11 */
KEYBOARD_UMP, /*!< Computer keyboard input */

DUMMY /*!< A compilable but non-functional API. */
};
using API = libremidi_api;

/**
* \brief A function to determine the available compiled MIDI 1.0 APIs.
Expand Down
96 changes: 78 additions & 18 deletions include/libremidi/libremidi-c.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// clang-format off
#include <libremidi/libremidi-c.h>
#include <libremidi/libremidi.hpp>
#include <libremidi/backends.hpp>
// clang-format on

#include <cerrno>
#include <cstdlib>
Expand Down Expand Up @@ -36,6 +39,45 @@ static void assign_error_callback(const auto& src, auto& dst)
}

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));
Expand Down Expand Up @@ -218,10 +260,8 @@ int libremidi_midi_in_new(
// Create the MIDI object
switch (c->version)
{
case libremidi_midi_configuration::MIDI1: {
if (!c->on_midi1_message.callback)
return -EINVAL;

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);
Expand All @@ -236,9 +276,20 @@ int libremidi_midi_in_new(
= [cb = c->get_timestamp](int64_t msg) { return cb.callback(cb.context, msg); };
}

conf.on_message = [cb = c->on_midi1_message](const libremidi::message& msg) {
cb.callback(cb.context, msg.bytes.data(), msg.size());
};
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
{
Expand All @@ -252,10 +303,8 @@ int libremidi_midi_in_new(
}
break;
}
case libremidi_midi_configuration::MIDI2: {
if (!c->on_midi1_message.callback)
return -EINVAL;

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);
Expand All @@ -270,9 +319,20 @@ int libremidi_midi_in_new(
= [cb = c->get_timestamp](int64_t msg) { return cb.callback(cb.context, msg); };
}

conf.on_message = [cb = c->on_midi2_message](const libremidi::ump& msg) {
cb.callback(cb.context, msg.data, msg.size());
};
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
{
Expand Down Expand Up @@ -401,7 +461,7 @@ int libremidi_midi_out_is_connected(const libremidi_midi_out_handle* out)
}

int libremidi_midi_out_send_message(
libremidi_midi_out_handle* out, const midi1_symbol* msg, size_t sz)
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;
Expand All @@ -410,7 +470,7 @@ int libremidi_midi_out_send_message(
return res != stdx::error{} ? -EIO : 0;
}

int libremidi_midi_out_send_ump(libremidi_midi_out_handle* out, const midi2_symbol* msg, size_t sz)
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;
Expand All @@ -420,7 +480,7 @@ int libremidi_midi_out_send_ump(libremidi_midi_out_handle* out, const midi2_symb
}

int libremidi_midi_out_schedule_message(
libremidi_midi_out_handle* out, int64_t ts, const midi1_symbol* msg, size_t sz)
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;
Expand All @@ -430,7 +490,7 @@ int libremidi_midi_out_schedule_message(
}

int libremidi_midi_out_schedule_ump(
libremidi_midi_out_handle* out, int64_t ts, const midi2_symbol* msg, size_t sz)
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;
Expand Down
Loading

0 comments on commit b495928

Please sign in to comment.