/*===================================================================================================
AAX_LinkedParameters.doxygen

Copyright 2011-2015, 2017, 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_linkedParameters Linked parameters
	@ingroup advancedTopics_ParameterUpdates
	
	@brief How to link parameters
	
	\section linkedParameters_contents On this page
		\li \ref linkedParameters_basics
		\li \ref linkedParameters_linkedParameterOperation
		\li \ref linkedParameters_changingTapers		
 	
 	\section linkedParameters_basics Basics of Linked Parameters
		A "linked" parameter can be defined as any parameter whose state is somehow dependent on another parameter. Within this general definition, there are various different kinds of parameter linking:
	
		- Linking behavior can operate one-way or parameters can be reciprocally linked
		- Linking between parameters can be one-to-one or one-to-many
 	
 		\subsection linkedParameters_considerations Basic considerations for parameter linking
 			Although the concept of parameter linking is simple, implementing linked parameter behavior that is intuitive and consistent can require careful design.
 			
 			- Parameter interdependencies and constraints can become complex, especially when handling multiple sets of linked parameters.
 			- Linked parameters that update other parameters during playback can result in subtle timing inconsistencies
 			- Automated parameters may contain arbitrary and conflicting automation data
 			- A user may attempt to edit multiple linked parameters simultaneously during playback, e.g. using multiple encoders on a control surface
 			- A plug-in may contain dependency cycles between interdependent parameters. These cycles can cause undesired behavior that is difficult to debug, especially if it only occurs in certain circumstances such as when loading particular presets.
 			
 			In all of these cases, a plug-in should provide consistent linked parameter behavior: every automated playback pass should be identical, parameters should never "fight" one another or trigger rapid and unexpected changes in other parameters, parameters should not become "stuck" in a particular state, etc.
 			
 			\nodox Image files must be copied to the /output/html directory \endnodox
			<IMG width="40%" alt="Here comes trouble" src="AutoOverwritePencil.png" />
			<DIV CLASS="imagecaption">Here comes trouble</DIV>
 		
 		\subsection linkedParameters_behavior Defining proper linked parameter behavior
 			A good way to approach parameter linking is to start with an understanding of exactly what behavior you desire.
 			
 			Here are some behaviors that you probably <EM>don't</EM> want in your plug-in:
 			
 			<UL CLASS="paragraphs">
 				<LI><DIV CLASS="SectionHead">BAD: Parameters are only linked when edited from the plug-in GUI </DIV>
 				Users may attempt to edit linked parameters from attached control surfaces or using the host's automation features. The parameters should behave the same way regardless of which method is used to edit them.
 				</LI>
 				<LI><DIV CLASS="SectionHead">BAD: Parameters try to match all automation data </DIV>
 				Automation data can be written arbitrarily: Pro Tools doesn't have any restrictions that a user with a pencil tool must draw inside the lines, or a user may attempt to edit multiple parameters on an attached control surface simultaneously. Any parameter that attempts to match both its own automation data and the automation data of another parameter, or any parameter that attempts to set another automatable parameter's state based on its own automation data, will lead to "fighting" during playback of non-conformant automation.
 				</LI>
 				<LI><DIV CLASS="SectionHead">BAD: Automation data is only written to one lane at a time </DIV>
 				One approach to parameter linking may be to only write automation data to a single parameter at a time. This could be the parameter that is currently being touched and edited, or it could be a dedicated "master" parameter within the linked group. While this approach can be used to solve some types of conflicts, it can still lead to unnecessarily complex or inconsistent behavior in certain situations: for example, arbitrary automation data can still be written to multiple parameters' automation lanes, or a user can choose to record automation for only one parameter in a set but can skip the "master" parameter. Furthermore, it is difficult if not impossible to properly handle parameters that can be dynamically linked or un-linked using this approach.
 				</LI>
 			</UL>
 			
 			With those potential problems in mind, here is a description of how parameter linking <EM>should</EM> behave.
 			 			
 				\subsubsection linkedParamters_behavior_correct Correct behavior for linked parameters
 				
 				<EM CLASS="Bold">Notes</EM>
				- In this proposal (and throughout the rest of this page) the term "linker" will refer to a parameter that initiates a change and the term "linked" will refer to a dependent parameter that receives the change.
				- The following discussion will focus on <EM CLASS="Bold">automatable</EM> parameters that are <EM CLASS="Bold">reciprocally linked</EM>. This case tends to be the most complex, with the greatest need for consistency of implementation.
 				
				<EM CLASS="Bold">During user-generated real-time edits</EM> (from the plug-in GUI or a control surface) both the linker and the linked parameters should be updated. Without this requirement, there would be no parameter linking. In order for this requirement to be enforced consistently the following behaviors must be maintained:
				<UL>
					<LI>The linked parameter should not jump to a new value if the user attempts to edit both parameters simultaneously using a control surface. </LI>
					<LI>To ensure proper automation playback, automation should be written to both the linker and the linked parameters. </LI>
				</UL>
			
				<EM CLASS="Bold">When playing back automation</EM>, parameters should operate independently and should not attempt to force dependent parameters to a new state. This prevents fighting in the presence of incompatible automation and ensures deterministic automation playback with every playback pass. As above, there are some more subtle behaviors that must be maintained for this to work properly:
				<UL>
					<LI>If the user begins a real-time edit during automation playback then the parameter linking behavior should resume as described above </LI>
					<LI>If the plug-in's algorithm cannot support certain parameter configurations then its automatable parameters should be decoupled from the algorithm using a set of coefficients that is aware of the algorithm's constraints. In this way every combination of parameter states can map to a particular coefficient state, maintaining determinism, and incompatible parameter combinations can simply resolve to the "closest" match in the possible coefficient space during playback of edited parameter automation data.</LI>
					<LI>Another, simpler approach for plug-ins that do not support arbitrary parameter configurations is to ensure that the problematic parameters are not automatable. Handling non-automatable parameter linking is much easier in general, so consider this approach if automation is not a requirement for some of your plug-in's parameters. </LI>
				</UL>
				
				<EM CLASS="Bold">When handling preset changes and plug-in initialization</EM>, a similar approach should be taken as with plug-in automation playback. In these cases it is very unlikely that the plug-in's parameters will be left in an incompatible state and attempts at linking may result in unwanted update cycles between inter-dependent parameters or unnecessary coefficient churn. This latter concern can be a real problem for %AAX DSP plug-ins that initialize internal algorithmic state based on initial coefficient data.
 				
				\subsubsection linkedParamters_behavior_caveat Compatibility caveat
				This behavior was not possible under the RTAS/TDM format, and many RTAS and TDM plug-ins reverted to workarounds such as writing automation to only one parameter at a time and linking the parameters during playback. Therefore, plug-ins that previously supported linked automatable parameters under the RTAS/TDM format may not be able to both implement this recommended parameter linking behavior and maintain compatibility with automation in saved sessions.
				
				Most of Avid's plug-ins that were available in the RTAS and TDM formats fall into this category and should not be used as examples of proper parameter linking behavior. Instead, use the SDK's DemoGain_LinkedParameters example plug-in as an example of proper linked parameter operation.
			
 	
 	
 	
 	
 	
 	
 	
	\section linkedParameters_linkedParameterOperation Linked Parameter Operation
		As described above, the key rule for linked parameters is to link during real-time user edits <EM>only</EM>, and should operate the parameters independently (without linked behavior) during automation playback and preset restore. This rule will simplify many issues: it will prevent conflicts with automation data, avoid potentially strange behaviors when restoring presets, and more.

		Here is how the system works WITH linked parameters, using code snippets from the DemoGain_LinkedParameters example plug-in:
		
		\subsection linkedParameters_linkedParameterOperation_userEditing User Editing
		
			-# User clicks on a parameter in the GUI or grabs a parameter on the controls surface. A TOUCH token should be sent at this point.
				- The touched parameter status comes back to the plug-in. If the parameters are linked the other linked parameter should have a TOUCH token sent. This really should only be done for linked continuous parameters. This is done by overriding the AAX_CEffectParameters::UpdateParameterTouch() method.
			-# The user changes the parameter from the GUI or controls surface. A SET token should be sent at this point.
			\code
			// *******************************************************************************
			// METHOD:	UpdateParameterTouch
			// *******************************************************************************
			AAX_Result DemoGain_Parameters::UpdateParameterTouch ( AAX_CParamID inParameterID, AAX_CBoolean inTouchState )
			{
				if ( inTouchState )
				{
					AAX_CParamID linkedControl = this->GetLinkedControl ( inParameterID );
					if ( linkedControl )
					{
						this->TouchParameter ( linkedControl );
						mLinkTouchMap.insert ( std::pair<std::string,std::string>( inParameterID, linkedControl ) );
					}
				}
				[...]
			}
			\endcode
			-# The SET token goes into the system and comes back to the plugin via AAX_CEffectParameters::UpdateParameterNormalizedValue().
				- If the parameter is linked then the other linked parameter should have its value set for its linked behaviour. The system knows this is a linked parameter so when the value comes back to the plug-in via UpdateParameterNormalizedValue() it will know not to perform linked behaviors on that value change. To determine if a parameter should set a linked parameter you check it with the AAX_CEffectParameters::IsParameterTouched() method.
			-# The plug-in updates its internal state and sends an UPDATE tokens for both parameters.
			\code
			// *******************************************************************************
			// METHOD:	UpdateParameterNormalizedValue
			// *******************************************************************************
			AAX_Result DemoGain_Parameters::UpdateParameterNormalizedValue ( AAX_CParamID inParameterID, double inValue, AAX_EUpdateSource inSource )
			{
				AAX_Result	result = AAX_CEffectParameters::UpdateParameterNormalizedValue ( inParameterID, inValue, inSource );
				bool		touched = this->IsParameterTouched ( inParameterID );
	
				[...]
							if ( touched && inSource == AAX_eUpdateSource_Unspecified )
							{
								if ( type == eType_Pan )
									this->SetParameterNormalizedValue( linkedControl, (1.0 - inValue) );
								else if ( type == eType_Gain )
									this->SetParameterNormalizedValue( linkedControl, inValue );
							}
				[...]
			}
			\endcode
			-# Repeat steps 2-4 while changing the parameter.
			-# The user lets go of the GUI or controls surface. A TOUCH token with the released state should be sent.
				- The touched parameter status comes back to the plug-in. If the parameters were linked the other linked parameter should have a TOUCH token with the release status sent. This again is done by overriding the AAX_CEffectParameters::UpdateParameterTouch() method.
			\code
			// *******************************************************************************
			// METHOD:	UpdateParameterTouch
			// *******************************************************************************
			AAX_Result DemoGain_Parameters::UpdateParameterTouch ( AAX_CParamID inParameterID, AAX_CBoolean inTouchState )
			{
				if ( inTouchState )
				{
					[...]
				}
				else
				{
					[...]
						this->ReleaseParameter ( iter->second.c_str () );
					[...]
				}
	
				return AAX_SUCCESS;
			}

			\endcode
			
		\subsection linkedParameters_linkedParameterOperation_automationPlayback Automation Playback
		
			-# The SET token comes from the automation system and enters the plugin via \ref AAX_IACFEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()".
				- The plug-in will know this is not from the user editing therefore it will NOT set the other linked parameter. Remember ONLY LINK USER EDITING. That way there's no conflicts if the user edited the automation or if the order in which automation arrives at the plug-in changes.
			-# The plug-in updates its internal state and sends an UPDATE token.
			-# Repeat steps 1-2 while playing back automation.
		
		\subsection linkedParameters_linkedParameterOperation_chunkRestoring Chunk Restoring
		
			-# Plug-in loads the chuck.
			-# The plug-in sets every parameters value.
			-# The SET tokens comes back to the plugin via UpdateParameterNormalizedValue().
				- The plug-in will know this is not from the user editing therefore it will NOT set the other linked parameter. Remember ONLY LINK USER EDITING. Hopefully the result of this is that the contents of the chunk will be restored to its exact state.
			-# The plug-in updates its internal state and sends out UPDATE tokens.
		
 
	\section linkedParameters_changingTapers Changing Tapers
	
		One common use of linked parameters is to change the taper associated with a parameter. For changing tapers there are basically only a two rules you need to follow:

		-# When you're loading a new chunk you need to set the taper values first. If a parameter is what updates the taper then set that value first. That way when the value of a parameter is set from a chunk it wont change because of a taper change.
		-# Update the taper from the UpdateParameterNormalizedValue() method. If the new taper needs to change the value of the parameter you only do so if the user is editing the linked parameter. This still follows the ONLY LINK USER EDITING rule.
		
		\code
		AAX_Result Simple_Parameters::UpdateParameterNormalizedValue ( AAX_CParamID inParameterID, double inValue, AAX_EUpdateSource inSource )
		{
			// GetLinkedControl() is a user defined method which determines the linked control ID.
			AAX_CParamID linkedControl = this->GetLinkedControl ( inParameterID );
			if ( linkedControl )
			{
				// IsParameterLinkReady()* is a built in method of AAX_CEffectParameters which determines if the 
				// parameter should perform linked behaviors based on the touch state of the parameter and the 
				// source of the UpdateParameterNormalizedValue() call.
				if ( this->IsParameterLinkReady ( inParameterID, inSource ) )
					this->SetParameterNormalizedValue( linkedControl, inValue );
			}

			// Call the inherited method for the original parameter
			AAX_Result   result = AAX_CEffectParameters::UpdateParameterNormalizedValue ( inParameterID, inValue, inSource );
			return result;
		}
		\endcode

 */
 
 
 
 
 
 
		
