From bea600a13ad97d48229a80a50f69352c613905f2 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Thu, 5 Mar 2020 17:00:45 +0100 Subject: [PATCH] Pass through getParameter and setParameter --- src/common/communication.h | 33 +++++++++++++++++++++++++++++++-- src/plugin/host-bridge.cpp | 23 ++++++++++++++++------- src/plugin/host-bridge.h | 8 ++++++++ src/wine-host/plugin-bridge.cpp | 26 ++++++++++++++++++++++++++ src/wine-host/plugin-bridge.h | 11 ++++++++++- 5 files changed, 91 insertions(+), 10 deletions(-) diff --git a/src/common/communication.h b/src/common/communication.h index ed29fe26..b268b47a 100644 --- a/src/common/communication.h +++ b/src/common/communication.h @@ -104,8 +104,6 @@ struct EventResult { */ std::optional data; - // TODO: Add missing return value fields; - template void serialize(S& s) { s.value8b(return_value); @@ -114,6 +112,37 @@ struct EventResult { } }; +/** + * Represents a call to either `getParameter` or `setParameter`, depending on + * whether `value` contains a value or not. + */ +struct Parameter { + int32_t index; + std::optional value; + + template + void serialize(S& s) { + s.value4b(index); + s.ext(value, bitsery::ext::StdOptional(), + [](S& s, auto& v) { s.value4b(v); }); + } +}; + +/** + * The result of a `getParameter` or a `setParameter` call. For `setParameter` + * this struct won't contain any values and mostly acts as an acknowledgement + * from the Wine VST host. + */ +struct ParameterResult { + std::optional value; + + template + void serialize(S& s) { + s.ext(value, bitsery::ext::StdOptional(), + [](S& s, auto& v) { s.value4b(v); }); + } +}; + /** * The serialization function for `AEffect` structs. This will s serialize all * of the values but it will not touch any of the pointer fields. That way you diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index 17bc113c..32e9e56d 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -72,6 +72,7 @@ HostBridge::HostBridge(audioMasterCallback host_callback) socket_acceptor(io_context, socket_endpoint), host_vst_dispatch(io_context), vst_host_callback(io_context), + host_vst_parameters(io_context), vst_host_aeffect(io_context), host_callback_function(host_callback), vst_host(find_wine_vst_host(), @@ -84,6 +85,7 @@ HostBridge::HostBridge(audioMasterCallback host_callback) // in the Wine VST host socket_acceptor.accept(host_vst_dispatch); socket_acceptor.accept(vst_host_callback); + socket_acceptor.accept(host_vst_parameters); socket_acceptor.accept(vst_host_aeffect); // Set up all pointers for our `AEffect` struct. We will fill this with data @@ -160,15 +162,22 @@ void HostBridge::process_replacing(AEffect* /*plugin*/, } void HostBridge::set_parameter(AEffect* /*plugin*/, - int32_t /*index*/, - float /*value*/) { - // TODO: Unimplmemented + int32_t index, + float value) { + Parameter request{index, value}; + write_object(host_vst_parameters, request); + + // This should not contain any values and just serve as an acknowledgement + const auto response = read_object(host_vst_parameters); + assert(!response.value.has_value()); } -float HostBridge::get_parameter(AEffect* /*plugin*/, int32_t /*index*/ -) { - // TODO: Unimplmemented - return 0.0f; +float HostBridge::get_parameter(AEffect* /*plugin*/, int32_t index) { + Parameter request{index, std::nullopt}; + write_object(host_vst_parameters, request); + + const auto response = read_object(host_vst_parameters); + return response.value.value(); } /** diff --git a/src/plugin/host-bridge.h b/src/plugin/host-bridge.h index 7156dbc3..e3054515 100644 --- a/src/plugin/host-bridge.h +++ b/src/plugin/host-bridge.h @@ -84,6 +84,14 @@ class HostBridge { // plugin (through the Wine VST host). boost::asio::local::stream_protocol::socket host_vst_dispatch; boost::asio::local::stream_protocol::socket vst_host_callback; + /** + * Used for both `getParameter` and `setParameter` since they mostly + * overlap. + * + * TODO: Verify that these 100% won't be called simultanously since that + * would cause a race condition. + */ + boost::asio::local::stream_protocol::socket host_vst_parameters; /** * This socket only handles updates of the `AEffect` struct instead of diff --git a/src/wine-host/plugin-bridge.cpp b/src/wine-host/plugin-bridge.cpp index b2886d43..f09e0269 100644 --- a/src/wine-host/plugin-bridge.cpp +++ b/src/wine-host/plugin-bridge.cpp @@ -57,6 +57,7 @@ PluginBridge::PluginBridge(std::string plugin_dll_path, socket_endpoint(socket_endpoint_path), host_vst_dispatch(io_context), vst_host_callback(io_context), + host_vst_parameters(io_context), vst_host_aeffect(io_context) { // Got to love these C APIs if (plugin_handle == nullptr) { @@ -86,6 +87,7 @@ PluginBridge::PluginBridge(std::string plugin_dll_path, // in the Linus plugin host_vst_dispatch.connect(socket_endpoint); vst_host_callback.connect(socket_endpoint); + host_vst_parameters.connect(socket_endpoint); vst_host_aeffect.connect(socket_endpoint); // Initialize after communication has been set up We'll try to do the same @@ -117,6 +119,30 @@ PluginBridge::PluginBridge(std::string plugin_dll_path, passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher); } }); + + parameters_handler = std::thread([&]() { + while (true) { + // Both `getParameter` and `setParameter` functions are passed + // through on this socket since they have a lot of overlap. The + // presence of the `value` field tells us which one we're dealing + // with. + auto request = read_object(host_vst_parameters); + if (request.value.has_value()) { + // `setParameter` + plugin->setParameter(plugin, request.index, + request.value.value()); + + ParameterResult response{std::nullopt}; + write_object(host_vst_parameters, response); + } else { + // `getParameter` + float value = plugin->getParameter(plugin, request.index); + + ParameterResult response{value}; + write_object(host_vst_parameters, response); + } + } + }); } void PluginBridge::wait() { diff --git a/src/wine-host/plugin-bridge.h b/src/wine-host/plugin-bridge.h index 040d0334..2f18a59f 100644 --- a/src/wine-host/plugin-bridge.h +++ b/src/wine-host/plugin-bridge.h @@ -77,6 +77,11 @@ class PluginBridge { // plugin (through the Wine VST host). boost::asio::local::stream_protocol::socket host_vst_dispatch; boost::asio::local::stream_protocol::socket vst_host_callback; + /** + * Used for both `getParameter` and `setParameter` since they mostly + * overlap. + */ + boost::asio::local::stream_protocol::socket host_vst_parameters; /** * This socket only handles updates of the `AEffect` struct instead of @@ -89,6 +94,10 @@ class PluginBridge { * The thread that handles dispatch events from the host. */ std::thread dispatch_handler; + /** + * The thread that responds to `getParameter` and `setParameter` requests. + */ + std::thread parameters_handler; - // TODO: Set up all other callback handlers + // TODO: Set up process and processReplacing callback handlers };