1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Re-worked plug-in wrappers to all use new parameter system via LegacyAudioParameter wrapper class

This commit is contained in:
hogliux 2018-04-04 11:02:43 +01:00
parent 2ff4d858c6
commit e05a1549f2
13 changed files with 842 additions and 779 deletions

View file

@ -307,6 +307,7 @@ struct GraphEditorPanel::FilterComponent : public Component
case 12: showWindow (PluginWindow::Type::generic); break;
case 20: showWindow (PluginWindow::Type::audioIO); break;
case 21: testStateSaveLoad(); break;
default: break;
}
}

View file

@ -34,6 +34,8 @@
#include "../utility/juce_WindowsHooks.h"
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wnon-virtual-dtor"
@ -635,6 +637,7 @@ namespace AAXClasses
AAX_Result Uninitialize() override
{
cancelPendingUpdate();
juceParameters.clear();
if (isPrepared && pluginInstance != nullptr)
{
@ -724,11 +727,11 @@ namespace AAXClasses
// * The preset is loaded in PT 10 using the AAX version.
// * The session is then saved, and closed.
// * The saved session is loaded, but acting as if the preset was never loaded.
auto numParameters = pluginInstance->getNumParameters();
auto numParameters = juceParameters.getNumParameters();
for (int i = 0; i < numParameters; ++i)
if (auto paramID = getAAXParamIDFromJuceIndex(i))
SetParameterNormalizedValue (paramID, (double) pluginInstance->getParameter(i));
SetParameterNormalizedValue (paramID, juceParameters.getParamForIndex (i)->getValue());
return AAX_SUCCESS;
}
@ -782,22 +785,20 @@ namespace AAXClasses
return AAX_SUCCESS;
}
void setAudioProcessorParameter (int index, float value)
void setAudioProcessorParameter (AAX_CParamID paramID, double value)
{
if (auto* param = pluginInstance->getParameters()[index])
if (auto* param = getParameterFromID (paramID))
{
if (value != param->getValue())
auto newValue = static_cast<float> (value);
if (newValue != param->getValue())
{
param->setValue (value);
param->setValue (newValue);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
param->sendValueChangedMessageToListeners (newValue);
}
}
else
{
pluginInstance->setParameter (index, value);
}
}
AAX_Result UpdateParameterNormalizedValue (AAX_CParamID paramID, double value, AAX_EUpdateSource source) override
@ -805,7 +806,7 @@ namespace AAXClasses
auto result = AAX_CEffectParameters::UpdateParameterNormalizedValue (paramID, value, source);
if (! isBypassParam (paramID))
setAudioProcessorParameter (getParamIndexFromID (paramID), (float) value);
setAudioProcessorParameter (paramID, value);
return result;
}
@ -818,10 +819,13 @@ namespace AAXClasses
return AAX_SUCCESS;
}
if (AudioProcessorParameter* param = pluginInstance->getParameters() [getParamIndexFromID (paramID)])
if (auto* param = getParameterFromID (paramID))
{
*result = param->getValueForText (text.Get());
return AAX_SUCCESS;
if (! LegacyAudioParameter::isLegacy (param))
{
*result = param->getValueForText (text.Get());
return AAX_SUCCESS;
}
}
return AAX_CEffectParameters::GetParameterValueFromString (paramID, result, text);
@ -835,15 +839,8 @@ namespace AAXClasses
}
else
{
auto paramIndex = getParamIndexFromID (paramID);
juce::String text;
if (auto* param = pluginInstance->getParameters() [paramIndex])
text = param->getText ((float) value, maxLen);
else
text = pluginInstance->getParameterText (paramIndex, maxLen);
result->Set (text.toRawUTF8());
if (auto* param = getParameterFromID (paramID))
result->Set (param->getText ((float) value, maxLen).toRawUTF8());
}
return AAX_SUCCESS;
@ -852,9 +849,14 @@ namespace AAXClasses
AAX_Result GetParameterNumberofSteps (AAX_CParamID paramID, int32_t* result) const
{
if (isBypassParam (paramID))
{
*result = 2;
}
else
*result = pluginInstance->getParameterNumSteps (getParamIndexFromID (paramID));
{
if (auto* param = getParameterFromID (paramID))
*result = param->getNumSteps();
}
return AAX_SUCCESS;
}
@ -864,7 +866,11 @@ namespace AAXClasses
if (isBypassParam (paramID))
return AAX_CEffectParameters::GetParameterNormalizedValue (paramID, result);
*result = pluginInstance->getParameter (getParamIndexFromID (paramID));
if (auto* param = getParameterFromID (paramID))
*result = (double) param->getValue();
else
*result = 0.0;
return AAX_SUCCESS;
}
@ -876,7 +882,7 @@ namespace AAXClasses
if (auto* p = mParameterManager.GetParameterByID (paramID))
p->SetValueWithFloat ((float) newValue);
setAudioProcessorParameter (getParamIndexFromID (paramID), (float) newValue);
setAudioProcessorParameter (paramID, (float) newValue);
return AAX_SUCCESS;
}
@ -886,13 +892,15 @@ namespace AAXClasses
if (isBypassParam (paramID))
return AAX_CEffectParameters::SetParameterNormalizedRelative (paramID, newDeltaValue);
auto paramIndex = getParamIndexFromID (paramID);
auto newValue = pluginInstance->getParameter (paramIndex) + (float) newDeltaValue;
if (auto* param = getParameterFromID (paramID))
{
auto newValue = param->getValue() + (float) newDeltaValue;
setAudioProcessorParameter (paramIndex, jlimit (0.0f, 1.0f, newValue));
setAudioProcessorParameter (paramID, jlimit (0.0f, 1.0f, newValue));
if (auto* p = mParameterManager.GetParameterByID (paramID))
p->SetValueWithFloat (newValue);
if (auto* p = mParameterManager.GetParameterByID (paramID))
p->SetValueWithFloat (newValue);
}
return AAX_SUCCESS;
}
@ -900,11 +908,15 @@ namespace AAXClasses
AAX_Result GetParameterNameOfLength (AAX_CParamID paramID, AAX_IString* result, int32_t maxLen) const override
{
if (isBypassParam (paramID))
{
result->Set (maxLen >= 13 ? "Master Bypass"
: (maxLen >= 8 ? "Mast Byp"
: (maxLen >= 6 ? "MstByp" : "MByp")));
else
result->Set (pluginInstance->getParameterName (getParamIndexFromID (paramID), maxLen).toRawUTF8());
}
else if (auto* param = getParameterFromID (paramID))
{
result->Set (param->getName (maxLen).toRawUTF8());
}
return AAX_SUCCESS;
}
@ -913,8 +925,8 @@ namespace AAXClasses
{
if (isBypassParam (paramID))
result->Set ("Master Bypass");
else
result->Set (pluginInstance->getParameterName (getParamIndexFromID (paramID), 31).toRawUTF8());
else if (auto* param = getParameterFromID (paramID))
result->Set (param->getName (31).toRawUTF8());
return AAX_SUCCESS;
}
@ -923,7 +935,10 @@ namespace AAXClasses
{
if (! isBypassParam (paramID))
{
*result = (double) pluginInstance->getParameterDefaultValue (getParamIndexFromID (paramID));
if (auto* param = getParameterFromID (paramID))
*result = (double) param->getDefaultValue();
else
*result = 0.0;
jassert (*result >= 0 && *result <= 1.0f);
}
@ -1014,13 +1029,13 @@ namespace AAXClasses
{
++mNumPlugInChanges;
auto numParameters = pluginInstance->getNumParameters();
auto numParameters = juceParameters.getNumParameters();
for (int i = 0; i < numParameters; ++i)
{
if (auto* p = mParameterManager.GetParameterByID (getAAXParamIDFromJuceIndex (i)))
{
auto newName = processor->getParameterName (i, 31);
auto newName = juceParameters.getParamForIndex (i)->getName (31);
if (p->Name() != newName.toRawUTF8())
p->SetName (AAX_CString (newName.toRawUTF8()));
@ -1158,7 +1173,7 @@ namespace AAXClasses
if (meterBuffers != nullptr)
for (int i = 0; i < numMeters; ++i)
meterBuffers[i] = pluginInstance->getParameter (aaxMeters[i]);
meterBuffers[i] = aaxMeters[i]->getValue();
}
}
@ -1422,53 +1437,56 @@ namespace AAXClasses
void addAudioProcessorParameters()
{
auto& audioProcessor = getPluginInstance();
auto numParameters = audioProcessor.getNumParameters();
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const bool usingManagedParameters = false;
const bool forceLegacyParamIDs = true;
#else
const bool usingManagedParameters = (audioProcessor.getParameters().size() == numParameters);
const bool forceLegacyParamIDs = false;
#endif
for (int parameterIndex = 0; parameterIndex < numParameters; ++parameterIndex)
juceParameters.update (audioProcessor, forceLegacyParamIDs);
int parameterIndex = 0;
for (auto* juceParam : juceParameters.params)
{
auto category = audioProcessor.getParameterCategory (parameterIndex);
auto category = juceParam->getCategory();
auto paramID = juceParameters.getParamID (audioProcessor, parameterIndex)
.toRawUTF8();
aaxParamIDs.add (usingManagedParameters ? audioProcessor.getParameterID (parameterIndex)
: String (parameterIndex));
aaxParamIDs.add (paramID);
auto aaxParamID = aaxParamIDs.getReference (parameterIndex++).getCharPointer();
auto paramID = aaxParamIDs.getReference (parameterIndex).getCharPointer();
paramMap.set (AAXClasses::getAAXParamHash (paramID), parameterIndex);
paramMap.set (AAXClasses::getAAXParamHash (aaxParamID), juceParam);
// is this a meter?
if (((category & 0xffff0000) >> 16) == 2)
{
aaxMeters.add (parameterIndex);
aaxMeters.add (juceParam);
continue;
}
auto parameter = new AAX_CParameter<float> (paramID,
AAX_CString (audioProcessor.getParameterName (parameterIndex, 31).toRawUTF8()),
audioProcessor.getParameterDefaultValue (parameterIndex),
auto parameter = new AAX_CParameter<float> (aaxParamID,
AAX_CString (juceParam->getName (31).toRawUTF8()),
juceParam->getDefaultValue(),
AAX_CLinearTaperDelegate<float, 0>(),
AAX_CNumberDisplayDelegate<float, 3>(),
audioProcessor.isParameterAutomatable (parameterIndex));
juceParam->isAutomatable());
parameter->AddShortenedName (audioProcessor.getParameterName (parameterIndex, 4).toRawUTF8());
parameter->AddShortenedName (juceParam->getName (4).toRawUTF8());
auto parameterNumSteps = audioProcessor.getParameterNumSteps (parameterIndex);
auto parameterNumSteps = juceParam->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 (audioProcessor.isParameterDiscrete (parameterIndex) ? AAX_eParameterType_Discrete
: AAX_eParameterType_Continuous);
parameter->SetType (juceParam->isDiscrete() ? AAX_eParameterType_Discrete
: AAX_eParameterType_Continuous);
#endif
parameter->SetOrientation (audioProcessor.isParameterOrientationInverted (parameterIndex)
parameter->SetOrientation (juceParam->isOrientationInverted()
? (AAX_eParameterOrientation_RightMinLeftMax | AAX_eParameterOrientation_TopMinBottomMax
| AAX_eParameterOrientation_RotarySingleDotMode | AAX_eParameterOrientation_RotaryRightMinLeftMax)
: (AAX_eParameterOrientation_LeftMinRightMax | AAX_eParameterOrientation_BottomMinTopMax
@ -1696,7 +1714,10 @@ namespace AAXClasses
//==============================================================================
inline int getParamIndexFromID (AAX_CParamID paramID) const noexcept
{
return paramMap [AAXClasses::getAAXParamHash (paramID)];
if (auto* param = getParameterFromID (paramID))
return LegacyAudioParameter::getParamIndex (getPluginInstance(), param);
return -1;
}
inline AAX_CParamID getAAXParamIDFromJuceIndex (int index) const noexcept
@ -1707,6 +1728,11 @@ namespace AAXClasses
return nullptr;
}
AudioProcessorParameter* getParameterFromID (AAX_CParamID paramID) const noexcept
{
return paramMap [AAXClasses::getAAXParamHash (paramID)];
}
//==============================================================================
static AudioProcessor::BusesLayout getDefaultLayout (const AudioProcessor& p, bool enableAll)
{
@ -1757,9 +1783,10 @@ namespace AAXClasses
Array<int> inputLayoutMap, outputLayoutMap;
Array<String> aaxParamIDs;
HashMap<int32, int> paramMap;
HashMap<int32, AudioProcessorParameter*> paramMap;
LegacyAudioParametersWrapper juceParameters;
Array<int> aaxMeters;
Array<AudioProcessorParameter*> aaxMeters;
struct ChunkMemoryBlock
{
@ -1835,12 +1862,21 @@ namespace AAXClasses
//==============================================================================
static int addAAXMeters (AudioProcessor& p, AAX_IEffectDescriptor& descriptor)
{
const int n = p.getNumParameters();
LegacyAudioParametersWrapper params;
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const bool forceLegacyParamIDs = true;
#else
const bool forceLegacyParamIDs = false;
#endif
params.update (p, forceLegacyParamIDs);
int meterIdx = 0;
for (int i = 0; i < n; ++i)
for (auto* param : params.params)
{
auto category = p.getParameterCategory (i);
auto category = param->getCategory();
// is this a meter?
if (((category & 0xffff0000) >> 16) == 2)
@ -1851,7 +1887,7 @@ namespace AAXClasses
meterProperties->AddProperty (AAX_eProperty_Meter_Orientation, AAX_eMeterOrientation_TopRight);
descriptor.AddMeterDescription ('Metr' + static_cast<AAX_CTypeID> (meterIdx++),
p.getParameterName (i).toRawUTF8(), meterProperties);
param->getName (1024).toRawUTF8(), meterProperties);
}
}
}

View file

@ -81,6 +81,7 @@
#include "../utility/juce_CarbonVisibility.h"
#include "../../juce_audio_basics/native/juce_mac_CoreAudioLayouts.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#include "../../juce_audio_processors/format_types/juce_AU_Shared.h"
//==============================================================================
@ -527,15 +528,18 @@ public:
{
if (juceFilter != nullptr)
{
const int i = getJuceIndexForAUParameterID (pv->inParamID);
const String text (String::fromCFString (pv->inString));
if (auto* param = getParameterForAUParameterID (pv->inParamID))
{
const String text (String::fromCFString (pv->inString));
if (AudioProcessorParameter* param = juceFilter->getParameters()[i])
pv->outValue = param->getValueForText (text) * getMaximumParameterValue (i);
else
pv->outValue = text.getFloatValue();
if (LegacyAudioParameter::isLegacy (param))
pv->outValue = text.getFloatValue();
else
pv->outValue = param->getValueForText (text) * getMaximumParameterValue (param);
return noErr;
return noErr;
}
}
}
}
@ -547,18 +551,20 @@ public:
{
if (juceFilter != nullptr)
{
const int i = getJuceIndexForAUParameterID (pv->inParamID);
const float value = (float) *(pv->inValue);
String text;
if (auto* param = getParameterForAUParameterID (pv->inParamID))
{
const float value = (float) *(pv->inValue);
String text;
if (AudioProcessorParameter* param = juceFilter->getParameters()[i])
text = param->getText (value / getMaximumParameterValue (i), 0);
else
text = String (value);
if (LegacyAudioParameter::isLegacy (param))
text = String (value);
else
text = param->getText (value / getMaximumParameterValue (param), 0);
pv->outString = text.toCFString();
pv->outString = text.toCFString();
return noErr;
return noErr;
}
}
}
}
@ -793,7 +799,7 @@ public:
if (inLayout == nullptr)
return kAudioUnitErr_InvalidPropertyValue;
if (const AUIOElement* ioElement = GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element))
if (const AUIOElement* ioElement = GetIOElement (isInput ? kAudioUnitScope_Input : kAudioUnitScope_Output, element))
{
const AudioChannelSet newChannelSet = CoreAudioLayouts::fromCoreAudio (*inLayout);
const int currentNumChannels = static_cast<int> (ioElement->GetStreamFormat().NumberChannels());
@ -825,82 +831,73 @@ public:
//==============================================================================
// When parameters are discrete we need to use integer values.
float getMaximumParameterValue (int parameterIndex)
float getMaximumParameterValue (AudioProcessorParameter* param)
{
#if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
ignoreUnused (parameterIndex);
return 1.0f;
#else
return juceFilter->isParameterDiscrete (parameterIndex) ? (float) (juceFilter->getParameterNumSteps (parameterIndex) - 1) : 1.0f;
#endif
return param->isDiscrete() && (! forceUseLegacyParamIDs) ? (float) (param->getNumSteps() - 1) : 1.0f;
}
ComponentResult GetParameterInfo (AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
AudioUnitParameterInfo& outParameterInfo) override
{
const int index = getJuceIndexForAUParameterID (inParameterID);
if (inScope == kAudioUnitScope_Global
&& juceFilter != nullptr
&& isPositiveAndBelow (index, juceFilter->getNumParameters()))
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
| kAudioUnitParameterFlag_IsReadable
| kAudioUnitParameterFlag_HasCFNameString
| kAudioUnitParameterFlag_ValuesHaveStrings);
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
#endif
const String name (juceFilter->getParameterName (index));
// Set whether the param is automatable (unnamed parameters aren't allowed to be automated)
if (name.isEmpty() || ! juceFilter->isParameterAutomatable (index))
outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
const bool isParameterDiscrete = juceFilter->isParameterDiscrete (index);
if (! isParameterDiscrete)
outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp;
if (juceFilter->isMetaParameter (index))
outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta;
// Is this a meter?
if (((juceFilter->getParameterCategory (index) & 0xffff0000) >> 16) == 2)
{
outParameterInfo.flags &= ~kAudioUnitParameterFlag_IsWritable;
outParameterInfo.flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
outParameterInfo.unit = kAudioUnitParameterUnit_LinearGain;
}
else
if (auto* param = getParameterForAUParameterID (inParameterID))
{
outParameterInfo.unit = kAudioUnitParameterUnit_Generic;
outParameterInfo.flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
| kAudioUnitParameterFlag_IsReadable
| kAudioUnitParameterFlag_HasCFNameString
| kAudioUnitParameterFlag_ValuesHaveStrings);
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
if (isParameterDiscrete)
{
outParameterInfo.unit = kAudioUnitParameterUnit_Indexed;
outParameterInfo.flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
#endif
if (auto* param = juceFilter->getParameters()[index])
const String name = param->getName (1024);
// Set whether the param is automatable (unnamed parameters aren't allowed to be automated)
if (name.isEmpty() || ! param->isAutomatable())
outParameterInfo.flags |= kAudioUnitParameterFlag_NonRealTime;
const bool isParameterDiscrete = param->isDiscrete();
if (! isParameterDiscrete)
outParameterInfo.flags |= kAudioUnitParameterFlag_CanRamp;
if (param->isMetaParameter())
outParameterInfo.flags |= kAudioUnitParameterFlag_IsGlobalMeta;
// 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
if (isParameterDiscrete)
{
outParameterInfo.unit = kAudioUnitParameterUnit_Indexed;
if (param->isBoolean())
outParameterInfo.unit = kAudioUnitParameterUnit_Boolean;
}
#endif
}
#endif
MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true);
outParameterInfo.minValue = 0.0f;
outParameterInfo.maxValue = getMaximumParameterValue (param);
outParameterInfo.defaultValue = param->getDefaultValue() * getMaximumParameterValue (param);
jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue
&& outParameterInfo.defaultValue <= outParameterInfo.maxValue);
return noErr;
}
MusicDeviceBase::FillInParameterName (outParameterInfo, name.toCFString(), true);
outParameterInfo.minValue = 0.0f;
outParameterInfo.maxValue = getMaximumParameterValue (index);
outParameterInfo.defaultValue = juceFilter->getParameterDefaultValue (index) * getMaximumParameterValue (index);
jassert (outParameterInfo.defaultValue >= outParameterInfo.minValue
&& outParameterInfo.defaultValue <= outParameterInfo.maxValue);
return noErr;
}
return kAudioUnitErr_InvalidParameter;
@ -913,21 +910,24 @@ public:
if (outStrings == nullptr)
return noErr;
const int index = getJuceIndexForAUParameterID (inParameterID);
if (inScope == kAudioUnitScope_Global
&& juceFilter != nullptr
&& isPositiveAndBelow (index, juceFilter->getNumParameters())
&& juceFilter->isParameterDiscrete (index))
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
if (auto* valueStrings = parameterValueStringArrays[index])
if (auto* param = getParameterForAUParameterID (inParameterID))
{
*outStrings = CFArrayCreate (NULL,
(const void **) valueStrings->getRawDataPointer(),
valueStrings->size(),
NULL);
if (param->isDiscrete())
{
auto index = LegacyAudioParameter::getParamIndex (*juceFilter, param);
return noErr;
if (auto* valueStrings = parameterValueStringArrays[index])
{
*outStrings = CFArrayCreate (NULL,
(const void **) valueStrings->getRawDataPointer(),
valueStrings->size(),
NULL);
return noErr;
}
}
}
}
@ -941,11 +941,13 @@ public:
{
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
const auto index = getJuceIndexForAUParameterID (inID);
const auto normValue = juceFilter->getParameter (index);
if (auto* param = getParameterForAUParameterID (inID))
{
const auto normValue = param->getValue();
outValue = normValue * getMaximumParameterValue (index);
return noErr;
outValue = normValue * getMaximumParameterValue (param);
return noErr;
}
}
return MusicDeviceBase::GetParameter (inID, inScope, inElement, outValue);
@ -959,22 +961,17 @@ public:
{
if (inScope == kAudioUnitScope_Global && juceFilter != nullptr)
{
auto index = getJuceIndexForAUParameterID (inID);
auto value = inValue / getMaximumParameterValue (index);
if (auto* param = juceFilter->getParameters()[index])
if (auto* param = getParameterForAUParameterID (inID))
{
auto value = inValue / getMaximumParameterValue (param);
param->setValue (value);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
}
else
{
juceFilter->setParameter (index, value);
}
return noErr;
return noErr;
}
}
return MusicDeviceBase::SetParameter (inID, inScope, inElement, inValue, inBufferOffsetInFrames);
@ -1660,12 +1657,17 @@ private:
bool prepared, isBypassed;
//==============================================================================
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
bool usingManagedParameter;
Array<AudioUnitParameterID> auParamIDs;
HashMap<int32, int> paramMap;
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
static constexpr bool forceUseLegacyParamIDs = true;
#else
static constexpr bool forceUseLegacyParamIDs = false;
#endif
//==============================================================================
LegacyAudioParametersWrapper juceParameters;
HashMap<int32, AudioProcessorParameter*> paramMap;
Array<AudioUnitParameterID> auParamIDs;
//==============================================================================
AudioUnitEvent auEvent;
mutable Array<AUPreset> presetsArray;
@ -1814,109 +1816,95 @@ private:
//==============================================================================
void addParameters()
{
juceParameters.update (*juceFilter, forceUseLegacyParamIDs);
// check if all parameters are managed?
const int numParams = juceFilter->getNumParameters();
const int numParams = juceParameters.getNumParameters();
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
usingManagedParameter = (juceFilter->getParameters().size() == numParams);
if (usingManagedParameter)
for (auto* param : juceParameters.params)
{
for (int i = 0; i < numParams; ++i)
{
const AudioUnitParameterID auParamID = generateAUParameterIDForIndex (i);
const AudioUnitParameterID auParamID = generateAUParameterID (param);
// Consider yourself very unlucky if you hit this assertion. The hash code of your
// parameter ids are not unique.
jassert (! paramMap.contains (static_cast<int32> (auParamID)));
// Consider yourself very unlucky if you hit this assertion. The hash code of your
// parameter ids are not unique.
jassert (! paramMap.contains (static_cast<int32> (auParamID)));
auParamIDs.add (auParamID);
paramMap.set (static_cast<int32> (auParamID), i);
auParamIDs.add (auParamID);
paramMap.set (static_cast<int32> (auParamID), param);
Globals()->SetParameter (auParamID, juceFilter->getParameter (i));
}
if (juceParameters.isUsingManagedParameters())
Globals()->SetParameter (auParamID, param->getValue());
}
else
#endif
{
if (! juceParameters.isUsingManagedParameters())
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())
for (auto* param : juceParameters.params)
if (param->isDiscrete())
jassert (param->getNumSteps() != AudioProcessor::getDefaultNumParameterSteps());
#endif
parameterValueStringArrays.ensureStorageAllocated (numParams);
for (int index = 0; index < numParams; ++index)
for (auto* param : juceParameters.params)
{
OwnedArray<const __CFString>* stringValues = nullptr;
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
if (auto* param = juceFilter->getParameters()[index])
auto initialValue = param->getValue();
if (param->isDiscrete() && (! forceUseLegacyParamIDs))
{
if (param->isDiscrete())
const auto numSteps = param->getNumSteps();
stringValues = new OwnedArray<const __CFString>();
stringValues->ensureStorageAllocated (numSteps);
const auto maxValue = getMaximumParameterValue (param);
for (int i = 0; i < numSteps; ++i)
{
const auto numSteps = param->getNumSteps();
stringValues = new OwnedArray<const __CFString>();
stringValues->ensureStorageAllocated (numSteps);
auto value = (float) i / maxValue;
const auto maxValue = getMaximumParameterValue (index);
for (int i = 0; i < numSteps; ++i)
stringValues->add (CFStringCreateCopy (nullptr, (param->getText ((float) i / maxValue, 0)).toCFString()));
// Once legacy parameters are deprecated this can be replaced by getText
param->setValue (value);
stringValues->add (CFStringCreateCopy (nullptr, (param->getCurrentValueAsText().toCFString())));
}
}
#endif
param->setValue (initialValue);
parameterValueStringArrays.add (stringValues);
}
}
//==============================================================================
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
inline AudioUnitParameterID getAUParameterIDForIndex (int paramIndex) const noexcept { return static_cast<AudioUnitParameterID> (paramIndex); }
inline int getJuceIndexForAUParameterID (AudioUnitParameterID address) const noexcept { return static_cast<int> (address); }
#else
AudioUnitParameterID generateAUParameterIDForIndex (int paramIndex) const
AudioUnitParameterID generateAUParameterID (AudioProcessorParameter* param) const
{
const int n = juceFilter->getNumParameters();
const String& juceParamID = LegacyAudioParameter::getParamID (param, forceUseLegacyParamIDs);
AudioUnitParameterID paramHash = static_cast<AudioUnitParameterID> (juceParamID.hashCode());
if (isPositiveAndBelow (paramIndex, n))
{
const String& juceParamID = juceFilter->getParameterID (paramIndex);
#if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
// studio one doesn't like negative parameters
paramHash &= ~(1 << (sizeof (AudioUnitParameterID) * 8 - 1));
#endif
AudioUnitParameterID paramHash = static_cast<AudioUnitParameterID> (juceParamID.hashCode());
#if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
// studio one doesn't like negative parameters
paramHash &= ~(1 << (sizeof (AudioUnitParameterID) * 8 - 1));
#endif
return usingManagedParameter ? paramHash
: static_cast<AudioUnitParameterID> (juceParamID.getIntValue());
}
return static_cast<AudioUnitParameterID> (-1);
return juceParameters.isUsingManagedParameters() ? paramHash
: static_cast<AudioUnitParameterID> (juceParamID.getIntValue());
}
inline AudioUnitParameterID getAUParameterIDForIndex (int paramIndex) const noexcept
{
return usingManagedParameter ? auParamIDs.getReference (paramIndex)
: static_cast<AudioUnitParameterID> (paramIndex);
return juceParameters.isUsingManagedParameters() ? auParamIDs.getReference (paramIndex)
: static_cast<AudioUnitParameterID> (paramIndex);
}
inline int getJuceIndexForAUParameterID (AudioUnitParameterID address) const noexcept
AudioProcessorParameter* getParameterForAUParameterID (AudioUnitParameterID address) const noexcept
{
return usingManagedParameter ? paramMap[static_cast<int32> (address)]
: static_cast<int> (address);
return paramMap[static_cast<int32> (address)];
}
#endif
//==============================================================================
OSStatus syncAudioUnitWithProcessor()
@ -1934,7 +1922,7 @@ private:
addSupportedLayoutTags();
for (int i = 0; i < enabledInputs; ++i)
if ((err = syncAudioUnitWithChannelSet (true, i, juceFilter->getChannelLayoutOfBus (true, i))) != noErr) return err;
if ((err = syncAudioUnitWithChannelSet (true, i, juceFilter->getChannelLayoutOfBus (true, i))) != noErr) return err;
for (int i = 0; i < enabledOutputs; ++i)
if ((err = syncAudioUnitWithChannelSet (false, i, juceFilter->getChannelLayoutOfBus (false, i))) != noErr) return err;

