Trouble with APVTS ParameterListeners

Hi everyone,
I’ve been working on trying to implement a simple version of a lock-free queue for parameter changes in my current plugin project, but I keep running into seg faults with my parameter messengers. I think I’m making a silly mistake somewhere…

In my processor, I’ve defined a simple class whose purpose is to attach to a specific parameter and push messages with that parameter’s unique identifier into the queue:

class ParameterMessenger :  public juce::AudioProcessorValueTreeState::Listener
    {
    public:
        ParameterMessenger(bav::MessageQueue& queue, int paramIDtoListen):
            q(queue), paramID(paramIDtoListen)
        { }
        
        void parameterChanged (const juce::String& s, float value) override
        {
            juce::ignoreUnused (s);
            q.pushMessage (paramID, value);
        }
        
    private:
        bav::MessageQueue& q;
        const int paramID;
    };

My pluginProcessor has as a member:

std::vector<ParameterMessenger> parameterMessengers;  // all parameter messengers are stored in here

I created a function attempting to initialize a messenger for a specified parameter - the goal with this function is to create a messenger object, add it to the parameterMessengers vector, and add it as a listener to my APVTS:

void ImogenAudioProcessor::addParameterMessenger (juce::String stringID, int paramID)
{
    auto& messenger { parameterMessengers.emplace_back (ParameterMessenger(paramChanges, paramID)) };
    tree.addParameterListener (stringID, &messenger);
}

so that I can call it like this in my constructor:

    addParameterMessenger ("dryPan",                dryPanID);
    addParameterMessenger ("masterDryWet",          dryWetID);
    addParameterMessenger ("adsrAttack",            adsrAttackID);
    addParameterMessenger ("adsrDecay",             adsrDecayID);
  // etc etc

However, I keep hitting this error when testing with pluginval:

I suspect that I’m doing something wrong in my addParameterMessenger function…

Any help would be greatly appreciated!! :slight_smile:

Each time you call emplace_back, the vector needs to be resized, and its data possibly moved, so your previous pointers become invalid. To avoid this, reserve the final vector size before emplacing the elements and taking their pointers.

Oh that makes a lot of sense! I thought the error was something like that…

I already have an enum with the same number of items as there are parameters - is there any operation to find the number of items in an enum, so I don’t have to manually count each time?

I don’t think there’s a straightforward way to do that. Just in case -reserve should only be called once, before adding any element. If you don’t want to hard-code that number, your parameters are already created at that point, and you have an enum value for every parameter, you could use AudioProcessor::getParameters().size().

The common way to get the size of an enum is add another item at the end:

enum class MyEnum
{
    First,
    Second,
    NumItems
};

duh! thanks!

OK, I’ve got my listeners working and successfully adding messages to my queue.

But I’m getting some unexpected errors in processing the messages from the queue. What kind of value, exactly, gets sent to the APVTS::Listener’s parameterChanged? I was assuming it would be the normalized float value in the range 0.0 to 1.0, but my messages are coming through with values like 9, 17… :thinking:

Is it likely an error in my queue implementation, or is parameterChanged not behaving like I thought?

APVTS::Listener::parameterChanged gets denormalized values. AudioProcessorParameter::Listener::parameterValueChanged gets normalized values.

Ah, I see. Thanks!