Jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail!


#1

Hi I’m just using trying latest version (v5.3.2) with my plug-in which was working fine. In debug I get this assert in ‘juce_ValueTree.cpp’

 jassert (object != nullptr); // Trying to add a property to a null ValueTree will fail!

The call stack has none of my code in it, and it appears to be on a timer, if I let it run for a while it stays unbroken until I start to move a parameter then quite quickly it asserts again, although I can see the parameter move slightly before it stops. Anybody have any idea what it’s doing? With the previous version was fine in debug. Has anyone seen that before? I thought my parameters were fine, well they all worked without problems.


#2

I’ve gone back to 5.3.1 and everything fine again. I would like to know what’s been added to cause this?


#3

It’s impossible to guess what might have led to that assertion being hit without more info.

But I suspect it’s not something that we’ve broken in the latest version - more likely you were doing something dodgy with threads etc and were just getting lucky until something else changed. If you can give us a stand-alone piece of code that reproduces the problem then we can have a look.


#4

The issue can easily be reproduced by creating an AudioProcessorValueTreeState and calling createAndAddParameter() without subsequently assigning an initialised ValueTree to AudioProcessorValueTreeState::state.

The docs say:

To use:
1) Create an AudioProcessorValueTreeState, and give it some parameters using createAndAddParameter().
2) Initialise the state member variable with a type name.

But in JUCE 5.3.1 you could get away with not performing ‘2’.

However, in JUCE 5.3.2 you get a crash because of this change, specifically removing the check if (state.isValid()) from copyValueToValueTree()

The call stack for the crash is:

|#0|0x00000001002c02b6 in juce::ValueTree::setPropertyExcludingListener(juce::ValueTree::Listener*, juce::Identifier const&, juce::var const&, juce::UndoManager*) at /Users/jamie/Desktop/TestCrash/Builds/MacOSX/../../../../Documents/JUCE5/modules/juce_data_structures/values/juce_ValueTree.cpp:737|
|---|---|
|#1|0x00000001002bee5d in juce::ValueTree::setProperty(juce::Identifier const&, juce::var const&, juce::UndoManager*) at /Users/jamie/Desktop/TestCrash/Builds/MacOSX/../../../../Documents/JUCE5/modules/juce_data_structures/values/juce_ValueTree.cpp:730|
|#2|0x0000000100142d27 in juce::AudioProcessorValueTreeState::Parameter::copyValueToValueTree() at /Users/jamie/Desktop/TestCrash/Builds/MacOSX/../../../../Documents/JUCE5/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:132|
|#3|0x0000000100142143 in juce::AudioProcessorValueTreeState::flushParameterValuesToValueTree() at /Users/jamie/Desktop/TestCrash/Builds/MacOSX/../../../../Documents/JUCE5/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:349|
|#4|0x0000000100142d89 in juce::AudioProcessorValueTreeState::timerCallback() at /Users/jamie/Desktop/TestCrash/Builds/MacOSX/../../../../Documents/JUCE5/modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp:359|

The solution is to initialise AudioProcessorValueTreeState::state as stated in the docs, e.g.

    AudioProcessorValueTreeState paramState(*this, nullptr);
    String paramID = "foo";
    paramState.createAndAddParameter (paramID, paramID, paramID,
                                      NormalisableRange<float>(0.f, 1.f),
                                      0.f, nullptr, nullptr);
    
    paramState.state = ValueTree("Foo");    /* <--- initialise!!! */

#5

Thank-you for a fantastic answer from admittedly a late-night panicky question.
So if I have to do this for every parameter why is it not done in “createAndAddParameter” ?


#6

That’s a misunderstanding. You only have to do it once after you added all parameters.
IIRC you will get an assert if you try to add a parameter after you attached the ValueTree to the public state member (that’s what this line does).


#7

It works, thanks all. I can update again!!! wooo. :grin:


#8

But - what if I want to add a parameter dynamically? (Imagine an expanding oscillator bank, with attached sub-params per oscillator type) What’s best practice for this?

-M


#9

AFAIK this is only available on some SDKs, and even less hosts support that.
That is the reason why JUCE doesn’t support that use case.


#11

Really? I’ll have to do some testing - removing the assert, for now. (Thank you for the quick reply)

Would you say that, if the former was a requirement, it would be best to create a fixed number of “dummy” parameters and then attach and remove controls to those parameters dynamically?

It seems messy. There has to be a better way.

-M


#12

If you have lot’s of parameters in the plugin or they are dynamic (modular devices), it is the best way to have a fixed number of public parameters (plugin parameters) which then are connected to one or more internal parameters. I would regard them as one type of control modulation sources in addition to internal ones, LFO’s, envelopes etc.