Hey, just getting started in JUCE today and ran into this issue after clicking Scan for my VST3 plugin to hook up to AudioPluginHost using the basic audio/midi plugin tutorial found here → Create a basic Audio/MIDI plugin, Part 1 - JUCE
JUCE Assertion failure in juce_VST3PluginFormatImpl.h:298
I assume something is being called on the message thread when it shouldn’t be but I’m quite clueless. The AudioPluginHost locks up and must be force quit.
ChatGPT is equally clueless in fighting this one, and is hallucinating an issue about the JUCE UI missing buttons
Examine the stack trace when you hit this assert, as this will let you know what is calling it. While you are in the debugger, you can also determine which thread you are on. While this might not help you fix the issue, knowing those details will be helpful to others trying to help you.
* thread #33, name = 'Pool', stop reason = EXC_BREAKPOINT (code=1, subcode=0x102662588)
* frame #0: 0x000000010266258c AudioPluginHost`juce::getNumSingleDirectionChannelsFor(component=0x000000014d706e70, busDirection=input) at juce_VST3PluginFormatImpl.h:298:5
frame #1: 0x00000001025fbcbc AudioPluginHost`juce::DescriptionLister::findDescriptionsSlow(host=0x0000600002615830, factory=0x000000014f373ef0, file=0x000000016dd5a9a0) at juce_VST3PluginFormatImpl.h:1036:43
frame #2: 0x00000001025fb3c4 AudioPluginHost`juce::VST3PluginFormatHeadless::findAllTypesForFile(this=0x0000600001408620, results=0x000000016dd5ac50, fileOrIdentifier=0x000000016dd5ad20) at juce_VST3PluginFormatHeadless.cpp:87:30
frame #3: 0x000000010226d724 AudioPluginHost`CustomPluginScanner::findPluginTypesFor(this=0x0000600001469a00, format=0x0000600001408620, result=0x000000016dd5ac50, fileOrIdentifier=0x000000016dd5ad20) at MainHostWindow.cpp:131:20
frame #4: 0x0000000102445e3c AudioPluginHost`juce::KnownPluginList::scanAndAddFile(this=0x000000013d822e98, fileOrIdentifier=0x000000016dd5ad20, dontRescanIfAlreadyInList=true, typesFound=0x000000016dd5ad60, format=0x0000600001408620) at juce_KnownPluginList.cpp:195:28
frame #5: 0x000000010244866c AudioPluginHost`juce::PluginDirectoryScanner::scanNextFile(this=0x000060000302c2a0, dontRescanIfAlreadyInList=true, nameOfPluginBeingScanned=0x00000001500a3f18) at juce_PluginDirectoryScanner.cpp:113:18
frame #6: 0x000000010250d0fc AudioPluginHost`juce::PluginListComponent::Scanner::doNextScan(this=0x00000001500a2618) at juce_PluginListComponent.cpp:379:54
frame #7: 0x000000010250ccd0 AudioPluginHost`juce::PluginListComponent::Scanner::ScanJob::runJob(this=0x0000600003f7cd90) at juce_PluginListComponent.cpp:392:28
frame #8: 0x000000010278a3a4 AudioPluginHost`juce::ThreadPool::runNextJob(this=0x0000600002b393b0, thread=0x000000011d70a740) at juce_ThreadPool.cpp:389:27
frame #9: 0x00000001027d2eb4 AudioPluginHost`juce::ThreadPool::ThreadPoolThread::run(this=0x000000011d70a740) at juce_ThreadPool.cpp:50:24
frame #10: 0x0000000102786db8 AudioPluginHost`juce::Thread::threadEntryPoint(this=0x000000011d70a740) at juce_Thread.cpp:110:13
frame #11: 0x000000010278717c AudioPluginHost`juce::juce_threadEntryPoint(userData=0x000000011d70a740) at juce_Thread.cpp:132:38
frame #12: 0x00000001027e05f0 AudioPluginHost`juce::Thread::createNativeThread(juce::Thread::Priority)::$_0::operator()(this=0x000000016dd5afb7, userData=0x000000016dcd0fd8) const at juce_Threads_mac.mm:159:13
frame #13: 0x00000001027e0550 AudioPluginHost`juce::Thread::createNativeThread(juce::Thread::Priority)::$_0::__invoke(userData=0x000000016dcd0fd8) at juce_Threads_mac.mm:143:73
frame #14: 0x0000000105ce908c libsystem_pthread.dylib`_pthread_start + 136
Snippet of the offending assertion:
/** This macro is used to catch unsafe use of functions which expect to only be called
on the message thread.
It will also fail if you try to use the function before the message manager has been
created, which could happen if you accidentally invoke it during a static constructor.
*/
#define JUCE_ASSERT_MESSAGE_THREAD \
jassert (juce::MessageManager::existsAndIsCurrentThread());
I am pretty ignorant in C++ and Xcode as an IDE so bear with me.
Hello fellow ModWiggler! Glad to see you exploring JUCE and C++. This is not an area of the code that I am familiar with, but hopefully this additional info will be helpful to others who have more experience with it.
What I can say is that in the initialise () function of the VST3PluginFormatImpl class, there is a comment that says the following
// It’s highly advisable to create your plugins using the message thread.
// The VST3 spec requires that many of the functions called during
// initialisation are only called from the message thread.
Given that the AudioPluginHost code is part of JUCE, I am not sure why these functions are being called on a thread that isn’t the message thread. Again, hopefully one of the JUCE team (who are on vacation at the moment) or another developer will be able to shed some light on the problem.
I could be wrong, I haven’t looked at this myself, but I think this may be due to the same reason reported recently on GitHub.
This was the response we left in that case.
…
The default approach taken by the AudioPluginHost is to scan plugins in-process but on a background thread. This technically violates the VST3 spec, so it’s not guaranteed to work for all plugins, but it’s fine most of the time. The assertions you’re seeing are raised when querying VST3 speaker arrangements from a background thread during scanning. Most of the time, this is a useful warning for developers because this is explicitly disallowed by the VST3 spec. Therefore, I don’t think these assertions should be removed. I also don’t think it’s viable to dispatch these calls to the main thread, since this has very high potential to produce deadlocks in user applications. We could consider avoiding querying speaker layouts when scanning VST3 plugins, but as this would change the behaviour of existing software I’d be reluctant to do this without a very strong rationale.
The AudioPluginHost includes a second, “out-of-process” scanning mode. This is the recommended mode to use most of the time. This mode creates a whole new subprocess to carry out the plugin scan, allowing the subprocess to scan plugins from its main thread in accordance with the VST3 spec, while leaving the main thread of the original host application unblocked and responsive. This mode has the added benefit that if any plugins crash during scanning, only the subprocess will be affected, and the main host will continue to function normally. Please try scanning using the out-of-process mode and check whether this still causes problems.
…
We can’t move the scan to the main thread, as this makes the host app unresponsive.
We can’t move just the speaker-layout check to the main thread as this risks deadlocks.
We can’t avoid scanning speaker layouts completely as this would be a silent behavioural change in existing software.
I believe that the current behaviour is the least bad of the available options.
The recommended approach is to use out-of-process scanning instead of in-process scanning.
Regarding out-of-process scanning, we have considered making this the default behaviour, however that then also makes debugging more difficult. So it seems there are no easy answers but also it’s probably not something you are doing wrong or need to worry about.