setValueNotifyingHost() behaving weirdly

I’m trying to overwrite some audio-parameters by their name with a new value:

String name = "foo";
var value = 1;
//set value on AudioProcessorValueTreeState:
m_value_tree.getParameter(name)->setValueNotifyingHost(m_value_tree.getParameter(name)->convertTo0to1((float)value));
//read value from APVTS:
DBG("Value on tree is now: " + m_value_tree.getParameterAsValue(name).getValue().toString());

The first time I try to load, it will somehow ignore that the value was set, output is:

Value on tree is now: 0

However when I retrigger the load the next time, it will be updated:

Value on tree is now: 1

It will act in this kind of “buffered” manner: Everytime I load a new value onto the tree, it will set the value which was used in the load before that:
I load values 1->3->5, the state will be 0->1->3.

However, running the code above twice in a row, will not set the correct value. I’m calling this from the GUI-thread.
I’d imagine my problem lies somewhere in having an outdated reference to the APVTS, but I’m using the same m_value_tree twice in a row.

Any help appreciated…!

First of all, please make your code a bit more readable:

var value = 1; // I assume you have a reason to not make this value float to avoid later cast

// set value on AudioProcessorValueTreeState:
auto* param = m_value_tree.getParameter (name);
auto  oldValue = param->convertTo0to1 ((float)value);
param->setValueNotifyingHost (param->convertTo0to1 ((float)value));

Your problem could be, that the host is not expecting the value to change, because you didn’t send a beginChangeGesture() and endChangeGesture(). So it could either ignore it or immediately overwrite it with the previous automated value. I think it is not defined, what should happen.

You should call

auto* param = m_value_tree.getParameter (name);
auto  oldValue = param->convertTo0to1 ((float)value);
param->beginChangeGesture();
param->setValueNotifyingHost (param->convertTo0to1 ((float)value));
param->endChangeGesture();

see the docs: setValueNotifyingHost()

1 Like

Hi Daniel and thanks for your answer!

Yeah the actual code is hidden behind some macros, and this was my poor attempt to present it here while being on the train. Sorry for that.

Good call, but this didn’t change the behaviour.

In the mean time, I started another thread to fix the underlying concept rather, which is loading patches. I guess there’s a better way to do this and I will try to find another more elegant way if possible.

I did some more research and found that the APVTS will be updated, but seems to be exactly one ProcessBlock() after I load the patch. So somehow it appears to me that the value is set, but is stuck somewhere in a message queue.

I have to add that everything works fine for standard JUCE components, which have standard two-way connections to values, like Sliders for example. The problem arises from my custom components, which only have listeners as the value never changes by itself, apart from patch loading.

So what I do is use a forceValuesOntoGUI() function to update the GUI after loading a patch, but it happens too fast, before the APVTS has received its values, so the GUI laggs behind one load iteration.

Is there any way I can enforce this messaging to the APVTS by setValueNotifyingHost()?
Or would it be better to write proper parameter connections? (I’d really like to avoid this…)

Are you loading the patch on the audio thread? Otherwise how could you tell, that it is exactly one call later.

The wrapper works by continuously

  • updating the parameters from the SDK (AU/VST(3)/AAX), since the methods are different
  • preparing an AudioBuffer pointing to the audio provided by the SDK
  • updating the AudioPlayHead if applicable
  • calling your processBlock()

You see, if you load your patch in processBlock, they can only be updated the next run.

So those should probably not be AudioParameterXYZ, but rather be saved manually in a child node of the APVTS’ public state ValueTree. If they are not supposed to be changed by the host, why exposing them? It is sufficient, that they are stored with the session, which happens if you place it into said ValueTree.

No, see above. If you try, all you can achieve is causing major inconsistencies.

If they are AudioParameterXYZs, that are exposed to the host, then yes. You have to stick to the protocol and leave the host the final say to use or discard a value to work nicely with automation and control surfaces.

Yes I think this is my problem! I somehow managed to make these audioparameters, but hide them from the host. I am yet unsure why I did this or how I achieved it, but I guess it’s the root of the problem!

Thank you for your answer!