Handle AEffect object updates

This commit is contained in:
Robbert van der Helm
2020-03-11 16:33:44 +01:00
parent ea8feb07a9
commit 8464706336
5 changed files with 48 additions and 15 deletions
-2
View File
@@ -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
+28 -1
View File
@@ -186,11 +186,12 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket,
[&](const std::string& s) -> void* {
return const_cast<char*>(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
+1
View File
@@ -167,6 +167,7 @@ void Logger::log_event(bool is_dispatch,
message << "<" << s.size() << " bytes>";
}
},
[&](const AEffect&) { message << "<nullptr>"; },
[&](const DynamicVstEvents& events) {
message << "<" << events.events.size() << " midi_events>";
},
+5 -4
View File
@@ -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<std::nullptr_t,
std::string,
AEffect,
DynamicVstEvents,
WantsChunkBuffer,
WantsVstTimeInfo,
@@ -211,6 +211,7 @@ void serialize(S& s, EventPayload& payload) {
// data
s.text1b(string, binary_buffer_size);
},
[](S& s, AEffect& effect) { s.object(effect); },
[](S& s, DynamicVstEvents& events) {
s.container(events.events, max_midi_events,
[](S& s, VstEvent& event) {
+14 -8
View File
@@ -109,10 +109,8 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
"' failed to initialize.");
}
// Send the plugin's information to the Linux VST plugin
// TODO: This is now done only once at startup, do plugins update their
// parameters? In that case we should be detecting updates and pass
// them along accordingly.
// Send the plugin's information to the Linux VST plugin. Any updates during
// runtime are handled using the `audioMasterIOChanged` host callback.
write_object(vst_host_aeffect, *plugin);
// We only needed this little hack during initialization
@@ -195,7 +193,8 @@ void PluginBridge::wait() {
class HostCallbackDataConverter : DefaultDataConverter {
public:
HostCallbackDataConverter(VstTimeInfo& time_info) : time(time_info) {}
HostCallbackDataConverter(AEffect* plugin, VstTimeInfo& time_info)
: plugin(plugin), time_info(time_info) {}
std::optional<EventPayload> 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<VstTimeInfo>(response.payload);
time_info = std::get<VstTimeInfo>(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);
}