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

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 Likes

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

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.

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!!! */
10 Likes

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” ?

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).

1 Like

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

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

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.

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

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.

1 Like

Thanks…
It solved my problem

1 Like

Oh, wow, thanks for this reply!

I’ve been having quite a day of troubleshooting a few old tutorials in The Audio Programmer’s tutorial series. I thought I must’ve missed something in the video… but it seems not. Thanks so much for this answer! Not sure if there are some videos in the tutorial series that address these issues. Didn’t see anything obvious earlier