mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Handle AEffect object updates
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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>";
|
||||
},
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user