upgrade to libremidi 5.1, raylib and raygui latest
This commit is contained in:
@@ -7,8 +7,193 @@
|
||||
#include <libremidi/error.hpp>
|
||||
#include <libremidi/message.hpp>
|
||||
#include <libremidi/ump.hpp>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
static inline void cmidi2_reverse(int64_t v, cmidi2_ump* output)
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t u[2];
|
||||
int64_t i;
|
||||
} e0, e1;
|
||||
e0.i = v;
|
||||
e1.u[0] = e0.u[1];
|
||||
e1.u[1] = e0.u[0];
|
||||
memcpy(output, &e1, 8);
|
||||
}
|
||||
|
||||
static inline auto u7_to_u16(uint8_t in) -> uint16_t
|
||||
{
|
||||
static constexpr auto ratio = float(std::numeric_limits<uint16_t>::max()) / 127.f;
|
||||
return std::clamp(std::round(in * ratio), 0.f, float(std::numeric_limits<uint16_t>::max()));
|
||||
};
|
||||
|
||||
static inline auto u7_to_u32(uint8_t in) -> uint32_t
|
||||
{
|
||||
static constexpr auto ratio = double(std::numeric_limits<uint32_t>::max()) / 127.;
|
||||
return std::clamp(std::round(in * ratio), 0., double(std::numeric_limits<uint32_t>::max()));
|
||||
};
|
||||
|
||||
static inline auto u16_to_u32(uint16_t in) -> uint32_t
|
||||
{
|
||||
static constexpr auto ratio = double(std::numeric_limits<uint32_t>::max())
|
||||
/ double(std::numeric_limits<uint16_t>::max());
|
||||
return std::clamp(std::round(in * ratio), 0., double(std::numeric_limits<uint32_t>::max()));
|
||||
};
|
||||
|
||||
static inline bool
|
||||
cmidi2_midi1_channel_voice_to_midi2(const uint8_t* bytes, std::size_t sz, cmidi2_ump* output)
|
||||
{
|
||||
if (sz < 2)
|
||||
return false;
|
||||
if (sz > 3)
|
||||
return false;
|
||||
const auto status = libremidi::message_type(bytes[0] & 0xF0);
|
||||
const int channel = bytes[0] & 0x0F;
|
||||
const int group = 0;
|
||||
switch (status)
|
||||
{
|
||||
case libremidi::message_type::NOTE_OFF: {
|
||||
const int64_t msg
|
||||
= cmidi2_ump_midi2_note_off(group, channel, bytes[1], 0, u7_to_u16(bytes[2]), 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::NOTE_ON: {
|
||||
const int64_t msg
|
||||
= cmidi2_ump_midi2_note_on(group, channel, bytes[1], 0, u7_to_u16(bytes[2]), 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::POLY_PRESSURE: {
|
||||
const int64_t msg = cmidi2_ump_midi2_paf(group, channel, bytes[1], u7_to_u32(bytes[2]));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::CONTROL_CHANGE: {
|
||||
const int64_t msg = cmidi2_ump_midi2_cc(group, channel, bytes[1], u7_to_u32(bytes[2]));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::PROGRAM_CHANGE: {
|
||||
const int64_t msg = cmidi2_ump_midi2_program(group, channel, 0, bytes[1], 0, 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::AFTERTOUCH: {
|
||||
const int64_t msg = cmidi2_ump_midi2_caf(group, channel, u7_to_u32(bytes[1]));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case libremidi::message_type::PITCH_BEND: {
|
||||
const auto pb = bytes[1] + bytes[2] * 0x80;
|
||||
const int64_t msg = cmidi2_ump_midi2_pitch_bend_direct(group, channel, u16_to_u32(pb));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
cmidi2_ump_upgrade_midi1_channel_voice_to_midi2(const cmidi2_ump* input, cmidi2_ump* output)
|
||||
{
|
||||
if (cmidi2_ump_get_message_type(input) != CMIDI2_MESSAGE_TYPE_MIDI_1_CHANNEL)
|
||||
return false;
|
||||
|
||||
const auto group = cmidi2_ump_get_group(input);
|
||||
const auto channel = cmidi2_ump_get_channel(input);
|
||||
const auto status = cmidi2_ump_get_status_code(input);
|
||||
const auto b1 = cmidi2_ump_get_midi1_byte2(input);
|
||||
const auto b2 = cmidi2_ump_get_midi1_byte3(input);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
// Not in midi 1:
|
||||
case CMIDI2_STATUS_PER_NOTE_RCC:
|
||||
case CMIDI2_STATUS_PER_NOTE_ACC:
|
||||
case CMIDI2_STATUS_RPN:
|
||||
case CMIDI2_STATUS_NRPN:
|
||||
case CMIDI2_STATUS_RELATIVE_RPN:
|
||||
case CMIDI2_STATUS_RELATIVE_NRPN:
|
||||
case CMIDI2_STATUS_PER_NOTE_PITCH_BEND:
|
||||
case CMIDI2_STATUS_PER_NOTE_MANAGEMENT:
|
||||
return false;
|
||||
|
||||
case CMIDI2_STATUS_NOTE_OFF: {
|
||||
const int64_t msg = cmidi2_ump_midi2_note_off(group, channel, b1, 0, u7_to_u16(b2), 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_NOTE_ON: {
|
||||
const int64_t msg = cmidi2_ump_midi2_note_on(group, channel, b1, 0, u7_to_u16(b2), 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_PAF: {
|
||||
const int64_t msg = cmidi2_ump_midi2_paf(group, channel, b1, u7_to_u32(b2));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_CC: {
|
||||
int64_t msg = cmidi2_ump_midi2_cc(group, channel, b1, u7_to_u32(b2));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_PROGRAM: {
|
||||
const int64_t msg = cmidi2_ump_midi2_program(group, channel, 0, b1, 0, 0);
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_CAF: {
|
||||
const int64_t msg = cmidi2_ump_midi2_caf(group, channel, u7_to_u32(b1));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
case CMIDI2_STATUS_PITCH_BEND: {
|
||||
const auto pb = b1 + b2 * 0x80;
|
||||
const int64_t msg = cmidi2_ump_midi2_pitch_bend_direct(group, channel, u16_to_u32(pb));
|
||||
cmidi2_reverse(msg, output);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace libremidi
|
||||
{
|
||||
static inline libremidi::message midi1_from_ump(libremidi::ump u)
|
||||
{
|
||||
libremidi::message ret;
|
||||
ret.bytes.resize(4);
|
||||
if (auto n = cmidi2_convert_single_ump_to_midi1((uint8_t*)ret.bytes.data(), 4, u.data))
|
||||
{
|
||||
ret.timestamp = u.timestamp;
|
||||
ret.bytes.resize(n);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.bytes.clear();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline libremidi::ump ump_from_midi1(libremidi::message u)
|
||||
{
|
||||
libremidi::ump ret;
|
||||
if (!u.bytes.empty())
|
||||
{
|
||||
ret.timestamp = u.timestamp;
|
||||
cmidi2_midi1_channel_voice_to_midi2(u.bytes.data(), u.bytes.size(), ret.data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct midi1_to_midi2
|
||||
{
|
||||
stdx::error
|
||||
@@ -20,11 +205,31 @@ struct midi1_to_midi2
|
||||
context.ump = ump;
|
||||
context.ump_num_bytes = sizeof(ump);
|
||||
context.ump_proceeded_bytes = 0;
|
||||
context.skip_delta_time = true;
|
||||
|
||||
if (auto res = cmidi2_convert_midi1_to_ump(&context); res != CMIDI2_CONVERSION_RESULT_OK)
|
||||
return std::errc::invalid_argument;
|
||||
|
||||
return on_ump(context.ump, context.ump_proceeded_bytes / 4, timestamp);
|
||||
switch (cmidi2_convert_midi1_to_ump(&context))
|
||||
{
|
||||
case CMIDI2_CONVERSION_RESULT_OK: {
|
||||
if (auto n = context.ump_proceeded_bytes; n > 0)
|
||||
return on_ump(context.ump, context.ump_proceeded_bytes / 4, timestamp);
|
||||
else
|
||||
return std::errc::operation_not_supported;
|
||||
}
|
||||
case CMIDI2_CONVERSION_RESULT_OUT_OF_SPACE:
|
||||
return std::errc::no_buffer_space;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_SYSEX:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_DTE_SEQUENCE:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_STATUS:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INCOMPLETE_SYSEX7:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_INPUT:
|
||||
return std::errc::invalid_argument;
|
||||
default:
|
||||
return std::errc::operation_not_supported;
|
||||
}
|
||||
}
|
||||
|
||||
cmidi2_midi_conversion_context context = [] {
|
||||
@@ -32,20 +237,45 @@ struct midi1_to_midi2
|
||||
cmidi2_midi_conversion_context_initialize(&tmp);
|
||||
return tmp;
|
||||
}();
|
||||
|
||||
uint32_t ump[65536 / 4];
|
||||
};
|
||||
|
||||
struct midi2_to_midi1
|
||||
{
|
||||
stdx::error
|
||||
convert(const uint32_t* message, std::size_t /* size */, int64_t timestamp, auto on_midi)
|
||||
stdx::error convert(const uint32_t* message, std::size_t size, int64_t timestamp, auto on_midi)
|
||||
{
|
||||
auto n
|
||||
= cmidi2_convert_single_ump_to_midi1(midi, sizeof(midi), const_cast<uint32_t*>(message));
|
||||
if (n > 0)
|
||||
return on_midi(midi, n, timestamp);
|
||||
else
|
||||
return std::errc::no_buffer_space;
|
||||
context.midi1 = static_cast<unsigned char*>(midi);
|
||||
context.midi1_num_bytes = sizeof(midi);
|
||||
context.midi1_proceeded_bytes = 0;
|
||||
context.ump = const_cast<uint32_t*>(message);
|
||||
context.ump_num_bytes = size * sizeof(uint32_t);
|
||||
context.ump_proceeded_bytes = 0;
|
||||
context.skip_delta_time = true;
|
||||
|
||||
switch (cmidi2_convert_ump_to_midi1(&context))
|
||||
{
|
||||
case CMIDI2_CONVERSION_RESULT_OK: {
|
||||
if (auto n = context.midi1_proceeded_bytes; n > 0)
|
||||
return on_midi(midi, n, timestamp);
|
||||
else
|
||||
return std::errc::operation_not_supported;
|
||||
}
|
||||
case CMIDI2_CONVERSION_RESULT_OUT_OF_SPACE:
|
||||
return std::errc::no_buffer_space;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_SYSEX:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_DTE_SEQUENCE:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_STATUS:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INCOMPLETE_SYSEX7:
|
||||
return std::errc::invalid_argument;
|
||||
case CMIDI2_CONVERSION_RESULT_INVALID_INPUT:
|
||||
return std::errc::invalid_argument;
|
||||
default:
|
||||
return std::errc::operation_not_supported;
|
||||
}
|
||||
}
|
||||
|
||||
cmidi2_midi_conversion_context context = [] {
|
||||
@@ -53,6 +283,7 @@ struct midi2_to_midi1
|
||||
cmidi2_midi_conversion_context_initialize(&tmp);
|
||||
return tmp;
|
||||
}();
|
||||
|
||||
uint8_t midi[65536];
|
||||
};
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <libremidi/cmidi2.hpp>
|
||||
#include <libremidi/detail/conversion.hpp>
|
||||
#include <libremidi/detail/midi_in.hpp>
|
||||
|
||||
#include <libremidi/cmidi2.hpp>
|
||||
#include <cmath>
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cinttypes>
|
||||
#include <span>
|
||||
|
||||
namespace libremidi
|
||||
@@ -107,12 +109,12 @@ struct input_state_machine : input_state_machine_base<input_configuration>
|
||||
{
|
||||
message.bytes.clear();
|
||||
message.timestamp = {};
|
||||
state = main;
|
||||
m_state = main;
|
||||
}
|
||||
|
||||
bool has_finished_sysex(std::span<const uint8_t> bytes) const noexcept
|
||||
{
|
||||
return (((bytes.front() == 0xF0) || (state == in_sysex)) && (bytes.back() == 0xF7));
|
||||
return (((bytes.front() == 0xF0) || (m_state == in_sysex)) && (bytes.back() == 0xF7));
|
||||
}
|
||||
|
||||
// Function to process a byte stream which may contain multiple successive
|
||||
@@ -139,22 +141,22 @@ private:
|
||||
void on_bytes_multi_segmented(
|
||||
const message_callback& cb, std::span<const uint8_t> bytes, int64_t timestamp)
|
||||
{
|
||||
int64_t nBytes = bytes.size();
|
||||
int64_t iByte = 0;
|
||||
int64_t n_bytes = bytes.size();
|
||||
int64_t i_byte = 0;
|
||||
|
||||
const bool finished_sysex = has_finished_sysex(bytes);
|
||||
switch (state)
|
||||
switch (m_state)
|
||||
{
|
||||
case in_sysex: {
|
||||
return on_continue_sysex(cb, bytes, finished_sysex);
|
||||
}
|
||||
case main: {
|
||||
while (iByte < nBytes)
|
||||
while (i_byte < n_bytes)
|
||||
{
|
||||
int64_t size = 1;
|
||||
// We are expecting that the next byte in the packet is a status
|
||||
// byte.
|
||||
const auto status = bytes[iByte];
|
||||
const auto status = bytes[i_byte];
|
||||
if (!(status & 0x80))
|
||||
break;
|
||||
|
||||
@@ -170,17 +172,17 @@ private:
|
||||
if (configuration.ignore_sysex)
|
||||
{
|
||||
size = 0;
|
||||
iByte = nBytes;
|
||||
i_byte = n_bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
size = nBytes - iByte;
|
||||
size = n_bytes - i_byte;
|
||||
}
|
||||
|
||||
if (bytes[nBytes - 1] != 0xF7)
|
||||
if (bytes[n_bytes - 1] != 0xF7)
|
||||
{
|
||||
// We know per CoreMIDI API there can't be anything else in this packet
|
||||
state = in_sysex;
|
||||
m_state = in_sysex;
|
||||
message.assign(bytes.begin(), bytes.begin() + size);
|
||||
message.timestamp = timestamp;
|
||||
return;
|
||||
@@ -192,7 +194,7 @@ private:
|
||||
if (configuration.ignore_timing)
|
||||
{
|
||||
size = 0;
|
||||
iByte += 2;
|
||||
i_byte += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -209,7 +211,7 @@ private:
|
||||
if (configuration.ignore_timing)
|
||||
{
|
||||
size = 0;
|
||||
iByte += 1;
|
||||
i_byte += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -222,7 +224,7 @@ private:
|
||||
if (configuration.ignore_sensing)
|
||||
{
|
||||
size = 0;
|
||||
iByte += 1;
|
||||
i_byte += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -238,14 +240,14 @@ private:
|
||||
// Now process the actual bytes of the message
|
||||
if (size > 0)
|
||||
{
|
||||
auto begin = bytes.begin() + iByte;
|
||||
auto begin = bytes.begin() + i_byte;
|
||||
message.assign(begin, begin + size);
|
||||
message.timestamp = timestamp;
|
||||
|
||||
cb(std::move(message));
|
||||
message.clear();
|
||||
|
||||
iByte += size;
|
||||
i_byte += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,7 +258,7 @@ private:
|
||||
const message_callback& cb, std::span<const uint8_t> bytes, bool finished_sysex)
|
||||
{
|
||||
if (finished_sysex)
|
||||
state = main;
|
||||
m_state = main;
|
||||
|
||||
if (configuration.ignore_sysex)
|
||||
{
|
||||
@@ -283,7 +285,7 @@ private:
|
||||
// SYSEX start
|
||||
case 0xF0: {
|
||||
if (!finished_sysex)
|
||||
state = in_sysex;
|
||||
m_state = in_sysex;
|
||||
|
||||
if (!this->configuration.ignore_sysex)
|
||||
{
|
||||
@@ -328,7 +330,7 @@ private:
|
||||
return;
|
||||
|
||||
const bool finished_sysex = has_finished_sysex(bytes);
|
||||
switch (state)
|
||||
switch (m_state)
|
||||
{
|
||||
case in_sysex:
|
||||
return on_continue_sysex(cb, bytes, finished_sysex);
|
||||
@@ -346,7 +348,7 @@ private:
|
||||
{
|
||||
main,
|
||||
in_sysex
|
||||
} state{main};
|
||||
} m_state{main};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -453,6 +455,18 @@ private:
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMIDI2_MESSAGE_TYPE_MIDI_1_CHANNEL: {
|
||||
if (this->configuration.midi1_channel_events_to_midi2)
|
||||
{
|
||||
libremidi::ump msg;
|
||||
cmidi2_ump_upgrade_midi1_channel_voice_to_midi2(bytes.data(), msg.data);
|
||||
msg.timestamp = timestamp;
|
||||
cb(std::move(msg));
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
libremidi::ump msg;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <semaphore>
|
||||
|
||||
struct semaphore_pair_lock
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <libremidi/cmidi2.hpp>
|
||||
#include <libremidi/error.hpp>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
|
||||
namespace libremidi
|
||||
|
||||
Reference in New Issue
Block a user