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
+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);
}