AudioProcessorParameter - validation issue for some 3rd party plug-ins

Hi JUCE devs,

I’ve seen a problem validating some 3rd party plugins.

The code hangs-up in here:

StringArray AudioProcessorParameter::getAllValueStrings() const
{
    if (isDiscrete() && valueStrings.isEmpty())
    {
        auto maxIndex = getNumSteps() - 1;

        for (int i = 0; i < getNumSteps(); ++i)
            valueStrings.add (getText ((float) i / (float) maxIndex, 1024));
    }

The reason? getNumSteps() is a valid off the scale!

Plug-in:

MIDI Route for iOS

  componentType = 1635085685 'aumu'
  componentSubType = 1836476777 'mvii'
  componentManufacturer = 1447380299 'VEEK'
  componentFlags = 14
  componentFlagsMask = 0

...
Printing description of this->discrete:
(const bool) discrete = true
Printing description of this->numSteps:
(const int) numSteps = 2147483647
Printing description of this->minValue:
(const AudioUnitParameterValue) minValue = -2.14748365E+9
Printing description of this->maxValue:
(const AudioUnitParameterValue) maxValue = 2.14748365E+9

I’m not really sure how to handle this. Other than imposing some sort of limit on numSteps :slight_smile:

Pete

My ongoing “fix” is:

juce_AudioUnitPluginFormat.mm

    void refreshParameterList() override
    {
        paramIDToParameter.clear();
        AudioProcessorParameterGroup newParameterTree;

        if (audioUnit != nullptr)
        {
            UInt32 paramListSize = 0;
            auto err = AudioUnitGetPropertyInfo (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global,
                                                 0, &paramListSize, nullptr);

            haveParameterList = (paramListSize > 0 && err == noErr);

            if (! haveParameterList)
                return;

            if (paramListSize > 0)
            {
                const size_t numParams = paramListSize / sizeof (int);

                std::vector<UInt32> ids (numParams, 0);

                AudioUnitGetProperty (audioUnit, kAudioUnitProperty_ParameterList, kAudioUnitScope_Global,
                                      0, ids.data(), &paramListSize);

                std::map<UInt32, AudioProcessorParameterGroup*> groupIDMap;

                for (size_t i = 0; i < numParams; ++i)
                {
                    AudioUnitParameterInfo info;
                    memset(&info, 0, sizeof(info)); // MPC!
                    UInt32 sz = sizeof (info);

                    if (AudioUnitGetProperty (audioUnit,
                                              kAudioUnitProperty_ParameterInfo,
                                              kAudioUnitScope_Global,
                                              ids[i], &info, &sz) == noErr)
                    {
                        String paramName;

                        if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0)
                        {
                            paramName = String::fromCFString (info.cfNameString);

                            if ((info.flags & kAudioUnitParameterFlag_CFNameRelease) != 0)
                                CFRelease (info.cfNameString);
                        }
                        else
                        {
                            paramName = String (info.name, sizeof (info.name));
                        }

                        bool isDiscrete = (info.unit == kAudioUnitParameterUnit_Indexed
                                        || info.unit == kAudioUnitParameterUnit_Boolean);
                        bool isBoolean = info.unit == kAudioUnitParameterUnit_Boolean;

                        auto label = [info]() -> String
                        {
                            if (info.unit == kAudioUnitParameterUnit_Percent)       return "%";
                            if (info.unit == kAudioUnitParameterUnit_Seconds)       return "s";
                            if (info.unit == kAudioUnitParameterUnit_Hertz)         return "Hz";
                            if (info.unit == kAudioUnitParameterUnit_Decibels)      return "dB";
                            if (info.unit == kAudioUnitParameterUnit_Milliseconds)  return "ms";

                            return {};
                        }();

                        // MPC - some plug-ins (e.g. MIDI Route) show *HUGE* ranges (begin)
                        auto numSteps = isDiscrete ? (int) (info.maxValue - info.minValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps();
                        if (numSteps > 1024) {
                            if (isDiscrete) {
                                numSteps = 1024;
                            }
                        }
                        // MPC - some plug-ins (e.g. MIDI Route) show *HUGE* ranges (end)


                        auto parameter = std::make_unique<AUInstanceParameter> (*this,
                                                                                ids[i],
                                                                                paramName,
                                                                                info.minValue,
                                                                                info.maxValue,
                                                                                info.defaultValue,
                                                                                (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0,
                                                                                isDiscrete,
                                                                                // MPC - some plug-ins (e.g. MIDI Route) show *HUGE* ranges (end)
                                                                               numSteps, // isDiscrete ? (int) (info.maxValue - info.minValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps(),
                                                                                // MPC - some plug-ins (e.g. MIDI Route) show *HUGE* ranges (end)
                                                                                isBoolean,
                                                                                label,
                                                                                (info.flags & kAudioUnitParameterFlag_ValuesHaveStrings) != 0);

This came out of the following thread, FWIW… Pete

2147483647 is std::limit<int_32>::max()

so maybe the plan was to say not discrete so instead of checking for 1024 maybe just checking for this particular value make sense.

Hi @otristan I agree: that is what I ended-up thinking!

Best if the JUCE team build that in to the code base.

It seems strange that nobody else has reported this problem, however? Maybe not many people are building plug-in host apps for iOS using JUCE!

Best wishes, Pete

@ed95 not sure if I should tag this with your handle, but wanted to make sure at least one JUCE dev saw it :slight_smile:

Pete