JUCE Assertion in AudioProcessesorValueTreeState::createAndAddParameter - isThisMessageThread()


#1

Hi Guys,

I’m not at my project machine at the moment to experiment but last night I was debugging some issues in my project and stumbled across a problem which causes GDB to crash out and kill Linux.

If I step through I can see a JUCE assertion is being thrown in AudioProcessorValueTreeState.cpp at line 186:

jassert (MessageManager::getInstance()->isThisTheMessageThread());

Is anyone able to give me an idea as to what might be causing this when I call createAndAddParameter() on my processor’s AudioProcessorValueTreeState member ?

Looks like I’m doing something wrong between the processor and editor constructors ? Trying to read something param wise before initialisation ?

The odd thing is this only causes a crash when I actually debug with GDB. When I run the plugin in the plugin-host the assertion doesn’t cause execution to terminate.

EDIT: Looking at platform defs it may be expected for the jassert to only kill execution if running under the debugger…

Any ideas on what I might be doing wrong would be much appreciated. Can post constructor code if needed.

Cheers


#2

May have just solved this. Will check back in this evening.


#3

Not figured this out yet. Does anyone have any ideas ?

Cheers


#4

Well, are you attempting to create parameters on the audio thread?


#5

I am creating my parameters in the processor’s constructor. As far as I was aware this is the right approach. I’ve posted the relevant construction code below.

Constructor:

BeatboxVoxAudioProcessor::BeatboxVoxAudioProcessor() 
    : classifier(256, 48000, 2)
      
{ 
    usingOSDTestSound.store(false);

    setupParameters();
    initialiseSynth(); 
}

Then my setupParameters function:

void BeatboxVoxAudioProcessor::setupParameters()
{
    
    processorUndoManager = std::make_unique<UndoManager>();
    processorState = std::make_unique<AudioProcessorValueTreeState>(*this, processorUndoManager.get());
    
    processorState->createAndAddParameter(paramOSDNoiseRatio, 
                                          "OSD Noise Ratio",
                                          "", 
                                          NormalisableRange<float> (0.01, 1.0, 0.01), 
                                          0.05, 
                                          nullptr, 
                                          nullptr);

    processorState->addParameterListener(paramOSDNoiseRatio, this);



    processorState->createAndAddParameter(paramOSDMeanCoeff, 
                                          "OSD Mean Coefficient",
                                          "",
                                          NormalisableRange<float> (0.01, 1.0, 0.01),
                                          1.0, 
                                          nullptr,
                                          nullptr);

    processorState->addParameterListener(paramOSDMeanCoeff, this);


    processorState->createAndAddParameter(paramOSDMedianCoeff, 
                                          "OSD Median Coefficient",
                                          "",
                                          NormalisableRange<float> (0.01, 1.0, 0.01),
                                          1.0, 
                                          nullptr,
                                          nullptr);

    processorState->addParameterListener(paramOSDMedianCoeff, this);


    processorState->createAndAddParameter(paramOSDMsBetweenOnsets, 
                                          "OSD Ms Between Onsets",
                                          "ms",
                                          NormalisableRange<float> (0.0, 50.0, 5.0),
                                          20.0,
                                          nullptr,
                                          nullptr);

    processorState->addParameterListener(paramOSDMsBetweenOnsets, this);


    processorState->state = ValueTree (Identifier ("Beatbox Vox"));

    auto onsetDetectMeanCallback = [this] (float newMeanCoeff) { this->classifier.setOnsetDetectorMeanCoeff(newMeanCoeff); };
    auto onsetDetectMedianCallback = [this] (float newMedianCoeff) { this->classifier.setOnsetDetectorMedianCoeff(newMedianCoeff); };
    auto onsetDetectNoiseCallback = [this] (float newNoiseRatio) { this->classifier.setOnsetDetectorNoiseRatio(newNoiseRatio); };
    auto onsetDetectMsBetweenCallback = [this] (float newMsBetweenOnsets) { this->classifier.setOSDMsBetweenOnsets(newMsBetweenOnsets); };
    
    paramCallbacks.insert(std::make_pair(paramOSDMeanCoeff, onsetDetectMeanCallback));
    paramCallbacks.insert(std::make_pair(paramOSDMedianCoeff, onsetDetectMedianCallback));
    paramCallbacks.insert(std::make_pair(paramOSDNoiseRatio, onsetDetectNoiseCallback));
    paramCallbacks.insert(std::make_pair(paramOSDMsBetweenOnsets, onsetDetectMsBetweenCallback));
}

