Parameters are not saved accurately

Hello everyone.
I`m using AudioProcessorValueTreeState for save parameters of my compressor, but I was collapsed with a problem;
I converted values from gain to decibels with NormalisableRange and lambda in createParameter() method.

auto value = [](float value, int) { return String(std::log10(value) * 20.0f); };
auto userValue = [](const String& string)
{
    if (string.getFloatValue() >= -48.0f)
    {
        return juce::jlimit(0.0f, 2.0f, std::powf(10, string.getFloatValue() * 0.05));
    }
    if (string.getFloatValue() < -48.0f)
    {
        return 0.0f / 20.0f;
    }
};
auto overallGainParam = std::make_unique<AudioParameterFloat>(OVERALL_GAIN_ID, OVERALL_GAIN_NAME, NormalisableRange<float>(0.0f, 2.0f, 0.1f), 1.0f, "", AudioProcessorParameter::inputGain, value, userValue);
params.push_back(std::move(overallGainParam));

But now I can not correctly save parameters to XML. I noticed that when I build the code and run the plugin for the first time, a file is created in my Users folder with the extension .settings . When I call the plugin a second time, my previous settings are returned in a slightly modified form. Each subsequent time the plugin restores the state that was saved after the first call. .settings file is not updated.
Has anyone had this problem? Does anyone know how to deal with this?
I have run out of solutions to the problem, SOS!!!

Please observe:

  • Convert the second if into “else”… (why test again?)
  • What is the purpose of returning zero divided by 20?

This enum value is not a parameter, but instead it is used to send a current value to the host to display in their meters (first seen in AAX, but I think other formats have that as well).
You should keep using AudioProcessorParameter::genericParameter if you want to save that value.

With 0 / 20 I`m getting “-inf” value on my slider. In any case, even if we remove this branch from the code, the problem remains.

I was trying to point your attention to some bad coding style… and to learn a bit.

0.0f / 20.0f equals 0.0f for what it’s worth…

And the else clause was invented for you in this case :wink:

I tried to write this value there, the problem is not solved. Sliders are saved only once. Whatever I change further, every time I open the project, the state is returned to me as after the first session. Perhaps the problem is in the XML format or in my file system? I have not tested the plugin on other machines and I do not have this option.

Additionally this code should yield a warning of potentially not returning a value.

The juce coding styles even say remove the else entirely, since the return 0 shouldbe seen as a catch all:

auto value = [](float value, int) { return String(std::log10(value) * 20.0f); };
auto userValue = [](const String& string)
{
    if (string.getFloatValue() >= -48.0f)
        return juce::jlimit(0.0f, 2.0f, std::powf(10, string.getFloatValue() * 0.05));

    return 0.0f;
};

But it is probably unrelated to your problem anyway.

Did you implement the setStateInformation/getStateInformation at all?
Did you make sure the editor doesn’t reset values?

Good luck

EDIT: another N.B.: you can use the juce::Decibels::decibelsToGain, which makes it even more readable:

return juce::jlimit (0.0f, 2.0f, juce::Decibels::decibelsToGain (string.getFloatValue()));

Thank you, Peter, I will fix this place

1 Like

Yes, I implemented setStateInformation/getStateInfomation with standart way:

void DevilPumperInfinityAudioProcessor::getStateInformation(MemoryBlock& destData)
{
    std::unique_ptr<juce::XmlElement>xml(parameters.state.createXml());
    copyXmlToBinary(*xml, destData);
}

void DevilPumperInfinityAudioProcessor::setStateInformation(const void* data, int sizeInBytes)
{
    std::unique_ptr<juce::XmlElement>xmlState(getXmlFromBinary(data, sizeInBytes));
    if (xmlState != nullptr)
    {
        if (xmlState->hasTagName(parameters.state.getType()))
        {
            parameters.state = juce::ValueTree::fromXml(*xmlState);
        }
    }
}

Ok, thanks for answering. Did you debug into the setStateInformation, if you actually get a proper state returned?

Also adding a debug print could help understanding the issue:

DBG (parameters.state.toXmlString());

Not sure what you mean by “call the plugin a second time”. Maybe a stupid question, but are you loading a saved session that had that plugin in it, or opening a new instance of the plugin?

I load the last saved session along with the plugin

I used your tip for debug, thank you! However, the output shows that the OverallGain and Gain values have not changed:

First output:

<savedParameters>
  <PARAM id="attack_id" value="250.0"/>
  **<PARAM id="gain_id" value="1.800000071525574"/>**
  <PARAM id="knee_id" value="7.96999979019165"/>
  **<PARAM id="overall_gain_id" value="1.300000071525574"/>**
  <PARAM id="ratio_id" value="100.0"/>
  <PARAM id="release_id" value="2500.0"/>
  <PARAM id="threshold_id" value="0.0"/>
</savedParameters>

Then, I changed slider values. Second output:

<savedParameters>
  <PARAM id="attack_id" value="1.0"/>
  **<PARAM id="gain_id" value="1.800000071525574"/>**
  <PARAM id="knee_id" value="0.0"/>
  **<PARAM id="overall_gain_id" value="1.300000071525574"/>**
  <PARAM id="ratio_id" value="2.980000019073486"/>
  <PARAM id="release_id" value="177.8799896240234"/>
  <PARAM id="threshold_id" value="-47.63999938964844"/>
</savedParameters>

What I see is that the volume values have not changed, and some other values have not been preserved accurately. Because I remember exactly that I lowered the threshold to -50.