View file

@ -64,6 +64,7 @@
#include "../../juce_graphics/native/juce_mac_CoreGraphicsHelpers.h"
#include "../../juce_audio_basics/native/juce_mac_CoreAudioLayouts.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#include "../../juce_audio_processors/format_types/juce_AU_Shared.h"
#define JUCE_VIEWCONTROLLER_OBJC_NAME(x) JUCE_JOIN_MACRO (x, FactoryAUv3)
@ -909,7 +910,7 @@ public:
return;
}
if (isPositiveAndBelow (idx, getAudioProcessor().getNumParameters()))
if (isPositiveAndBelow (idx, juceParameters.getNumParameters()))
{
if (AUParameter* param = [paramTree parameterWithAddress: getAUParameterAddressForIndex (idx)])
{
@ -1121,14 +1122,13 @@ private:
}
// When parameters are discrete we need to use integer values.
float getMaximumParameterValue (int parameterIndex)
float getMaximumParameterValue (AudioProcessorParameter* juceParam)
{
#if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
ignoreUnused (parameterIndex);
ignoreUnused (juceParam);
return 1.0f;
#else
auto& processor = getAudioProcessor();
return processor.isParameterDiscrete (parameterIndex) ? (float) (processor.getParameterNumSteps (parameterIndex) - 1) : 1.0f;
return juceParam->isDiscrete() ? (float) (juceParam->getNumSteps() - 1) : 1.0f;
#endif
}
@ -1139,17 +1139,16 @@ private:
overviewParams = [[NSMutableArray<NSNumber*> alloc] init];
auto& processor = getAudioProcessor();
const int n = processor.getNumParameters();
juceParameters.update (processor, forceLegacyParamIDs);
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
// check if all parameters are managed?
usingManagedParameter = (processor.getParameters().size() == processor.getNumParameters());
#endif
const int n = juceParameters.getNumParameters();
for (int idx = 0; idx < n; ++idx)
{
auto* juceParam = juceParameters.getParamForIndex (idx);
const String identifier (idx);
const String name = processor.getParameterName (idx);
const String name = juceParam->getName (512);
AudioUnitParameterUnit unit = kAudioUnitParameterUnit_Generic;
AudioUnitParameterOptions flags = (UInt32) (kAudioUnitParameterFlag_IsWritable
@ -1157,27 +1156,26 @@ private:
| kAudioUnitParameterFlag_HasCFNameString
| kAudioUnitParameterFlag_ValuesHaveStrings);
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
#endif
if (! forceLegacyParamIDs)
flags |= (UInt32) kAudioUnitParameterFlag_IsHighResolution;
// set whether the param is automatable (unnamed parameters aren't allowed to be automated)
if (name.isEmpty() || ! processor.isParameterAutomatable (idx))
if (name.isEmpty() || ! juceParam->isAutomatable())
flags |= kAudioUnitParameterFlag_NonRealTime;
const bool isParameterDiscrete = processor.isParameterDiscrete (idx);
const bool isParameterDiscrete = juceParam->isDiscrete();
if (! isParameterDiscrete)
flags |= kAudioUnitParameterFlag_CanRamp;
if (processor.isMetaParameter (idx))
if (juceParam->isMetaParameter())
flags |= kAudioUnitParameterFlag_IsGlobalMeta;
auto deleter = [](NSMutableArray* arr) { [arr release]; };
std::unique_ptr<NSMutableArray, decltype (deleter)> valueStrings (nullptr, deleter);
// is this a meter?
if (((processor.getParameterCategory (idx) & 0xffff0000) >> 16) == 2)
if (((juceParam->getCategory() & 0xffff0000) >> 16) == 2)
{
flags &= ~kAudioUnitParameterFlag_IsWritable;
flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
@ -1185,14 +1183,13 @@ private:
}
else
{
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
if (auto* param = processor.getParameters()[idx])
if (! forceLegacyParamIDs)
{
if (param->isDiscrete())
if (juceParam->isDiscrete())
{
unit = param->isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed;
auto maxValue = getMaximumParameterValue (idx);
auto numSteps = param->getNumSteps();
unit = juceParam->isBoolean() ? kAudioUnitParameterUnit_Boolean : kAudioUnitParameterUnit_Indexed;
auto maxValue = getMaximumParameterValue (juceParam);
auto numSteps = juceParam->getNumSteps();
// Some hosts can't handle the huge numbers of discrete parameter values created when
// using the default number of steps.
@ -1201,24 +1198,22 @@ private:
valueStrings.reset ([NSMutableArray new]);
for (int i = 0; i < numSteps; ++i)
[valueStrings.get() addObject: juceStringToNS (param->getText ((float) i / maxValue, 0))];
[valueStrings.get() addObject: juceStringToNS (juceParam->getText ((float) i / maxValue, 0))];
}
}
#endif
}
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
AUParameterAddress address = static_cast<AUParameterAddress> (idx);
#else
AUParameterAddress address = generateAUParameterAddressForIndex (idx);
AUParameterAddress address = forceLegacyParamIDs ? static_cast<AUParameterAddress> (idx)
: generateAUParameterAddress (juceParam);
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
// Consider yourself very unlucky if you hit this assertion. The hash codes of your
// parameter ids are not unique.
jassert (! paramMap.contains (static_cast<int64> (address)));
paramAddresses.add (address);
paramMap.set (static_cast<int64> (address), idx);
#endif
#endif
// create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h
@ -1226,14 +1221,14 @@ private:
name: juceStringToNS (name)
address: address
min: 0.0f
max: getMaximumParameterValue (idx)
max: getMaximumParameterValue (juceParam)
unit: unit
unitName: nullptr
flags: flags
valueStrings: valueStrings.get()
dependentParameters: nullptr] retain];
[param.get() setValue: processor.getParameterDefaultValue (idx)];
[param.get() setValue: juceParam->getDefaultValue()];
[params addObject: param];
[overviewParams addObject: [NSNumber numberWithUnsignedLongLong:address]];
@ -1259,21 +1254,14 @@ private:
}
}
void setAudioProcessorParameter (int index, float value)
void setAudioProcessorParameter (AudioProcessorParameter* juceParam, float value)
{
if (auto* param = getAudioProcessor().getParameters()[index])
if (value != juceParam->getValue())
{
if (value != param->getValue())
{
param->setValue (value);
juceParam->setValue (value);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
}
}
else if (isPositiveAndBelow (index, getAudioProcessor().getNumParameters()))
{
getAudioProcessor().setParameter (index, value);
inParameterChangedCallback = true;
juceParam->sendValueChangedMessageToListeners (value);
}
}
@ -1329,9 +1317,9 @@ private:
case AURenderEventParameterRamp:
{
const AUParameterEvent& paramEvent = event->parameter;
const int idx = getJuceParameterIndexForAUAddress (paramEvent.parameterAddress);
setAudioProcessorParameter (idx, paramEvent.value);
if (auto* p = getJuceParameterForAUAddress (paramEvent.parameterAddress))
setAudioProcessorParameter (p, paramEvent.value);
}
break;
@ -1349,7 +1337,7 @@ private:
jassert (static_cast<int> (frameCount) <= getAudioProcessor().getBlockSize());
// process params
const int numParams = processor.getNumParameters();
const int numParams = juceParameters.getNumParameters();
processEvents (realtimeEventListHead, numParams, static_cast<AUEventSampleTime> (timestamp->mSampleTime));
if (lastTimeStamp.mSampleTime != timestamp->mSampleTime)
@ -1477,10 +1465,11 @@ private:
{
if (param != nullptr)
{
int idx = getJuceParameterIndexForAUAddress ([param address]);
auto normalisedValue = value / getMaximumParameterValue (idx);
setAudioProcessorParameter (idx, normalisedValue);
if (auto* p = getJuceParameterForAUAddress ([param address]))
{
auto normalisedValue = value / getMaximumParameterValue (p);
setAudioProcessorParameter (p, normalisedValue);
}
}
}
@ -1488,11 +1477,8 @@ private:
{
if (param != nullptr)
{
const int idx = getJuceParameterIndexForAUAddress ([param address]);
auto& processor = getAudioProcessor();
if (isPositiveAndBelow (idx, processor.getNumParameters()))
return processor.getParameter (idx) * getMaximumParameterValue (idx);
if (auto* p = getJuceParameterForAUAddress ([param address]))
return p->getValue() * getMaximumParameterValue (p);
}
return 0;
@ -1509,13 +1495,13 @@ private:
if (param != nullptr && value != nullptr)
{
const int idx = getJuceParameterIndexForAUAddress ([param address]);
auto& processor = getAudioProcessor();
if (auto* p = processor.getParameters()[idx])
text = p->getText (*value / getMaximumParameterValue (idx), 0);
else
text = String (*value);
if (auto* p = getJuceParameterForAUAddress ([param address]))
{
if (LegacyAudioParameter::isLegacy (p))
text = String (*value);
else
text = p->getText (*value / getMaximumParameterValue (p), 0);
}
}
return juceStringToNS (text);
@ -1525,14 +1511,15 @@ private:
{
if (param != nullptr && str != nullptr)
{
const int idx = getJuceParameterIndexForAUAddress ([param address]);
auto& processor = getAudioProcessor();
const String text (nsStringToJuce (str));
if (auto* p = getJuceParameterForAUAddress ([param address]))
{
const String text (nsStringToJuce (str));
if (auto* p = processor.getParameters()[idx])
return p->getValueForText (text) * getMaximumParameterValue (idx);
else
return text.getFloatValue();
if (LegacyAudioParameter::isLegacy (p))
return text.getFloatValue();
else
return p->getValueForText (text) * getMaximumParameterValue (p);
}
}
return 0;
@ -1543,34 +1530,32 @@ private:
inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept { return static_cast<AUParameterAddress> (paramIndex); }
inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept { return static_cast<int> (address); }
#else
AUParameterAddress generateAUParameterAddressForIndex (int paramIndex) const
{
auto& processor = getAudioProcessor();
const int n = processor.getNumParameters();
if (isPositiveAndBelow (paramIndex, n))
{
const String& juceParamID = processor.getParameterID (paramIndex);
return usingManagedParameter ? static_cast<AUParameterAddress> (juceParamID.hashCode64())
: static_cast<AUParameterAddress> (juceParamID.getIntValue());
}
return static_cast<AUParameterAddress> (-1);
}
inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept
{
return usingManagedParameter ? paramAddresses.getReference (paramIndex)
: static_cast<AUParameterAddress> (paramIndex);
return juceParameters.isUsingManagedParameters() ? paramAddresses.getReference (paramIndex)
: static_cast<AUParameterAddress> (paramIndex);
}
inline int getJuceParameterIndexForAUAddress (AUParameterAddress address) const noexcept
{
return usingManagedParameter ? paramMap[static_cast<int64> (address)]
: static_cast<int> (address);
return juceParameters.isUsingManagedParameters() ? paramMap[static_cast<int64> (address)]
: static_cast<int> (address);
}
#endif
AUParameterAddress generateAUParameterAddress (AudioProcessorParameter* param) const
{
const String& juceParamID = LegacyAudioParameter::getParamID (param, forceLegacyParamIDs);
return juceParameters.isUsingManagedParameters() ? static_cast<AUParameterAddress> (juceParamID.hashCode64())
: static_cast<AUParameterAddress> (juceParamID.getIntValue());
}
AudioProcessorParameter* getJuceParameterForAUAddress (AUParameterAddress address) const noexcept
{
return juceParameters.getParamForIndex (getJuceParameterIndexForAUAddress (address));
}
//==============================================================================
static const double kDefaultSampleRate;
@ -1587,10 +1572,10 @@ private:
ObjCBlock<AUImplementorValueFromStringCallback> valueFromStringProvider;
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
bool usingManagedParameter;
Array<AUParameterAddress> paramAddresses;
HashMap<int64, int> paramMap;
#endif
LegacyAudioParametersWrapper juceParameters;
// to avoid recursion on parameter changes, we need to add an
// editor observer to do the parameter changes
@ -1620,6 +1605,11 @@ private:
String contextName;
ThreadLocalValue<bool> inParameterChangedCallback;
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
static constexpr bool forceLegacyParamIDs = true;
#else
static constexpr bool forceLegacyParamIDs = false;
#endif
};
const double JuceAudioUnitv3::kDefaultSampleRate = 44100.0;

View file

@ -79,6 +79,7 @@
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../utility/juce_WindowsHooks.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#include "../../juce_audio_processors/format_types/juce_VSTCommon.h"
#ifdef _MSC_VER
@ -281,6 +282,8 @@ public:
processor->setPlayHead (this);
processor->addListener (this);
juceParameters.update (*processor, false);
memset (&vstEffect, 0, sizeof (vstEffect));
vstEffect.interfaceIdentifier = juceVstInterfaceIdentifier;
vstEffect.dispatchFunction = dispatcherCB;
@ -288,7 +291,7 @@ public:
vstEffect.setParameterValueFunction = setParameterCB;
vstEffect.getParameterValueFunction = getParameterCB;
vstEffect.numPrograms = jmax (1, af->getNumPrograms());
vstEffect.numParameters = af->getNumParameters();
vstEffect.numParameters = juceParameters.getNumParameters();
vstEffect.numInputChannels = maxNumInChannels;
vstEffect.numOutputChannels = maxNumOutChannels;
vstEffect.latency = processor->getLatencySamples();
@ -706,11 +709,10 @@ public:
//==============================================================================
float getParameter (int32 index) const
{
if (processor == nullptr)
return 0.0f;
if (auto* param = juceParameters.getParamForIndex (index))
return param->getValue();
jassert (isPositiveAndBelow (index, processor->getNumParameters()));
return processor->getParameter (index);
return 0.0f;
}
static float getParameterCB (VstEffectInterface* vstInterface, int32 index)
@ -720,20 +722,12 @@ public:
void setParameter (int32 index, float value)
{
if (processor != nullptr)
if (auto* param = juceParameters.getParamForIndex (index))
{
if (auto* param = processor->getParameters()[index])
{
param->setValue (value);
param->setValue (value);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
}
else
{
jassert (isPositiveAndBelow (index, processor->getNumParameters()));
processor->setParameter (index, value);
}
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
}
}
@ -1472,6 +1466,8 @@ private:
VSTMidiEventList outgoingEvents;
float editorScaleFactor = 1.0f;
LegacyAudioParametersWrapper juceParameters;
bool isProcessing = false, isBypassed = false, hasShutdown = false;
bool firstProcessCallback = true, shouldDeleteEditor = false;
@ -1664,11 +1660,10 @@ private:
pointer_sized_int handleGetParameterLabel (VstOpCodeArguments args)
{
if (processor != nullptr)
if (auto* param = juceParameters.getParamForIndex (args.index))
{
jassert (isPositiveAndBelow (args.index, processor->getNumParameters()));
// length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
processor->getParameterLabel (args.index).copyToUTF8 ((char*) args.ptr, 24 + 1);
param->getLabel().copyToUTF8 ((char*) args.ptr, 24 + 1);
}
return 0;
@ -1676,11 +1671,10 @@ private:
pointer_sized_int handleGetParameterText (VstOpCodeArguments args)
{
if (processor != nullptr)
if (auto* param = juceParameters.getParamForIndex (args.index))
{
jassert (isPositiveAndBelow (args.index, processor->getNumParameters()));
// length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
processor->getParameterText (args.index, 24).copyToUTF8 ((char*) args.ptr, 24 + 1);
param->getCurrentValueAsText().copyToUTF8 ((char*) args.ptr, 24 + 1);
}
return 0;
@ -1688,11 +1682,10 @@ private:
pointer_sized_int handleGetParameterName (VstOpCodeArguments args)
{
if (processor != nullptr)
if (auto* param = juceParameters.getParamForIndex (args.index))
{
jassert (isPositiveAndBelow (args.index, processor->getNumParameters()));
// length should technically be kVstMaxParamStrLen, which is 8, but hosts will normally allow a bit more.
processor->getParameterName (args.index, 32).copyToUTF8 ((char*) args.ptr, 32 + 1);
param->getName (32).copyToUTF8 ((char*) args.ptr, 32 + 1);
}
return 0;
@ -1823,20 +1816,20 @@ private:
pointer_sized_int handleIsParameterAutomatable (VstOpCodeArguments args)
{
if (processor == nullptr)
return 0;
if (auto* param = juceParameters.getParamForIndex (args.index))
{
const bool isMeter = (((param->getCategory() & 0xffff0000) >> 16) == 2);
return (param->isAutomatable() && (! isMeter) ? 1 : 0);
}
const bool isMeter = (((processor->getParameterCategory (args.index) & 0xffff0000) >> 16) == 2);
return (processor->isParameterAutomatable (args.index) && (! isMeter) ? 1 : 0);
return 0;
}
pointer_sized_int handleParameterValueForText (VstOpCodeArguments args)
{
if (processor != nullptr)
if (auto* param = juceParameters.getParamForIndex (args.index))
{
jassert (isPositiveAndBelow (args.index, processor->getNumParameters()));
if (auto* param = processor->getParameters()[args.index])
if (! LegacyAudioParameter::isLegacy (param))
{
auto value = param->getValueForText (String::fromUTF8 ((char*) args.ptr));
param->setValue (value);
@ -2120,11 +2113,14 @@ private:
{
if (processor != nullptr && dest != nullptr)
{
if (auto* param = processor->getParameters()[(int) paramIndex])
if (auto* param = juceParameters.getParamForIndex ((int) paramIndex))
{
String text (param->getText (value, 1024));
memcpy (dest, text.toRawUTF8(), ((size_t) text.length()) + 1);
return 0xbeef;
if (! LegacyAudioParameter::isLegacy (param))
{
String text (param->getText (value, 1024));
memcpy (dest, text.toRawUTF8(), ((size_t) text.length()) + 1);
return 0xbeef;
}
}
}

View file

@ -42,6 +42,7 @@
#include "../utility/juce_IncludeModuleHeaders.h"
#include "../utility/juce_WindowsHooks.h"
#include "../utility/juce_FakeMouseMoveGenerator.h"
#include "../../juce_audio_processors/format_types/juce_LegacyAudioParameter.cpp"
#include "../../juce_audio_processors/format_types/juce_VST3Common.h"
#ifndef JUCE_VST3_CAN_REPLACE_VST2
@ -89,7 +90,12 @@ using namespace Steinberg;
class JuceAudioProcessor : public FUnknown
{
public:
JuceAudioProcessor (AudioProcessor* source) noexcept : audioProcessor (source) {}
JuceAudioProcessor (AudioProcessor* source) noexcept
: audioProcessor (source)
{
setupParameters();
}
virtual ~JuceAudioProcessor() {}
AudioProcessor* get() const noexcept { return audioProcessor; }
@ -97,15 +103,85 @@ public:
JUCE_DECLARE_VST3_COM_QUERY_METHODS
JUCE_DECLARE_VST3_COM_REF_METHODS
static const FUID iid;
//==============================================================================
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept { return static_cast<Vst::ParamID> (paramIndex); }
#else
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept
{
return isUsingManagedParameters() ? vstParamIDs.getReference (paramIndex)
: static_cast<Vst::ParamID> (paramIndex);
}
#endif
AudioProcessorParameter* getParamForVSTParamID (Vst::ParamID paramID) const noexcept
{
return paramMap[static_cast<int32> (paramID)];
}
int getNumParameters() const noexcept { return vstParamIDs.size(); }
bool isUsingManagedParameters() const noexcept { return juceParameters.isUsingManagedParameters(); }
//==============================================================================
static const FUID iid;
Array<Vst::ParamID> vstParamIDs;
Vst::ParamID bypassParamID = 0;
bool isBypassed = false;
private:
enum InternalParameters
{
paramBypass = 0x62797073 // 'byps'
};
//==============================================================================
void setupParameters()
{
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const bool forceLegacyParamIDs = true;
#else
const bool forceLegacyParamIDs = false;
#endif
juceParameters.update (*audioProcessor, forceLegacyParamIDs);
auto numParameters = juceParameters.getNumParameters();
int i = 0;
for (auto* juceParam : juceParameters.params)
{
Vst::ParamID vstParamID = forceLegacyParamIDs ? static_cast<Vst::ParamID> (i++)
: generateVSTParamIDForParam (juceParam);
vstParamIDs.add (vstParamID);
paramMap.set (static_cast<int32> (vstParamID), juceParam);
}
bypassParamID = static_cast<Vst::ParamID> (isUsingManagedParameters() ? paramBypass : numParameters);
}
Vst::ParamID generateVSTParamIDForParam (AudioProcessorParameter* param)
{
auto juceParamID = LegacyAudioParameter::getParamID (param, false);
auto paramHash = static_cast<Vst::ParamID> (juceParamID.hashCode());
#if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
// studio one doesn't like negative parameters
paramHash &= ~(1 << (sizeof (Vst::ParamID) * 8 - 1));
#endif
return isUsingManagedParameters() ? paramHash
: static_cast<Vst::ParamID> (juceParamID.getIntValue());
}
//==============================================================================
Atomic<int> refCount;
ScopedPointer<AudioProcessor> audioProcessor;
ScopedJuceInitialiser_GUI libraryInitialiser;
//==============================================================================
LegacyAudioParametersWrapper juceParameters;
HashMap<int32, AudioProcessorParameter*> paramMap;
JuceAudioProcessor() = delete;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceAudioProcessor)
};
@ -197,39 +273,38 @@ public:
enum InternalParameters
{
paramPreset = 0x70727374, // 'prst'
paramBypass = 0x62797073, // 'byps'
paramMidiControllerOffset = 0x6d636d00 // 'mdm*'
};
struct Param : public Vst::Parameter
{
Param (AudioProcessor& p, int index, Vst::ParamID paramID) : owner (p), paramIndex (index)
Param (JuceVST3EditController& editController, AudioProcessorParameter& p,
Vst::ParamID vstParamID, bool forceLegacyParamIDs)
: owner (editController), param (p)
{
info.id = paramID;
info.id = vstParamID;
toString128 (info.title, p.getParameterName (index));
toString128 (info.shortTitle, p.getParameterName (index, 8));
toString128 (info.units, p.getParameterLabel (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 (p.isParameterDiscrete (index))
#endif
if (! forceLegacyParamIDs && param.isDiscrete())
{
const int numSteps = p.getParameterNumSteps (index);
const int numSteps = param.getNumSteps();
info.stepCount = (Steinberg::int32) (numSteps > 0 && numSteps < 0x7fffffff ? numSteps - 1 : 0);
}
info.defaultNormalizedValue = p.getParameterDefaultValue (index);
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)
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;
}
@ -251,17 +326,10 @@ public:
{
auto value = static_cast<float> (v);
if (auto* param = owner.getParameters()[paramIndex])
{
param->setValue (value);
param.setValue (value);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (value);
}
else
{
owner.setParameter (paramIndex, value);
}
inParameterChangedCallback = true;
param.sendValueChangedMessageToListeners (value);
}
changed();
@ -273,18 +341,14 @@ public:
void toString (Vst::ParamValue value, Vst::String128 result) const override
{
if (auto* p = owner.getParameters()[paramIndex])
toString128 (result, p->getText ((float) value, 128));
else
// remain backward-compatible with old JUCE code
toString128 (result, owner.getParameterText (paramIndex, 128));
toString128 (result, param.getText ((float) value, 128));
}
bool fromString (const Vst::TChar* text, Vst::ParamValue& outValueNormalized) const override
{
if (auto* p = owner.getParameters()[paramIndex])
if (! LegacyAudioParameter::isLegacy (&param))
{
outValueNormalized = p->getValueForText (getStringFromVstTChars (text));
outValueNormalized = param.getValueForText (getStringFromVstTChars (text));
return true;
}
@ -300,8 +364,8 @@ public:
Vst::ParamValue toNormalized (Vst::ParamValue v) const override { return v; }
private:
AudioProcessor& owner;
int paramIndex;
JuceVST3EditController& owner;
AudioProcessorParameter& param;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Param)
};
@ -502,12 +566,8 @@ public:
// Cubase and Nuendo need to inform the host of the current parameter values
if (auto* pluginInstance = getPluginInstance())
{
auto numParameters = pluginInstance->getNumParameters();
for (int i = 0; i < numParameters; ++i)
setParamNormalized (getVSTParamIDForIndex (i), (double) pluginInstance->getParameter (i));
setParamNormalized (bypassParamID, audioProcessor->isBypassed ? 1.0f : 0.0f);
for (auto vstParamId : audioProcessor->vstParamIDs)
setParamNormalized (vstParamId, audioProcessor->getParamForVSTParamID (vstParamId)->getValue());
auto numPrograms = pluginInstance->getNumPrograms();
@ -601,10 +661,7 @@ public:
}
//==============================================================================
void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override { beginEdit (getVSTParamIDForIndex (index)); }
void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override { endEdit (getVSTParamIDForIndex (index)); }
void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override
void paramChanged (Vst::ParamID vstParamId, float newValue)
{
if (inParameterChangedCallback.get())
{
@ -613,8 +670,17 @@ public:
}
// NB: Cubase has problems if performEdit is called without setParamNormalized
EditController::setParamNormalized (getVSTParamIDForIndex (index), (double) newValue);
performEdit (getVSTParamIDForIndex (index), (double) newValue);
EditController::setParamNormalized (vstParamId, (double) newValue);
performEdit (vstParamId, (double) newValue);
}
//==============================================================================
void audioProcessorParameterChangeGestureBegin (AudioProcessor*, int index) override { beginEdit (audioProcessor->getVSTParamIDForIndex (index)); }
void audioProcessorParameterChangeGestureEnd (AudioProcessor*, int index) override { endEdit (audioProcessor->getVSTParamIDForIndex (index)); }
void audioProcessorParameterChanged (AudioProcessor*, int index, float newValue) override
{
paramChanged (audioProcessor->getVSTParamIDForIndex (index), newValue);
}
void audioProcessorChanged (AudioProcessor*) override
@ -641,6 +707,7 @@ public:
private:
friend class JuceVST3Component;
friend struct Param;
//==============================================================================
ComSmartPtr<JuceAudioProcessor> audioProcessor;
@ -657,53 +724,41 @@ private:
Vst::ParamID midiControllerToParameter[numMIDIChannels][Vst::kCountCtrlNumber];
//==============================================================================
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
bool usingManagedParameter = false;
Array<Vst::ParamID> vstParamIDs;
#endif
Vst::ParamID bypassParamID;
Atomic<int> vst3IsPlaying { 0 };
//==============================================================================
void setupParameters()
{
if (auto* pluginInstance = getPluginInstance())
{
pluginInstance->addListener (this);
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const bool usingManagedParameter = false;
#endif
if (parameters.getParameterCount() <= 0)
{
auto numParameters = pluginInstance->getNumParameters();
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const bool forceLegacyParamIDs = true;
#else
const bool forceLegacyParamIDs = false;
#endif
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
usingManagedParameter = (pluginInstance->getParameters().size() == numParameters);
#endif
auto n = audioProcessor->getNumParameters();
for (int i = 0; i < numParameters; ++i)
for (int i = 0; i < n; ++i)
{
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
const Vst::ParamID vstParamID = static_cast<Vst::ParamID> (i);
#else
const Vst::ParamID vstParamID = generateVSTParamIDForIndex (pluginInstance, i);
vstParamIDs.add (vstParamID);
#endif
auto vstParamID = audioProcessor->getVSTParamIDForIndex (i);
auto* juceParam = audioProcessor->getParamForVSTParamID (vstParamID);
parameters.addParameter (new Param (*pluginInstance, i, vstParamID));
parameters.addParameter (new Param (*this, *juceParam, vstParamID, forceLegacyParamIDs));
}
bypassParamID = static_cast<Vst::ParamID> (usingManagedParameter ? paramBypass : numParameters);
parameters.addParameter (new BypassParam (bypassParamID));
parameters.addParameter (new BypassParam (audioProcessor->bypassParamID));
if (pluginInstance->getNumPrograms() > 1)
parameters.addParameter (new ProgramChangeParameter (*pluginInstance));
}
#if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS
parameterToMidiControllerOffset = static_cast<Vst::ParamID> (usingManagedParameter ? paramMidiControllerOffset
: parameters.getParameterCount());
parameterToMidiControllerOffset = static_cast<Vst::ParamID> (audioProcessor->isUsingManagedParameters() ? paramMidiControllerOffset
: parameters.getParameterCount());
initialiseMidiControllerMappings();
#endif
@ -742,41 +797,6 @@ private:
}
}
//==============================================================================
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept { return static_cast<Vst::ParamID> (paramIndex); }
#else
static Vst::ParamID generateVSTParamIDForIndex (AudioProcessor* const pluginFilter, int paramIndex)
{
jassert (pluginFilter != nullptr);
const int n = pluginFilter->getNumParameters();
const bool managedParameter = (pluginFilter->getParameters().size() == n);
if (isPositiveAndBelow (paramIndex, n))
{
auto juceParamID = pluginFilter->getParameterID (paramIndex);
auto paramHash = static_cast<Vst::ParamID> (juceParamID.hashCode());
#if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS
// studio one doesn't like negative parameters
paramHash &= ~(1 << (sizeof (Vst::ParamID) * 8 - 1));
#endif
return managedParameter ? paramHash
: static_cast<Vst::ParamID> (juceParamID.getIntValue());
}
return static_cast<Vst::ParamID> (-1);
}
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept
{
return usingManagedParameter ? vstParamIDs.getReference (paramIndex)
: static_cast<Vst::ParamID> (paramIndex);
}
#endif
//==============================================================================
class JuceVST3Editor : public Vst::EditorView,
public Steinberg::IPlugViewContentScaleSupport,
@ -1172,17 +1192,14 @@ public:
processSetup.sampleRate = 44100.0;
processSetup.symbolicSampleSize = Vst::kSample32;
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
vstBypassParameterId = static_cast<Vst::ParamID> (pluginInstance->getNumParameters());
#else
cacheParameterIDs();
#endif
pluginInstance->setPlayHead (this);
}
~JuceVST3Component()
{
if (juceVST3EditController != nullptr)
juceVST3EditController->vst3IsPlaying = 0;
if (pluginInstance != nullptr)
if (pluginInstance->getPlayHead() == this)
pluginInstance->setPlayHead (nullptr);
@ -1246,6 +1263,9 @@ public:
tresult PLUGIN_API disconnect (IConnectionPoint*) override
{
if (juceVST3EditController != nullptr)
juceVST3EditController->vst3IsPlaying = 0;
juceVST3EditController = nullptr;
return kResultTrue;
}
@ -2020,7 +2040,7 @@ public:
{
auto vstParamID = paramQueue->getParameterId();
if (vstParamID == vstBypassParameterId)
if (vstParamID == comPluginInstance->bypassParamID)
setBypassed (static_cast<float> (value) != 0.0f);
#if JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS
else if (juceVST3EditController->isMidiControllerParamID (vstParamID))
@ -2037,20 +2057,15 @@ public:
}
else
{
auto index = getJuceIndexForVSTParamID (vstParamID);
auto floatValue = static_cast<float> (value);
if (auto* param = pluginInstance->getParameters()[index])
if (auto* param = comPluginInstance->getParamForVSTParamID (vstParamID))
{
param->setValue (floatValue);
inParameterChangedCallback = true;
param->sendValueChangedMessageToListeners (floatValue);
}
else if (isPositiveAndBelow (index, pluginInstance->getNumParameters()))
{
pluginInstance->setParameter (index, floatValue);
}
}
}
}
@ -2088,12 +2103,16 @@ public:
if (data.processContext != nullptr)
{
processContext = *data.processContext;
pluginInstance->vst3IsPlaying = processContext.state & Vst::ProcessContext::kPlaying;
if (juceVST3EditController != nullptr)
juceVST3EditController->vst3IsPlaying = processContext.state & Vst::ProcessContext::kPlaying;
}
else
{
zerostruct (processContext);
pluginInstance->vst3IsPlaying = 0;
if (juceVST3EditController != nullptr)
juceVST3EditController->vst3IsPlaying = 0;
}
midiBuffer.clear();
@ -2164,14 +2183,6 @@ private:
#endif
ScopedJuceInitialiser_GUI libraryInitialiser;
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
bool usingManagedParameter;
Array<Vst::ParamID> vstParamIDs;
HashMap<int32, int> paramMap;
#endif
Vst::ParamID vstBypassParameterId;
static const char* kJucePrivateDataIdentifier;
//==============================================================================
@ -2387,44 +2398,6 @@ private:
p.prepareToPlay (sampleRate, bufferSize);
}
//==============================================================================
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept { return static_cast<Vst::ParamID> (paramIndex); }
inline int getJuceIndexForVSTParamID (Vst::ParamID paramID) const noexcept { return static_cast<int> (paramID); }
#else
void cacheParameterIDs()
{
const int numParameters = pluginInstance->getNumParameters();
usingManagedParameter = (pluginInstance->getParameters().size() == numParameters);
vstBypassParameterId = static_cast<Vst::ParamID> (usingManagedParameter ? JuceVST3EditController::paramBypass : numParameters);
for (int i = 0; i < numParameters; ++i)
{
auto paramID = JuceVST3EditController::generateVSTParamIDForIndex (pluginInstance, i);
// Consider yourself very unlucky if you hit this assertion. The hash code of your
// parameter ids are not unique.
jassert (! vstParamIDs.contains (paramID));
vstParamIDs.add (paramID);
paramMap.set (static_cast<int32> (paramID), i);
}
}
inline Vst::ParamID getVSTParamIDForIndex (int paramIndex) const noexcept
{
return usingManagedParameter ? vstParamIDs.getReference (paramIndex)
: static_cast<Vst::ParamID> (paramIndex);
}
inline int getJuceIndexForVSTParamID (Vst::ParamID paramID) const noexcept
{
return usingManagedParameter ? paramMap[static_cast<int32> (paramID)]
: static_cast<int> (paramID);
}
#endif
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (JuceVST3Component)
};

View file

@ -0,0 +1,185 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2017 - ROLI Ltd.
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 5 End-User License
Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
27th April 2017).
End User License Agreement: www.juce.com/juce-5-licence
Privacy Policy: www.juce.com/juce-5-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#if JUCE_GCC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif JUCE_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif JUCE_MSVC
#pragma warning (push, 0)
#pragma warning (disable: 4996)
#endif
class LegacyAudioParameter : public AudioProcessorParameter
{
public:
LegacyAudioParameter (AudioProcessor& audioProcessorToUse, int audioParameterIndex)
: audioProcessor (audioProcessorToUse), idx (audioParameterIndex)
{
jassert (idx < audioProcessor.getNumParameters());
}
//==============================================================================
float getValue() const override { return audioProcessor.getParameter (idx); }
void setValue (float newValue) override { audioProcessor.setParameter (idx, newValue); }
float getDefaultValue() const override { return audioProcessor.getParameterDefaultValue (idx); }
String getName (int maxLen) const override { return audioProcessor.getParameterName (idx, maxLen); }
String getLabel() const override { return audioProcessor.getParameterLabel (idx); }
int getNumSteps() const override { return audioProcessor.getParameterNumSteps (idx); }
bool isDiscrete() const override { return audioProcessor.isParameterDiscrete (idx); }
bool isBoolean() const override { return false; }
bool isOrientationInverted() const override { return audioProcessor.isParameterOrientationInverted (idx); }
bool isAutomatable() const override { return audioProcessor.isParameterAutomatable (idx); }
bool isMetaParameter() const override { return audioProcessor.isMetaParameter (idx); }
Category getCategory() const override { return audioProcessor.getParameterCategory (idx); }
String getCurrentValueAsText() const override { return audioProcessor.getParameterText (idx); }
String getParamID() const { return audioProcessor.getParameterID (idx); }
//==============================================================================
float getValueForText (const String&) const override
{
// legacy parameters do not support this method
jassertfalse;
return 0.0f;
}
String getText (float, int) const override
{
// legacy parameters do not support this method
jassertfalse;
return {};
}
//==============================================================================
static bool isLegacy (AudioProcessorParameter* param) noexcept
{
return (dynamic_cast<LegacyAudioParameter*> (param) != nullptr);
}
static int getParamIndex (AudioProcessor& processor, AudioProcessorParameter* param) noexcept
{
if (auto* legacy = dynamic_cast<LegacyAudioParameter*> (param))
{
return legacy->idx;
}
else
{
auto n = processor.getNumParameters();
jassert (n == processor.getParameters().size());
for (int i = 0; i < n; ++i)
{
if (processor.getParameters()[i] == param)
return i;
}
}
return -1;
}
static String getParamID (AudioProcessorParameter* param, bool forceLegacyParamIDs) noexcept
{
if (auto* legacy = dynamic_cast<LegacyAudioParameter*> (param))
{
return legacy->getParamID();
}
else if (auto* paramWithID = dynamic_cast<AudioProcessorParameterWithID*> (param))
{
if (! forceLegacyParamIDs)
return paramWithID->paramID;
}
return String (param->getParameterIndex());
}
private:
AudioProcessor& audioProcessor;
int idx;
};
//==============================================================================
class LegacyAudioParametersWrapper
{
public:
void update (AudioProcessor& audioProcessor, bool forceLegacyParamIDs)
{
clear();
legacyParamIDs = forceLegacyParamIDs;
auto numParameters = audioProcessor.getNumParameters();
usingManagedParameters = (audioProcessor.getParameters().size() == numParameters) && (! legacyParamIDs);
for (int i = 0; i < numParameters; ++i)
{
AudioProcessorParameter* param = usingManagedParameters ? audioProcessor.getParameters()[i]
: (legacy.add (new LegacyAudioParameter (audioProcessor, i)));
params.add (param);
}
}
void clear()
{
legacy.clear();
params.clear();
}
AudioProcessorParameter* getParamForIndex (int index) const
{
if (isPositiveAndBelow (index, params.size()))
return params[index];
return nullptr;
}
String getParamID (AudioProcessor& processor, int idx) const noexcept
{
return usingManagedParameters ? processor.getParameterID (idx) : String (idx);
}
bool isUsingManagedParameters() const noexcept { return usingManagedParameters; }
int getNumParameters() const noexcept { return params.size(); }
Array<AudioProcessorParameter*> params;
private:
OwnedArray<LegacyAudioParameter> legacy;
bool legacyParamIDs = false, usingManagedParameters = false;
};
#if JUCE_GCC
#pragma GCC diagnostic pop
#elif JUCE_CLANG
#pragma clang diagnostic pop
#elif JUCE_MSVC
#pragma warning (pop)
#endif
} // namespace juce

View file

@ -154,6 +154,7 @@ struct AutoResizingNSViewComponentWithParent : public AutoResizingNSViewCompone
#include "format/juce_AudioPluginFormat.cpp"
#include "format/juce_AudioPluginFormatManager.cpp"
#include "format_types/juce_LegacyAudioParameter.cpp"
#include "processors/juce_AudioProcessor.cpp"
#include "processors/juce_AudioPluginInstance.cpp"
#include "processors/juce_AudioProcessorEditor.cpp"

View file

@ -27,6 +27,14 @@
namespace juce
{
#if JUCE_MSVC
#pragma warning (push, 0)
// MSVC does not like it if you override a deprecated method even if you
// keep the deprecation attribute. Other compilers are more forgiving.
#pragma warning (disable: 4996)
#endif
//==============================================================================
/**
Base class for an active instance of a plugin.
@ -123,4 +131,8 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginInstance)
};
#if JUCE_MSVC
#pragma warning (pop)
#endif
} // namespace juce

View file

@ -414,6 +414,18 @@ void AudioProcessor::setLatencySamples (const int newLatency)
}
}
//==============================================================================
#if JUCE_GCC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif JUCE_CLANG
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#elif JUCE_MSVC
#pragma warning (push, 0)
#pragma warning (disable: 4996)
#endif
void AudioProcessor::setParameterNotifyingHost (int parameterIndex, float newValue)
{
if (auto* param = getParameters()[parameterIndex])
@ -427,12 +439,6 @@ void AudioProcessor::setParameterNotifyingHost (int parameterIndex, float newVal
}
}
AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noexcept
{
const ScopedLock sl (listenerLock);
return listeners[index];
}
void AudioProcessor::sendParamChangeMessageToListeners (int parameterIndex, float newValue)
{
if (auto* param = getParameters()[parameterIndex])
@ -511,6 +517,49 @@ void AudioProcessor::endParameterChangeGesture (int parameterIndex)
}
}
String AudioProcessor::getParameterName (int index, int maximumStringLength)
{
if (auto* p = managedParameters[index])
return p->getName (maximumStringLength);
return getParameterName (index).substring (0, maximumStringLength);
}
const String AudioProcessor::getParameterText (int index)
{
#if JUCE_DEBUG
// if you hit this, then you're probably using the old parameter control methods,
// but have forgotten to implement either of the getParameterText() methods.
jassert (! textRecursionCheck);
ScopedValueSetter<bool> sv (textRecursionCheck, true, false);
#endif
return getParameterText (index, 1024);
}
String AudioProcessor::getParameterText (int index, int maximumStringLength)
{
if (auto* p = managedParameters[index])
return p->getText (p->getValue(), maximumStringLength);
return getParameterText (index).substring (0, maximumStringLength);
}
#if JUCE_GCC
#pragma GCC diagnostic pop
#elif JUCE_CLANG
#pragma clang diagnostic pop
#elif JUCE_MSVC
#pragma warning (pop)
#endif
//==============================================================================
AudioProcessorListener* AudioProcessor::getListenerLocked (int index) const noexcept
{
const ScopedLock sl (listenerLock);
return listeners[index];
}
void AudioProcessor::updateHostDisplay()
{
for (int i = listeners.size(); --i >= 0;)
@ -567,34 +616,6 @@ String AudioProcessor::getParameterID (int index)
return String (index);
}
String AudioProcessor::getParameterName (int index, int maximumStringLength)
{
if (auto* p = managedParameters[index])
return p->getName (maximumStringLength);
return getParameterName (index).substring (0, maximumStringLength);
}
const String AudioProcessor::getParameterText (int index)
{
#if JUCE_DEBUG
// if you hit this, then you're probably using the old parameter control methods,
// but have forgotten to implement either of the getParameterText() methods.
jassert (! textRecursionCheck);
ScopedValueSetter<bool> sv (textRecursionCheck, true, false);
#endif
return getParameterText (index, 1024);
}
String AudioProcessor::getParameterText (int index, int maximumStringLength)
{
if (auto* p = managedParameters[index])
return p->getText (p->getValue(), maximumStringLength);
return getParameterText (index).substring (0, maximumStringLength);
}
int AudioProcessor::getParameterNumSteps (int index)
{
if (auto* p = managedParameters[index])
@ -1368,9 +1389,6 @@ AudioProcessorParameter::~AudioProcessorParameter()
void AudioProcessorParameter::setValueNotifyingHost (float newValue)
{
// This method can't be used until the parameter has been attached to a processor!
jassert (processor != nullptr && parameterIndex >= 0);
setValue (newValue);
sendValueChangedMessageToListeners (newValue);
}
@ -1394,11 +1412,14 @@ void AudioProcessorParameter::beginChangeGesture()
if (auto* l = listeners[i])
l->parameterGestureChanged (getParameterIndex(), true);
// audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex());
if (processor != nullptr && parameterIndex >= 0)
{
// audioProcessorParameterChangeGestureBegin callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChangeGestureBegin (processor, getParameterIndex());
}
}
void AudioProcessorParameter::endChangeGesture()
@ -1420,11 +1441,14 @@ void AudioProcessorParameter::endChangeGesture()
if (auto* l = listeners[i])
l->parameterGestureChanged (getParameterIndex(), false);
// audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex());
if (processor != nullptr && parameterIndex >= 0)
{
// audioProcessorParameterChangeGestureEnd callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChangeGestureEnd (processor, getParameterIndex());
}
}
void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue)
@ -1435,11 +1459,14 @@ void AudioProcessorParameter::sendValueChangedMessageToListeners (float newValue
if (auto* l = listeners [i])
l->parameterValueChanged (getParameterIndex(), newValue);
// audioProcessorParameterChanged callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue);
if (processor != nullptr && parameterIndex >= 0)
{
// audioProcessorParameterChanged callbacks will shortly be deprecated and
// this code will be removed.
for (int i = processor->listeners.size(); --i >= 0;)
if (auto* l = processor->listeners[i])
l->audioProcessorParameterChanged (processor, getParameterIndex(), newValue);
}
}
bool AudioProcessorParameter::isOrientationInverted() const { return false; }

View file

@ -962,14 +962,14 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual int getNumParameters();
JUCE_DEPRECATED (virtual int getNumParameters());
/** Returns the name of a particular parameter.
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual const String getParameterName (int parameterIndex);
JUCE_DEPRECATED (virtual const String getParameterName (int parameterIndex));
/** Returns the ID of a particular parameter.
@ -980,7 +980,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameterWithID class instead to manage your parameters.
*/
virtual String getParameterID (int index);
JUCE_DEPRECATED (virtual String getParameterID (int index));
/** Called by the host to find out the value of one of the processor's parameters.
@ -993,7 +993,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use the
AudioProcessorParameter class instead to manage your parameters.
*/
virtual float getParameter (int parameterIndex);
JUCE_DEPRECATED (virtual float getParameter (int parameterIndex));
/** Returns the name of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter names that
@ -1005,13 +1005,13 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getName() instead.
*/
virtual String getParameterName (int parameterIndex, int maximumStringLength);
JUCE_DEPRECATED (virtual String getParameterName (int parameterIndex, int maximumStringLength));
/** Returns the value of a parameter as a text string.
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getText() instead.
*/
virtual const String getParameterText (int parameterIndex);
JUCE_DEPRECATED (virtual const String getParameterText (int parameterIndex));
/** Returns the value of a parameter as a text string with a preferred maximum length.
If you want to provide customised short versions of your parameter values that
@ -1023,7 +1023,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getText() instead.
*/
virtual String getParameterText (int parameterIndex, int maximumStringLength);
JUCE_DEPRECATED (virtual String getParameterText (int parameterIndex, int maximumStringLength));
/** Returns the number of discrete steps that this parameter can represent.
@ -1043,7 +1043,7 @@ public:
@see isParameterDiscrete
*/
virtual int getParameterNumSteps (int parameterIndex);
JUCE_DEPRECATED (virtual int getParameterNumSteps (int parameterIndex));
/** Returns the default number of steps for a parameter.
@ -1067,7 +1067,7 @@ public:
@see getParameterNumSteps
*/
virtual bool isParameterDiscrete (int parameterIndex) const;
JUCE_DEPRECATED (virtual bool isParameterDiscrete (int parameterIndex) const);
/** Returns the default value for the parameter.
By default, this just returns 0.
@ -1076,7 +1076,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getDefaultValue() instead.
*/
virtual float getParameterDefaultValue (int parameterIndex);
JUCE_DEPRECATED (virtual float getParameterDefaultValue (int parameterIndex));
/** Some plugin types may be able to return a label string for a
parameter's units.
@ -1084,7 +1084,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getLabel() instead.
*/
virtual String getParameterLabel (int index) const;
JUCE_DEPRECATED (virtual String getParameterLabel (int index) const);
/** This can be overridden to tell the host that particular parameters operate in the
reverse direction. (Not all plugin formats or hosts will actually use this information).
@ -1092,7 +1092,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isOrientationInverted() instead.
*/
virtual bool isParameterOrientationInverted (int index) const;
JUCE_DEPRECATED (virtual bool isParameterOrientationInverted (int index) const);
/** The host will call this method to change the value of one of the processor's parameters.
@ -1110,7 +1110,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::setValue() instead.
*/
virtual void setParameter (int parameterIndex, float newValue);
JUCE_DEPRECATED (virtual void setParameter (int parameterIndex, float newValue));
/** Your processor can call this when it needs to change one of its parameters.
@ -1133,7 +1133,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isAutomatable() instead.
*/
virtual bool isParameterAutomatable (int parameterIndex) const;
JUCE_DEPRECATED (virtual bool isParameterAutomatable (int parameterIndex) const);
/** Should return true if this parameter is a "meta" parameter.
A meta-parameter is a parameter that changes other params. It is used
@ -1143,7 +1143,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::isMetaParameter() instead.
*/
virtual bool isMetaParameter (int parameterIndex) const;
JUCE_DEPRECATED (virtual bool isMetaParameter (int parameterIndex) const);
/** Should return the parameter's category.
By default, this returns the "generic" category.
@ -1151,7 +1151,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::getCategory() instead.
*/
virtual AudioProcessorParameter::Category getParameterCategory (int parameterIndex) const;
JUCE_DEPRECATED (virtual AudioProcessorParameter::Category getParameterCategory (int parameterIndex) const);
/** Sends a signal to the host to tell it that the user is about to start changing this
parameter.
@ -1164,7 +1164,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::beginChangeGesture() instead.
*/
void beginParameterChangeGesture (int parameterIndex);
JUCE_DEPRECATED (void beginParameterChangeGesture (int parameterIndex));
/** Tells the host that the user has finished changing this parameter.
@ -1176,7 +1176,7 @@ public:
NOTE! This method will eventually be deprecated! It's recommended that you use
AudioProcessorParameter::endChangeGesture() instead.
*/
void endParameterChangeGesture (int parameterIndex);
JUCE_DEPRECATED (void endParameterChangeGesture (int parameterIndex));
/** The processor can call this when something (apart from a parameter value) has changed.
@ -1626,8 +1626,6 @@ private:
friend class AudioUnitPluginInstance;
friend class LADSPAPluginInstance;
Atomic<int> vst3IsPlaying { 0 };
// This method is no longer used - you can delete it from your AudioProcessor classes.
JUCE_DEPRECATED_WITH_BODY (virtual bool silenceInProducesSilenceOut() const, { return false; })

View file

@ -27,166 +27,6 @@
namespace juce
{
class ProcessorParameterPropertyComp : public PropertyComponent,
private AudioProcessorListener,
private Timer
{
public:
ProcessorParameterPropertyComp (const String& name, AudioProcessor& p, int paramIndex)
: PropertyComponent (name),
owner (p),
index (paramIndex),
slider (p, paramIndex)
{
startTimer (100);
addAndMakeVisible (slider);
owner.addListener (this);
}
~ProcessorParameterPropertyComp()
{
owner.removeListener (this);
}
void refresh() override
{
paramHasChanged = false;
if (slider.getThumbBeingDragged() < 0)
slider.setValue (owner.getParameter (index), dontSendNotification);
slider.updateText();
}
void audioProcessorChanged (AudioProcessor*) override {}
void audioProcessorParameterChanged (AudioProcessor*, int parameterIndex, float) override
{
if (parameterIndex == index)
paramHasChanged = true;
}
void timerCallback() override
{
if (paramHasChanged)
{
refresh();
startTimerHz (50);
}
else
{
startTimer (jmin (1000 / 4, getTimerInterval() + 10));
}
}
private:
//==============================================================================
class ParamSlider : public Slider
{
public:
ParamSlider (AudioProcessor& p, int paramIndex) : owner (p), index (paramIndex)
{
auto steps = owner.getParameterNumSteps (index);
auto category = p.getParameterCategory (index);
bool isLevelMeter = (((category & 0xffff0000) >> 16) == 2);
if (steps > 1 && steps < 0x7fffffff)
setRange (0.0, 1.0, 1.0 / (steps - 1.0));
else
setRange (0.0, 1.0);
setEnabled (! isLevelMeter);
setSliderStyle (Slider::LinearBar);
setTextBoxIsEditable (false);
setScrollWheelEnabled (true);
}
void valueChanged() override
{
auto newVal = static_cast<float> (getValue());
if (owner.getParameter (index) != newVal)
{
owner.setParameterNotifyingHost (index, newVal);
updateText();
}
}
void startedDragging() override
{
owner.beginParameterChangeGesture (index);
}
void stoppedDragging() override
{
owner.endParameterChangeGesture (index);
}
String getTextFromValue (double /*value*/) override
{
return (owner.getParameterText (index) + " " + owner.getParameterLabel (index)).trimEnd();
}
private:
//==============================================================================
AudioProcessor& owner;
const int index;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider)
};
AudioProcessor& owner;
const int index;
bool volatile paramHasChanged = false;
ParamSlider slider;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorParameterPropertyComp)
};
struct LegacyParametersPanel : public Component
{
LegacyParametersPanel (AudioProcessor* const processor)
{
addAndMakeVisible (panel);
Array<PropertyComponent*> params;
auto numParams = processor->getNumParameters();
int totalHeight = 0;
for (int i = 0; i < numParams; ++i)
{
String name (processor->getParameterName (i));
if (name.trim().isEmpty())
name = "Unnamed";
auto* pc = new ProcessorParameterPropertyComp (name, *processor, i);
params.add (pc);
totalHeight += pc->getPreferredHeight();
}
panel.addProperties (params);
setSize (400, jmax (25, totalHeight));
}
void paint (Graphics& g) override
{
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
}
void resized() override
{
panel.setBounds (getLocalBounds());
}
PropertyPanel panel;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LegacyParametersPanel)
};
//==============================================================================
class ParameterListener : private AudioProcessorParameter::Listener,
private Timer
{
@ -615,7 +455,7 @@ private:
class ParametersPanel : public Component
{
public:
ParametersPanel (const OwnedArray<AudioProcessorParameter>& parameters)
ParametersPanel (const Array<AudioProcessorParameter*>& parameters)
{
for (auto* param : parameters)
if (param->isAutomatable())
@ -647,25 +487,40 @@ private:
};
//==============================================================================
GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor* const p)
: AudioProcessorEditor (p)
struct GenericAudioProcessorEditor::Pimpl
{
jassert (p != nullptr);
setOpaque (true);
Pimpl (GenericAudioProcessorEditor& parent)
: owner (parent)
{
auto* p = parent.getAudioProcessor();
jassert (p != nullptr);
auto& parameters = p->getParameters();
juceParameters.update (*p, false);
if (parameters.size() == p->getNumParameters())
view.setViewedComponent (new ParametersPanel (parameters));
else
view.setViewedComponent (new LegacyParametersPanel (p));
owner.setOpaque (true);
addAndMakeVisible (view);
view.setViewedComponent (new ParametersPanel (juceParameters.params));
owner.addAndMakeVisible (view);
view.setScrollBarsShown (true, false);
setSize (view.getViewedComponent()->getWidth() + view.getVerticalScrollBar().getWidth(),
jmin (view.getViewedComponent()->getHeight(), 400));
}
view.setScrollBarsShown (true, false);
owner.setSize (view.getViewedComponent()->getWidth() + view.getVerticalScrollBar().getWidth(),
jmin (view.getViewedComponent()->getHeight(), 400));
}
//==============================================================================
GenericAudioProcessorEditor& owner;
LegacyAudioParametersWrapper juceParameters;
Viewport view;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
};
//==============================================================================
GenericAudioProcessorEditor::GenericAudioProcessorEditor (AudioProcessor* const p)
: AudioProcessorEditor (p), pimpl (new Pimpl (*this))
{}
GenericAudioProcessorEditor::~GenericAudioProcessorEditor() {}
@ -676,7 +531,7 @@ void GenericAudioProcessorEditor::paint (Graphics& g)
void GenericAudioProcessorEditor::resized()
{
view.setBounds (getLocalBounds());
pimpl->view.setBounds (getLocalBounds());
}
} // namespace juce

View file

@ -52,7 +52,8 @@ public:
private:
//==============================================================================
Viewport view;
struct Pimpl;
ScopedPointer<Pimpl> pimpl;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericAudioProcessorEditor)
};