OSStatus AUBase::ProcessForScheduledParams()

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;
}