mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +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:
|
- Implement missing features:
|
||||||
- GUIs.
|
- 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
|
- 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
|
to cause any other problems. This can probably be fixed by catching
|
||||||
exceptions thrown in the threads caused by sockets being closed. It's
|
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* {
|
[&](const std::string& s) -> void* {
|
||||||
return const_cast<char*>(s.c_str());
|
return const_cast<char*>(s.c_str());
|
||||||
},
|
},
|
||||||
|
[&](const AEffect&) -> void* { return nullptr; },
|
||||||
[&](DynamicVstEvents& events) -> void* {
|
[&](DynamicVstEvents& events) -> void* {
|
||||||
return &events.as_c_events();
|
return &events.as_c_events();
|
||||||
},
|
},
|
||||||
[&](WantsChunkBuffer&) -> void* { return string_buffer.data(); },
|
[&](WantsChunkBuffer&) -> void* { return string_buffer.data(); },
|
||||||
[&](WantsVstTimeInfo&) -> void* { return nullptr; },
|
[&](const WantsVstTimeInfo&) -> void* { return nullptr; },
|
||||||
[&](WantsString&) -> void* { return string_buffer.data(); }},
|
[&](WantsString&) -> void* { return string_buffer.data(); }},
|
||||||
event.payload);
|
event.payload);
|
||||||
|
|
||||||
@@ -203,6 +204,32 @@ void passthrough_event(boost::asio::local::stream_protocol::socket& socket,
|
|||||||
// report some data back?
|
// report some data back?
|
||||||
const auto response_data = std::visit(
|
const auto response_data = std::visit(
|
||||||
overload{[&](auto) -> EventResposnePayload { return std::monostate(); },
|
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 {
|
[&](WantsChunkBuffer&) -> EventResposnePayload {
|
||||||
// In this case the plugin will have written its data
|
// In this case the plugin will have written its data
|
||||||
// stored in an array to which a pointer is stored in
|
// 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>";
|
message << "<" << s.size() << " bytes>";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
[&](const AEffect&) { message << "<nullptr>"; },
|
||||||
[&](const DynamicVstEvents& events) {
|
[&](const DynamicVstEvents& events) {
|
||||||
message << "<" << events.events.size() << " midi_events>";
|
message << "<" << events.events.size() << " midi_events>";
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -180,10 +180,9 @@ struct WantsString {};
|
|||||||
* clarity's sake.
|
* clarity's sake.
|
||||||
*
|
*
|
||||||
* - Specific data structures from `aeffextx.h`. For instance an event with the
|
* - Specific data structures from `aeffextx.h`. For instance an event with the
|
||||||
* opcode `effProcessEvents` comes with a struct containing a list of midi
|
* opcode `effProcessEvents` the hosts passes a `VstEvents` struct containing
|
||||||
* events.
|
* midi events, and `audioMasterIOChanged` lets the host know that the
|
||||||
*
|
* `AEffect` struct has changed.
|
||||||
* TODO: A lot of these are still missing
|
|
||||||
*
|
*
|
||||||
* - Some empty buffer for the plugin to write its own data to, for instance for
|
* - 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
|
* 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,
|
using EventPayload = std::variant<std::nullptr_t,
|
||||||
std::string,
|
std::string,
|
||||||
|
AEffect,
|
||||||
DynamicVstEvents,
|
DynamicVstEvents,
|
||||||
WantsChunkBuffer,
|
WantsChunkBuffer,
|
||||||
WantsVstTimeInfo,
|
WantsVstTimeInfo,
|
||||||
@@ -211,6 +211,7 @@ void serialize(S& s, EventPayload& payload) {
|
|||||||
// data
|
// data
|
||||||
s.text1b(string, binary_buffer_size);
|
s.text1b(string, binary_buffer_size);
|
||||||
},
|
},
|
||||||
|
[](S& s, AEffect& effect) { s.object(effect); },
|
||||||
[](S& s, DynamicVstEvents& events) {
|
[](S& s, DynamicVstEvents& events) {
|
||||||
s.container(events.events, max_midi_events,
|
s.container(events.events, max_midi_events,
|
||||||
[](S& s, VstEvent& event) {
|
[](S& s, VstEvent& event) {
|
||||||
|
|||||||
@@ -109,10 +109,8 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
|
|||||||
"' failed to initialize.");
|
"' failed to initialize.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the plugin's information to the Linux VST plugin
|
// Send the plugin's information to the Linux VST plugin. Any updates during
|
||||||
// TODO: This is now done only once at startup, do plugins update their
|
// runtime are handled using the `audioMasterIOChanged` host callback.
|
||||||
// parameters? In that case we should be detecting updates and pass
|
|
||||||
// them along accordingly.
|
|
||||||
write_object(vst_host_aeffect, *plugin);
|
write_object(vst_host_aeffect, *plugin);
|
||||||
|
|
||||||
// We only needed this little hack during initialization
|
// We only needed this little hack during initialization
|
||||||
@@ -195,7 +193,8 @@ void PluginBridge::wait() {
|
|||||||
|
|
||||||
class HostCallbackDataConverter : DefaultDataConverter {
|
class HostCallbackDataConverter : DefaultDataConverter {
|
||||||
public:
|
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,
|
std::optional<EventPayload> read(const int opcode,
|
||||||
const intptr_t value,
|
const intptr_t value,
|
||||||
@@ -219,6 +218,12 @@ class HostCallbackDataConverter : DefaultDataConverter {
|
|||||||
case audioMasterGetTime:
|
case audioMasterGetTime:
|
||||||
return WantsVstTimeInfo{};
|
return WantsVstTimeInfo{};
|
||||||
break;
|
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:
|
default:
|
||||||
return DefaultDataConverter::read(opcode, value, data);
|
return DefaultDataConverter::read(opcode, value, data);
|
||||||
break;
|
break;
|
||||||
@@ -230,7 +235,7 @@ class HostCallbackDataConverter : DefaultDataConverter {
|
|||||||
case audioMasterGetTime:
|
case audioMasterGetTime:
|
||||||
// Write the returned `VstTimeInfo` struct into a field and make
|
// Write the returned `VstTimeInfo` struct into a field and make
|
||||||
// the function return a poitner to it in the function below
|
// 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;
|
break;
|
||||||
default:
|
default:
|
||||||
DefaultDataConverter::write(opcode, data, response);
|
DefaultDataConverter::write(opcode, data, response);
|
||||||
@@ -252,7 +257,8 @@ class HostCallbackDataConverter : DefaultDataConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VstTimeInfo& time;
|
AEffect* plugin;
|
||||||
|
VstTimeInfo& time_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
|
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
|
||||||
@@ -261,7 +267,7 @@ intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
|
|||||||
intptr_t value,
|
intptr_t value,
|
||||||
void* data,
|
void* data,
|
||||||
float option) {
|
float option) {
|
||||||
HostCallbackDataConverter converter(time_info);
|
HostCallbackDataConverter converter(plugin, time_info);
|
||||||
return send_event(vst_host_callback, converter, opcode, index, value, data,
|
return send_event(vst_host_callback, converter, opcode, index, value, data,
|
||||||
option, std::nullopt);
|
option, std::nullopt);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user