/** @defgroup advancedTopics_linkedParameters_sequences Linked parameter update sequences
	@ingroup advancedTopics_ParameterUpdates
	
	@brief Sequence diagrams for some common linked parameter update scenarios
	
	\section advancedTopics_linkedParameters_sequences_contents On this page
		\li \ref linkedParameters_sequences_user_gui
		\li \ref linkedParameters_sequences_automation
		
	\note To enable logging for these events at run time set <TT>DTF_AUTOMATION=file\@DTP_LOW</TT> in the \ref AAX_DigiTrace_Guide "DigiTrace" configuration file.
		
		\subsection advancedTopics_linkedParameters_sequences_notes Notes on threading for these sequences
			- Calls from the host into \ref AAX_IEffectParameters may occur on any thread. In general, the only synchronization that is guaranteed for data model calls in these diagrams is that the call will follow whatever event is indicated as its trigger.
			- Calls from the host into \ref AAX_IEffectGUI will occur on the main application thread unless indicated otherwise in the \ref AAX_IEffectGUI documentation.
			- Host-driven updates to the algorithm context are always synchronized with the real-time processing thread
		
		\sa \ref advancedTopics_parameterUpdates_sequences
	
	\section linkedParameters_sequences_user_gui User-generated update
		This is the sequence of calls for a parameter update triggered by the user. For this sequence, we assume that the edit was triggered by a GUI event. Updates from control surfaces are handled in exactly the same way, except that the parameter touch, set value, and release tokens are generated by the control surface.
		
		In this example the updated parameter is reciprocally linked to one other parameter. These are the "linker" and "linked" parameters, respectively.
		
		This procedure is very similar to the non-linked case described \ref parameterUpdates_sequences_user "here". In the diagrams below, red arcs and pink section headings are used to indicate events that are specific to the linked parameter case.
		
		Notes:
		-# This sequence shows the linked parameter reciprocally issuing a touch on the linker parameter. The touch fails since the linker parameter is already touched at this time. If the roles were reversed (if an edit occurred on the linked parameter) then this touch would succeed.
		-# The host flags all set value tokens that are triggered by a plug-in within the scope of AAX_IEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()". When those set value tokens are processed they result in additional calls to AAX_IEffectParameters::UpdateParameterNormalizedValue() "UpdateParameterNormalizedValue()". The host sets \c iSource to \ref AAX_eUpdateSource_Parameter for each of these subsequent calls to indicate that the update originated from within a parameter update event.
		-# \ref AAX_CEffectParameters::IsParameterLinkReady() "IsParameterLinkReady()" returns \c true during the linker parameter update because the update source is unknown and the parameter is touched. Both conditions must be true in order for the linking logic to proceed with setting linked parameters' values.
		-# \ref AAX_CEffectParameters::IsParameterLinkReady() "IsParameterLinkReady()" returns \c false during the linked parameter update because the source is \ref AAX_eUpdateSource_Parameter. This prevents update cycles for reciprocally linked parameters, as demonstrated here.
	
		\subsection linkedParameters_sequences_user_gui_highLevel High-level interface calls and events
			\mscfile AAX_LinkedParameterUpdate_GUI_HighLevel.msc "High-level sequence of interface calls and events for a reciprocally linked parameter update following a user-generated edit"
		
		\subsection linkedParameters_sequences_user_gui_detail Detailed interface calls and events
			Note that this diagram assumes a GUI implementation that uses \ref AAX_IACFEffectParameters::SetParameterNormalizedValue() "SetParameterNormalizedValue()". The implementation could also use other parameter set methods, either in \ref AAX_IEffectParameters or directly on an \ref AAX_IParameter. The overall sequence would remain the same.
			
			\mscfile AAX_LinkedParameterUpdate_GUI.msc "Detailed sequence of method calls and events for a reciprocally linked parameter update following a user-generated edit on the plug-in GUI"
		
	\section linkedParameters_sequences_automation Update from automation playback
		Since all parameter linking occurs while recording automation, automation playback is very simple. The automation lanes may contain any arbitrary values, so, in order to avoid fighting between incompatible values, the plug-in should respect all automation values during playback.
		
		Notes:
		-# \ref AAX_CEffectParameters::IsParameterLinkReady() "IsParameterLinkReady()" returns \c false during automation playback because the updated parameter is not touched. This ensures that automation playback will proceed with the written values and also guarantees that the user will always be able to override the automation using a control surface encoder or GUI editor.
				
		\mscfile AAX_LinkedParameterUpdate_Automation.msc "Sequence of method calls and events during automation playback with linked parameters"
	
*/
			
