NOTE: This is the English version of
my Japanese article.
I'm on the way to developing a vibrato unit by referring to FilterDemo at
AudioUnitV3Example: A Basic AudioUnit Extension and Host Implementation.
In this article, I tried to add parameters.
In the template code of AudioUnit App Extension, it is seemed to add "Parameter 1" parameter as follows:
// Create parameter objects.
AUParameter *param1 = [AUParameterTree createParameterWithIdentifier:@"param1" name:@"Parameter 1" address:myParam1 min:0 max:100 unit:kAudioUnitParameterUnit_Percent unitName:nil flags:0 valueStrings:nil dependentParameters:nil];
A myParam1 is defined as
// Define parameter addresses. (These needn't be static).
#define myParam1 0
In FilterDemo, the addresses are defined as enum as:
enum {
FilterParamCutoff = 0,
FilterParamResonance = 1
};
I think any unique values will be OK.
In my case, I defined the paas follows
typedef NS_ENUM(AUParameterAddress, VibratoParameterAddress) {
VibratoParameterAddressFrequency = 0,
VibratoParameterAddressDepth = 1
};
Then, I actually added parameters as:
AUParameter *freqParameter = [AUParameterTree createParameterWithIdentifier:VibratoParameterIdentifierFrequency
name:VibratoParameterNameFrequency
address:VibratoParameterAddressFrequency
min:0
max:1
unit:kAudioUnitParameterUnit_Hertz
unitName:nil
flags:0
valueStrings:nil
dependentParameters:nil];
freqParameter.value = .0025;
self.freq = freqParameter.value;
AUParameter *depthParameter = [AUParameterTree createParameterWithIdentifier:VibratoParameterIdentifierDepth
name:VibratoParameterNameDepth
address:VibratoParameterAddressDepth
min:0
max:250
unit:kAudioUnitParameterUnit_Seconds
unitName:nil
flags:0
valueStrings:nil
dependentParameters:nil];
depthParameter.value = 250;
self.depth = depthParameter.value;
self.parameterTree = [AUParameterTree createTreeWithChildren:@[freqParameter, depthParameter]];
where, name and identifier strings were defined as
NSString *VibratoParameterIdentifierFrequency = @"VibratoParameterIdentifierFrequency";
NSString *VibratoParameterIdentifierDepth = @"VibratoParameterIdentifierDepth";
NSString *VibratoParameterNameFrequency = @"Frequency";
NSString *VibratoParameterNameDepth = @"Depth";
By the way, as for detecting the changes in these parameters from outside, FilterDemo's implementation is
// implementorValueObserver is called when a parameter changes value.
_parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) {
filterKernel->setParameter(param.address, value);
};
// implementorValueProvider is called when the value needs to be refreshed.
_parameterTree.implementorValueProvider = ^(AUParameter *param) {
return filterKernel->getParameter(param.address);
};
I think this code means that blocks are executed when parameters were set/got.
In my case, I implemented as
MyAudioUnit *unit = self;
self.parameterTree.implementorValueObserver = ^(AUParameter *param, AUValue value) {
switch (param.address) {
case VibratoParameterAddressFrequency:
unit.freq = value;
break;
case VibratoParameterAddressDepth:
unit.depth = value;
default:
break;
}
};
self.parameterTree.implementorValueProvider = ^(AUParameter *param) {
switch (param.address) {
case VibratoParameterAddressFrequency:
return unit.freq;
case VibratoParameterAddressDepth:
return unit.depth;
default:
break;
}
return 0.0f;
};
By the way, it is noted that a block is needed to express these parameters as strings.
In FilterDemo, the implementations are
// A function to provide string representations of parameter values.
_parameterTree.implementorStringFromValueCallback = ^(AUParameter *param, const AUValue *__nullable valuePtr) {
AUValue value = valuePtr == nil ? param.value : *valuePtr;
switch (param.address) {
case FilterParamCutoff:
return [NSString stringWithFormat:@"%.f", value];
case FilterParamResonance:
return [NSString stringWithFormat:@"%.2f", value];
default:
return @"?";
}
};
So, I implemented as follows:
self.parameterTree.implementorStringFromValueCallback = ^(AUParameter *param, const AUValue *__nullable valuePtr) {
AUValue value = valuePtr == nil ? param.value : *valuePtr;
switch (param.address) {
case VibratoParameterAddressFrequency:
return [NSString stringWithFormat:@"%.f", value];
case VibratoParameterAddressDepth:
return [NSString stringWithFormat:@"%.0f", value];
default:
return @"?";
}
};
Finally, parameter setting will be completed.
Nextly, I tried to change the parameters from outside.
However, my AudioUnit's UI was not displayed on host applications such as AUV3Host or
Hosting AU...
For v3 AudioUnits, custom UIs may be required.
So, before checking parameter changes, I think I'm going to make a custom UI...
That's all for today!!