Browse Source

Added an option to declare plug-in parameters as either continuous or discrete, irrespective of their number of steps

tags/2021-05-28
tpoole 7 years ago
parent
commit
4dcce5083c
16 changed files with 276 additions and 65 deletions
  1. +38
    -8
      BREAKING-CHANGES.txt
  2. +14
    -6
      modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp
  3. +47
    -15
      modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm
  4. +20
    -9
      modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp
  5. +16
    -3
      modules/juce_audio_plugin_client/juce_audio_plugin_client.h
  6. +20
    -1
      modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm
  7. +33
    -9
      modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp
  8. +12
    -0
      modules/juce_audio_processors/juce_audio_processors.h
  9. +14
    -5
      modules/juce_audio_processors/processors/juce_AudioProcessor.cpp
  10. +25
    -0
      modules/juce_audio_processors/processors/juce_AudioProcessor.h
  11. +19
    -3
      modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h
  12. +1
    -0
      modules/juce_audio_processors/utilities/juce_AudioParameterBool.h
  13. +1
    -0
      modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h
  14. +2
    -0
      modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp
  15. +10
    -5
      modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp
  16. +4
    -1
      modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h

+ 38
- 8
BREAKING-CHANGES.txt View File

@@ -6,14 +6,44 @@ Develop Branch

Change
------
A new FrameRateType fps23976 has been added to AudioPlayHead
The method used to classify AudioUnit, VST3 and AAX plug-in parameters as
either continuous or discrete has changed.

Possible Issues
---------------
Previously JUCE would report the FrameRateType fps24 for both 24 and
23.976 fps. If your code uses switch statements (or similar) to handle
all possible frame rate types, then this change may cause it to fall
through.
Plug-ins: DAW projects with automation data written by an AudioUnit, VST3 or
AAX plug-in built with JUCE version 5.1.1 or earlier may load incorrectly when
opened by an AudioUnit, VST3 or AAX plug-in built with JUCE version 5.2.0 and
later.

Hosts: The AudioPluginInstance::getParameterNumSteps method now returns correct
values for AU and VST3 plug-ins.

Workaround
----------
Plug-ins: Enable JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE in the
juce_audio_plugin_client module config page in the Projucer.

Hosts: Use AudioPluginInstance::getDefaultNumParameterSteps as the number of
steps for all parameters.

Rationale
---------
The old system for presenting plug-in parameters to a host as either continuous
or discrete is inconsistent between plug-in types and lacks sufficient
flexibility. This change harmonises the behaviour and allows individual
parameters to be marked as continuous or discrete.


Change
------
A new FrameRateType fps23976 has been added to AudioPlayHead,

Possible Issues
---------------
Previously JUCE would report the FrameRateType fps24 for both 24 and 23.976
fps. If your code uses switch statements (or similar) to handle all possible
frame rate types, then this change may cause it to fall through.

Workaround
----------
@@ -21,8 +51,8 @@ Add fps23976 to your switch statement and handle it appropriately.

Rationale
---------
JUCE should be able to handle all popular frame rate codes but was
missing support for 23.976.
JUCE should be able to handle all popular frame rate codes but was missing
support for 23.976.


Change
@@ -120,7 +150,7 @@ or

2. Override the Look&Feel method
PopupMenu::LookAndFeelMethods::shouldPopupMenuScaleWithTargetComponent and
return false. See
return false. See
https://github.com/WeAreROLI/JUCE/blob/c288c94c2914af20f36c03ca9c5401fcb555e4e9/modules/juce_gui_basics/menus/juce_PopupMenu.h#725

Rationale


+ 14
- 6
modules/juce_audio_plugin_client/AAX/juce_AAX_Wrapper.cpp View File

