Specifying search path for PluginListComponent

Hi, I’m writing an app that will select a plugin from a list of available plugins, and then host it for testing purposes. I am successfully using the PluginListComponent class to scan and display the list of available plugins.

However, I would like to specify the search path that the PluginListComponent and its scanner use to locate plugins. Currently, the PluginListComponent gives me every single plugin (in this case, AudioUnit) available on my system.

I have tried preparing a PropertiesFile for the PluginListComponent constructor with the PluginListComponent::setLastSearchPath() method, as well as overriding the AudioUnitPluginFormat class’s getDefaultLocationsToSearch() method, but the PluginListComponent seemed to ignore both of these.

What’s the right way to go about this?

I was doing something similar today. You can pass a custom search path to PluginDirectoryScanner on construction e.g.:

juce::VST3PluginFormat vst3Format;
juce::FileSearchPath vst3SearchPath ("~/Desktop/CustomVST3");
juce::PluginDirectoryScanner pluginScanner(mKnownPluginList, vst3Format, vst3SearchPath, true, mDeadManFile);

Thanks for the suggestion. Applying this to AUs, I tried:
(where knownPluginList is previously declared)

juce::AudioUnitPluginFormat pluginFormat;
juce::FileSearchPath searchPath("~/Library/Audio/Plug-Ins/Components/");
juce::PluginDirectoryScanner pluginScanner(knownPluginList, pluginFormat, searchPath, true, File());

String scanString;
while (pluginScanner.scanNextFile(false, scanString)) {}

This got me similar results – my knownPluginList was filled with every AU available on system (48 AUs), not just those in the specified search path (4 AUs).

Digging into the PluginDirectoryScanner constructor, I noticed the method format.searchPathsForPlugins():

directoriesToSearch.removeRedundantPaths();
setFilesOrIdentifiersToScan (format.searchPathsForPlugins (directoriesToSearch, recursive, allowAsync));

Which points to AudioUnitPluginFormat::searchPathsForPlugins. According to the documentation:
“Searches a suggested set of directories for any plugins in this format.
The path might be ignored, e.g. by AUs, which are found by the OS rather than manually.”

Within this method, the provided FileSearchPath is ignored, and the AudioComponent method AudioComponentFindNext() is used, which uses the OS to iterate for each single AU it is aware of.

StringArray AudioUnitPluginFormat::searchPathsForPlugins (const FileSearchPath&, bool /*recursive*/, bool allowPluginsWhichRequireAsynchronousInstantiation)
{
    StringArray result;
    AudioComponent comp = nullptr;

    for (;;)
    {
        AudioComponentDescription desc;
        zerostruct (desc);

        comp = AudioComponentFindNext (comp, &desc);

        if (comp == nullptr)
            break;

       ... // abbreviated for post
    }

    return result;
}

All that to say, it seems like the PluginDirectoryScanner is incapable of following a search path for AUs on MacOS?

“Searches a suggested set of directories for any plugins in this format.
The path might be ignored, e.g. by AUs, which are found by the OS rather than manually.”

That makes sense due to how tightly integrated AudioUnits are with macOS and CoreAudio. Whereas VSTs can be installed to a custom location and most VST hosts give users the option to add custom locations to scan.

PluginDirectoryScanner also provides the setFilesOrIdentifiersToScan method. I haven’t used it but it looks like you can pass AU identifiers e.g. com.mycompany.MyPlugin to narrow the search down to a set of plugins you want to test. That’s my understanding of it anyway.

https://docs.juce.com/master/classPluginDirectoryScanner.html#a3e350200665544042affea6c11b0c5f1

Thanks for your feedback - I think that method would help limit the search.

For now, I’ve saved the KnownPluginList as XML to a file which is read at launch, which pre-populates the PluginListComponent. This removes the necessity (and time) to re-scan the system’s AUs at launch. Not the solution I was looking for, but it works just as well.