in Source/AUBase.cpp [1110:1202]
OSStatus AUBase::ProcessForScheduledParams(
ParameterEventList& inParamList, UInt32 inFramesToProcess, void* inUserData)
{
OSStatus result = noErr;
UInt32 framesRemaining = inFramesToProcess;
UInt32 currentStartFrame = 0; // start of the whole buffer
// sort the ParameterEventList by startBufferOffset
std::sort(inParamList.begin(), inParamList.end(), ParameterEventListSortPredicate);
while (framesRemaining > 0) {
// first of all, go through the ramped automation events and find out where the next
// division of our whole buffer will be
UInt32 currentEndFrame = inFramesToProcess; // start out assuming we'll process all the way
// to the end of the buffer
// find the next break point
for (const auto& event : inParamList) {
SInt32 offset =
event.eventType == kParameterEvent_Immediate
? static_cast<SInt32>(event.eventValues.immediate.bufferOffset) // NOLINT
: event.eventValues.ramp.startBufferOffset;
if (offset > static_cast<SInt32>(currentStartFrame) &&
offset < static_cast<SInt32>(currentEndFrame)) {
currentEndFrame = static_cast<UInt32>(offset);
break;
}
// consider ramp end to be a possible choice (there may be gaps in the supplied ramp
// events)
if (event.eventType == kParameterEvent_Ramped) {
offset = event.eventValues.ramp.startBufferOffset +
static_cast<SInt32>(event.eventValues.ramp.durationInFrames); // NOLINT
if (offset > static_cast<SInt32>(currentStartFrame) &&
offset < static_cast<SInt32>(currentEndFrame)) {
currentEndFrame = static_cast<UInt32>(offset);
}
}
}
const UInt32 framesThisTime = currentEndFrame - currentStartFrame;
// next, setup the parameter maps to be current for the ramp parameters active during
// this time segment...
for (const auto& event : inParamList) {
bool eventFallsInSlice = false;
if (event.eventType == kParameterEvent_Ramped) {
const auto& ramp = event.eventValues.ramp;
eventFallsInSlice =
ramp.startBufferOffset < static_cast<SInt32>(currentEndFrame) &&
(ramp.startBufferOffset + static_cast<SInt32>(ramp.durationInFrames)) >
static_cast<SInt32>(currentStartFrame);
} else { /* kParameterEvent_Immediate */
// actually, for the same parameter, there may be future immediate events which
// override this one, but it's OK since the event list is sorted in time order,
// we're guaranteed to end up with the current one
eventFallsInSlice = event.eventValues.immediate.bufferOffset <= currentStartFrame;
}
if (eventFallsInSlice) {
AUElement* const element = GetElement(event.scope, event.element);
if (element != nullptr) {
element->SetScheduledEvent(event.parameter, event, currentStartFrame,
currentEndFrame - currentStartFrame);
}
}
}
// Finally, actually do the processing for this slice.....
result =
ProcessScheduledSlice(inUserData, currentStartFrame, framesThisTime, inFramesToProcess);
if (result != noErr) {
break;
}
framesRemaining -= std::min(framesThisTime, framesRemaining);
currentStartFrame = currentEndFrame; // now start from where we left off last time
}
return result;
}