diff --git a/src/plugin/bridges/vst3-impls.cpp b/src/plugin/bridges/vst3-impls.cpp index 0a18bf9e..d47c4dcd 100644 --- a/src/plugin/bridges/vst3-impls.cpp +++ b/src/plugin/bridges/vst3-impls.cpp @@ -24,11 +24,14 @@ YaPluginFactoryPluginImpl::createInstance(Steinberg::FIDString /*cid*/, Steinberg::FIDString /*_iid*/, void** /*obj*/) { // TODO: Send a control message - return 0; + return Steinberg::kNotImplemented; } tresult PLUGIN_API YaPluginFactoryPluginImpl::setHostContext(Steinberg::FUnknown* /*context*/) { - // TODO: Send a control message - return 0; + // TODO: The docs don't clearly specify what this should be doing, but from + // what I've seen this is only used to pass a `IHostApplication` + // instance. That's used to allow the plugin to create objects in the + // host. + return Steinberg::kNotImplemented; } diff --git a/src/plugin/bridges/vst3.cpp b/src/plugin/bridges/vst3.cpp index 3575fbd4..780c199e 100644 --- a/src/plugin/bridges/vst3.cpp +++ b/src/plugin/bridges/vst3.cpp @@ -81,13 +81,24 @@ Vst3PluginBridge::Vst3PluginBridge() overload{[&](const WantsConfiguration&) -> WantsConfiguration::Response { return config; }}); }); - - // Set up the plugin factory, since this is the first thing the host will - // request after loading the module. Host callback handlers should have - // started before this since the Wine plugin host will request a copy of the - // configuration during its initialization. - plugin_factory = std::make_unique(*this); - sockets.host_vst_control.receive_into( - WantsPluginFactory{}, *plugin_factory, - std::pair(logger, true)); +} + +Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() { + // Even though we're working with raw pointers here, we should pretend that + // we're `IPtr` and do the reference counting + // ourselves because you can't always safely pass those around + if (plugin_factory) { + plugin_factory->addRef(); + } else { + // Set up the plugin factory, since this is the first thing the host + // will request after loading the module. Host callback handlers should + // have started before this since the Wine plugin host will request a + // copy of the configuration during its initialization. + plugin_factory = std::make_unique(*this); + sockets.host_vst_control.receive_into( + WantsPluginFactory{}, *plugin_factory, + std::pair(logger, true)); + } + + return plugin_factory.get(); } diff --git a/src/plugin/bridges/vst3.h b/src/plugin/bridges/vst3.h index 93fc0a7e..651ff3da 100644 --- a/src/plugin/bridges/vst3.h +++ b/src/plugin/bridges/vst3.h @@ -52,6 +52,17 @@ class Vst3PluginBridge : PluginBridge> { */ Vst3PluginBridge(); + /** + * When the host loads the module it will call `GetPluginFactory()` which + * will in turn call this function. The idea is that we return an + * `IPluginFactory*` while doing all the reference counting that `IPtr` + * would normally do for us ourselves. This means that when the host frees + * its last instance of this factory, `plugin_factory` will also be cleared. + * + * @see plugin_factory + */ + Steinberg::IPluginFactory* get_plugin_factory(); + private: /** * Handles callbacks from the plugin to the host over the @@ -65,16 +76,16 @@ class Vst3PluginBridge : PluginBridge> { */ Vst3Logger logger; - public: /** - * Our plugin factory. This will be set up directly after initialization. - * All information about the plugin and its supported classes are copied - * directly from the Windows VST3 plugin's factory on the Wine side, and - * we'll provide an implementation that can send control messages to the - * Wine plugin host. + * Our plugin factory. All information about the plugin and its supported + * classes are copied directly from the Windows VST3 plugin's factory on the + * Wine side, and we'll provide an implementation that can send control + * messages to the Wine plugin host. Even though we're passign plain + * pointers around, we should pretend that they're wrapped in the VST3 SDK's + * reference counting p pointers so we should do the reference counting + * ourselves. * - * A pointer to this implementation will be returned to the host in - * GetPluginFactory(). + * @related get_plugin_factory */ std::unique_ptr plugin_factory; }; diff --git a/src/plugin/vst3-plugin.cpp b/src/plugin/vst3-plugin.cpp index 32866497..75b5e201 100644 --- a/src/plugin/vst3-plugin.cpp +++ b/src/plugin/vst3-plugin.cpp @@ -69,21 +69,5 @@ SMTG_EXPORT_SYMBOL Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory() { // The host should have called `InitModule()` first assert(bridge); - // TODO: I think there is a flag that indicates that the class configuration - // may change, but I don't remember if it's at runtime or every time - // the module is loaded. If it's the former then this will take some - // special handling. - return bridge->plugin_factory.get(); - - // TODO: In the normal implementation of this function they manually call - // part of the reference counting mechanism. Is this something we also - // have to? And how does the `delete self` in the `removeRef()` play - // with our `std::unique_ptr` (aka, should we also use IPtr here)? The - // normal implementation looks like this: - // if (!gPluginFactory) { - // // Instantiate the factory - // } else { - // gPluginFactory->addRef(); - // } - // return gPluginFactory; + return bridge->get_plugin_factory(); }