Hi all,
I am getting a strange behaviour when using AudioParameterFloat with a value tree state: the values actually passed from the slider to my variables are not the one set in the default. Here my code snippets:
auto SystemDecayFilter1Param = std::make_unique<AudioParameterFloat> ("system_decay_panel_filter1",// parameterID
"System Decay Filter1", // parameter name
0.9999f, // minimum value
0.999999f, // maximum value
0.9965f); // default value
With the debugger placed in updateParameters() of PluginProcessor.cpp I see that the actual value is 0.999899983, which is not the one I set as default (i.e., 0.9965). Why is this happening? I need exact values of my parameters.
Moreover, if I change the minimum value of AudioParameterFloat from 0.9999f to 0.0f I get with the debugger that the actual value is now 0.999998986, yet different from the default value I set (and also from the previous value using the previous range).
This is an inconsistent behaviour of the default value and I can’t understand how to make Juce to have the right value from my slider set default value.
you’re setting a default lower than the minimum. that’s not gonna happen. otoh, that 0.999998986 seems to be your maximum -it’s the actual float value for 0.999999.
floating point has limited precision, and your range is too tiny. you may need to use a wider range for the parameter and then scale it in the process, maybe converting to double. otherwise you’re working on very few bits and scalings will turn them to noise.
So, in PluginProcessor.h I have set the variable const float scalingFactor = 10000.0f;. Then I called:
auto SystemDecayFilter1Param = std::make_unique<AudioParameterFloat> ("system_decay_panel_filter1",// parameterID
"System Decay Filter1", // parameter name
0.0f * scalingFactor, // minimum value
0.999999f * scalingFactor, // maximum value
0.9965f * scalingFactor); // default value
And then in my updateParameters() function I have scaled down:
However, this does not work. The compiler complains with JUCE Message Thread (1): EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
What is the right approach to solve the issue?
if you’re using from 0 to 0.999999, i’d make the parameter go from 0 to 1 and limit it in the process. scaling with such a small difference seems like a bad idea. if you’re using a small range like 0.9999-0.999999, i’d also make the parameter go from 0 to 1, or 0 to 100, and then scale in the process -say, setting a member variable for each parameter change. i don’t know your use case, but a small range like that is weird from a user’s perspective anyway -i’d hide it in the implementation.
My method worked. The issue was that the constructor was not called before the use of that variable. Indeed I am using the value tree and that is called first so the variable is not initialized.
Now I have another issue. I would like that the label associated to my slider displays the scaled value, not the value of the slider. I can’t find a function that allows me to do this. I am using this code for handling the slider and associated label in my gui editor subcomponent:
I think that is a crutch. The accuracy of float is not determined by the number of decimals after the comma, it is a binary expression in an scientific notation like number. Moving the comma just changes the exponent, and since you don’t do that in binary domain, you are even adding more conversion artifacts.
Ok, when reading again, I realised it might make sense. BUT when you specify the values, you should use double for your scaling factor, otherwise you still have the artifacts. Or just fill in the scaled numbers, so you don’t get conversion warnings, if you have turned them on.
And specify the NormalisedRange like I wrote in your other thread. You didn’t supply a step range, so the numbers are allowed to be somewhere between the nicely readable ones.
How about that for example:
auto SystemDecayFilter1Param = std::make_unique<AudioParameterFloat>
("system_decay_panel_filter1", // parameterID
"System Decay Filter1", // parameter name
NormalisableRange<float>(0f, // minimum
0.999999f, // maximum
0.000001f), // step size
0.9965f, // default value
String(), // label
AudioProcessorParameter::genericParameter,
[](float value, int maximumStringLength)
{
return String (value * 0.00001); // double is intended!
},
[](const String &text)
{
return float (text.getDoubleValue() * 0.00001); // explicit cast to avoid warning
}
);
However, I was wondering how user friendly a parameter is, that is changing 6 digits after the comma? Maybe re-think, what the value is actually representing?