getPluginFactory hit jassert

Hello,

I have encountered a problem I cannot resolve. I try to load in my app a plugin I just created with projucer. I did not change anything in the generated plugin code.

I compile the plugin code thanks to this CMakeList:

project(Reverb_v2 VERSION 0.0.1)

set (BaseTargetName Reverb_v2)

juce_add_plugin("${BaseTargetName}"
        # VERSION ...                               # Set this if the plugin version is different to the project version
        # ICON_BIG ...                              # ICON_* arguments specify a path to an image file to use as an icon for the Standalone
        # ICON_SMALL ...
        COMPANY_NAME "MyCompany"
        IS_SYNTH FALSE
        NEEDS_MIDI_INPUT TRUE
        NEEDS_MIDI_OUTPUT FALSE
        IS_MIDI_EFFECT FALSE
        EDITOR_WANTS_KEYBOARD_FOCUS FALSE
        COPY_PLUGIN_AFTER_BUILD TRUE
        PLUGIN_MANUFACTURER_CODE Juce
        PLUGIN_CODE Dem0
        FORMATS AU VST3 Standalone
        PRODUCT_NAME "Reverb_v2")

target_sources(${BaseTargetName} PRIVATE
        Source/PluginProcessor.cpp
        Source/PluginEditor.cpp)

target_compile_definitions(${BaseTargetName}
        PUBLIC
        JUCE_DISABLE_JUCE_VERSION_PRINTING=1
        JUCE_WEB_BROWSER=0
        JUCE_USE_CURL=0
        JUCE_VST3_CAN_REPLACE_VST2=0)

target_link_libraries(${BaseTargetName} PRIVATE
        juce::juce_core
        juce::juce_dsp
        juce::juce_audio_processors
        juce::juce_audio_utils
        juce::juce_audio_devices
        juce::juce_audio_utils
        juce::juce_recommended_config_flags
        juce::juce_recommended_lto_flags
        juce::juce_recommended_warning_flags)

When JUCE calls the getPluginFactory function it hit the: jassert (factory != nullptr) where it says.

// The plugin NEEDS to provide a factory to be able to be called a VST3!
// Most likely you are trying to load a 32-bit VST3 from a 64-bit host
// or vice versa.

I do not understand why, is there a parameter in projucer I had missed to correctly set the plugin ?

I saw on the forum that the question has been asked many times, but never clearly answered.

Thank you in advance for your help

How are you configuring CMake? If you’re on Windows, perhaps the comment is correct and you accidentally built the plugin for 32-bit instead of 64-bit. You can pass -A Win32 or -A x64 when initially configuring the project to control the platform name of the Visual Studio generator.

Also, how are you testing the plugin? It sounds like you might be using the AudioPluginHost. If this is the case, how did you build the host?

Thank you for your answer,

I am currently working on Ubuntu. And when I use the file command as follow :

file ./Plugins/Reverb_v2/Reverb_v2_artefacts/Debug/VST3/Reverb_v2.vst3/Contents/x86_64-linux/Reverb_v2d.so

the response is

./Plugins/Reverb_v2/Reverb_v2_artefacts/Debug/VST3/Reverb_v2.vst3/Contents/x86_64-linux/Reverb_v2d.so: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=3416bdd3b1baad0b6212c603404f58590a17ad67, with debug_info, not stripped

So I assume it has been correctly built. Am I wrong?

I am not sure to correctly understand your last question, what do you mean by “host”?

A VST3 plugin is not directly executable. It must be run inside a host application of some kind. You might use JUCE’s AudioPluginHost, or another host like REAPER, Ardour, Bitwig Studio etc.

What executable program are you running under a debugger when you see the jassert?

It is my own application.

Maybe the way I load it will help you to help me ?

Here’s the function (filepath is the file to the .vst3):

std::unique_ptr<juce::AudioPluginInstance> Vst3Loader::getPluginInstanceFromVst3(const std::string &filepath,
                                                                                 const juce::AudioPluginFormatManager &formatManager) {
    static juce::KnownPluginList knownPluginList;
    static juce::OwnedArray<juce::PluginDescription> pluginDescriptions;
    static juce::VST3PluginFormat vst3PluginFormat;
    juce::String errorMessage("Failed to load effect " + filepath);

    knownPluginList.scanAndAddFile(juce::String(filepath), true, pluginDescriptions, vst3PluginFormat);
    return formatManager.createPluginInstance(*pluginDescriptions.getLast(), 48000, 1024, errorMessage);
}

Are you passing the path to the Reverb_v2.vst3, or to the Reverb_v2d.so?