@@ -1319,12 +1319,14 @@ namespace AAXClasses
for (int parameterIndex = 0; parameterIndex < numParameters; ++parameterIndex)
{
const AudioProcessorParameter::Category category = audioProcessor.getParameterCategory (parameterIndex);
auto* processorParam = audioProcessor.getParameters().getUnchecked (parameterIndex);
const AudioProcessorParameter::Category category = processorParam->getCategory();
aaxParamIDs.add (usingManagedParameters ? audioProcessor.getParameterID (parameterIndex)
: String (parameterIndex));
AAX_CString paramName (audioProcessor.getParameterName (parameterIndex, 31).toRawUTF8());
AAX_CString paramName (processorParam->getName (31).toRawUTF8());
AAX_CParamID paramID = aaxParamIDs.getReference (parameterIndex).getCharPointer();
paramMap.set (AAXClasses::getAAXParamHash (paramID), parameterIndex);
@@ -1339,19 +1341,25 @@ namespace AAXClasses
AAX_IParameter* parameter
= new AAX_CParameter<float> (paramID,
paramName,
audioProcessor.getParameterDefaultValue (parameterIndex),
processorParam->getDefaultValue(),
AAX_CLinearTaperDelegate<float, 0>(),
AAX_CNumberDisplayDelegate<float, 3>(),
audioProcessor.isParameterAutomatable (parameterIndex));
parameter->AddShortenedName (audioProcessor.getParameterName (parameterIndex, 4).toRawUTF8());
parameter->AddShortenedName (processorParam->getName (4).toRawUTF8());
const int parameterNumSteps = audioProcessor.getParameterNumSteps (parameterIndex);
const int parameterNumSteps = processorParam->getNumSteps();
parameter->SetNumberOfSteps ((uint32_t) parameterNumSteps);
#if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
parameter->SetType (parameterNumSteps > 1000 ? AAX_eParameterType_Continuous
: AAX_eParameterType_Discrete);
#else
parameter->SetType (processorParam->isDiscrete() ? AAX_eParameterType_Discrete
: AAX_eParameterType_Continuous);
#endif
parameter->SetOrientation (audioProcessor.isParameterOrientationInverted (parameterIndex)
parameter->SetOrientation (processorParam->isOrientationInverted()
? (AAX_eParameterOrientation_RightMinLeftMax | AAX_eParameterOrientation_TopMinBottomMax
| AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryRightMinLeftMax)
: (AAX_eParameterOrientation_LeftMinRightMax | AAX_eParameterOrientation_BottomMinTopMax


+ 47
- 15
modules/juce_audio_plugin_client/AU/juce_AU_Wrapper.mm View File

@@ -525,7 +525,7 @@ public:
const String text (String::fromCFString (pv->inString));
if (AudioProcessorParameter* param = juceFilter->getParameters() [paramID])
pv->outValue = param->getValueForText (text);
pv->outValue = param->getValueForText (text) * getMaximumParameterValue (param);
else
pv->outValue = text.getFloatValue();
@@ -546,11 +546,12 @@ public:
String text;
if (AudioProcessorParameter* param = juceFilter->getParameters() [paramID])
text = param->getText (value, 0);
text = param->getText (value / getMaximumParameterValue (param), 0);
else
text = String (value);
pv->outString = text.toCFString();
return noErr;
}
}
@@ -803,6 +804,17 @@ public:
}
//==============================================================================
// When parameters are discrete we need to use integer values.
static float getMaximumParameterValue (AudioProcessorParameter* param)
{
#if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
ignoreUnused (param);
return 1.0f;
#else
return param->isDiscrete() ? (float) (param->getNumSteps() - 1) : 1.0f;
#endif
}
ComponentResult GetParameterInfo (AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo& outParameterInfo) override
@@ -811,7 +823,7 @@ public:
if (inScope == kAudioUnitScope_Global
&& juceFilter != nullptr
&& index < juceFilter->getNumParameters())
&& isPositiveAndBelow (index, juceFilter->getNumParameters()))
{
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
@@ -823,28 +835,40 @@ public:
outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
#endif
const String name (juceFilter->getParameterName (index));
auto* param = juceFilter->getParameters().getUnchecked (index);
const String name (param->getName (512));
// set whether the param is automatable (unnamed parameters aren't allowed to be automated)
if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index))
// Set whether the param is automatable (unnamed parameters aren't allowed to be automated)
if (name.isEmpty() || ! param->isAutomatable())
outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
if (juceFilter->isMetaParameter (index))
if (! param->isDiscrete())
outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp;
if (param->isMetaParameter())
outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta;
// is this a meter?
if (((juceFilter->getParameterCategory (index) & 0xffff0000) >> 16) == 2)
// Is this a meter?
if (((param->getCategory() & 0xffff0000) >> 16) == 2)
{
outParameterInfo.flags &= ~kAudioUnitParameterFlag_IsWritable;
outParameterInfo.flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain;
}
else
{
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
outParameterInfo.unit = param->isDiscrete() ? kAudioUnitParameterUnit_Indexed
: kAudioUnitParameterUnit_Generic;
#endif
}
MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true);
outParameterInfo.minValue = 0.0f;
outParameterInfo.maxValue = 1.0f;
outParameterInfo.defaultValue = juceFilter->getParameterDefaultValue (index);
outParameterInfo.maxValue = getMaximumParameterValue (param);
outParameterInfo.defaultValue = param->getDefaultValue();
jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue
&& outParameterInfo.defaultValue <= outParameterInfo.maxValue);
@@ -861,9 +885,9 @@ public:
{
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
const int index = getJuceIndexForAUParameterID (inID);
auto* param = juceFilter->getParameters().getUnchecked (getJuceIndexForAUParameterID (inID));
outValue = juceFilter->getParameter (index);
outValue = param->getValue() * getMaximumParameterValue (param);
return noErr;
}
@@ -878,9 +902,9 @@ public:
{
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
const int index = getJuceIndexForAUParameterID (inID);
auto* param = juceFilter->getParameters().getUnchecked (getJuceIndexForAUParameterID (inID));
juceFilter->setParameter (index, inValue);
param->setValue (inValue / getMaximumParameterValue (param));
return noErr;
}
@@ -1727,6 +1751,14 @@ private:
{
Globals()->UseIndexedParameters (numParams);
}
#if JUCE_DEBUG
// Some hosts can't handle the huge numbers of discrete parameter values created when
// using the default number of steps.
for (auto* param : juceFilter->getParameters())
if (param->isDiscrete())
jassert (param->getNumSteps() != juceFilter->getDefaultNumParameterSteps());
#endif
}
//==============================================================================


