mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
AudioProcessorParameter: Add getVersionHint function
This commit is contained in:
parent
5186ac71e2
commit
7068e70758
17 changed files with 118 additions and 39 deletions
|
|
@ -1492,8 +1492,6 @@ void AudioProcessorListener::audioProcessorParameterChangeGestureBegin (AudioPro
|
|||
void AudioProcessorListener::audioProcessorParameterChangeGestureEnd (AudioProcessor*, int) {}
|
||||
|
||||
//==============================================================================
|
||||
AudioProcessorParameter::AudioProcessorParameter() noexcept {}
|
||||
|
||||
AudioProcessorParameter::~AudioProcessorParameter()
|
||||
{
|
||||
#if JUCE_DEBUG && ! JUCE_DISABLE_AUDIOPROCESSOR_BEGIN_END_GESTURE_CHECKING
|
||||
|
|
|
|||
|
|
@ -39,7 +39,58 @@ class AudioProcessor;
|
|||
class JUCE_API AudioProcessorParameter
|
||||
{
|
||||
public:
|
||||
AudioProcessorParameter() noexcept;
|
||||
AudioProcessorParameter() noexcept = default;
|
||||
|
||||
/** The version hint supplied to this constructor is used in Audio Unit plugins to aid ordering
|
||||
parameter identifiers when JUCE_FORCE_USE_LEGACY_PARAM_IDS is not enabled.
|
||||
|
||||
When adding a parameter that is not present in a previous version of the Audio Unit, you
|
||||
must ensure that the version hint supplied is a number higher than that of any parameter in
|
||||
any previous plugin version.
|
||||
|
||||
For example, in the first release of a plugin, every parameter was created with "1" as a
|
||||
version hint. If you add some parameters in the second release of the plugin, all of the
|
||||
new parameters should have "2" as a version hint. Additional parameters added in subsequent
|
||||
plugin versions should have "3", "4", and so forth, increasing monotonically.
|
||||
|
||||
Note that adding or removing parameters with a version hint that is lower than the maximum
|
||||
version hint of all parameters will break saved automation in some hosts, so be careful!
|
||||
|
||||
A version hint of "0" will be treated as though the version hint has not been set
|
||||
explicitly. When targeting the AU format, the version hint may be checked at runtime in
|
||||
debug builds to ensure that it has been set.
|
||||
|
||||
Rationale:
|
||||
|
||||
According to <a href="https://developer.apple.com/documentation/audiotoolbox/audiounitparameter?language=objc">Apple's Documentation</a>:
|
||||
> An audio unit parameter is uniquely identified by the combination of its scope, element, and ID.
|
||||
|
||||
However, Logic Pro and GarageBand have a known limitation that causes them to use parameter
|
||||
indices instead of IDs to identify parameters. The effect of this is that adding parameters
|
||||
to a later version of a plugin can break automation saved with an earlier version of the
|
||||
plugin if the indices of existing parameters are changed. It is *always* unsafe to remove
|
||||
parameters from an Audio Unit plugin that will be used in one of these hosts, because
|
||||
removing a parameter will always modify the indices of following parameters.
|
||||
|
||||
In order to work around this limitation, parameters in AUv2 plugins are sorted first by
|
||||
their version hint, and then by the hash of their string identifier. As long as the
|
||||
parameters from later versions of the plugin always have a version hint that is higher than
|
||||
the parameters from earlier versions of the plugin, recall of automation data will work as
|
||||
expected in Logic and GarageBand.
|
||||
|
||||
Note that we can't just use the JUCE parameter index directly in order to preserve ordering.
|
||||
This would require all new parameters to be added at the end of the parameter list, which
|
||||
would make it impossible to add parameters to existing parameter groups. It would also make
|
||||
it awkward to structure code sensibly, undoing all of the benefits of string-based parameter
|
||||
identifiers.
|
||||
|
||||
At time of writing, AUv3 plugins seem to be affected by the same issue, but there does not
|
||||
appear to be any API to control parameter indices in this format. Therefore, when building
|
||||
AUv3 plugins you must not add or remove parameters in subsequent plugin versions if you
|
||||
wish to support Logic and GarageBand.
|
||||
*/
|
||||
explicit AudioProcessorParameter (int versionHint)
|
||||
: version (versionHint) {}
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~AudioProcessorParameter();
|
||||
|
|
@ -224,6 +275,10 @@ public:
|
|||
*/
|
||||
virtual StringArray getAllValueStrings() const;
|
||||
|
||||
//==============================================================================
|
||||
/** @see AudioProcessorParameter(int) */
|
||||
int getVersionHint() const { return version; }
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A base class for listeners that want to know about changes to an
|
||||
|
|
@ -291,6 +346,7 @@ private:
|
|||
friend class LegacyAudioParameter;
|
||||
AudioProcessor* processor = nullptr;
|
||||
int parameterIndex = -1;
|
||||
int version = 0;
|
||||
CriticalSection listenerLock;
|
||||
Array<Listener*> listeners;
|
||||
mutable StringArray valueStrings;
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ namespace juce
|
|||
*/
|
||||
struct HostedAudioProcessorParameter : public AudioProcessorParameter
|
||||
{
|
||||
using AudioProcessorParameter::AudioProcessorParameter;
|
||||
|
||||
/** Returns an ID that is unique to this parameter.
|
||||
|
||||
Parameter indices are unstable across plugin versions, which means that the
|
||||
|
|
|
|||
|
|
@ -26,11 +26,14 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
AudioParameterBool::AudioParameterBool (const String& idToUse, const String& nameToUse,
|
||||
bool def, const String& labelToUse,
|
||||
AudioParameterBool::AudioParameterBool (const String& idToUse,
|
||||
const String& nameToUse,
|
||||
bool def,
|
||||
const String& labelToUse,
|
||||
std::function<String (bool, int)> stringFromBool,
|
||||
std::function<bool (const String&)> boolFromString)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse),
|
||||
std::function<bool (const String&)> boolFromString,
|
||||
int versionHintToUse)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse),
|
||||
value (def ? 1.0f : 0.0f),
|
||||
defaultValue (value),
|
||||
stringFromBoolFunction (stringFromBool),
|
||||
|
|
|
|||
|
|
@ -48,11 +48,13 @@ public:
|
|||
@param boolFromString An optional lambda function that parses a string and
|
||||
converts it into a bool value. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
AudioParameterBool (const String& parameterID, const String& parameterName, bool defaultValue,
|
||||
const String& parameterLabel = String(),
|
||||
std::function<String (bool value, int maximumStringLength)> stringFromBool = nullptr,
|
||||
std::function<bool (const String& text)> boolFromString = nullptr);
|
||||
std::function<bool (const String& text)> boolFromString = nullptr,
|
||||
int versionHint = 0);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterBool() override;
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@ namespace juce
|
|||
AudioParameterChoice::AudioParameterChoice (const String& idToUse, const String& nameToUse,
|
||||
const StringArray& c, int def, const String& labelToUse,
|
||||
std::function<String (int, int)> stringFromIndex,
|
||||
std::function<int (const String&)> indexFromString)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse), choices (c),
|
||||
std::function<int (const String&)> indexFromString,
|
||||
int versionHintToUse)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse),
|
||||
choices (c),
|
||||
range ([this]
|
||||
{
|
||||
NormalisableRange<float> rangeWithInterval { 0.0f, (float) choices.size() - 1.0f,
|
||||
|
|
|
|||
|
|
@ -50,13 +50,15 @@ public:
|
|||
@param indexFromString An optional lambda function that parses a string and
|
||||
converts it into a choice index. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
AudioParameterChoice (const String& parameterID, const String& parameterName,
|
||||
const StringArray& choices,
|
||||
int defaultItemIndex,
|
||||
const String& parameterLabel = String(),
|
||||
std::function<String (int index, int maximumStringLength)> stringFromIndex = nullptr,
|
||||
std::function<int (const String& text)> indexFromString = nullptr);
|
||||
std::function<int (const String& text)> indexFromString = nullptr,
|
||||
int versionHint = 0);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterChoice() override;
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ AudioParameterFloat::AudioParameterFloat (const String& idToUse, const String& n
|
|||
NormalisableRange<float> r, float def,
|
||||
const String& labelToUse, Category categoryToUse,
|
||||
std::function<String (float, int)> stringFromValue,
|
||||
std::function<float (const String&)> valueFromString)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse),
|
||||
std::function<float (const String&)> valueFromString,
|
||||
int versionHintToUse)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse, categoryToUse, versionHintToUse),
|
||||
range (r), value (def), defaultValue (def),
|
||||
stringFromValueFunction (stringFromValue),
|
||||
valueFromStringFunction (valueFromString)
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ public:
|
|||
@param valueFromString An optional lambda function that parses a string and
|
||||
converts it into a non-normalised value. Some hosts use
|
||||
this to allow users to type in parameter values.
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
AudioParameterFloat (const String& parameterID,
|
||||
const String& parameterName,
|
||||
|
|
@ -59,7 +60,8 @@ public:
|
|||
const String& parameterLabel = String(),
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
std::function<String (float value, int maximumStringLength)> stringFromValue = nullptr,
|
||||
std::function<float (const String& text)> valueFromString = nullptr);
|
||||
std::function<float (const String& text)> valueFromString = nullptr,
|
||||
int versionHint = 0);
|
||||
|
||||
/** Creates a AudioParameterFloat with an ID, name, and range.
|
||||
On creation, its value is set to the default value.
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ AudioParameterInt::AudioParameterInt (const String& idToUse, const String& nameT
|
|||
int minValue, int maxValue, int def,
|
||||
const String& labelToUse,
|
||||
std::function<String (int, int)> stringFromInt,
|
||||
std::function<int (const String&)> intFromString)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse),
|
||||
std::function<int (const String&)> intFromString,
|
||||
int versionHintToUse)
|
||||
: RangedAudioParameter (idToUse, nameToUse, labelToUse, Category::genericParameter, versionHintToUse),
|
||||
range ([minValue, maxValue]
|
||||
{
|
||||
NormalisableRange<float> rangeWithInterval { (float) minValue, (float) maxValue,
|
||||
|
|
|
|||
|
|
@ -51,13 +51,15 @@ public:
|
|||
@param intFromString An optional lambda function that parses a string
|
||||
and converts it into an int. Some hosts use this
|
||||
to allow users to type in parameter values.
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
AudioParameterInt (const String& parameterID, const String& parameterName,
|
||||
int minValue, int maxValue,
|
||||
int defaultValue,
|
||||
const String& parameterLabel = String(),
|
||||
std::function<String (int value, int maximumStringLength)> stringFromInt = nullptr,
|
||||
std::function<int (const String& text)> intFromString = nullptr);
|
||||
std::function<int (const String& text)> intFromString = nullptr,
|
||||
int versionHint = 0);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioParameterInt() override;
|
||||
|
|
|
|||
|
|
@ -29,9 +29,15 @@ namespace juce
|
|||
AudioProcessorParameterWithID::AudioProcessorParameterWithID (const String& idToUse,
|
||||
const String& nameToUse,
|
||||
const String& labelToUse,
|
||||
AudioProcessorParameter::Category categoryToUse)
|
||||
: paramID (idToUse), name (nameToUse), label (labelToUse), category (categoryToUse) {}
|
||||
AudioProcessorParameterWithID::~AudioProcessorParameterWithID() {}
|
||||
AudioProcessorParameter::Category categoryToUse,
|
||||
int versionHintToUse)
|
||||
: HostedAudioProcessorParameter (versionHintToUse),
|
||||
paramID (idToUse),
|
||||
name (nameToUse),
|
||||
label (labelToUse),
|
||||
category (categoryToUse)
|
||||
{
|
||||
}
|
||||
|
||||
String AudioProcessorParameterWithID::getName (int maximumStringLength) const { return name.substring (0, maximumStringLength); }
|
||||
String AudioProcessorParameterWithID::getLabel() const { return label; }
|
||||
|
|
|
|||
|
|
@ -38,14 +38,18 @@ class JUCE_API AudioProcessorParameterWithID : public HostedAudioProcessorPara
|
|||
public:
|
||||
/** The creation of this object requires providing a name and ID which will be
|
||||
constant for its lifetime.
|
||||
|
||||
@param parameterID Used to uniquely identify the parameter
|
||||
@param parameterName The user-facing name of the parameter
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param parameterCategory The semantics of this parameter
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
AudioProcessorParameterWithID (const String& parameterID,
|
||||
const String& parameterName,
|
||||
const String& parameterLabel = {},
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter);
|
||||
|
||||
/** Destructor. */
|
||||
~AudioProcessorParameterWithID() override;
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
int versionHint = 0);
|
||||
|
||||
/** Provides access to the parameter's ID string. */
|
||||
const String paramID;
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ AudioProcessorValueTreeState::Parameter::Parameter (const String& parameterID,
|
|||
bool isAutomatableParameter,
|
||||
bool isDiscrete,
|
||||
AudioProcessorParameter::Category parameterCategory,
|
||||
bool isBoolean)
|
||||
bool isBoolean,
|
||||
int versionHintToUse)
|
||||
: AudioParameterFloat (parameterID,
|
||||
parameterName,
|
||||
valueRange,
|
||||
|
|
@ -47,7 +48,8 @@ AudioProcessorValueTreeState::Parameter::Parameter (const String& parameterID,
|
|||
parameterCategory,
|
||||
valueToTextFunction == nullptr ? std::function<String (float v, int)>()
|
||||
: [valueToTextFunction] (float v, int) { return valueToTextFunction (v); },
|
||||
std::move (textToValueFunction)),
|
||||
std::move (textToValueFunction),
|
||||
versionHintToUse),
|
||||
unsnappedDefault (valueRange.convertTo0to1 (defaultParameterValue)),
|
||||
metaParameter (isMetaParameter),
|
||||
automatable (isAutomatableParameter),
|
||||
|
|
|
|||
|
|
@ -409,7 +409,8 @@ public:
|
|||
bool isAutomatableParameter = true,
|
||||
bool isDiscrete = false,
|
||||
AudioProcessorParameter::Category parameterCategory = AudioProcessorParameter::genericParameter,
|
||||
bool isBoolean = false);
|
||||
bool isBoolean = false,
|
||||
int versionHint = 0);
|
||||
|
||||
float getDefaultValue() const override;
|
||||
int getNumSteps() const override;
|
||||
|
|
|
|||
|
|
@ -26,14 +26,6 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
RangedAudioParameter::RangedAudioParameter (const String& parameterID,
|
||||
const String& parameterName,
|
||||
const String& parameterLabel,
|
||||
Category parameterCategory)
|
||||
: AudioProcessorParameterWithID (parameterID, parameterName, parameterLabel, parameterCategory)
|
||||
{
|
||||
}
|
||||
|
||||
int RangedAudioParameter::getNumSteps() const
|
||||
{
|
||||
const auto& range = getNormalisableRange();
|
||||
|
|
|
|||
|
|
@ -38,11 +38,14 @@ class JUCE_API RangedAudioParameter : public AudioProcessorParameterWithID
|
|||
public:
|
||||
/** The creation of this object requires providing a name and ID which will be
|
||||
constant for its lifetime.
|
||||
|
||||
@param parameterID Used to uniquely identify the parameter
|
||||
@param parameterName The user-facing name of the parameter
|
||||
@param parameterLabel An optional label for the parameter's value
|
||||
@param parameterCategory The semantics of this parameter
|
||||
@param versionHint See AudioProcessorParameter::getVersionHint()
|
||||
*/
|
||||
RangedAudioParameter (const String& parameterID,
|
||||
const String& parameterName,
|
||||
const String& parameterLabel = {},
|
||||
Category parameterCategory = AudioProcessorParameter::genericParameter);
|
||||
using AudioProcessorParameterWithID::AudioProcessorParameterWithID;
|
||||
|
||||
/** Returns the range of values that the parameter can take. */
|
||||
virtual const NormalisableRange<float>& getNormalisableRange() const = 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue