Tracktion / pluginval

Cross platform plugin testing and validation tool

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"Validate in process" hits JUCE_ASSERT_MESSAGE_THREAD

jcooper-korg opened this issue · comments

pluginval develop branch, commit 149588a. built with juce 6.1.4, Xcode 13.1. on macOS 11.6 on intel

I was hoping to use Validate In Process to try to debug issues in our plugin, as suggested in "Debugging a failed validation.md", but it seems like something must have changed in JUCE? It's not workable even with a simple test plugin. E.g.

I built the juce NoiseGateTutorial vst3 plugin.

With Validate In Process turned off, it runs fine at Strictness Level 10.
But with Validate In Process turned on, Strictness Level 2, it hits JUCE_ASSERT_MESSAGE_THREAD in getStateInformation. if I increase the Strictness Level 10, it hits the assertion in prepareToPlay

I saw the same thing in juce 6.1.4 and 6.1.0.

With juce 6.0.1, it hits the jassertfalse in setComponentState after if (! MessageManager::existsAndIsCurrentThread())

What's the stack trace? I.e. where is the assertion getting hit?

It sounds like JUCE has added an assertion to ensure this method is only called on the message thread? If that's the case, I should probably remove the test that runs it on a background thread.

#0	0x0000000106d035f4 in juce::VST3PluginInstance::prepareToPlay(double, int) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:2347
#1	0x000000010679d576 in AudioProcessingTest::runAudioProcessingTest(PluginTests&, juce::AudioPluginInstance&, bool) at /Users/john/Downloads/pluginval-develop/Source/tests/BasicTests.cpp:196
#2	0x000000010679ced6 in AudioProcessingTest::runTest(PluginTests&, juce::AudioPluginInstance&) at /Users/john/Downloads/pluginval-develop/Source/tests/BasicTests.cpp:245
#3	0x000000010676ea8a in PluginTests::testType(juce::PluginDescription const&) at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:192
#4	0x000000010676cbde in PluginTests::runTest() at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:107
#5	0x0000000107020f55 in juce::UnitTest::performTest(juce::UnitTestRunner*) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:77
#6	0x0000000107023197 in juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:165
#7	0x00000001068037aa in runTests(PluginTests&, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:205
#8	0x00000001067ffed9 in validate(juce::PluginDescription const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:218
#9	0x00000001067fd169 in ValidatorChildProcess::processRequest(juce::MemoryBlock) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:519
#10	0x00000001067fa626 in ValidatorChildProcess::processRequests() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:463
#11	0x00000001067f6ca4 in ValidatorChildProcess::run() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:426

introduced in juce-framework/JUCE@9f03bbc

and if you continue through that assert, you hit the JUCE_ASSERT_MESSAGE_THREAD at getStateInformation (same file, same commit)

#0	0x000000010c738531 in juce::VST3PluginInstance::getStateInformation(juce::MemoryBlock&) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:2832
#1	0x000000010c1d284f in PluginStateTest::runTest(PluginTests&, juce::AudioPluginInstance&) at /Users/john/Downloads/pluginval-develop/Source/tests/BasicTests.cpp:287
#2	0x000000010c19fa8a in PluginTests::testType(juce::PluginDescription const&) at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:192
#3	0x000000010c19dbde in PluginTests::runTest() at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:107
#4	0x000000010ca51f55 in juce::UnitTest::performTest(juce::UnitTestRunner*) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:77
#5	0x000000010ca54197 in juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:165
#6	0x000000010c2347aa in runTests(PluginTests&, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:205
#7	0x000000010c230ed9 in validate(juce::PluginDescription const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:218
#8	0x000000010c22e169 in ValidatorChildProcess::processRequest(juce::MemoryBlock) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:519
#9	0x000000010c22b626 in ValidatorChildProcess::processRequests() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:463

then the one in setStateInformation (same file, same commit)

#0	0x000000010c738a2d in juce::VST3PluginInstance::setStateInformation(void const*, int) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:2852
#1	0x000000010c1d2ab2 in PluginStateTest::runTest(PluginTests&, juce::AudioPluginInstance&) at /Users/john/Downloads/pluginval-develop/Source/tests/BasicTests.cpp:294
#2	0x000000010c19fa8a in PluginTests::testType(juce::PluginDescription const&) at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:192
#3	0x000000010c19dbde in PluginTests::runTest() at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:107
#4	0x000000010ca51f55 in juce::UnitTest::performTest(juce::UnitTestRunner*) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:77
#5	0x000000010ca54197 in juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:165
#6	0x000000010c2347aa in runTests(PluginTests&, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:205
#7	0x000000010c230ed9 in validate(juce::PluginDescription const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:218
#8	0x000000010c22e169 in ValidatorChildProcess::processRequest(juce::MemoryBlock) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:519
#9	0x000000010c22b626 in ValidatorChildProcess::processRequests() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:463
#10	0x000000010c227ca4 in ValidatorChildProcess::run() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:426

