I’m not an expert, but I think this method is not as “automagic" as you and I both assumed. I believe what you are really scheduling is sample accurate ramping of a parameter change that should be done in a render notification callback. You are responsible for keeping track of the incremental parameter values across frames.
So you need to add a render notification callback:
AudioUnitAddRenderNotify(mixerUnit, MixerRenderProc, &mixerUnit/* Or whatever you need */);
And the parameter event like this (for example):
AudioUnitParameterEvent parameterEvent = {
.scope = parameter.mScope,
.element = parameter.mElement,
.parameter = parameter.mParameterID,
.eventType = kParameterEvent_Ramped,
.eventValues.ramp.startBufferOffset = 0,
.eventValues.ramp.durationInFrames = 0,
.eventValues.ramp.startValue = 0.0,
.eventValues.ramp.endValue = 0.01
};
And this callback that would continually ramp from from a volume of 0.0 to 1.0:
OSStatus MixerRenderProc(void* inRefCon,
AudioUnitRenderActionFlags* ioActionFlags,
const AudioTimeStamp* inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList* ioData)
{
AudioUnit* mixerUnit = (AudioUnit*)inRefCon;
if ((*ioActionFlags & kAudioUnitRenderAction_PreRender) == kAudioUnitRenderAction_PreRender)
{
parameterEvent.eventValues.ramp.startBufferOffset = 0;
parameterEvent.eventValues.ramp.durationInFrames = inNumberFrames;
CheckError(AudioUnitScheduleParameters(*mixerUnit, ¶meterEvent, 1),
"ramped volume parameter could not be scheduled");
if (parameterEvent.eventValues.ramp.endValue >= 1.0)
{
parameterEvent.eventValues.ramp.startValue = 0.0;
parameterEvent.eventValues.ramp.endValue = 0.01;
}
else
{
parameterEvent.eventValues.ramp.startValue += 0.01;
parameterEvent.eventValues.ramp.endValue += 0.01;
}
}
return noErr;
}
If this is not how this is intended to work I hope someone else answers, because I would also like to better understand.
- Matt Grippaldi