mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Work around improperly late initializing plugins
This fixes the Roland Cloud plugins.
This commit is contained in:
@@ -6,6 +6,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||||||
and this project adheres to [Semantic
|
and this project adheres to [Semantic
|
||||||
Versioning](https://semver.org/spec/v2.0.0.html).
|
Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added a workaround for plugins that improperly defer part of their
|
||||||
|
initialization process without telling the host. This fixes the Roland Cloud
|
||||||
|
plugins.
|
||||||
|
|
||||||
## [1.1.2] - 2020-05-09
|
## [1.1.2] - 2020-05-09
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -283,6 +283,14 @@ auto passthrough_event(AEffect* plugin, F callback) {
|
|||||||
[&](DynamicSpeakerArrangement& speaker_arrangement) -> void* {
|
[&](DynamicSpeakerArrangement& speaker_arrangement) -> void* {
|
||||||
return &speaker_arrangement.as_c_speaker_arrangement();
|
return &speaker_arrangement.as_c_speaker_arrangement();
|
||||||
},
|
},
|
||||||
|
[&](WantsAEffectUpdate&) -> void* {
|
||||||
|
// The host will never actually ask for an updated `AEffect`
|
||||||
|
// object since that should not be a thing. This is purely a
|
||||||
|
// meant as a workaround for plugins that initialize their
|
||||||
|
// `AEffect` object after the plugin has already finished
|
||||||
|
// initializing.
|
||||||
|
return nullptr;
|
||||||
|
},
|
||||||
[&](WantsChunkBuffer&) -> void* { return string_buffer.data(); },
|
[&](WantsChunkBuffer&) -> void* { return string_buffer.data(); },
|
||||||
[&](VstIOProperties& props) -> void* { return &props; },
|
[&](VstIOProperties& props) -> void* { return &props; },
|
||||||
[&](VstMidiKeyName& key_name) -> void* { return &key_name; },
|
[&](VstMidiKeyName& key_name) -> void* { return &key_name; },
|
||||||
@@ -335,6 +343,7 @@ auto passthrough_event(AEffect* plugin, F callback) {
|
|||||||
[&](VstParameterProperties& props) -> EventResultPayload {
|
[&](VstParameterProperties& props) -> EventResultPayload {
|
||||||
return props;
|
return props;
|
||||||
},
|
},
|
||||||
|
[&](WantsAEffectUpdate&) -> EventResultPayload { return *plugin; },
|
||||||
[&](WantsVstRect&) -> EventResultPayload {
|
[&](WantsVstRect&) -> EventResultPayload {
|
||||||
// The plugin has written a pointer to a VstRect struct into the
|
// The plugin has written a pointer to a VstRect struct into the
|
||||||
// data poitner
|
// data poitner
|
||||||
|
|||||||
@@ -201,14 +201,15 @@ void Logger::log_event(bool is_dispatch,
|
|||||||
message << "<" << speaker_arrangement.speakers.size()
|
message << "<" << speaker_arrangement.speakers.size()
|
||||||
<< " output_speakers>";
|
<< " output_speakers>";
|
||||||
},
|
},
|
||||||
[&](const WantsChunkBuffer&) {
|
|
||||||
message << "<writable_buffer>";
|
|
||||||
},
|
|
||||||
[&](const VstIOProperties&) { message << "<io_properties>"; },
|
[&](const VstIOProperties&) { message << "<io_properties>"; },
|
||||||
[&](const VstMidiKeyName&) { message << "<key_name>"; },
|
[&](const VstMidiKeyName&) { message << "<key_name>"; },
|
||||||
[&](const VstParameterProperties&) {
|
[&](const VstParameterProperties&) {
|
||||||
message << "<writable_buffer>";
|
message << "<writable_buffer>";
|
||||||
},
|
},
|
||||||
|
[&](const WantsAEffectUpdate&) { message << "<nullptr>"; },
|
||||||
|
[&](const WantsChunkBuffer&) {
|
||||||
|
message << "<writable_buffer>";
|
||||||
|
},
|
||||||
[&](const WantsVstRect&) { message << "<writable_buffer>"; },
|
[&](const WantsVstRect&) { message << "<writable_buffer>"; },
|
||||||
[&](const WantsVstTimeInfo&) { message << "<nullptr>"; },
|
[&](const WantsVstTimeInfo&) { message << "<nullptr>"; },
|
||||||
[&](const WantsString&) { message << "<writable_string>"; }},
|
[&](const WantsString&) { message << "<writable_string>"; }},
|
||||||
|
|||||||
@@ -285,6 +285,15 @@ class alignas(16) DynamicSpeakerArrangement {
|
|||||||
std::vector<uint8_t> speaker_arrangement_buffer;
|
std::vector<uint8_t> speaker_arrangement_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marker struct to indicate that the other side (the Wine VST host) should send
|
||||||
|
* an updated copy of the plugin's `AEffect` object. Should not be needed since
|
||||||
|
* the plugin should be calling `audioMasterIOChanged()` after it has changed
|
||||||
|
* its object, but some improperly coded plugins will only initialize their
|
||||||
|
* flags, IO properties and parameter counts after `effEditOpen()`.
|
||||||
|
*/
|
||||||
|
struct WantsAEffectUpdate {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marker struct to indicate that that the event writes arbitrary data into one
|
* Marker struct to indicate that that the event writes arbitrary data into one
|
||||||
* of its own buffers and uses the void pointer to store start of that data,
|
* of its own buffers and uses the void pointer to store start of that data,
|
||||||
@@ -352,6 +361,7 @@ using EventPayload = std::variant<std::nullptr_t,
|
|||||||
AEffect,
|
AEffect,
|
||||||
DynamicVstEvents,
|
DynamicVstEvents,
|
||||||
DynamicSpeakerArrangement,
|
DynamicSpeakerArrangement,
|
||||||
|
WantsAEffectUpdate,
|
||||||
WantsChunkBuffer,
|
WantsChunkBuffer,
|
||||||
VstIOProperties,
|
VstIOProperties,
|
||||||
VstMidiKeyName,
|
VstMidiKeyName,
|
||||||
@@ -382,8 +392,9 @@ void serialize(S& s, EventPayload& payload) {
|
|||||||
[](S& s, VstIOProperties& props) { s.object(props); },
|
[](S& s, VstIOProperties& props) { s.object(props); },
|
||||||
[](S& s, VstMidiKeyName& key_name) { s.object(key_name); },
|
[](S& s, VstMidiKeyName& key_name) { s.object(key_name); },
|
||||||
[](S& s, VstParameterProperties& props) { s.object(props); },
|
[](S& s, VstParameterProperties& props) { s.object(props); },
|
||||||
[](S&, WantsChunkBuffer&) {}, [](S&, WantsVstRect&) {},
|
[](S&, WantsAEffectUpdate&) {}, [](S&, WantsChunkBuffer&) {},
|
||||||
[](S&, WantsVstTimeInfo&) {}, [](S&, WantsString&) {}});
|
[](S&, WantsVstRect&) {}, [](S&, WantsVstTimeInfo&) {},
|
||||||
|
[](S&, WantsString&) {}});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -229,8 +229,9 @@ PluginBridge::PluginBridge(audioMasterCallback host_callback)
|
|||||||
class DispatchDataConverter : DefaultDataConverter {
|
class DispatchDataConverter : DefaultDataConverter {
|
||||||
public:
|
public:
|
||||||
DispatchDataConverter(std::vector<uint8_t>& chunk_data,
|
DispatchDataConverter(std::vector<uint8_t>& chunk_data,
|
||||||
|
AEffect& plugin,
|
||||||
VstRect& editor_rectangle)
|
VstRect& editor_rectangle)
|
||||||
: chunk(chunk_data), rect(editor_rectangle) {}
|
: chunk(chunk_data), plugin(plugin), rect(editor_rectangle) {}
|
||||||
|
|
||||||
EventPayload read(const int opcode,
|
EventPayload read(const int opcode,
|
||||||
const int index,
|
const int index,
|
||||||
@@ -239,6 +240,13 @@ class DispatchDataConverter : DefaultDataConverter {
|
|||||||
// There are some events that need specific structs that we can't simply
|
// There are some events that need specific structs that we can't simply
|
||||||
// serialize as a string because they might contain null bytes
|
// serialize as a string because they might contain null bytes
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
case effOpen:
|
||||||
|
// This should not be needed, but some improperly coded plugins
|
||||||
|
// such as the Roland Cloud plugins will initialize part of
|
||||||
|
// their `AEffect` only after the host calls `effOpen`, instead
|
||||||
|
// of during the initialization.
|
||||||
|
return WantsAEffectUpdate{};
|
||||||
|
break;
|
||||||
case effEditGetRect:
|
case effEditGetRect:
|
||||||
return WantsVstRect();
|
return WantsVstRect();
|
||||||
break;
|
break;
|
||||||
@@ -325,6 +333,14 @@ class DispatchDataConverter : DefaultDataConverter {
|
|||||||
|
|
||||||
void write(const int opcode, void* data, const EventResult& response) {
|
void write(const int opcode, void* data, const EventResult& response) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
case effOpen: {
|
||||||
|
// Update our `AEffect` object one last time for improperly
|
||||||
|
// coded late initialing plugins. Hopefully the host will see
|
||||||
|
// that the object is updated because these plugins don't send
|
||||||
|
// any notification about this.
|
||||||
|
const auto updated_plugin = std::get<AEffect>(response.payload);
|
||||||
|
update_aeffect(plugin, updated_plugin);
|
||||||
|
} break;
|
||||||
case effEditGetRect: {
|
case effEditGetRect: {
|
||||||
// Write back the (hopefully) updated editor dimensions
|
// Write back the (hopefully) updated editor dimensions
|
||||||
const auto new_rect = std::get<VstRect>(response.payload);
|
const auto new_rect = std::get<VstRect>(response.payload);
|
||||||
@@ -423,6 +439,7 @@ class DispatchDataConverter : DefaultDataConverter {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<uint8_t>& chunk;
|
std::vector<uint8_t>& chunk;
|
||||||
|
AEffect& plugin;
|
||||||
VstRect& rect;
|
VstRect& rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -449,7 +466,7 @@ intptr_t PluginBridge::dispatch(AEffect* /*plugin*/,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchDataConverter converter(chunk_data, editor_rectangle);
|
DispatchDataConverter converter(chunk_data, plugin, editor_rectangle);
|
||||||
|
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case effClose: {
|
case effClose: {
|
||||||
|
|||||||
Reference in New Issue
Block a user