continuing from there, you hit the JUCE_ASSERT_MESSAGE_THREAD in VST3HostContext::restartComponent, introduced in juce-framework/JUCE@47c77517

#0	0x00000001097a9c8d in juce::VST3HostContext::restartComponent(int) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:3473
#1	0x0000000127be1358 in juce::JuceVST3EditController::setComponentState(Steinberg::IBStream*) at /Users/john/Documents/Development/Spark/library/JUCE/modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp:959
#2	0x00000001098ad6d6 in juce::VST3PluginInstance::setComponentStateAndResetParameters(Steinberg::MemoryStream&) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:2885
#3	0x000000010984fdbf in juce::VST3PluginInstance::setStateInformation(void const*, int) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp:2870
#4	0x00000001092e9ab2 in PluginStateTest::runTest(PluginTests&, juce::AudioPluginInstance&) at /Users/john/Downloads/pluginval-develop/Source/tests/BasicTests.cpp:294
#5	0x00000001092b6a8a in PluginTests::testType(juce::PluginDescription const&) at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:192
#6	0x00000001092b4bde in PluginTests::runTest() at /Users/john/Downloads/pluginval-develop/Source/PluginTests.cpp:107
#7	0x0000000109b68f55 in juce::UnitTest::performTest(juce::UnitTestRunner*) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:77
#8	0x0000000109b6b197 in juce::UnitTestRunner::runTests(juce::Array<juce::UnitTest*, juce::DummyCriticalSection, 0> const&, long long) at /Users/john/Downloads/pluginval-develop/modules/juce/modules/juce_core/unit_tests/juce_UnitTest.cpp:165
#9	0x000000010934b7aa in runTests(PluginTests&, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:205
#10	0x0000000109347ed9 in validate(juce::PluginDescription const&, PluginTests::Options, std::__1::function<void (juce::String const&)>) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:218
#11	0x0000000109345169 in ValidatorChildProcess::processRequest(juce::MemoryBlock) at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:519
#12	0x0000000109342626 in ValidatorChildProcess::processRequests() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:463
#13	0x000000010933eca4 in ValidatorChildProcess::run() at /Users/john/Downloads/pluginval-develop/Source/Validator.cpp:426

I got the same issue today with VS 2019

a simple fix is to defer execution of pluginStateTest and pluginStateTestRestoration to the message thread (as required by VST3) as follows:

struct PluginStateTest  : public PluginTest
{
    PluginStateTest()
        : PluginTest ("Plugin state", 2)
    {
    }

    void runTest (PluginTests& ut, AudioPluginInstance& instance) override
    {
      WaitableEvent completionEvent;
      MessageManager::callAsync([&, this]() mutable
      {
        auto r = ut.getRandom();

        // Read state
        MemoryBlock originalState;
        instance.getStateInformation(originalState);

        // Set random parameter values
        for (auto parameter : getNonBypassAutomatableParameters(instance))
          parameter->setValue(r.nextFloat());

        // Restore original state
        instance.setStateInformation(originalState.getData(), (int)originalState.getSize());

        completionEvent.signal();
      });
      completionEvent.wait();
    }
};

and likewise for PluginStateTestRestoration

I have a feeling that if this is now a requirement by the APIs a more general fix would be to specify this in the PluginTest:

    PluginStateTest()
        : PluginTest ("Plugin state", 2, { Requirements::Thread::messageThread, Requirements::GUI::noGUI })
    {

Does that make it work without asserting?

This is even better indeed. Thanks.

Now if I use --strictness-level 9 then (obviously) the BackgroundThreadStateTest asserts, but as its name suggests, it's meant to harness plugins.

and I also have the following assert in juce_VST3PluginFormat.cpp when AudioProcessingTest calls prepareToPlay()

    void prepareToPlay (double newSampleRate, int estimatedSamplesPerBlock) override
    {
        // The VST3 spec requires that IComponent::setupProcessing() is called on the message
        // thread. If you call it from a different thread, some plugins may break.
        JUCE_ASSERT_MESSAGE_THREAD
        MessageManagerLock lock;

Here however, the fix might not be so simple, because you may want to call prepareToPlay() from the message thread and processBlock() from an audio thread to simulate real world behaviour.

I think this is fixed in the 1.0.0 release