JuceVST3Component::terminate + AudioProcessor::releaseResources ()

Hello,

I have a plugin which advertises itself as a server to receive audio from other sources. In the destructor I need to shut down the server and terminate the advertisement.

The problem is that with VST3, it seems that sometimes terminate () can be called by the host when a plugin is removed from a track, but release () is never called, so the plugin never actually gets destructed. I’ve encountered this in both DP and Steinberg’s VST3PluginTestHost.

Terminate does call AudioProcessor::releaseResources (), but this is not an appropriate place to take down the server and advertisement. In the AAX version, releaseResources () only gets called when the plugin is removed from a track, right before its destructed, so in this case, taking down the server in releaseResources () would be fine.

However in the Juce Plugin Host and Logic, releaseResources can be called any time the block size, sample rate, or processing precision changes, in which case I absolutely would not like to close all the connections to my plugin, take down the server, and terminate the advertisement.

In this case, there’s no real solution, except to tell users NOT to use the VST3 version in DP or modify the JUCE SDK and add a AudioProcesser::terminate () method for cases when a VST host terminates my plugin but doesn’t bother to release it.

What would be great is if the JuceVST3Component could actually delete the plugin instance when terminate was called and create a new instance when initialize is called, if there is no instance. I tried releasing the plugin in JuceVST3Component::terminate (), but then we crash in JuceVST3Component::initialize () as getPluginInstance () simply returns a pointer and won’t construct the plugin if it doesn’t already exits.

Or at least I would wish for some solution where I actually know when my VST3 plugin is being removed from a host which is distinguishable from the host just changing the block size or sample rate.

Thanks,

Best,

Joe

To fix this problem I modified JuceVST3Component in the following ways:

    tresult PLUGIN_API initialize (FUnknown* hostContext) override
    {
        if (host != hostContext)
            host.loadFrom (hostContext);

#warning AudioImpressionsModification
#if 1
        // Because terminate() can be called without the plugin every being 
        // deleted, we are deleting now in terminate() by setting comPluginInstance
        // to nullptr.  That means, however, that it's possible that pluginInstance
        // can be nullptr here, in which case we need to create our plugin again.

        if (pluginInstance == nullptr) {
            pluginInstance = createPluginFilterOfType (AudioProcessor::wrapperType_VST3);
        
            inParameterChangedCallback = false;
        
#ifdef JucePlugin_PreferredChannelConfigurations
            short configs[][2] = { JucePlugin_PreferredChannelConfigurations };
            const int numConfigs = sizeof (configs) / sizeof (short[2]);
        
            jassert (numConfigs > 0 && (configs[0][0] > 0 || configs[0][1] > 0));
        
            pluginInstance->setPlayConfigDetails (configs[0][0], configs[0][1], 44100.0, 1024);
#endif // JucePlugin_PreferredChannelConfigurations
            
            jassert (checkBusFormatsAreNotDiscrete());
        
            comPluginInstance = new JuceAudioProcessor (pluginInstance);
            pluginInstance->setPlayHead (this);
        }
#endif
        
        processContext.sampleRate = processSetup.sampleRate;
        preparePlugin (processSetup.sampleRate, (int) processSetup.maxSamplesPerBlock);

        return kResultTrue;
    }

    tresult PLUGIN_API terminate() override
    {
#warning Audio Impressions Modification
#if 1
        /** DP never calls release on it's plugins, so I'm deleting the AudioProcessor here, that way at lease
          * only the JuceVst3Processor is left hanging.
          */

        if (pluginInstance != nullptr) {
            pluginInstance->releaseResources ();
            
            if (pluginInstance->getPlayHead() == this)
                pluginInstance->setPlayHead (nullptr);

            pluginInstance = nullptr;
            
            // We don't delete plugin instance here because comPluginInstance has a reference to JuceAudioProcessor,
            // which has ScopedPointer to our plugin instance.
        }

        // Instead we set comPluginInstance to nullptr to trigger all references to be released and everything
        // to be destructed.
        
        comPluginInstance = nullptr;
#else
        getPluginInstance().releaseResources();
#endif
        return kResultTrue;
    }

Anyway, if we can’t rely on VST hosts to actually release the plugin instance so that the destructor is actually called, it would be good to have some other way of knowing when the plugin has been removed from the host.

Thanks!

Best,

Joe