From ef00bcc02441714a75bf51ff07c344c5e5854940 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 22 Nov 2013 10:40:33 +0000 Subject: [PATCH] Cleaned up some VST3 code to deal with plugins that fail to initialise. --- .../format_types/juce_VST3PluginFormat.cpp | 169 +++++++++--------- 1 file changed, 82 insertions(+), 87 deletions(-) diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 6bb27a8f1f..64044e8f0f 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -125,13 +125,13 @@ struct VST3Classes #endif #if JUCE_DEBUG -static void warnOnFailure (int result) +static int warnOnFailure (int result) { const char* message = "Unknown result!"; switch (result) { - case kResultOk: return; + case kResultOk: return result; case kNotImplemented: message = "kNotImplemented"; break; case kNoInterface: message = "kNoInterface"; break; case kResultFalse: message = "kResultFalse"; break; @@ -143,6 +143,7 @@ static void warnOnFailure (int result) } DBG (message); + return result; } #else #define warnOnFailure(x) x @@ -188,11 +189,6 @@ public: return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == kResultOk; } - bool loadFrom (IPluginFactory* factory, const PClassInfo& info) - { - return loadFrom (factory, info.cid); - } - private: ObjectType* source; }; @@ -678,6 +674,8 @@ public: JUCE_DECLARE_VST3_COM_REF_METHODS + FUnknown* getFUnknown() { return static_cast (this); } + //============================================================================== tresult PLUGIN_API beginEdit (Vst::ParamID) override { @@ -831,7 +829,7 @@ public: { if (doIdsMatch (iid, Vst::IAttributeList::iid)) { - *obj = dynamic_cast (attributeList.get()); + *obj = attributeList.get(); return kResultOk; } @@ -1141,9 +1139,9 @@ public: { ComSmartPtr component; - if (component.loadFrom (factory, info)) + if (component.loadFrom (factory, info.cid)) { - if (component->initialize (dynamic_cast (vst3HostContext.get())) == kResultOk) + if (component->initialize (vst3HostContext->getFUnknown()) == kResultOk) { numInputs = getNumSingleDirectionChannelsFor (component, true, true); numOutputs = getNumSingleDirectionChannelsFor (component, false, true); @@ -1678,16 +1676,14 @@ public: VST3PluginInstance (const VST3ModuleHandle::Ptr& handle) : module (handle), result (1, 1), + inputParameterChanges (new ParameterChangeList()), + outputParameterChanges (new ParameterChangeList()), + midiInputs (new MidiEventList()), + midiOutputs (new MidiEventList()), isComponentInitialised (false), isControllerInitialised (false) { - midiInputs = new MidiEventList(); - midiOutputs = new MidiEventList(); - inputParameterChanges = new ParameterChangeList(); - outputParameterChanges = new ParameterChangeList(); - host = new VST3HostContext (this); - initialise(); } ~VST3PluginInstance() @@ -1711,6 +1707,36 @@ public: component = nullptr; } + bool initialise() + { + #if JUCE_WINDOWS + // On Windows it's highly advisable to create your plugins using the message thread, + // because many plugins need a chance to create HWNDs that will get their messages + // delivered by the main message thread, and that's not possible from a background thread. + jassert (MessageManager::getInstance()->isThisTheMessageThread()); + #endif + + ComSmartPtr factory (module->getPluginFactory()); + + PFactoryInfo factoryInfo; + factory->getFactoryInfo (&factoryInfo); + company = toString (factoryInfo.vendor).trim(); + + if (! fetchComponentAndController (factory, factory->countClasses())) + return false; + + if (warnOnFailure (editController->initialize (host->getFUnknown())) != kResultTrue) + return false; + + isControllerInitialised = true; + editController->setComponentHandler (host); + grabInformationObjects(); + synchroniseStates(); + interconnectComponentAndController(); + setupIO(); + return true; + } + //============================================================================== void fillInPluginDescription (PluginDescription& description) const override { @@ -1744,11 +1770,8 @@ public: warnOnFailure (processor->setupProcessing (setup)); - if (! isControllerInitialised) - isControllerInitialised = editController->initialize (dynamic_cast (host.get())) == kResultTrue; - if (! isComponentInitialised) - isComponentInitialised = component->initialize (dynamic_cast (host.get())) == kResultTrue; + isComponentInitialised = component->initialize (host->getFUnknown()) == kResultTrue; editController->setComponentHandler (host); @@ -1768,8 +1791,11 @@ public: void releaseResources() override { - processor->setProcessing (false); - component->setActive (false); + if (processor != nullptr) + processor->setProcessing (false); + + if (component != nullptr) + component->setActive (false); } void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages) override @@ -2081,12 +2107,10 @@ private: ComSmartPtr inputParameterChanges, outputParameterChanges; ComSmartPtr midiInputs, midiOutputs; Vst::ProcessContext timingInfo; //< Only use this in processBlock()! - - bool isComponentInitialised; - bool isControllerInitialised; + bool isComponentInitialised, isControllerInitialised; //============================================================================== - void fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses) + bool fetchComponentAndController (IPluginFactory* factory, const Steinberg::int32 numClasses) { jassert (numClasses >= 0); // The plugin must provide at least an IComponent and IEditController! @@ -2119,7 +2143,7 @@ private: if (pf3.loadFrom (factory)) { - pf3->setHostContext (dynamic_cast (host.get())); + pf3->setHostContext (host->getFUnknown()); infoW = new PClassInfoW(); pf3->getClassInfoUnicode (i, infoW); } @@ -2131,42 +2155,38 @@ private: bool failed = true; - if (component.loadFrom (factory, *info) && component != nullptr) + if (component.loadFrom (factory, info->cid) && component != nullptr) { warnOnFailure (component->setIoMode (isNonRealtime() ? Vst::kOffline : Vst::kRealtime)); - if (component->initialize (dynamic_cast (host.get())) == kResultOk) - { - isComponentInitialised = true; + if (warnOnFailure (component->initialize (host->getFUnknown())) != kResultOk) + return false; - // Get the IEditController: - TUID controllerCID = { 0 }; + isComponentInitialised = true; - if (component->getControllerClassId (controllerCID) == kResultTrue && FUID (controllerCID).isValid()) - editController.loadFrom (factory, controllerCID); + // Get the IEditController: + TUID controllerCID = { 0 }; - if (editController == nullptr) - editController.loadFrom (component); + if (component->getControllerClassId (controllerCID) == kResultTrue && FUID (controllerCID).isValid()) + editController.loadFrom (factory, controllerCID); - if (editController == nullptr) + if (editController == nullptr) + { + // Try finding the IEditController the long way around: + for (Steinberg::int32 i = 0; i < numClasses; ++i) { - // Try finding the IEditController the long way around: - for (Steinberg::int32 i = 0; i < numClasses; ++i) - { - PClassInfo classInfo; - factory->getClassInfo (i, &classInfo); - - if (std::strcmp (classInfo.category, kVstComponentControllerClass) == 0) - editController.loadFrom (factory, classInfo); - } - } + PClassInfo classInfo; + factory->getClassInfo (i, &classInfo); - failed = editController == nullptr; - } - else - { - jassertfalse; + if (std::strcmp (classInfo.category, kVstComponentControllerClass) == 0) + editController.loadFrom (factory, classInfo.cid); + } } + + if (editController == nullptr) + editController.loadFrom (component); + + failed = editController == nullptr; } if (failed) @@ -2185,11 +2205,13 @@ private: editController = nullptr; } - return; + break; } - break; + return true; } + + return false; } /** Some plugins need to be "connected" to intercommunicate between their implemented classes */ @@ -2250,38 +2272,6 @@ private: setup.sampleRate, (int) setup.maxSamplesPerBlock); } - void initialise() - { - jassert (module != nullptr); - - #if JUCE_WINDOWS - // On Windows it's highly advisable to create your plugins using the message thread, - // because many plugins need a chance to create HWNDs that will get their messages - // delivered by the main message thread, and that's not possible from a background thread. - jassert (MessageManager::getInstance()->isThisTheMessageThread()); - #endif - - ComSmartPtr factory (module->getPluginFactory()); - - PFactoryInfo factoryInfo; - factory->getFactoryInfo (&factoryInfo); - company = toString (factoryInfo.vendor).trim(); - - fetchComponentAndController (factory, factory->countClasses()); - - jassert (info != nullptr); - - isControllerInitialised = editController->initialize (dynamic_cast (host.get())) == kResultTrue; - jassert (isControllerInitialised); - - editController->setComponentHandler (host); - - grabInformationObjects(); - synchroniseStates(); - interconnectComponentAndController(); - setupIO(); - } - //============================================================================== Vst::BusInfo getBusInfo (bool forInput, bool forAudio, int index = 0) const { @@ -2387,8 +2377,13 @@ AudioPluginInstance* VST3PluginFormat::createInstanceFromDescription (const Plug file.getParentDirectory().setAsCurrentWorkingDirectory(); if (const VST3Classes::VST3ModuleHandle::Ptr module = VST3Classes::VST3ModuleHandle::findOrCreateModule (file, description)) + { result = new VST3Classes::VST3PluginInstance (module); + if (! result->initialise()) + result = nullptr; + } + previousWorkingDirectory.setAsCurrentWorkingDirectory(); }