+ 20
- 9
modules/juce_audio_plugin_client/VST3/juce_VST3_Wrapper.cpp View File

@@ -204,21 +204,32 @@ public:
Param (AudioProcessor& p, int index, Vst::ParamID paramID) : owner (p), paramIndex (index)
{
info.id = paramID;
toString128 (info.title, p.getParameterName (index));
toString128 (info.shortTitle, p.getParameterName (index, 8));
toString128 (info.units, p.getParameterLabel (index));
const int numSteps = p.getParameterNumSteps (index);
info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0);
info.defaultNormalizedValue = p.getParameterDefaultValue (index);
auto* param = p.getParameters().getUnchecked (index);
toString128 (info.title, param->getName (128));
toString128 (info.shortTitle, param->getName (8));
toString128 (info.units, param->getLabel());
info.stepCount = (Steinberg::int32) 0;
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
if (param->isDiscrete())
#endif
{
const int numSteps = param->getNumSteps();
info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0);
}
info.defaultNormalizedValue = param->getDefaultValue();
jassert (info.defaultNormalizedValue >= 0 && info.defaultNormalizedValue <= 1.0f);
info.unitId = Vst::kRootUnitId;
// is this a meter?
if (((p.getParameterCategory (index) & 0xffff0000) >> 16) == 2)
// Is this a meter?
if (((param->getCategory() & 0xffff0000) >> 16) == 2)
info.flags = Vst::ParameterInfo::kIsReadOnly;
else
info.flags = p.isParameterAutomatable (index) ? Vst::ParameterInfo::kCanAutomate : 0;
info.flags = param->isAutomatable() ? Vst::ParameterInfo::kCanAutomate : 0;
valueNormalized = info.defaultNormalizedValue;
}


+ 16
- 3
modules/juce_audio_plugin_client/juce_audio_plugin_client.h View File

@@ -65,15 +65,28 @@
#define JUCE_FORCE_USE_LEGACY_PARAM_IDS 0
#endif
/** Config: JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
Enable this if you want to force JUCE to use a legacy scheme for
identifying plug-in parameters as either continuous or discrete.
DAW projects with automation data written by an AudioUnit, VST3 or
AAX plug-in built with JUCE version 5.1.1 or earlier may load
incorrectly when opened by an AudioUnit, VST3 or AAX plug-in built
with JUCE version 5.2.0 and later.
*/
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 0
#endif
/** Config: JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
Enable this if you want JUCE to use parameter ids which are compatible
to Studio One. Studio One ignores any parameter ids which are negative.
with Studio One. Studio One ignores any parameter ids which are negative.
Enabling this option will make JUCE generate only positive parameter ids.
Note that if you have already released a plug-in prio to JUCE 4.3.0 then
Note that if you have already released a plug-in prior to JUCE 4.3.0 then
enabling this will change your parameter ids making your plug-in
incompatible to old automation data.
*/
*/
#ifndef JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
#define JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS 1
#endif


