AudioProcessorValueTreeState - update text to value / value to text functions [resolved]


#1

Hi

With an AudioProcessorValueTreeState after I’ve done a createAndAddParameter passing the relevant std::function for valueToTextFunction and textToValueFunction, can I change those at a later time? I can’t see how.

If a run-time change in a plug-in’s state/mode causes there to be a need to modify the way a parameter’s 0…1 is converted to the range the user sees it would be useful to be able to change these functions. I can of course replumb the UI side of it easily with trivial extensions to Slider etc, but I can’t see how I would do this for what the host reports to the user. I would want the host and the UI’s version of a conversion to be the same of course.

Thanks
Matt


#2

Hi Matt,

If you take https://www.juce.com/doc/tutorial_audio_processor_value_tree_state as a starting point you can rewrite it to use two classes that respond to the () operator instead of using the static functions. So if you remove these functions from the code:

static String invertPhaseToText (float value)
{
    return value < 0.5 ? "Normal" : "Inverted";
}

static float textToInvertPhase (const String& text)
{
    if (text == "Normal")    return 0.0f;
    if (text == "Inverted")  return 1.0f;
    return 0.0f;
}

And before the TutorialProcessor class define these two classes:

class InvertPhaseToTextHelper
{
public:
    String operator() (float value)
    {
        return value < 0.5 ? "Normal" : "Inverted";
    }
};

class TextToInvertPhaseHelper
{
public:
    float operator() (const String& text)
    {
        if (text == "Normal")    return 0.0f;
        if (text == "Inverted")  return 1.0f;
        return 0.0f;
    }
};

Finally, add two members to the TutorialProcessor class, one for each of these two new classes:

private:
    //==============================================================================
    AudioProcessorValueTreeState parameters;
    float previousGain; // [1]
    
    InvertPhaseToTextHelper invertPhaseToText; //< Add this..
    TextToInvertPhaseHelper textToInvertPhase; //< ..and this
    ...

And since these two members have the same name as the original static functions this code will just work as before!

Now, this doesn’t give you the dynamic behaviour that your question is looking for but hopefully you can see how these can easily be made dynamic now that they are classes.

Perhaps better than this, could even define both functions in the same class as they have different arguments, for example:

class InvertPhaseTextHelper
{
public:
    String operator() (float value)
    {
        return value < 0.5 ? "Normal" : "Inverted";
    }
    
    float operator() (const String& text)
    {
        if (text == "Normal")    return 0.0f;
        if (text == "Inverted")  return 1.0f;
        return 0.0f;
    }
};

And that would, of course, make it easier to ensure the translations in both directions are always correct.


#3
float operator() (const String& text)
{
    return (text == "Inverted") ? 1.0f : 0.0f;
}

#4

That’s really neat and works just like I wanted, thanks Martin.


#5

Just did a search for this and the solution is great, thanks!