Why would ValueTree become invalid/missing by PluginEditor construction? [Solved]

Hello JUCErs,

I am trying to build the mechanics for storing & retrieving of automatable and non-automatable parameters of my plugin.

The basic structure is:

AudioProcessorValueTreeState
    -> ValueTree ("automatable params")
        -> ValueTree ("non-automatable params")

This state is created in the constructor of PluginProcessor.

Problem:

  • the child ValueTree (the ‘non-auto’ one) gets invalid by the time the PluginEditor needs to use it.

So, for the auto-params - I don’t touch APVTS’s tree directly. I add them through the interface of the APVTS:

void StateManager::createAutomatableFloatParameter (
    const String& parameterId,
    ...
)
{
    audioProcessorValueTreeState->createAndAddParameter(
        parameterId,
        ...
    );

    audioProcessorValueTreeState->addParameterListener (parameterId, this);
}

And for these which I don’t want visible by the DAW/automatable, I’m directly setting properties on the child tree of the APVTS->state (the ‘non-auto’ one):

void StateManager::createFloatParameter (
    const String& parameterId,
    const float defaultValue
)
{
    nonAutomatableParamsValueTree.setProperty (
        parameterId,
        defaultValue,
        nullptr
    );
}

Here is how I initialize the nonAutomatableParamsValueTree:

void StateManager::initNonAutomatableParamsValueTree ()
{
    // shouldn't be executed twice
    jassert (
        nonAutomatableParamsValueTree.getType ().toString ()
        != PARAMS::PLUGIN_STATE_IDENTIFIER_NON_AUTOMATABLE_BRANCH
    );

    nonAutomatableParamsValueTree = audioProcessorValueTreeState->state.getOrCreateChildWithName (
        PARAMS::PLUGIN_STATE_IDENTIFIER_NON_AUTOMATABLE_BRANCH,
        nullptr
    );

    nonAutomatableParamsValueTree.addListener (this);
}

Finally, this is the order all of this happens in the processor:

MyPluginProcessor::MyPluginProcessor ()
{
    undoManager = new UndoManager();
    pluginState = new AudioProcessorValueTreeState (*this, undoManager);

    // create automatable params
    stateManager->createAutomatableFloatParameter (...);
    stateManager->createAutomatableFloatParameter (...);
    ...

    pluginState->state = ValueTree (PARAMS::PLUGIN_STATE_IDENTIFIER);
    stateManager->initNonAutomatableParamsValueTree ();

    // create non-automatable params
    stateManager->createFloatParameter (...);
    stateManager->createFloatParameter (...);
    ...

    DBG (pluginState->state.getChildWithName (
        PARAMS::PLUGIN_STATE_IDENTIFIER_NON_AUTOMATABLE_BRANCH
    ).isValid ()); // this prints '1'
}

This same check (the DBG print at the bottom) prints ‘0’ in the constructor of PluginEditor.

I am guessing that I don’t understand something very basic about the ValueTree or/and the AudioProcessorValueTreeState…

Any help is much appreciated.

@daniel Any chance you have an idea why would this happen?

I feel so dumb… The loading of an older version of plugin’s state through PluginProcessor::setStateInformation(…) (which doesn’t have the inner ValueTree) was overriding the tree with the old format one.

Glad you found it :slight_smile: For completeness the answer to your question is: a tree that is created with the default constructor, see ValueTree():

Creates an empty, invalid ValueTree.
A ValueTree that is created with this constructor can’t actually be used for anything, it’s just a default ‘null’ ValueTree that can be returned to indicate some sort of failure. To create a real one, use the constructor that takes a string.

To be valid it needs to have an Identifier (which is the requirement in XML and JSON, which are the formats the ValueTree can be transformed in.

1 Like