I think there are a few things that might cause problems in your code:

  • The pluginDescriptions array will live for the lifetime of your program, so it will grow and grow every time a new plugin instance is scanned.
  • If the knownPluginList doesn’t find anything, pluginDescriptions may be empty when its first element is accessed. This is undefined behaviour and is likely to crash the program. Alternatively, because the array is static, you might end up instantiating a ‘previous’ plugin instead.
  • The errorMessage argument is an out-parameter that modifies the string to contain a description of the error if plugin creation fails. You should pass an empty string to createPluginInstance, and inspect it after the function to check that it is still empty (i.e. no error occurred).

I’d recommend the following:

  • Use KnownPluginList::scanAndAddDragAndDroppedFiles to identify plugins, rather than scanAndAddFile. This function has a simpler interface, and will recurse into plugin bundles automatically.
  • Remove all static variables with function scope. These are not necessary, and are likely to cause issues in the future, e.g. if you need to call the function from multiple threads simultaneously. Your knownPluginList should probably be a data member of the class, pluginDescriptions should be function-local but non-static, and vst3PluginFormat is not required at all.
1 Like

Thank you so much for this very complete answer.

Are you passing the path to the Reverb_v2.vst3, or to the Reverb_v2d.so?

I am passing the path to the .vst3 but I suppose that checking the shared object is the way to verify if my plugin is in 32 or 64, right?

I am going to work on every bullet points and I will then return to you.

So,

I edited my function and remove all static.

std::unique_ptr<juce::AudioPluginInstance> Vst3Loader::getPluginInstanceFromVst3(const std::string &filepath,
                                                                                 juce::AudioPluginFormatManager &formatManager) {
    juce::String errorMessage("");
    juce::OwnedArray<juce::PluginDescription> pluginDescriptions;

    knownPluginList.scanAndAddDragAndDroppedFiles(formatManager, juce::StringArray(filepath), pluginDescriptions);
    if (pluginDescriptions.size() > 0) {
        auto plugin = formatManager.createPluginInstance(*pluginDescriptions.getLast(), 48000, 1024, errorMessage);
        std::cout << "Message: " << errorMessage << std::endl;
        return plugin;
    }
    return nullptr;
}

But the problem is still here. It hit juce VST3PluginFormat.cpp jassert. Because scanAndAddDragAndDroppedFiles failed, the process don’t even reach createPluginInstance…

Does the plugin open in other hosts? If not, that might indicate a problem with the plugin itself. If it does open in other hosts, then the problem is likely to be on the hosting side.

You could also try loading some other known-good plugins in your host. If you’re not able to load anything in your host, then that will give you some hints where to look. However, if you’re only unable to load the Reverb_v2 plugin, then the problem is probably in the plugin.

You are right. I tried to load it with the Juce Plug-in host and it says :

the following files appeared to be plugin files but failed to load correctly

But how is it possible? I generated the plugin from projucer and tried to load it after. The only possible reason I see is that my compilation went wrong?

You can test whether the plugin bundle exports the correct function by running
nm path/to/dso/Reverb_v2d.so > symbols.txt and then search in symbols.txt for GetPluginFactory. There should be a T next to the name of this function in the output.

If it does, you could try sticking a breakpoint at VST3PluginFormat.cpp:995 and step through DLLHandle::open(), checking whether the library opens successfully. If the library loads but doesn’t contain GetPluginFactory then something’s prevented this symbol from being emitted in the plugin build, and I’m not sure how that could happen… If the library doesn’t load at all, then something about the build has made it incompatible with this host. Perhaps it depends on different (standard) libraries.

Does the plugin load in any non-JUCE hosts, such as REAPER?

Neither my host nor Reaper can open it. DynamicLibrary::open (juce_posix_SharedCode.h) fail and return nullptr :frowning:

In that case, you could try adding a call to dlerror after the failed call to dlopen and print out the error string. Hopefully that will tell you why the library failed to load.

1 Like

Ok.

dlerror is telling me : Reverb_v2.so No such file or directory
In fact, my shared object is called Reverb_v2d.so…

/Plugins/Reverb_v2/Reverb_v2_artefacts/Debug/VST3/Reverb_v2.vst3/Contents/x86_64-linux/Reverb_v2d.so

instead of

/Plugins/Reverb_v2/Reverb_v2_artefacts/Debug/VST3/Reverb_v2.vst3/Contents/x86_64-linux/Reverb_v2.so

I have no idea why this “d” has been added at the end of the name of the file. It does the same for all my plugins.
I need to investigate… (if you have any idea let me know)

Thank you so much for your help, for the time you spent for me.

Maybe CMAKE_DEBUG_POSTFIX is being set somewhere? Are you using any other libraries in your CMake project that might set this variable? You could try reconfiguring and force this variable to be an empty string, and see whether that removes the d suffixes.

https://cmake.org/cmake/help/latest/variable/CMAKE_DEBUG_POSTFIX.html

1 Like

It was this ! Boost add CMAKE_DEBUG_POSTFIX…
Adding set(CMAKE_DEBUG_POSTFIX "") at the top of the CMakeList of my plugins solve my problems

Thank you so much again !