When I use te::Plugin::restorePluginStateFromValueTree(preset) to restore the state of a plugin, a subsequent call to te::Plugin::flushPluginStateToValueTree() leaves the state ValueTree with an unexpected te::IDs::parameters property like this:
The base64:parameters property prevents the plugin from using the updated āfeedbackā setting that I am attempting to recall.
Stepping through the code, I see
The base64:parameters property is being added by void AutomatableEditItem::saveChangedParametersToState() but I havenāt been able to figure out what the parameters property is for.
Updating internal plugin parameters via the .state ValueTree updates the value returned by AutomatableParameter::getCurrentValue(), but NOT the value returned by AutomatableParameter::getCurrentExplicitValue(). This discrepancy causes saveChangedParametersToState() to add the base64:parameters property to the pluginās state.
How can I correctly recall te::Plugin configuration from a ValueTree?
The parameters property is there due to modifiers. It is basically a way of recording any parameters that have been changed due to some kind of modifier (i.e. via a call to updateToFollowCurve or updateFromAutomationSources).
If you look at AutomatableParameter::setParameterValue, youāll see that the value the pluginās parameter is set to is based on the currentBaseValue and the currentModifierValue.
AutomatableParameter::setParameter sets currentParameterValue and is set when the user moves a parameter from a UI element.
Itās a bit tricky to explain but without it, setting a plugin parameter would change the state of the plugin. If this then gets saved and reloaded, any modifiers that are being used in the Edit (e.g. an LFO) simply get added to that saved value. This means thereās no way of knowing what the LFO should be applied to.
Hence the parameters property which stores the values explicitly set so we can restore these after a preset chunk is loaded.
I think in your case, you simply shouldnāt be updating the ValueTree state directly but going via one of the AutomatableParameters instead?
I was hoping to load and save presets for arbitrary plugins (similar to .trkpreset files). Is there a way I can do this that plays nicely with modifiers?
I am using the restorePluginStateFromValueTree method.
I call restorePluginStateFromValueTree to recall the plugins state.
The next time I call flushPluginStateToValueTree(), the state gets a parameters property, which effectively undoes the preset recall that I attempted to do.
For some reason, restorePluginStateFromValueTree updates the values returned by getCurrentValue() but not the values returned by getCurrentExplicitValue(), causing saveChangedParametersToState() to add the parameters property.
I thought maybe I had to wait to call flushPluginStateToValueTree (until the tree watchers handle the change, and update the plugin), but it doesnāt matter when I call it, it always adds the parameters property.
Ah ok, I think I know what you mean. Itās because youāre calling flushPluginStateToValueTree twice and restorePluginStateFromValueTree isnāt calling AutomatableParameter::setParameter.
Does calling AutomatableEditItem::restoreChangedParametersFromState on the plugin after restorePluginStateFromValueTree help?
That does sound like the function I need ā itās currently a protected method ā I tried moving under the public access specifier, and Iām still getting the same results.
Update: AutomatableEditItem::restoreChangedParametersFromState reads from the parameters property, and writes to the properties on the ValueTree. This doesnāt help, because the ValueTree properties (feedback="-30.0" in my example) are correct. The parameters property that contains old values that I am trying to update.
What plugin are you trying to do this with?
I think the ExternalPlugin overrides this to do the correct behaviour?
If itās an internal one, is there any chance you could construct a failing unit test I can replicate with? (grep the module for existing UnitTest subclasses as an example).
@dave96 Iām going to work on this sometime in the coming days, but before I do ā I donāt see an easy way to run the existing test in the tracktion_engine repo. I see the TempoSequenceTests : public UnitTest class, but no instances or subclasses of juceās UnitTestRunner.
Should I just send you a PIP that includes the tests?
This gets built and run by our CI on every commit.
If you can simply create the unit test subclass, I can add it where appropriate to the Engine code, fix the Engine so it passes and then it will be part of on going tests.
Iām just a bit slammed with NAMM at the moment and having a failing unit test make fixing this a lot quicker.
Sorry, I have seen it and itās on my list. Iāve been thinking about the appropriate solution and it might just be to set the parameters in restoreStateFromValueTree rather than directly set the cached values. I think that would work.
The other alternative is to modify AttachedValue to respond to changes in the ValueTree but I have a feeling that will result in recursive updatesā¦
Iāll try and look tomorrow.
Thanks for the test though, thatās extremely helpful.
Iām not sure if this is a bug or not, but I noticed that the āchorusā internal plugin has no
automatable parameters: (plugin->getAutomatableParameters() returns an empty list). It looks like it should have depthMs, width, mixProportion, and speedHz.
Yeah, those internal plugins are very old. I seem to remember that some parameters canāt be automated due to the implementation. If you change those parameters youāll get break-ups in the sound.
In our premium plugins (DAW Essentials) we do lots of things to work around that.