Skip to content

"Plugin state restoration" fails discrete parameters after "Fuzz parameters" in randomized order #188

Open

Description

@nkratochwill

With --strictness-level 10 --randomise (for example --random-seed 0x471e459), "Fuzz parameters" can run before "Plugin state restoration". Fuzzing sets a boolean or other discrete parameter to an arbitrary normalized value such as 0.2007; the plugin stores the parameter's logical value (off) in its state.

After setStateInformation, the restoration test compares the parameter's value with the raw 0.2007 it set. For a VST3, the value it reads comes from the host-side cache of the last value written, so the comparison fails although the plugin restored exactly what the parameter can hold.

Could the test compare discrete parameters by their logical value (snapped to the parameter's steps, or by getText) rather than the raw normalized value, or skip values set by the fuzzer that a discrete parameter cannot hold?

Seen with pluginval 1.0.4 on JUCE 9.0.2 plugins (VST3, macOS); reproduces with --random-seed 0x471e459.

Activity

  1. drowaudio commented on Oct 13, 2026

    @drowaudio
    Contributor

    Thanks for the report and the seed. There are two separate causes here, one in pluginval and one in JUCE.

    pluginval: hosted VST3 and AU parameters report the last value the host sent until a state is restored. "Plugin state restoration" read its "original" value without restoring first, so it could pick up whatever a previous test (such as "Fuzz parameters") had left behind. #191 fixes this by restoring the original state once before reading any values. That removes the false failures for choice and other multi-step parameters.

    JUCE: juce::AudioParameterBool::setValue keeps the raw normalised value it is given, while the state it saves holds the on/off step (checked against JUCE 9.0.3; Choice, Int and Float snap). The value a bool reports therefore depends on how it got there, and that still fails at strictness 8 and above after #191. The JUCE-side fix is value = convertFrom0to1 (newValue) in AudioParameterBool::setValue, matching the other parameter types.

    What changes with #191:

    • Below strictness 8, two-step (on/off) parameters are only sent 0 or 1, so these failures go away at levels 6 and 7.
    • At 8 and above pluginval still sends arbitrary values, since any normalised value is valid for a host to send. A new "Discrete parameter state restoration" test reports the bool behaviour explicitly.

    We decided against comparing by snapped value or getText, because only the plugin knows how a normalised value maps to a step.

    Until the JUCE change lands, at strictness 10 you can either snap the value in your own bool parameter, or pass --disabled-tests with a file listing "Plugin state restoration" and "Discrete parameter state restoration".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions