/*===================================================================================================
AAX_ParameterUpdateTiming.doxygen

Copyright 2016, 2018, 2023 Avid Technology, Inc. 
All rights reserved.

CONFIDENTIAL: this document contains confidential information of Avid. Do
not disclose to any third party. Use of the information contained in this
document is subject to an Avid SDK license.

===================================================================================================*/

/** @defgroup advancedTopics_parameterUpdateTiming Parameter update timing
	@ingroup advancedTopics_ParameterUpdates
	
	@brief Details about parameter timing and how to keep parameter updates in sync
	
	\section parameterUpdateTiming_contents On this page
		\li \ref parameterUpdateTiming_timelineLocations
		\li \ref parameterUpdateTiming_synchronization
		\li \ref parameterUpdateTiming_sharedData
		\li \ref parameterUpdateTiming_timestamps
	
	\section parameterUpdateTiming_timelineLocations Timeline Locations
		
		At any given moment, a plug-in may be asked to handle events from multiple locations on the timeline. Each module in an %AAX plug-in may be updated using a different timeline position. For example:
		\li During automation playback the host may choose to send parameter updates in advance, while the algorithm is still processing audio from earlier in the timeline.
		\li When a processing chain involves a significant amount of latency, the host may delay the metering data which is available to the plug-in's GUI until the point in time when the corresponding processed audio is actually being played back to the user.
		
		In this article, we will refer to the following timeline locations:
		\li <em class="BoldItalic">Automation time</em>: The location that corresponds to the state of the plug-in's data model
		\li <em class="BoldItalic">Playhead</em>: The location where the audio engine is currently gathering samples for processing
		\li <em class="BoldItalic">Render time</em>: The location of the audio samples currently being processed by the plug-in's algorithm
		\li <em class="BoldItalic">Presentation time</em>: The location that corresponds to the playback presentation to the user (i.e. the sound coming out of the speakers)
		
		\nodox Image files must be copied to the /output/html directory \endnodox
		<IMG width="60%" alt="Timeline locations" src="parameter_update_timing_basic_reference_times.png" />
		<DIV CLASS="imagecaption">Figure 1: Timeline locations</DIV>
		
	\section parameterUpdateTiming_synchronization Coordinating the data model and algorithm
		
		As an %AAX plug-in developer, you don't usually need to worry about the fact that your plug-in's data model and algorithm may each represent a different point in the timeline; the \ref alg_comm "AAX packet system" handles all of the necessary synchronization between these two locations.
		
		This works seamlessly in a normal %AAX plug-in because the real-time algorithm is fully decoupled from the plug-in's data model. Since all of the state information for the algorithm is delivered through its \ref alg_memmgmt "context structure", the host can simply swap in the correct context data for each call to the processing callback. The plug-in does not require any special handling code to synchronize between the two timeline locations, and, as a bonus, %AAX plug-ins can achieve deterministic, accurate automation playback without doing any extra work to handle time-stamped parameter update queues or other overhead.
		
		\nodox Image files must be copied to the /output/html directory \endnodox
		<IMG width="60%" alt="Synchronization through the AAX packet system" src="parameter_update_timing_standard_packet_queue.png" />
		<DIV CLASS="imagecaption">Figure 2: Synchronization through the %AAX packet system</DIV>
		
		\subsection parameterUpdateTiming_packet_delivery A closer look at the AAX packet delivery system
			
			\par Adding new packets for automation events
				\parblock
				When playing back automation, the %AAX host calls \ref AAX_IACFEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()" to update the data model state, then calls \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients()" to trigger the generation of new packets. See \ref advancedTopics_parameterUpdates_sequences for a full description of this sequence.
			
				Before the host calls \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients()" to generate packets for an automation breakpoint, it records the timeline position of the breakpoint (\ref AAX_IController::GetCurrentAutomationTimestamp() provides this value as a sample offset from the beginning of playback.) Every packet that is posted during execution of \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients()" is tagged with this timestamp when it is queued for delivery.
				\endparblock
			
			\par Packet delivery for %AAX Native plug-ins
				\parblock
				As the playhead advances and sample buffers are queued for processing, the host tracks the location of the next time-stamped packet in the packet queue. As the render time location for a Native plug-in processing chain approaches the next packet time-stamp for a plug-in in the chain, the host divides the plug-in's processing buffers into smaller buffers. When the render time location is as close as possible to the packet's time-stamp, the host delivers the packet. The packet data is available to the algorithm in its context the next time it is executed.
				
				Because the host may divide native processing buffers down to a minimum size of \ref AAX_eAudioBufferLengthNative_Min - 32 samples - the host can guarantee that all automation playback will be effected within 32 samples of the actual automation breakpoint location. In addition, with the help of some extra internal bookkeeping, %AAX hosts also guarantee that the exact sample where an automation breakpoint is applied will be deterministic and will not change between different playback passes.
				\endparblock
			
			\par Packet delivery for %AAX DSP plug-ins
				\parblock
				The packet delivery system for %AAX DSP plug-ins works similarly to the system for %AAX Native plug-ins. %AAX DSP plug-ins use a fixed buffer size, so the host is not able to divide their playback buffers into smaller units: the plug-in will receive each data packet in the fixed-size playback buffer which most closely corresponds to the location of the automation event which triggered the packet.
				
				An %AAX DSP plug-in which declares an \ref AAX_eProperty_DSP_AudioBufferLength value of N will be guaranteed to receive data packets within N/2 samples of the actual automation event position on the timeline. Since the default buffer size for an %AAX DSP plug-in is 4 samples, this yields extremely accurate automation playback with no extra work required in the plug-in algorithm.
				\endparblock
			
	\section parameterUpdateTiming_sharedData Fixing timing issues due to shared data
		
		The packet system works perfectly to synchronize the states of the plug-in data model and algorithm, <em class="Italic">but only when the plug-in algorithm is fully decoupled from the data model</em>. If the algorithm directly shares data with the data model then the algorithm will immediately start using any new data model state without waiting for the corresponding coefficient delivery.
		
		Figure 3 shows one kind of problem that can arise when a plug-in uses the same state for both its data model and its algorithm. In this case, the plug-in applied a volume trim (shown in the automation lane at the top of the image) to its algorithm as soon as the parameter update was applied to its data model, even though the algorithm was not yet processing the audio at the Automation time location. As a result, the audio trim was applied several hundred samples too early.
		
		\nodox Image files must be copied to the /output/html directory \endnodox
		<IMG width="60%" alt="Offset automation playback due to lack of timeline location synchronization in a monolithic plug-in" src="parameter_update_timing_offset_update.png" />
		<DIV CLASS="imagecaption">Figure 3: Offset automation playback due to lack of timeline location synchronization in a monolithic plug-in</DIV>
		
		\subsection parameterUpdateTiming_monolithic Monolithic plug-ins
		
			Plug-ins that share data directly between their data model and algorithm are referred to as <em class="Bold">monolithic</em>. All plug-ins that inherit from the \ref AAX_CMonolithicParameters helper class are monolithic.
		
			\note Monolithic plug-ins must always set the \ref AAX_eProperty_Constraint_Location property to include \ref AAX_eConstraintLocationMask_DataModel in order to avoid being loaded into incompatible %AAX hosts.
		
			All monolithic plug-ins must include special handling code to reconcile the plug-in's automation time state with its render time state.
		
		\subsection parameterUpdateTiming_resolvingOffsets How to resolve timing errors
			
			There are many possible solutions for the timing errors that arise when a plug-in combines data from different time locations. Ultimately, the plug-in must separate the state that is represented at different time locations.
			
			In most cases, this requires deferring data model state changes from being applied to the algorithm until the relevant samples are being processed in the render callback. One easy way to accomplish this separation is to take advantage of the synchronization provided by the %AAX packet delivery system. This approach benefits from the fact that it emulates the design of a normal, decoupled %AAX plug-in.
			
			After a packet is queued with a call to \ref AAX_IController::PostPacket() "PostPacket()", the packet delivery system will wait to update the algorithm's context structure with the packet's data until the Render time location is very close to the automation event (see \ref parameterUpdateTiming_packet_delivery "above".) This provides an appropriate mechanism for deferring state changes in the plug-in's data model until the Render time location has "caught up" to the correct sample.
			
			Figure 4 shows the same scenario as Figure 3, but now the plug-in has been updated to defer data model updates from the automation time location so that they are applied as coefficients in the algorithm when the render time location has reached the correct point on the timeline.
			
			\nodox Image files must be copied to the /output/html directory \endnodox
			<IMG width="70%" alt="Deferring a data model update in a monolithic plug-in using the packet queue" src="parameter_update_timing_monolithic_with_packet_queue.png" />
			<DIV CLASS="imagecaption">Figure 4: Deferring a data model update in a monolithic plug-in using the packet queue</DIV>
			
			Here is one way to use the packet delivery system to defer changes to the data model state:
\code			
AAX_Result
MyEffectParameters::UpdateParameterNormalizedValue(
  AAX_CParamID iParamID,
  double aValue,
  AAX_EUpdateSource inSource)
{
  // Call inherited
  AAX_Result result = AAX_CMonolithicParameters::UpdateParameterNormalizedValue(
    iParamID,
    aValue,
    inSource);
  if (AAX_SUCCESS != result) { return result; }
  
  // Do whatever additional work is required to note that the
  // parameter has been updated - for example, set a "dirty"
  // flag for the parameter.
  
  return result;
}
\endcode

\code
AAX_Result
MyEffectParameters::GenerateCoefficients()
{
  // Call inherited
  AAX_Result result = AAX_CMonolithicParameters::GenerateCoefficients();
  if (AAX_SUCCESS != result) { return result; }
  
  const uint32_t stateNum = mMyStateCounter++; // member uint32_t
  
  // Do whatever additional work is required to capture the current
  // parameter state and associate it with stateNum, for example
  // check for "dirty" parameters and create a list of these
  // parameters with their values, add this list to a map using
  // stateNum as a key, and clear the "dirty" flags.
  
  result = Controller()->PostPacket(
    kCurrentStateFieldIndex,
    &stateNum,
    sizeof(uint32_t));
   
  return result;
}
\endcode

\code
struct MyContextStructure
{
  int32_t * mCurrentStateNum; // Private data
  // ...
};

void
MyAudioRenderCallback(
  MyContextStructure* const	inInstancesBegin [],
  const void* inInstancesEnd)
{
  /* For each instance... */
  const uint32_t stateNum = instance->mCurrentStateNum;
  
  // Update the custom plug-in object state based on stateNum
  // and the additional data that was cached during
  // GenerateCoefficients().
}	
\endcode
			
			\nodox Image files must be copied to the /output/html directory \endnodox
			<IMG width="80%" alt="One specific solution for deferring a data model update in a monolithic plug-in using the packet queue" src="parameter_update_timing_monolithic_with_packet_queue_annotated.png" />
			<DIV CLASS="imagecaption">Figure 5: One specific solution for deferring a data model update in a monolithic plug-in using the packet queue</DIV>
			
			This approach is incorporated directly into the design of \ref AAX_CMonolithicParameters. If your plug-in data model is a subclass of \ref AAX_CMonolithicParameters then you can follow these steps to ensure accurate parameter update timing in your plug-in:
			
			<OL>
				<LI>
					After creating an automatable parameter, call \ref AAX_CMonolithicParameters::AddSynchronizedParameter() to add the parameter to an internal list of parameters to synchronize using the deferred-update system
				</LI>
				<LI>
					In the plug-in's \ref AAX_CMonolithicParameters::RenderAudio() "RenderAudio()" implementation, iterate through the incoming queue of deferred parameter values
				</LI>
				<LI>
					Update the coefficients used by the plug-in's algorithm or other processing components
				</LI>
			</OL>
			
			NOTES
			<UL>
				<LI>
					Remember to use the deferred parameter values, not values of the plug-in's \ref AAX_IParameter objects, when setting the state of the plug-in's coefficients
				</LI>
				<LI>
					The deferred parameter values are delivered in the real-time thread, so all synchronized updates should follow the basic principles of real-time operation such as avoiding memory allocation/free, thread synchronization, access to shared resources, or any other actions which could block the real-time thread
				</LI>
			</UL>
			
			For reference, see \ref DemoMIDI_Synth and the other example instrument plug-ins. All of the instrument examples in the %AAX SDK use these facilities to achieve deterministic, accurate playback for automated parameters.
			
			One benefit of this approach is that it provides a compatible interface with monolithic plug-in objects which are designed to work across multiple plug-in formats. For example, the set of parameter updates provided to AAX_CMonolithicParameters::RenderAudio() "RenderAudio" can be provided to plug-in objects which require a queue of time-stamped parameter updates for each audio render callback.
		
		\subsection parameterUpdateTiming_considerations Additional considerations
					
			Of course, the approach described in this section is just one possible solution. The \ref parameterUpdateTiming_timestamps "timestamp" section below provides some alternatives to using the packet queue system for synchronization. Ultimately, the best design for your plug-in will depend on the facilities that are available in the plug-in's monolithic state object, the size of this object, its interface, the number of parameters representing its state, and other internal details.
			
			Here are some additional factors to consider when using the packet queue system for time location synchronization of parameter updates:
			\li The algorithm callback / \ref AAX_CMonolithicParameters::RenderAudio() "RenderAudio()" method is called from a real-time thread, and may be called concurrently with data model methods. You should use a synchronization strategy that is optimized for high performance in this thread.
			\li If a parameter is not automatable then you should probably ignore these additional steps and directly update the plug-in's monolithic state object from within \ref AAX_IACFEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()" when that parameter is changed. Updates for non-automatable parameters can always be applied to the algorithm "as soon as possible".
			\li Depending on your plug-in's design you may not need or want to apply this solution to some automatable parameters either. For example, parameters that are unlikely to be automated or which require CPU-intensive changes in your instrument object should probably be updated on the object directly from within \ref AAX_IACFEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()", and not from within the real-time thread
			
	\section parameterUpdateTiming_timestamps Determining the absolute timestamp for a parameter update
		
		The %AAX packet queue provides a host-managed system for applying parameter updates at the correct location without requiring any special knowledge about the timeline. However, In some situations a plug-in may need to know the absolute sample position of a parameter change.
		
		For example, a plug-in that synchronizes parameter changes to some external system, and which wants to forward these changes over to the external system as early as possible, would want to know the sample position for a coefficient update when the update is first triggered by a call to \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients".
		
		In these situations it is not suitable to simply use a method like \ref AAX_ITransport::GetCurrentNativeSampleLocation() which returns the current position of the audio render thread. The parameter update may be occurring at a different location on the timeline from the current render position, so using the current render position for the update would result in timeline offset problems similar to those described above.
		
		\subsection parameterUpdateTiming_timelineMethods Obtaining timeline information
		
			%AAX provides a variety of information that can be used for timeline synchronization. This information is provided through a combination of \ref AAX_ITransport, \ref AAX_IController, and MIDI beat clock data. Here is a summary of the relevant ways that a plug-in can get information about the timeline and timing synchronization data:
			
			<UL CLASS="paragraphs">
				<LI>
					\ref AAX_ITransport::GetCurrentNativeSampleLocation()
					<DIV CLASS="TextInd1">
						Provides the absolute sample position of the first sample in the audio buffer that is currently being processed by the plug-in's worker chain
					</DIV>
				</LI>
				<LI>
					\ref AAX_IController::GetTODLocation()
					<DIV CLASS="TextInd1">
						Provides the current "time of day" value, which is a counter within the audio engine that counts the number of samples that the playhead has traversed since playback start
					</DIV>
				</LI>
				<LI>
					\ref AAX_IController::GetCurrentAutomationTimestamp()
					<DIV CLASS="TextInd1">
						Must be called from within \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients". Provides the timestamp for the beginning of the hardware audio buffer during which the generated coefficients will be applied to the algorithm. This timestamp is provided in terms of the "time of day" counter, i.e. the number of samples since playback started.
					</DIV>
				</LI>
				<LI>
					MIDI Beat Clock
					<DIV CLASS="TextInd1">
						Sends transport start/continue/stop events to plug-ins that register global MIDI nodes
					</DIV>
				</LI>
			</UL>
		
		\subsection parameterUpdateTiming_determiningTimelinePosition Determining the timeline position of a parameter update
		
			Each of the available methods for getting information about the timeline position has a particular purpose. No single interface method can be used to directly determine the sample location for a parameter update, but it is possible to determine this value by combining information from a few of the available methods.
			
			Here are some possible approaches for determining the timeline position of a parameter update
			
			\note Remember that these are not strict recipes; the specific requirements for what kinds of timeline information are needed will vary from plug-in to plug-in. You may be able to refine these approach to better match the needs of your specific plug-in.
			
			
			\subsubsection parameterUpdateTiming_determiningTimelinePosition_1 1. Defer the update to the real-time thread
			
				<OL>
					<LI>
						Queue state updates using a plug-in design similar to the one described \ref parameterUpdateTiming_resolvingOffsets "above"
					</LI>
					<LI>
						When a state update is received on the real-time thread, call \ref AAX_ITransport::GetCurrentNativeSampleLocation() "GetCurrentNativeSampleLocation" to get the sample location for the start of the current render buffer
					</LI>
					<LI>
						Perform all necessary update handling using this value as the sample location
					</LI>
				</OL>
				
				NOTES
				\li This approach yields a sample location value which is accurate within 32 samples
				\li Event handling must be performed on the real-time render thread, which may not be viable depending on the types of operations that the plug-in must perform
				\li Event handling cannot be performed in advance to reduce overall system latency
				
			
			\subsubsection parameterUpdateTiming_determiningTimelinePosition_2 2. Compute the timestamp as a TOD offset
			
				<OL>
					<LI>
						Add a queue for update events which will be used internally within the plug-in's \ref AAX_IEffectParameters object
					</LI>
					<LI>
						In \ref AAX_IEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue", enqueue an update event
					</LI>
					<LI>
						In \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients", call \ref AAX_IController::GetTODLocation() and \ref AAX_IController::GetCurrentAutomationTimestamp()
					</LI>
					<LI>
						Subtract the current TOD value from the automation timestamp to find the number of samples currently lie between the data model location and the render audio location on the timeline
					</LI>
					<LI>
						Call \ref AAX_ITransport::GetCurrentNativeSampleLocation() and add the resulting value to the sample offset that was determined in the last step. The sum of these two values is the approximate absolute sample location for the coefficient update.
					</LI>
					<LI>
						Once this sample location has been calculated, dequeue all pending update events and handle them using the calculated timestamp
					</LI>
				</OL>
				
				The reason that this approach yields an approximate value is that the TOD location and current playback location are both given in terms of the real-time audio workers, and these values continue to progress simultaneously with execution of methods on the automation update thread. As a result, this approach will yield an absolute timestamp that is "late" by between zero and one hardware buffer.
				
				NOTES
				\li Using this approach it is possible to handle parameter updates in advance to reduce overall system latency
				\li This approach yields a sample location value which is accurate within one hardware buffer
				\li This approach uses %AAX interface methods that are not supported in older %AAX hosts such as Pro Tools 10
				
			
			\subsubsection parameterUpdateTiming_determiningTimelinePosition_3 3. Compute the timestamp with improved accuracy using MIDI Beat Clock
			
				You can refine the approach described above by using MBC events to detect the location of playback start.
				
				<OL>
					<LI>
						Register a global MIDI node in your plug-in using \ref AAX_IEffectDescriptor::AddControlMIDINode() with \ref AAX_eMIDINodeType_Global and the appropriate event mask bitfield for MBC events
					</LI>
					<LI>
						Override \ref AAX_IEffectParameters::UpdateControlMIDINodes() to receive MBC data
					</LI>
					<LI>
						When an MBC Start or Continue event is received, call \ref AAX_ITransport::GetCurrentNativeSampleLocation() to get the current render location. Cache this value. This value should represent the absolute playback start sample since audio render will not have started before the MBC event dispatch.
					</LI>
					<LI>
						As in the previous solution, queue relevant update events in \ref AAX_IEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue"
					</LI>
					<LI>
						In \ref AAX_IACFEffectParameters::GenerateCoefficients() "GenerateCoefficients", call \ref AAX_IController::GetCurrentAutomationTimestamp() "GetCurrentAutomationTimestamp" and add the resulting value to the cached playback start sample location
					</LI>
					<LI>
						Dequeue all pending update events and handle them using the calculated absolute sample timestamp
					</LI>
				</OL>
				
				NOTES
				\li Using this approach it is possible to handle parameter updates in advance to reduce overall system latency
				\li This approach will yield timestamps within a few samples of the actual automation event location on the Pro Tools timeline
				\li This approach uses %AAX interface methods that are not supported in older %AAX hosts such as Pro Tools 10
 */
