diff --git a/src/plugin/bridges/vst3-impls/component.cpp b/src/plugin/bridges/vst3-impls/component.cpp index bf209c44..dae8e0b3 100644 --- a/src/plugin/bridges/vst3-impls/component.cpp +++ b/src/plugin/bridges/vst3-impls/component.cpp @@ -18,11 +18,14 @@ YaComponentPluginImpl::YaComponentPluginImpl(Vst3PluginBridge& bridge, YaComponent::ConstructArgs&& args) - : YaComponent(std::move(args)), bridge(bridge) {} + : YaComponent(std::move(args)), bridge(bridge) { + bridge.register_component(arguments.instance_id, *this); +} YaComponentPluginImpl::~YaComponentPluginImpl() { bridge.send_message( YaComponent::Destruct{.instance_id = arguments.instance_id}); + bridge.unregister_component(arguments.instance_id); } tresult PLUGIN_API diff --git a/src/plugin/bridges/vst3.cpp b/src/plugin/bridges/vst3.cpp index e7815fa9..9a16cdf6 100644 --- a/src/plugin/bridges/vst3.cpp +++ b/src/plugin/bridges/vst3.cpp @@ -105,3 +105,15 @@ Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() { return plugin_factory; } + +void Vst3PluginBridge::register_component(size_t instance_id, + YaComponentPluginImpl& component) { + std::lock_guard lock(component_instances_mutex); + component_instances.emplace(instance_id, + std::ref(component)); +} + +void Vst3PluginBridge::unregister_component(size_t instance_id) { + std::lock_guard lock(component_instances_mutex); + component_instances.erase(instance_id); +} diff --git a/src/plugin/bridges/vst3.h b/src/plugin/bridges/vst3.h index 944f4bb8..249bfc9e 100644 --- a/src/plugin/bridges/vst3.h +++ b/src/plugin/bridges/vst3.h @@ -23,6 +23,9 @@ #include "../../common/logging/vst3.h" #include "common.h" +// Forward declaration +class YaComponentPluginImpl; + /** * This handles the communication between the native host and a VST3 plugin * hosted in our Wine plugin host. VST3 is handled very differently from VST2 @@ -63,6 +66,35 @@ class Vst3PluginBridge : PluginBridge> { */ Steinberg::IPluginFactory* get_plugin_factory(); + /** + * Add a `YaComponentPluginImpl` to the list of registered components so we + * can handle host callbacks, called during its constructor. + * + * @param instance_id The instance ID generated by the plugin host when + * instantiating the `IComponent`. Used as a stable name to refer to + * these. + * @param component The actual component instance so we can use its host + * context. + * + * @see component_instances + */ + void register_component(size_t instance_id, + YaComponentPluginImpl& component); + + /** + * Remove a previously registered `YaComponentPluginImpl` from the list of + * registered components so we can handle host callbacks, called during its + * destructor after asking the Wine plugin host to destroy the component on + * its side.. + * + * @param instance_id The instance ID generated by the plugin host when + * instantiating the `IComponent`. Used as a stable name to refer to + * these. + * + * @see component_instances + */ + void unregister_component(size_t instance_id); + /** * Send a control message to the Wine plugin host return the response. This * is a shorthand for `sockets.host_vst_control.send_message` for use in @@ -98,4 +130,20 @@ class Vst3PluginBridge : PluginBridge> { * @related get_plugin_factory */ YaPluginFactory* plugin_factory; + + private: + /** + * All `IComponent` instances we created from this plugin. We only need to + * keep track of them in case the 'real' `IComponent` instance tries to do a + * callback through the host context. We store the copy of the host context + * passed during `initialize()` in the `YaComponentPluginImpl`. The IDs here + * are the same IDs as generated by the Wine plugin host. We store raw + * pointers instead of smart pointers because this shouldn't affect the + * reference counting. An instance is added here through a call by + * `register_component()` in the constractor, and an instance is then + * removed through a call to `unregister_component()` in the destructor. + */ + std::map> + component_instances; + std::mutex component_instances_mutex; };