Am I making some kind of school boy error here ?

Thanks Tom

EDIT: There is no suspicious looking code in the processBlock or anything daft but I am missing something in regards to which thread may be calling this constructor ?


#6

Just a thought, you get an assert called from the constructor, that you are not in the message thread.
Do you eventually construct the processor in a thread that is not the message thread?
Did you create other threads than the original message and audio thread, that may do the construction?


#7

Hi @daniel ,

No not as far as I can tell. I have not explicitly created any additional threads.

Literally loading this processor/plugin in the JUCE plugin-host as is.


#8

I should probably get rid of the unique_ptr for the AudioProcessorValueTreeState and UndoManager members and just make them regular member objects.

Not sure why I’ve got uniqe_ptr vars there actually …must have been on auto pilot. I’ll change that and see if it’s being caused by any weird lifetime bugs. May not be able to change till this evening though.


#9

Well, continuing down that path you could use this new tutorial as a guide:

https://www.juce.com/doc/tutorial_audio_processor_value_tree_state

Slowly make your plug-in as similar to the example as possible and it will work eventually (or, conversely, start with the example and make it more similar to your plug-in until it breaks).


#10

Yeah I’ll take a look through with a touch more scrutiny again this evening.

Thanks Tom


#11

Hi @t0m,

So I tried your suggestions, stripped out everything suspect from my plugin and was still unable to resolve the error.

Then I downloaded the zip file from the tutorial linked above and build the AudioProcessorValueTree plugin example on Ubuntu 16.04LTS with GCC 5.4.0 in Debug mode using the latest master branch.

I get the exact same error in gdb (and lldb) in the plugin’s constructor when loading it in the plugin host.

The assertion is thrown and I can view the DBG message in gdb which is below:

"JUCE Assertion failure in juce_AudioProcessorValueTreeState.cpp:186"

Any ideas ? I’m going to try a Windows build with both the tutorial project and my own project tomorrow to see if I get the same behaviour. I also tried rebuilding the plugin-host in debug mode but still received the same error.

I will do a fresh pull of the JUCE repo and rebuild the Projucer and host apps again to make certain in the mean time.

Cheers

Josh

EDIT: The assertion only causes execution to be killed when the debugger is attached and Ubuntu throws one of it’s much loved wobbly moments and resets.


#12

@t0m

UPDATE:

I have just pulled the latest repo and built the plugin-host and value tree tutorial projects and debugged in the constructor of the value tree tutorial plugin on Windows with VS 2015.

On windows the jassert in AudioProcessorValueTreeState::createAndAddParameter() passes and does not throw the assertion.

jassert (MessageManager::getInstance()->isThisTheMessageThread());

The above line does not cause any issues when the Visual Studio 2015 debugger is attached to the plugin-host.

Are you able to test this internally on Linux ?

EDIT: FYI my own plugin/project is also fine and does not throw the assertion in the Windows build


#13

I can confirm that this is a problem on Linux.

Thank you for all your effort in tracking this down!


#14

No Problem @t0m, thought I was loosing the plot there for a minute…

Cheers


#15

I can confirm the same bug running Linux and JUCE 4.3.0. All of the calls I make to createAndAddParameter are inside the processor’s constructor.


#16

This is fixed on the develop branch.