From 84647063363448951cdda73ccf2ab63f09f5f472 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Wed, 11 Mar 2020 16:33:44 +0100 Subject: [PATCH] Handle AEffect object updates --- README.md | 2 -- src/common/events.h | 29 ++++++++++++++++++++++++++++- src/common/logging.cpp | 1 + src/common/serialization.h | 9 +++++---- src/wine-host/plugin-bridge.cpp | 22 ++++++++++++++-------- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 94125214..f2c4734c 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,6 @@ There are a few things that should be done before making this public, including: - Implement missing features: - GUIs. - - `AEffect` updates. Apparently whenever that happens the plugin should call - `audioMasterIOChanged`, so that would be easy to handle. - The Wine process seems to segfault on shutdown even though it doesn't seem to cause any other problems. This can probably be fixed by catching exceptions thrown in the threads caused by sockets being closed. It's diff --git a/src/common/events.h b/src/common/events.h index c6d8016f..c4427d47 100644 --- a/src/common/events.h +++ b/src/common/events.h @@ -186,11 +186,12 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket, [&](const std::string& s) -> void* { return const_cast(s.c_str()); }, + [&](const AEffect&) -> void* { return nullptr; }, [&](DynamicVstEvents& events) -> void* { return &events.as_c_events(); }, [&](WantsChunkBuffer&) -> void* { return string_buffer.data(); }, - [&](WantsVstTimeInfo&) -> void* { return nullptr; }, + [&](const WantsVstTimeInfo&) -> void* { return nullptr; }, [&](WantsString&) -> void* { return string_buffer.data(); }}, event.payload); @@ -203,6 +204,32 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket, // report some data back? const auto response_data = std::visit( overload{[&](auto) -> EventResposnePayload { return std::monostate(); }, + [&](const AEffect& updated_plugin) -> EventResposnePayload { + // This is a bit of a special case! Instead of writing some + // return value, we will update values on the native VST + // plugin's `AEffect` object. This is triggered by the + // `audioMasterIOChanged` callback from the hsoted VST + // plugin. + + // These are the same fields written by bitsery in the + // initialization of `HostBridge`. I can't think of a way t + // oreuse the serializer without first having to serialize + // `updated_plugin` first though. + plugin->magic = updated_plugin.magic; + plugin->numPrograms = updated_plugin.numPrograms; + plugin->numParams = updated_plugin.numParams; + plugin->numInputs = updated_plugin.numInputs; + plugin->numOutputs = updated_plugin.numOutputs; + plugin->flags = updated_plugin.flags; + plugin->initialDelay = updated_plugin.initialDelay; + plugin->empty3a = updated_plugin.empty3a; + plugin->empty3b = updated_plugin.empty3b; + plugin->unkown_float = updated_plugin.unkown_float; + plugin->uniqueID = updated_plugin.uniqueID; + plugin->version = updated_plugin.version; + + return std::monostate(); + }, [&](WantsChunkBuffer&) -> EventResposnePayload { // In this case the plugin will have written its data // stored in an array to which a pointer is stored in diff --git a/src/common/logging.cpp b/src/common/logging.cpp index 1bd95081..6dac0676 100644 --- a/src/common/logging.cpp +++ b/src/common/logging.cpp @@ -167,6 +167,7 @@ void Logger::log_event(bool is_dispatch, message << "<" << s.size() << " bytes>"; } }, + [&](const AEffect&) { message << ""; }, [&](const DynamicVstEvents& events) { message << "<" << events.events.size() << " midi_events>"; }, diff --git a/src/common/serialization.h b/src/common/serialization.h index e2ba077f..17deb906 100644 --- a/src/common/serialization.h +++ b/src/common/serialization.h @@ -180,10 +180,9 @@ struct WantsString {}; * clarity's sake. * * - Specific data structures from `aeffextx.h`. For instance an event with the - * opcode `effProcessEvents` comes with a struct containing a list of midi - * events. - * - * TODO: A lot of these are still missing + * opcode `effProcessEvents` the hosts passes a `VstEvents` struct containing + * midi events, and `audioMasterIOChanged` lets the host know that the + * `AEffect` struct has changed. * * - Some empty buffer for the plugin to write its own data to, for instance for * a plugin to report its name or the label for a certain parameter. There are @@ -196,6 +195,7 @@ struct WantsString {}; */ using EventPayload = std::variant read(const int opcode, const intptr_t value, @@ -219,6 +218,12 @@ class HostCallbackDataConverter : DefaultDataConverter { case audioMasterGetTime: return WantsVstTimeInfo{}; break; + case audioMasterIOChanged: + // This is a helpful event that indicates that the VST plugin's + // `AEffect` struct has changed. Writing these results back is + // done inside of `passthrough_event`. + return AEffect(*plugin); + break; default: return DefaultDataConverter::read(opcode, value, data); break; @@ -230,7 +235,7 @@ class HostCallbackDataConverter : DefaultDataConverter { case audioMasterGetTime: // Write the returned `VstTimeInfo` struct into a field and make // the function return a poitner to it in the function below - time = std::get(response.payload); + time_info = std::get(response.payload); break; default: DefaultDataConverter::write(opcode, data, response); @@ -252,7 +257,8 @@ class HostCallbackDataConverter : DefaultDataConverter { } private: - VstTimeInfo& time; + AEffect* plugin; + VstTimeInfo& time_info; }; intptr_t PluginBridge::host_callback(AEffect* /*plugin*/, @@ -261,7 +267,7 @@ intptr_t PluginBridge::host_callback(AEffect* /*plugin*/, intptr_t value, void* data, float option) { - HostCallbackDataConverter converter(time_info); + HostCallbackDataConverter converter(plugin, time_info); return send_event(vst_host_callback, converter, opcode, index, value, data, option, std::nullopt); }