+ 20
- 1
modules/juce_audio_processors/format_types/juce_AudioUnitPluginFormat.mm View File

@@ -986,6 +986,22 @@ public:
const String getParameterText (int index) override { return String (getParameter (index)); }
int getParameterNumSteps (int index) override
{
if (auto* p = parameters[index])
return p->numSteps;
return AudioProcessor::getDefaultNumParameterSteps();
}
bool isParameterDiscrete (int index) const override
{
if (auto* p = parameters[index])
return p->discrete;
return false;
}
bool isParameterAutomatable (int index) const override
{
if (auto* p = parameters[index])
@@ -1178,6 +1194,8 @@ public:
param->minValue = info.minValue;
param->maxValue = info.maxValue;
param->automatable = (info.flags & kAudioUnitParameterFlag_NonRealTime) == 0;
param->discrete = (info.unit == kAudioUnitParameterUnit_Indexed);
param->numSteps = param->discrete ? (int) (info.maxValue + 1.0f) : AudioProcessor::getDefaultNumParameterSteps();
if ((info.flags & kAudioUnitParameterFlag_HasCFNameString) != 0)
{
@@ -1263,7 +1281,8 @@ private:
UInt32 paramID;
String name;
AudioUnitParameterValue minValue, maxValue;
bool automatable;
bool automatable, discrete;
int numSteps;
};
OwnedArray<ParamInfo> parameters;


+ 33
- 9
modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp View File

@@ -2247,30 +2247,54 @@ struct VST3PluginInstance : public AudioPluginInstance
return toString (getParameterInfoForIndex (parameterIndex).title);
}
float getParameter (int parameterIndex) override
const String getParameterText (int parameterIndex) override
{
if (editController != nullptr)
{
auto id = getParameterInfoForIndex (parameterIndex).id;
return (float) editController->getParamNormalized (id);
Vst::String128 result;
warnOnFailure (editController->getParamStringByValue (id, editController->getParamNormalized (id), result));
return toString (result);
}
return 0.0f;
return {};
}
const String getParameterText (int parameterIndex) override
int getParameterNumSteps (int parameterIndex) override
{
if (editController != nullptr)
{
auto id = getParameterInfoForIndex (parameterIndex).id;
const auto numSteps = getParameterInfoForIndex (parameterIndex).stepCount;
Vst::String128 result;
warnOnFailure (editController->getParamStringByValue (id, editController->getParamNormalized (id), result));
if (numSteps > 0)
return numSteps;
}
return toString (result);
return AudioProcessor::getDefaultNumParameterSteps();
}
bool isParameterDiscrete (int parameterIndex) const override
{
if (editController != nullptr)
{
const auto numSteps = getParameterInfoForIndex (parameterIndex).stepCount;
return numSteps > 0;
}
return {};
return false;
}
float getParameter (int parameterIndex) override
{
if (editController != nullptr)
{
auto id = getParameterInfoForIndex (parameterIndex).id;
return (float) editController->getParamNormalized (id);
}
return 0.0f;
}
void setParameter (int parameterIndex, float newValue) override


+ 12
- 0
modules/juce_audio_processors/juce_audio_processors.h View File

