|
|
|
@@ -1082,13 +1082,22 @@ private: |
|
|
|
busses: array];
|
|
|
|
}
|
|
|
|
|
|
|
|
// When parameters are discrete we need to use integer values.
|
|
|
|
float getMaximumParameterValue (int parameterIndex)
|
|
|
|
{
|
|
|
|
#if JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
|
|
|
|
ignoreUnused (parameterIndex);
|
|
|
|
return 1.0f;
|
|
|
|
#else
|
|
|
|
auto& processor = getAudioProcessor();
|
|
|
|
return processor.isParameterDiscrete (parameterIndex) ? (float) (processor.getParameterNumSteps (parameterIndex) - 1) : 1.0f;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void addParameters()
|
|
|
|
{
|
|
|
|
ScopedPointer<NSMutableArray<AUParameterNode*>> params = [[NSMutableArray<AUParameterNode*> alloc] init];
|
|
|
|
|
|
|
|
paramObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedFromHost);
|
|
|
|
paramProvider = CreateObjCBlock (this, &JuceAudioUnitv3::getValue);
|
|
|
|
|
|
|
|
overviewParams = [[NSMutableArray<NSNumber*> alloc] init];
|
|
|
|
|
|
|
|
auto& processor = getAudioProcessor();
|
|
|
|
@@ -1118,9 +1127,17 @@ private: |
|
|
|
if (name.isEmpty() || ! processor.isParameterAutomatable (idx))
|
|
|
|
flags |= kAudioUnitParameterFlag_NonRealTime;
|
|
|
|
|
|
|
|
const bool isParameterDiscrete = processor.isParameterDiscrete (idx);
|
|
|
|
|
|
|
|
if (! isParameterDiscrete)
|
|
|
|
flags |= kAudioUnitParameterFlag_CanRamp;
|
|
|
|
|
|
|
|
if (processor.isMetaParameter (idx))
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
@@ -1128,13 +1145,36 @@ private: |
|
|
|
flags |= kAudioUnitParameterFlag_MeterReadOnly | kAudioUnitParameterFlag_DisplayLogarithmic;
|
|
|
|
unit = kAudioUnitParameterUnit_LinearGain;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#if ! JUCE_FORCE_LEGACY_PARAMETER_AUTOMATION_TYPE
|
|
|
|
if (auto* param = processor.getParameters()[idx])
|
|
|
|
{
|
|
|
|
if (param->isDiscrete())
|
|
|
|
{
|
|
|
|
unit = kAudioUnitParameterUnit_Indexed;
|
|
|
|
auto maxValue = getMaximumParameterValue (idx);
|
|
|
|
auto numSteps = param->getNumSteps();
|
|
|
|
|
|
|
|
// Some hosts can't handle the huge numbers of discrete parameter values created when
|
|
|
|
// using the default number of steps.
|
|
|
|
jassert (numSteps != AudioProcessor::getDefaultNumParameterSteps());
|
|
|
|
|
|
|
|
valueStrings.reset ([NSMutableArray new]);
|
|
|
|
|
|
|
|
for (int i = 0; i < numSteps; ++i)
|
|
|
|
[valueStrings.get() addObject: juceStringToNS (param->getText ((float) i / maxValue, 0))];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
|
|
|
|
AUParameterAddress address = static_cast<AUParameterAddress> (idx);
|
|
|
|
#else
|
|
|
|
AUParameterAddress address = generateAUParameterAddressForIndex (idx);
|
|
|
|
|
|
|
|
// Consider yourself very unlucky if you hit this assertion. The hash code of your
|
|
|
|
// 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)));
|
|
|
|
|
|
|
|
@@ -1148,13 +1188,15 @@ private: |
|
|
|
name: juceStringToNS (name)
|
|
|
|
address: address
|
|
|
|
min: 0.0f
|
|
|
|
max: 1.0f
|
|
|
|
max: getMaximumParameterValue (idx)
|
|
|
|
unit: unit
|
|
|
|
unitName: nullptr
|
|
|
|
flags: flags
|
|
|
|
valueStrings: nullptr
|
|
|
|
valueStrings: valueStrings.get()
|
|
|
|
dependentParameters: nullptr] retain];
|
|
|
|
|
|
|
|
[param.get() setValue: processor.getParameterDefaultValue (idx)];
|
|
|
|
|
|
|
|
[params addObject: param];
|
|
|
|
[overviewParams addObject: [NSNumber numberWithUnsignedLongLong:address]];
|
|
|
|
}
|
|
|
|
@@ -1162,8 +1204,15 @@ private: |
|
|
|
// create methods in AUParameterTree return unretained objects (!) -> see Apple header AUAudioUnitImplementation.h
|
|
|
|
paramTree = [[AUParameterTree createTreeWithChildren: params] retain];
|
|
|
|
|
|
|
|
paramObserver = CreateObjCBlock (this, &JuceAudioUnitv3::valueChangedFromHost);
|
|
|
|
paramProvider = CreateObjCBlock (this, &JuceAudioUnitv3::getValue);
|
|
|
|
stringFromValueProvider = CreateObjCBlock (this, &JuceAudioUnitv3::stringFromValue);
|
|
|
|
valueFromStringProvider = CreateObjCBlock (this, &JuceAudioUnitv3::valueFromString);
|
|
|
|
|
|
|
|
[paramTree setImplementorValueObserver: paramObserver];
|
|
|
|
[paramTree setImplementorValueProvider: paramProvider];
|
|
|
|
[paramTree setImplementorStringFromValueCallback: stringFromValueProvider];
|
|
|
|
[paramTree setImplementorValueFromStringCallback: valueFromStringProvider];
|
|
|
|
|
|
|
|
if (processor.hasEditor())
|
|
|
|
{
|
|
|
|
@@ -1375,7 +1424,7 @@ private: |
|
|
|
auto& processor = getAudioProcessor();
|
|
|
|
|
|
|
|
if (isPositiveAndBelow (idx, processor.getNumParameters()))
|
|
|
|
processor.setParameter (idx, value);
|
|
|
|
processor.setParameter (idx, value / getMaximumParameterValue (idx));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1387,7 +1436,7 @@ private: |
|
|
|
auto& processor = getAudioProcessor();
|
|
|
|
|
|
|
|
if (isPositiveAndBelow (idx, processor.getNumParameters()))
|
|
|
|
return processor.getParameter (idx);
|
|
|
|
return processor.getParameter (idx) * getMaximumParameterValue (idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
@@ -1398,6 +1447,41 @@ private: |
|
|
|
// this will have already been handled by valueChangedFromHost
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString* stringFromValue (AUParameter* param, const AUValue* value)
|
|
|
|
{
|
|
|
|
String text;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return juceStringToNS (text);
|
|
|
|
}
|
|
|
|
|
|
|
|
AUValue valueFromString (AUParameter* param, NSString* str)
|
|
|
|
{
|
|
|
|
if (param != nullptr && str != nullptr)
|
|
|
|
{
|
|
|
|
const int idx = getJuceParameterIndexForAUAddress ([param address]);
|
|
|
|
auto& processor = getAudioProcessor();
|
|
|
|
const String text (nsStringToJuce (str));
|
|
|
|
|
|
|
|
if (auto* p = processor.getParameters()[idx])
|
|
|
|
return p->getValueForText (text) * getMaximumParameterValue (idx);
|
|
|
|
else
|
|
|
|
return text.getFloatValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//==============================================================================
|
|
|
|
#if JUCE_FORCE_USE_LEGACY_PARAM_IDS
|
|
|
|
inline AUParameterAddress getAUParameterAddressForIndex (int paramIndex) const noexcept { return static_cast<AUParameterAddress> (paramIndex); }
|
|
|
|
@@ -1443,6 +1527,8 @@ private: |
|
|
|
|
|
|
|
ObjCBlock<AUImplementorValueObserver> paramObserver;
|
|
|
|
ObjCBlock<AUImplementorValueProvider> paramProvider;
|
|
|
|
ObjCBlock<AUImplementorStringFromValueCallback> stringFromValueProvider;
|
|
|
|
ObjCBlock<AUImplementorValueFromStringCallback> valueFromStringProvider;
|
|
|
|
|
|
|
|
#if ! JUCE_FORCE_USE_LEGACY_PARAM_IDS
|
|
|
|
bool usingManagedParameter;
|
|
|
|
|