stringFromValue which depends on two values?

I don’t see any “[this]” used in that code. What line of code is causing that error now?

I was showing the way the code is arranged overall. The ‘this’ can be either:

auto valueToPercent = [this](float v, int) { return String (v * 100.0f, 1) + " %"; };

Or:

parameters.push_back (std::make_unique<AudioParameterFloat>
{
	"OscShape",
	"Osc Shape",
	range0To1,
	0.5f,
	"",
	AudioProcessorParameter::genericParameter,
	[this](float v, int) { return String (v * 100.0f, 1) + " %"; },
	percentToValue)
);

Either way, I get the error: ‘this’ may only be used inside a nonstatic member function.

Again, you wrote createParameterLayout() as a free function. Note it has no namespace attached, like FooProcessor::createParameterLayout(). That’s why it has no this pointer. It doesn’t even belong to a class/struct.

Howard’s approach is to create the AudioProcessorValueTreeState inside the constructor of his AudioProcessor, when all members are already initialised. It is doable, but not best practice.

In other words, going back to the message

the problem is not the function (createParameterLayout) being static (it’s not) -the problem is the function not being a member of anything.

Okay, so going back to my original question, how do I make a valueToString function which depends on two parameters?

Well, you can’t really change stringFromValue’s parameters (as in, arguments). If you need to involve another value, I think the first answer still applies -you need to capture it (which is to say, keep a pointer to it inside the function object). If it’s an instance field, you have to declare the lambda in a context where it exists -for example, in an instance member of the class. So you can, as Howard said, make createParameterLayout an instance member function of YourAudioProcessor and declare the lambda inside it.

class YourAudioProcessor : public AudioProcessor
{
    int wave{}; // or whatever type it has
    AudioProcessorValueTreeState state;
    AudioProcessorValueTreeState::ParameterLayout createParameterLayout()
    {
        std::vector<std::unique_ptr<RangedAudioParameter>> parameters;
        NormalisableRange<float> range0To1 (0.0f, 1.0f, 0.0f);
        auto stringFromOscShape = [this](float v, int) // or [&wave]
        {
            if (wave == PWM) // whatever PWM is
                return "Pulse Width: " + String (1.0f + v * 98.0f, 1) + "%";
            return String{};
        };
        parameters.push_back (std::make_unique<AudioParameterFloat>
        (
            "OscShape",
            "Osc Shape",
            range0To1,
            0.5f,
            "",
            AudioProcessorParameter::genericParameter,
            stringFromOscShape
        ));
        // etc
        return { parameters.begin(), parameters.end() };
    }
    // etc
}

You have to make sure of not using in createParameterLayout any field declared after state in YourAudioProcessor, because you’ll call the function in state’s initializer, and at that point anything declared after state doesn’t exist yet. That’s why it’s relevant that wave is declared before state.

Personally, I don’t like it. In a sense, you’re making one parameter depend on another, and stringFromValue is a tricky place to make that dependence. If the only purpose of this is changing the host’s display for the parameter, I wouldn’t make it just disappear for SAW. Somewhere you’re selecting SAW or PWM, and for anyone with the least understanding it’s evident that pulse width only applies when pulse width modulation is selected.

Thanks for this example code, kamedin. After some messing about, I’ve got it doing what I want.

I don’t see any issue with switching the parameter readout depending on what waveform is being generated - it’s just being done to make things clearer for the user. The SAW/PWM example I gave didn’t really need switching, but my actual code has 33 different formattings of the parameter depending on what waveform is selected. For example, one ‘waveform’ generates 16 different chords, and the parameter display gives the chord names, whereas 0-100% wouldn’t even give the user much clue which chord they were on. :slight_smile: