Loading VST3 Plugins From File Path in JUCE

JUCE Audio Programming

JUCE offers extensive support for working with audio plugins of all the major types. There is even PluginListComponent class that implements ready-to-use UI for scanning and managing plugins by the user. The class supports in-process scanning by default. However, some plugins crash while being scanned, so out-of-process scanning is often desirable. JUCE AudioPluginHost app extends PluginListComponent to support this scenario as well. PluginListComponent is an excellent choice for building fill-featured plugin hosts. But what if don’t want to perform full scanning and only need to instantiate a single plugin of specific type given its file path? It turns out that that’s ver easy to do, but it is not immediately obvious neither from JUCE documentation, nor from code samples.

Class ultimately responsible for creating plugin instances is AudioPluginFormat. We need a concrete subclass for specific format, for example VST3PluginFormat. To create a plugin instance, we must obtain its PluginDescription from given file. We do that by calling findAllTypesForFile on the audio format. Some plugins can have multiple plugin types bundled in a single file. That’s why findAllTypesForFile takes an array for adding all plugin descriptions it finds. In the example below, we simply grab the last description. Finally, we call createInstanceFromDescription which, if successful, returns a pointer to AudioPluginInstance.

Bellow is a complete code snippet demonstrating how to load a VST3 plugin from its file path:

void loadPlugin(const juce::String& pluginFilePath, 
                juce::String& errorMessage)
{
    juce::OwnedArray<juce::PluginDescription> descs;
    vst3Format.findAllTypesForFile(descs, pluginFilePath);
    
    if (descs.isEmpty())
    {
        errorMessage = "No VST3 plugin found at " + pluginFilePath;
        return;
    }
    
    auto pluginInstance = vst3Format.createInstanceFromDescription(*descs.getLast(),
                                                                   getSampleRate(),
                                                                   getBlockSize(),
                                                                   errorMessage);
    
    if (pluginInstance == nullptr)
    {
        // show errorMessage
        return;
    }
            
    hostedPluginInstance = std::move(pluginInstance);
}

juce::VST3PluginFormat vst3Format;
std::unique_ptr<juce::AudioPluginInstance> hostedPluginInstance;

There is also an asynchronous version of this method which creates plugin instance on a background thread, for example:

auto callback = [this](auto pluginInstance,  const auto& errorMessage)
{
    pluginLoadingError = errorMessage;
    hostedPluginInstance = std::move(pluginInstance);
    sendChangeMessage();
};

vst3Format.createPluginInstanceAsync(*descs.getLast(),
                                     getSampleRate(),
                                     getBlockSize(),
                                     std::move(callback));

Using background thread for plugin instantiation is not strictly necessary for the VST3 format, but it is required for AUv3.