@@ -56,6 +56,18 @@
#include <juce_gui_basics/juce_gui_basics.h>
#include <juce_audio_basics/juce_audio_basics.h>
/** Config: JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
Enable this if you want to force JUCE to use an old scheme for selecting
when parameters are classified as discrete or continuous in a host. If this
is not enabled then DAW projects with automation data written by an
AudioUnit, VST3 or AAX plug-in built with JUCE version 5.1.1 or earlier may
load incorrectly when opened by an AudioUnit, VST3 or AAX plug-in built
with JUCE version 5.2.0 and later.
*/
#ifndef JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
#define JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE 0
#endif
//==============================================================================
/** Config: JUCE_PLUGINHOST_VST


+ 14
- 5
modules/juce_audio_processors/processors/juce_AudioProcessor.cpp View File

@@ -625,6 +625,14 @@ int AudioProcessor::getDefaultNumParameterSteps() noexcept
return 0x7fffffff;
}
bool AudioProcessor::isParameterDiscrete (int index) const
{
if (auto* p = managedParameters[index])
return p->isDiscrete();
return false;
}
String AudioProcessor::getParameterLabel (int index) const
{
if (auto* p = managedParameters[index])
@@ -1401,11 +1409,12 @@ void AudioProcessorParameter::endChangeGesture()
processor->endParameterChangeGesture (parameterIndex);
}
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
bool AudioProcessorParameter::isAutomatable() const { return true; }
bool AudioProcessorParameter::isMetaParameter() const { return false; }
AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; }
int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); }
bool AudioProcessorParameter::isOrientationInverted() const { return false; }
bool AudioProcessorParameter::isAutomatable() const { return true; }
bool AudioProcessorParameter::isMetaParameter() const { return false; }
AudioProcessorParameter::Category AudioProcessorParameter::getCategory() const { return genericParameter; }
int AudioProcessorParameter::getNumSteps() const { return AudioProcessor::getDefaultNumParameterSteps(); }
bool AudioProcessorParameter::isDiscrete() const { return false; }
String AudioProcessorParameter::getText (float value, int /*maximumStringLength*/) const
{


+ 25
- 0
modules/juce_audio_processors/processors/juce_AudioProcessor.h View File

@@ -1020,13 +1020,22 @@ public:
virtual String getParameterText (int parameterIndex, int maximumStringLength);
/** Returns the number of discrete steps that this parameter can represent.
The default return value if you don't implement this method is
AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
If you want the host to display stepped automation values, rather than a
continuous interpolation between successive values, you should ensure that
isParameterDiscrete returns true.
The value that is returned may or may not be used, depending on the host.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getNumSteps() instead.
@see isParameterDiscrete
*/
virtual int getParameterNumSteps (int parameterIndex);
@@ -1034,10 +1043,26 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getNumSteps() instead.
@see getParameterNumSteps
*/
static int getDefaultNumParameterSteps() noexcept;
/** Returns true if the parameter should take discrete, rather than continuous
values.
If the parameter is boolean, this should return true (with getParameterNumSteps
returning 2).
The value that is returned may or may not be used, depending on the host.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isDiscrete() instead.
@see getParameterNumSteps
*/
virtual bool isParameterDiscrete (int parameterIndex) const;
/** Returns the default value for the parameter.
By default, this just returns 0.
The value that is returned may or may not be used, depending on the host.


+ 19
- 3
modules/juce_audio_processors/processors/juce_AudioProcessorParameter.h View File

@@ -106,16 +106,32 @@ public:
*/
virtual String getLabel() const = 0;
/** Returns the number of discrete interval steps that this parameter's range
should be quantised into.
/** Returns the number of steps that this parameter's range should be quantised into.
If you want a continuous range of values, don't override this method, and allow
the default implementation to return AudioProcessor::getDefaultNumParameterSteps().
If your parameter is boolean, then you may want to make this return 2.
The value that is returned may or may not be used, depending on the host.
The value that is returned may or may not be used, depending on the host. If you
want the host to display stepped automation values, rather than a continuous
interpolation between successive values, you should override isDiscrete to return true.
@see isDiscrete
*/
virtual int getNumSteps() const;
/** Returns whether the parameter uses discrete values, based on the result of
getNumSteps, or allows the host to select values continuously.
This information may or may not be used, depending on the host. If you
want the host to display stepped automation values, rather than a continuous
interpolation between successive values, override this method to return true.
@see getNumSteps
*/
virtual bool isDiscrete() const;
/** Returns a textual version of the supplied parameter value.
The default implementation just returns the floating point value
as a string, but this could do anything you need for a custom type


+ 1
- 0
modules/juce_audio_processors/utilities/juce_AudioParameterBool.h View File

@@ -58,6 +58,7 @@ private:
void setValue (float newValue) override;
float getDefaultValue() const override;
int getNumSteps() const override;
bool isDiscrete() const override;
String getText (float, int) const override;
float getValueForText (const String&) const override;


+ 1
- 0
modules/juce_audio_processors/utilities/juce_AudioParameterChoice.h View File

@@ -69,6 +69,7 @@ private:
void setValue (float newValue) override;
float getDefaultValue() const override;
int getNumSteps() const override;
bool isDiscrete() const override;
String getText (float, int) const override;
float getValueForText (const String&) const override;


+ 2
- 0
modules/juce_audio_processors/utilities/juce_AudioProcessorParameters.cpp View File

@@ -124,6 +124,7 @@ float AudioParameterBool::getValue() const { retur
void AudioParameterBool::setValue (float newValue) { value = newValue; }
float AudioParameterBool::getDefaultValue() const { return defaultValue; }
int AudioParameterBool::getNumSteps() const { return 2; }
bool AudioParameterBool::isDiscrete() const { return true; }
float AudioParameterBool::getValueForText (const String& text) const { return text.getIntValue() != 0 ? 1.0f : 0.0f; }
String AudioParameterBool::getText (float v, int /*length*/) const { return String ((int) (v > 0.5f ? 1 : 0)); }
@@ -156,6 +157,7 @@ float AudioParameterChoice::getValue() const { retur
void AudioParameterChoice::setValue (float newValue) { value = (float) convertFrom0to1 (newValue); }
float AudioParameterChoice::getDefaultValue() const { return defaultValue; }
int AudioParameterChoice::getNumSteps() const { return choices.size(); }
bool AudioParameterChoice::isDiscrete() const { return true; }
float AudioParameterChoice::getValueForText (const String& text) const { return convertTo0to1 (choices.indexOf (text)); }
String AudioParameterChoice::getText (float v, int /*length*/) const { return choices [convertFrom0to1 (v)]; }


+ 10
- 5
modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.cpp View File

@@ -34,13 +34,15 @@ struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParamete
std::function<String (float)> valueToText,
std::function<float (const String&)> textToValue,
bool meta,
bool automatable)
bool automatable,
bool discrete)
: AudioProcessorParameterWithID (parameterID, paramName, labelText),
owner (s), valueToTextFunction (valueToText), textToValueFunction (textToValue),
range (r), value (defaultVal), defaultValue (defaultVal),
listenersNeedCalling (true),
isMetaParam (meta),
isAutomatableParam (automatable)
isAutomatableParam (automatable),
isDiscreteParam (discrete)
{
state.addListener (this);
needsUpdate.set (1);
@@ -150,6 +152,7 @@ struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParamete
bool isMetaParameter() const override { return isMetaParam; }
bool isAutomatable() const override { return isAutomatableParam; }
bool isDiscrete() const override { return isDiscreteParam; }
AudioProcessorValueTreeState& owner;
ValueTree state;
@@ -160,7 +163,7 @@ struct AudioProcessorValueTreeState::Parameter : public AudioProcessorParamete
float value, defaultValue;
Atomic<int> needsUpdate;
bool listenersNeedCalling;
const bool isMetaParam, isAutomatableParam;
const bool isMetaParam, isAutomatableParam, isDiscreteParam;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Parameter)
};
@@ -185,7 +188,8 @@ AudioProcessorParameterWithID* AudioProcessorValueTreeState::createAndAddParamet
float defaultVal, std::function<String (float)> valueToTextFunction,
std::function<float (const String&)> textToValueFunction,
bool isMetaParameter,
bool isAutomatableParameter)
bool isAutomatableParameter,
bool isDiscreteParameter)
{
// All parameters must be created before giving this manager a ValueTree state!
jassert (! state.isValid());
@@ -195,7 +199,8 @@ AudioProcessorParameterWithID* AudioProcessorValueTreeState::createAndAddParamet
Parameter* p = new Parameter (*this, paramID, paramName, labelText, r,
defaultVal, valueToTextFunction, textToValueFunction,
isMetaParameter, isAutomatableParameter);
isMetaParameter, isAutomatableParameter,
isDiscreteParameter);
processor.addParameter (p);
return p;
}


+ 4
- 1
modules/juce_audio_processors/utilities/juce_AudioProcessorValueTreeState.h View File

@@ -77,6 +77,8 @@ public:
@param textToValueFunction The inverse of valueToTextFunction
@param isMetaParameter Set this value to true if this should be a meta parameter
@param isAutomatableParameter Set this value to false if this parameter should not be automatable
@param isDiscrete Set this value to true to make this parameter take discrete values in a host.
@see AudioProcessorParameter::isDiscrete
@returns the parameter object that was created
*/
@@ -88,7 +90,8 @@ public:
std::function<String (float)> valueToTextFunction,
std::function<float (const String&)> textToValueFunction,
bool isMetaParameter = false,
bool isAutomatableParameter = true);
bool isAutomatableParameter = true,
bool isDiscrete = false);
/** Returns a parameter by its ID string. */
AudioProcessorParameterWithID* getParameter (StringRef parameterID) const noexcept;


Loading…
Cancel
Save