From 7305178654082eb163867e5733385c19def681fa Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Tue, 27 Sep 2022 15:12:38 +0200 Subject: [PATCH] Fully implement the state extension --- src/common/serialization/clap.h | 7 +++- src/common/serialization/clap/README.md | 2 +- src/common/serialization/clap/ext/state.h | 1 + src/common/serialization/clap/host.cpp | 4 +- src/common/serialization/clap/host.h | 4 +- src/common/serialization/clap/plugin.cpp | 4 +- src/common/serialization/clap/plugin.h | 4 +- .../bridges/clap-impls/plugin-proxy.cpp | 37 +++++++++++++++++++ src/plugin/bridges/clap-impls/plugin-proxy.h | 8 ++++ src/plugin/bridges/clap.cpp | 15 ++++++++ .../bridges/clap-impls/host-proxy.cpp | 14 +++++++ src/wine-host/bridges/clap-impls/host-proxy.h | 4 ++ src/wine-host/bridges/clap.cpp | 32 ++++++++++++++++ src/wine-host/bridges/clap.h | 1 + 14 files changed, 130 insertions(+), 7 deletions(-) diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h index f0979534..c25c4492 100644 --- a/src/common/serialization/clap.h +++ b/src/common/serialization/clap.h @@ -62,7 +62,9 @@ using ClapMainThreadControlRequest = clap::ext::params::plugin::GetInfo, clap::ext::params::plugin::GetValue, clap::ext::params::plugin::ValueToText, - clap::ext::params::plugin::TextToValue>; + clap::ext::params::plugin::TextToValue, + clap::ext::state::plugin::Save, + clap::ext::state::plugin::Load>; template void serialize(S& s, ClapMainThreadControlRequest& payload) { @@ -152,7 +154,8 @@ using ClapMainThreadCallbackRequest = clap::ext::note_ports::host::SupportedDialects, clap::ext::note_ports::host::Rescan, clap::ext::params::host::Rescan, - clap::ext::params::host::Clear>; + clap::ext::params::host::Clear, + clap::ext::state::host::MarkDirty>; template void serialize(S& s, ClapMainThreadCallbackRequest& payload) { diff --git a/src/common/serialization/clap/README.md b/src/common/serialization/clap/README.md index d8f8eaf0..49a95930 100644 --- a/src/common/serialization/clap/README.md +++ b/src/common/serialization/clap/README.md @@ -26,7 +26,7 @@ Yabridge currently tracks CLAP 1.1.1. The implementation status for CLAP's core | `clap.params` | :heavy_check_mark: | | `clap.posix-fd-support` | :x: Not supported yet | | `clap.render` | :x: Not supported yet | -| `clap.state` | :x: Not supported yet | +| `clap.state` | :heavy_check_mark: | | `clap.tail` | :heavy_check_mark: | | `clap.thread-check` | :x: Not supported yet | | `clap.thread-pool` | :x: Not supported yet | diff --git a/src/common/serialization/clap/ext/state.h b/src/common/serialization/clap/ext/state.h index 866a76f6..7f3a4d6c 100644 --- a/src/common/serialization/clap/ext/state.h +++ b/src/common/serialization/clap/ext/state.h @@ -68,6 +68,7 @@ struct Load { template void serialize(S& s) { s.value8b(instance_id); + s.object(stream); } }; diff --git a/src/common/serialization/clap/host.cpp b/src/common/serialization/clap/host.cpp index a4bf863b..418eac02 100644 --- a/src/common/serialization/clap/host.cpp +++ b/src/common/serialization/clap/host.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include namespace clap { @@ -32,12 +33,13 @@ Host::Host(const clap_host_t& original) url(original.url ? std::optional(original.url) : std::nullopt), version((assert(original.version), original.version)) {} -std::array, 5> SupportedHostExtensions::list() +std::array, 6> SupportedHostExtensions::list() const noexcept { return {std::pair(supports_audio_ports, CLAP_EXT_AUDIO_PORTS), std::pair(supports_latency, CLAP_EXT_LATENCY), std::pair(supports_note_ports, CLAP_EXT_NOTE_PORTS), std::pair(supports_params, CLAP_EXT_PARAMS), + std::pair(supports_state, CLAP_EXT_STATE), std::pair(supports_tail, CLAP_EXT_TAIL)}; } diff --git a/src/common/serialization/clap/host.h b/src/common/serialization/clap/host.h index 4e4996d7..9c9b08ed 100644 --- a/src/common/serialization/clap/host.h +++ b/src/common/serialization/clap/host.h @@ -85,13 +85,14 @@ struct SupportedHostExtensions { bool supports_latency = false; bool supports_note_ports = false; bool supports_params = false; + bool supports_state = false; bool supports_tail = false; /** * Get a list of `` tuples for the supported * extensions. Used during logging. */ - std::array, 5> list() const noexcept; + std::array, 6> list() const noexcept; template void serialize(S& s) { @@ -99,6 +100,7 @@ struct SupportedHostExtensions { s.value1b(supports_latency); s.value1b(supports_note_ports); s.value1b(supports_params); + s.value1b(supports_state); s.value1b(supports_tail); } }; diff --git a/src/common/serialization/clap/plugin.cpp b/src/common/serialization/clap/plugin.cpp index 72d7d163..017aba47 100644 --- a/src/common/serialization/clap/plugin.cpp +++ b/src/common/serialization/clap/plugin.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "version.h" @@ -80,12 +81,13 @@ const clap_plugin_descriptor_t* Descriptor::get() const { return &clap_descriptor; } -std::array, 5> SupportedPluginExtensions::list() +std::array, 6> SupportedPluginExtensions::list() const noexcept { return {std::pair(supports_audio_ports, CLAP_EXT_AUDIO_PORTS), std::pair(supports_latency, CLAP_EXT_LATENCY), std::pair(supports_note_ports, CLAP_EXT_NOTE_PORTS), std::pair(supports_params, CLAP_EXT_PARAMS), + std::pair(supports_state, CLAP_EXT_STATE), std::pair(supports_tail, CLAP_EXT_TAIL)}; } diff --git a/src/common/serialization/clap/plugin.h b/src/common/serialization/clap/plugin.h index 795fba4c..42d96558 100644 --- a/src/common/serialization/clap/plugin.h +++ b/src/common/serialization/clap/plugin.h @@ -118,13 +118,14 @@ struct SupportedPluginExtensions { bool supports_latency = false; bool supports_note_ports = false; bool supports_params = false; + bool supports_state = false; bool supports_tail = false; /** * Get a list of `` tuples for the supported * extensions. Used during logging. */ - std::array, 5> list() const noexcept; + std::array, 6> list() const noexcept; template void serialize(S& s) { @@ -132,6 +133,7 @@ struct SupportedPluginExtensions { s.value1b(supports_latency); s.value1b(supports_note_ports); s.value1b(supports_params); + s.value1b(supports_state); s.value1b(supports_tail); } }; diff --git a/src/plugin/bridges/clap-impls/plugin-proxy.cpp b/src/plugin/bridges/clap-impls/plugin-proxy.cpp index 452c2c39..34760f49 100644 --- a/src/plugin/bridges/clap-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/clap-impls/plugin-proxy.cpp @@ -27,6 +27,8 @@ ClapHostExtensions::ClapHostExtensions(const clap_host& host) noexcept host.get_extension(&host, CLAP_EXT_NOTE_PORTS))), params(static_cast( host.get_extension(&host, CLAP_EXT_PARAMS))), + state(static_cast( + host.get_extension(&host, CLAP_EXT_STATE))), tail(static_cast( host.get_extension(&host, CLAP_EXT_TAIL))) {} @@ -39,6 +41,7 @@ clap::host::SupportedHostExtensions ClapHostExtensions::supported() .supports_latency = latency != nullptr, .supports_note_ports = note_ports != nullptr, .supports_params = params != nullptr, + .supports_state = state != nullptr, .supports_tail = tail != nullptr}; } @@ -83,6 +86,10 @@ clap_plugin_proxy::clap_plugin_proxy(ClapPluginBridge& bridge, .text_to_value = ext_params_text_to_value, .flush = ext_params_flush, }), + ext_state_vtable(clap_plugin_state_t{ + .save = ext_state_save, + .load = ext_state_load, + }), ext_tail_vtable(clap_plugin_tail_t{ .get = ext_tail_get, }), @@ -225,6 +232,9 @@ clap_plugin_proxy::plugin_get_extension(const struct clap_plugin* plugin, } else if (self->supported_extensions_.supports_params && strcmp(id, CLAP_EXT_PARAMS) == 0) { extension_ptr = &self->ext_params_vtable; + } else if (self->supported_extensions_.supports_state && + strcmp(id, CLAP_EXT_STATE) == 0) { + extension_ptr = &self->ext_state_vtable; } else if (self->supported_extensions_.supports_tail && strcmp(id, CLAP_EXT_TAIL) == 0) { extension_ptr = &self->ext_tail_vtable; @@ -436,6 +446,33 @@ clap_plugin_proxy::ext_params_flush(const clap_plugin_t* plugin, clap::ext::params::plugin::Flush{.instance_id = self->instance_id()}); } +bool CLAP_ABI clap_plugin_proxy::ext_state_save(const clap_plugin_t* plugin, + const clap_ostream_t* stream) { + assert(plugin && plugin->plugin_data && stream); + auto self = static_cast(plugin->plugin_data); + + const clap::ext::state::plugin::SaveResponse response = + self->bridge_.send_main_thread_message( + clap::ext::state::plugin::Save{.instance_id = self->instance_id()}); + if (response.result) { + response.result->write_to_stream(*stream); + + return true; + } else { + return false; + } +} + +bool CLAP_ABI clap_plugin_proxy::ext_state_load(const clap_plugin_t* plugin, + const clap_istream_t* stream) { + assert(plugin && plugin->plugin_data && stream); + auto self = static_cast(plugin->plugin_data); + + return self->bridge_.send_main_thread_message( + clap::ext::state::plugin::Load{.instance_id = self->instance_id(), + .stream = *stream}); +} + uint32_t CLAP_ABI clap_plugin_proxy::ext_tail_get(const clap_plugin_t* plugin) { assert(plugin && plugin->plugin_data); auto self = static_cast(plugin->plugin_data); diff --git a/src/plugin/bridges/clap-impls/plugin-proxy.h b/src/plugin/bridges/clap-impls/plugin-proxy.h index 117e7c36..99503e86 100644 --- a/src/plugin/bridges/clap-impls/plugin-proxy.h +++ b/src/plugin/bridges/clap-impls/plugin-proxy.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +65,7 @@ struct ClapHostExtensions { const clap_host_latency_t* latency = nullptr; const clap_host_note_ports_t* note_ports = nullptr; const clap_host_params_t* params = nullptr; + const clap_host_state_t* state = nullptr; const clap_host_tail_t* tail = nullptr; }; @@ -216,6 +218,11 @@ class clap_plugin_proxy { const clap_input_events_t* in, const clap_output_events_t* out); + static bool CLAP_ABI ext_state_save(const clap_plugin_t* plugin, + const clap_ostream_t* stream); + static bool CLAP_ABI ext_state_load(const clap_plugin_t* plugin, + const clap_istream_t* stream); + static uint32_t CLAP_ABI ext_tail_get(const clap_plugin_t* plugin); private: @@ -248,6 +255,7 @@ class clap_plugin_proxy { const clap_plugin_latency_t ext_latency_vtable; const clap_plugin_note_ports_t ext_note_ports_vtable; const clap_plugin_params_t ext_params_vtable; + const clap_plugin_state_t ext_state_vtable; const clap_plugin_tail_t ext_tail_vtable; /** diff --git a/src/plugin/bridges/clap.cpp b/src/plugin/bridges/clap.cpp index 384501ad..9aaa97b0 100644 --- a/src/plugin/bridges/clap.cpp +++ b/src/plugin/bridges/clap.cpp @@ -195,6 +195,21 @@ ClapPluginBridge::ClapPluginBridge(const ghc::filesystem::path& plugin_path) return Ack{}; }, + [&](const clap::ext::state::host::MarkDirty& request) + -> clap::ext::state::host::MarkDirty::Response { + const auto& [plugin_proxy, _] = + get_proxy(request.owner_instance_id); + + plugin_proxy + .run_on_main_thread( + [&, host = plugin_proxy.host_, + state = plugin_proxy.host_extensions_.state]() { + state->mark_dirty(host); + }) + .wait(); + + return Ack{}; + }, }); }); } diff --git a/src/wine-host/bridges/clap-impls/host-proxy.cpp b/src/wine-host/bridges/clap-impls/host-proxy.cpp index a118dce8..f9544b06 100644 --- a/src/wine-host/bridges/clap-impls/host-proxy.cpp +++ b/src/wine-host/bridges/clap-impls/host-proxy.cpp @@ -60,6 +60,9 @@ clap_host_proxy::clap_host_proxy(ClapBridge& bridge, .clear = ext_params_clear, .request_flush = ext_params_request_flush, }), + ext_state_vtable(clap_host_state_t{ + .mark_dirty = ext_state_mark_dirty, + }), ext_tail_vtable(clap_host_tail_t{ .changed = ext_tail_changed, }) {} @@ -83,6 +86,9 @@ clap_host_proxy::host_get_extension(const struct clap_host* host, } else if (self->supported_extensions_.supports_params && strcmp(extension_id, CLAP_EXT_PARAMS) == 0) { extension_ptr = &self->ext_params_vtable; + } else if (self->supported_extensions_.supports_state && + strcmp(extension_id, CLAP_EXT_STATE) == 0) { + extension_ptr = &self->ext_state_vtable; } else if (self->supported_extensions_.supports_tail && strcmp(extension_id, CLAP_EXT_TAIL) == 0) { extension_ptr = &self->ext_tail_vtable; @@ -222,6 +228,14 @@ clap_host_proxy::ext_params_request_flush(const clap_host_t* host) { self->owner_instance_id()}); } +void CLAP_ABI clap_host_proxy::ext_state_mark_dirty(const clap_host_t* host) { + assert(host && host->host_data); + auto self = static_cast(host->host_data); + + self->bridge_.send_main_thread_message(clap::ext::state::host::MarkDirty{ + .owner_instance_id = self->owner_instance_id()}); +} + void CLAP_ABI clap_host_proxy::ext_tail_changed(const clap_host_t* host) { assert(host && host->host_data); auto self = static_cast(host->host_data); diff --git a/src/wine-host/bridges/clap-impls/host-proxy.h b/src/wine-host/bridges/clap-impls/host-proxy.h index cb60e98d..080d50d1 100644 --- a/src/wine-host/bridges/clap-impls/host-proxy.h +++ b/src/wine-host/bridges/clap-impls/host-proxy.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -95,6 +96,8 @@ class clap_host_proxy { clap_param_clear_flags flags); static void CLAP_ABI ext_params_request_flush(const clap_host_t* host); + static void CLAP_ABI ext_state_mark_dirty(const clap_host_t* host); + static void CLAP_ABI ext_tail_changed(const clap_host_t* host); private: @@ -116,6 +119,7 @@ class clap_host_proxy { const clap_host_latency_t ext_latency_vtable; const clap_host_note_ports_t ext_note_ports_vtable; const clap_host_params_t ext_params_vtable; + const clap_host_state_t ext_state_vtable; const clap_host_tail_t ext_tail_vtable; /** diff --git a/src/wine-host/bridges/clap.cpp b/src/wine-host/bridges/clap.cpp index 3ed36da2..4d808cd1 100644 --- a/src/wine-host/bridges/clap.cpp +++ b/src/wine-host/bridges/clap.cpp @@ -35,6 +35,8 @@ ClapPluginExtensions::ClapPluginExtensions(const clap_plugin& plugin) noexcept plugin.get_extension(&plugin, CLAP_EXT_NOTE_PORTS))), params(static_cast( plugin.get_extension(&plugin, CLAP_EXT_PARAMS))), + state(static_cast( + plugin.get_extension(&plugin, CLAP_EXT_STATE))), tail(static_cast( plugin.get_extension(&plugin, CLAP_EXT_TAIL))) {} @@ -47,6 +49,7 @@ clap::plugin::SupportedPluginExtensions ClapPluginExtensions::supported() .supports_latency = latency != nullptr, .supports_note_ports = note_ports != nullptr, .supports_params = params != nullptr, + .supports_state = state != nullptr, .supports_tail = tail != nullptr}; } @@ -454,6 +457,35 @@ void ClapBridge::run() { .result = std::nullopt}; } }, + [&](clap::ext::state::plugin::Save& request) + -> clap::ext::state::plugin::Save::Response { + const auto& [instance, _] = get_instance(request.instance_id); + + return main_context_ + .run_in_context([&, plugin = instance.plugin.get(), + state = instance.extensions.state]() { + clap::stream::Stream stream{}; + if (state->save(plugin, stream.ostream())) { + return clap::ext::state::plugin::SaveResponse{ + .result = std::move(stream)}; + } else { + return clap::ext::state::plugin::SaveResponse{ + .result = std::nullopt}; + } + }) + .get(); + }, + [&](clap::ext::state::plugin::Load& request) + -> clap::ext::state::plugin::Load::Response { + const auto& [instance, _] = get_instance(request.instance_id); + + return main_context_ + .run_in_context([&, plugin = instance.plugin.get(), + state = instance.extensions.state]() { + return state->load(plugin, request.stream.istream()); + }) + .get(); + }, }); } diff --git a/src/wine-host/bridges/clap.h b/src/wine-host/bridges/clap.h index 17f1ee7f..3dbe8411 100644 --- a/src/wine-host/bridges/clap.h +++ b/src/wine-host/bridges/clap.h @@ -70,6 +70,7 @@ struct ClapPluginExtensions { const clap_plugin_latency_t* latency = nullptr; const clap_plugin_note_ports_t* note_ports = nullptr; const clap_plugin_params_t* params = nullptr; + const clap_plugin_state_t* state = nullptr; const clap_plugin_tail_t* tail = nullptr; };