diff --git a/src/common/serialization/clap/events.cpp b/src/common/serialization/clap/events.cpp new file mode 100644 index 00000000..2dca513e --- /dev/null +++ b/src/common/serialization/clap/events.cpp @@ -0,0 +1,197 @@ +// yabridge: a Wine plugin bridge +// Copyright (C) 2020-2022 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "events.h" + +namespace clap { +namespace events { + +std::optional Event::parse(const clap_event_header_t& generic_event) { + std::optional payload; + if (generic_event.space_id == CLAP_CORE_EVENT_SPACE_ID) { + switch (generic_event.type) { + case CLAP_EVENT_NOTE_ON: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Note{ + .event_type = payload::NoteEventType::On, + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .velocity = event.velocity, + }; + } break; + case CLAP_EVENT_NOTE_OFF: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Note{ + .event_type = payload::NoteEventType::Off, + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .velocity = event.velocity, + }; + } break; + case CLAP_EVENT_NOTE_CHOKE: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Note{ + .event_type = payload::NoteEventType::Choke, + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .velocity = event.velocity, + }; + } break; + case CLAP_EVENT_NOTE_END: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Note{ + .event_type = payload::NoteEventType::End, + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .velocity = event.velocity, + }; + } break; + case CLAP_EVENT_NOTE_EXPRESSION: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::NoteExpression{ + .expression_id = event.expression_id, + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .value = event.value, + }; + } break; + case CLAP_EVENT_PARAM_VALUE: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::ParamValue{ + .param_id = event.param_id, + .cookie = static_cast( + reinterpret_cast(event.cookie)), + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .value = event.value, + }; + } break; + case CLAP_EVENT_PARAM_MOD: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::ParamMod{ + .param_id = event.param_id, + .cookie = static_cast( + reinterpret_cast(event.cookie)), + .note_id = event.note_id, + .port_index = event.port_index, + .channel = event.channel, + .key = event.key, + .amount = event.amount, + }; + } break; + case CLAP_EVENT_PARAM_GESTURE_BEGIN: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::ParamGesture{ + .gesture_type = payload::ParamGestureType::Begin, + .param_id = event.param_id, + }; + } break; + case CLAP_EVENT_PARAM_GESTURE_END: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::ParamGesture{ + .gesture_type = payload::ParamGestureType::End, + .param_id = event.param_id, + }; + } break; + case CLAP_EVENT_TRANSPORT: { + const auto& event = + reinterpret_cast( + generic_event); + payload = payload::Transport{ + .flags = event.flags, + .song_pos_beats = event.song_pos_beats, + .song_pos_seconds = event.song_pos_seconds, + .tempo = event.tempo, + .tempo_inc = event.tempo_inc, + .loop_start_beats = event.loop_start_beats, + .loop_end_beats = event.loop_end_beats, + .loop_start_seconds = event.loop_start_seconds, + .loop_end_seconds = event.loop_end_seconds, + .bar_start = event.bar_start, + .bar_number = event.bar_number, + .tsig_num = event.tsig_num, + .tsig_denom = event.tsig_denom, + }; + } break; + case CLAP_EVENT_MIDI: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Midi{ + .port_index = event.port_index, + .data{event.data[0], event.data[1], event.data[2]}, + }; + } break; + case CLAP_EVENT_MIDI_SYSEX: { + const auto& event = + reinterpret_cast( + generic_event); + assert(event.buffer); + payload = payload::MidiSysex{ + .port_index = event.port_index, + .buffer = + std::string(reinterpret_cast(event.buffer), + event.size), + }; + } break; + case CLAP_EVENT_MIDI2: { + const auto& event = + reinterpret_cast(generic_event); + payload = payload::Midi2{ + .port_index = event.port_index, + .data{event.data[0], event.data[1], event.data[2], + event.data[3]}, + }; + } break; + } + } + + if (payload) { + return Event{.time = generic_event.time, + .flags = generic_event.flags, + .payload = std::move(*payload)}; + } else { + return std::nullopt; + } +} + +} // namespace events +} // namespace clap diff --git a/src/common/serialization/clap/events.h b/src/common/serialization/clap/events.h index f93d1bbc..91a396bd 100644 --- a/src/common/serialization/clap/events.h +++ b/src/common/serialization/clap/events.h @@ -268,6 +268,12 @@ struct Midi2 { * reconstructed back to a `clap_event_header`. */ struct alignas(16) Event { + /** + * Parse a CLAP event. Returns a nullopt if yabridge does not support the + * event. + */ + static std::optional parse(const clap_event_header_t& generic_event); + /** * The time from the event header. */ diff --git a/src/plugin/meson.build b/src/plugin/meson.build index f8ad36e5..3dfac8a0 100644 --- a/src/plugin/meson.build +++ b/src/plugin/meson.build @@ -80,6 +80,7 @@ if with_clap '../common/serialization/clap/ext/audio-ports.cpp', '../common/serialization/clap/ext/note-ports.cpp', '../common/serialization/clap/ext/params.cpp', + '../common/serialization/clap/events.cpp', '../common/serialization/clap/host.cpp', '../common/serialization/clap/plugin.cpp', '../common/serialization/clap/stream.cpp', diff --git a/src/wine-host/meson.build b/src/wine-host/meson.build index d8f9f550..5926f158 100644 --- a/src/wine-host/meson.build +++ b/src/wine-host/meson.build @@ -83,6 +83,7 @@ if with_clap '../common/serialization/clap/ext/audio-ports.cpp', '../common/serialization/clap/ext/note-ports.cpp', '../common/serialization/clap/ext/params.cpp', + '../common/serialization/clap/events.cpp', '../common/serialization/clap/host.cpp', '../common/serialization/clap/plugin.cpp', '../common/serialization/clap/stream.cpp',