// Example of a one button standard looper. Second loop length will be the length of all other loops  		
//				Second loop length will be a multiple of first loop length
//
// Author: LoopToGo
//
// Arguments or user arguments : 
// 		1 : (optional) gFirstTrack, track number to start the looping, default is 1, -1 = selected
// 		2 : (optional) gNbBars, number of bars For the first recording, default is 10
//		3 : (optional) if 1, loops length are all equal (same behavior as dtOne.ltgs)
//		4 : (optional) if 1, will use pDontChangeTrackMonitoring variable to determine if Track monitoring is unchanged or not
//
//  Warning when using with midi events, make sure "Use MIDI events as arg" is uncheck!	

loadScript ..\aliases.txt					// To use aliases instead of shortcut commands

/////////////////////////////////////////////////////////
///////////// For debugging

// Note: See LoopToGo\libs\debugUtilities.ltgl for details on how to use debugging

loadScript ..\libs\debugUtilities.ltgl

// Uncomment the following line to remove all debug prints. When uncommented, there is no impact on perfromance
alias debug doNothing

// Set tag Info, Info2 and Info3 to 1 to print or 0 to not print
debugTag Info 0
debugTag Info2 0
debugTag Info3 0
debugTag Info4 0

//alias debug print
alias print debug Info [ $scriptLineNumber ] 
alias print2 debug Info2 [ $scriptLineNumber ] 
alias print3 debug Info3 [ $scriptLineNumber ] 
alias print4 debug Info4 [ $scriptLineNumber ] 

// Uses { and } to increment and decrement debug message  
alias {		debugIncreaseIndentation
alias }		debugDecreaseIndentation

print " "  // new line!
print "Start of script: " $arg1 $arg2 $arg3 $arg4

///////////// End of debugging
/////////////////////////////////////////////////////////

// Do not call this script when there is no track!
if $nbTracks < 1
	setUserArgs  // reset the users args just in case!
	endScriptDynamic
endIf

// Refrain from calling this script twice in a short time (debounce of midi events below)

variable deltaTime $sysTime - $gLastExecutionTime
globalVariable gLastExecutionTime $sysTime

//print2 $deltaTime $sysTime $gLastExecutionTime

/////////////////////////////////////////////////////////
///////////// Script configuration

alias aDefaultFirstTrack					1			// The first track used for looping
alias aDefaultNbBars						10			// Lenght of first record loop if not specified by $arg1 or $userArg1
alias aGridLineColor						#224422		// Color for the grid lines
alias aBeforeLoopEnd						0.03		// Increase to make the extend before the end of the loop! Must not be greater than 0.03!!!

///////////// End of configuration
/////////////////////////////////////////////////////////

alias true 1
alias false 0

alias UnLockedState 0
alias LockedState 3

alias OverdubMode 6
alias RepeatRecord 2

// Looper States
alias LooperStoppedAndEmpty 0
alias LooperStopped 1
alias LooperRecord 2
alias LooperPlay 3
alias LooperOverdubFirst 4
alias LooperOverdubSecond 5

// Track monitoring mode
alias InLoopsOrWhileTrackSelected 3

// Debouncing : midi buttons can sen multiple events in a short period of time
if $deltaTime < 200
	print3 "Debouncing: " 	$deltaTime 
	endScriptDynamic
endIf	

// Code For pausing or resetting the looper with a double click. 
if  $deltaTime < 500
	print "Double click: " 	$deltaTime	$gLooperState $isRecording
		
	if $gLooperState = LooperStopped
		loadScript ..\LooperEmulations\resetSong.ltgs			// The user ask For stop twice to reset the looper	
		endScriptDynamic		
	endIf 
	
	if $isRecording
		pause
		endScriptDynamic
	endIf

endIf

print deltaTime : $deltaTime


print2 gLooperState Before : $gLooperState

callFunction fctComputeLooperState	// The looper state must be compute in case the user used Ctr-Z (undo) or Ctr-Y (Redo)

print2 gLooperState : $gLooperState  gFirstRecordLoopLength: $gFirstRecordLoopLength gSecondRecordLoopLength : $gSecondRecordLoopLength

// If we are not starting from scratch, just make sure we have a jam marker

print2 nbMarkers: $nbMarkers $gFirstRecordLoopLength $gSecondRecordLoopLength $gFirstRecordLoopID $gSecondRecordLoopID
if $nbMarkers < 1
	if $gSecondRecordLoopID		
		print2 startJamMode $gSecondRecordLoopID
		startJamMode $gSecondRecordLoopID
	else
		print2 startJamMode $gFirstRecordLoopID
		startJamMode $gFirstRecordLoopID		
	endIf
endIf 

if $arg1 = 0
	variable arg1 aDefaultFirstTrack
endIf

if $arg2 = 0
	variable arg2 aDefaultNbBars
endIf

setLooperMode 1 0 // 1 = FreeNoSync 0 = Do not add to stack

callFunction looperStateManager $arg1 $arg2 $arg3 $arg4

// Choose action depending on the actual looper state 
function looperStateManager
{
	if $gLooperState = LooperStoppedAndEmpty
	
		globalVariable gNbBars aDefaultNbBars
		globalVariable gFirstTrack	aDefaultFirstTrack
		persistentVariable pUniqueLoopLength $pUniqueLoopLengthChecked
		
		if $pNbMaxSecs
			globalVariable gNbBars $pNbMaxSecs*60/$tempo
		endIf
		
		if $arg4 // If not provided, it will be 0!
			variable dontChangeMonitoring  $pDontChangeTrackMonitoring
		else
			variable dontChangeMonitoring  0			
		endIf
		
		if $nbUserArgs
			callFunction setParameter 1 $nbUserArgs $userArg1 gFirstTrack 			g  			// g = global
			callFunction setParameter 2 $nbUserArgs $userArg2 gNbBars 				g				// g = global
			callFunction setParameter 3 $nbUserArgs $userArg3 pUniqueLoopLength 	p		// p = persistent
		
			setUserArgs // Make sure user args a resetted
		else
			callFunction setParameter 1 $nbArgs $arg1 	gFirstTrack 		g  			// g = global
			callFunction setParameter 2 $nbArgs $arg2 	gNbBars 			g				// g = global			
			callFunction setParameter 3 $nbArgs $arg3 	pUniqueLoopLength 	p		// p = persistent		
		endIf
		
				
		callFunction fctInitAndStartRecording	

		setAutoTrackBar false  // To zoom to almost 100% of the view
		// Adjust the view size 
		setUserArgs 0 // argument for next shortcut 1 = zoom
		shortcutByID  116  // horizontal zoom		
		
		exitFunction

	endIf
	setUserArgs  // reset the users args just in case!

		
	if $gLooperState = LooperRecord		
		callFunction fctStopFirstRecording		
		
		setAutoTrackBar false  // To zoom to almost 100% of the view
		// Adjust the view size 
		setUserArgs 0 // argument for next shortcut 1 = zoom
		shortcutByID  116  // horizontal zoom
		
		exitFunction
	endIf
																						
	if $gLooperState = LooperPlay	
		callFunction fctNewOverdubFirst		
		
		exitFunction
	endIf
					 			
	if $gLooperState = LooperOverdubFirst		
		callFunction fctStopExtendingSecondOverdub
	
		exitFunction
	endIf							
		
	if $gLooperState = LooperOverdubSecond		
		callFunction fctStopOverdubSecond
		
		exitFunction
	endIf
			
	if $isRecording	
		callFunction fctStopOverdubSecond
		
		exitFunction
	endIf
				
	setBar $gFirstRecordLoopStart
	
	record // Start recording
		
}
endFunction

// First initialization of variables and start of recording
function fctInitAndStartRecording
{	
	print  "fctInitAndStartRecording: " 
	
	globalVariable gFirstTime true
	globalVariable gFirstRecordLoopID 0
	globalVariable gInRecordLoop true
	globalVariable gLooperState LooperRecord
	globalVariable gFirstRecordLoopStart $songBar
	globalVariable gSecondRecordLoopLength 0
	globalVariable gSecondRecordLoopID 0

	
	setUserArgs 1		// Arg1 to for next shortcut 1: vertically zoomed
	shortcutByID 9		// Set vertical zomm mode
	
	selectTrack $gFirstTrack
	print Selected track $gFirstTrack
			
	if $selectedTrack = 0
		selectTrack aDefaultFirstTrack
	endIf
	
	ifNot $dontChangeMonitoring
		callFunction setTracksMonitoringMode
	endIf
	// First record loop	
	
	globalVariable gFirstRecordLoopEnd $gFirstRecordLoopStart + $gNbBars
	
	

	
	addRecordLoop $selectedTrack FirstLoop $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	print3 addRecordLoop $selectedTrack FirstLoop $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	setGridLinesVisibility 0
	
	removeAllCustomGridLines
	
	addCustomGridLine $gFirstRecordLoopStart				3	aGridLineColor
	addCustomGridLine $gFirstRecordLoopStart + $gNbBars		3 	aGridLineColor
	
	
	globalVariable gFirstRecordLoopID	$lastCreatedRecordLoopID
	globalVariable gFirstLoopTrack $selectedTrack
	
	
	
	record // Start recording
	
	startJamMode $lastCreatedRecordLoopID
		
	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Red"  // Green because we are playing back what was recorded		
	endIf
	
	// Adjust the view size 
	setUserArgs 0 // argument for next shortcut 1 = zoom
	shortcutByID  116  // horizontal zoom
			
}
endFunction

// Creation of the first overdubing loop
function fctNewOverdubFirst
{	
	print "fctNewOverdubFirst: " 
	
	setLoopLockState $lastCreatedRecordLoopID LockedState

	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Green"  // Green because we are playing back what was recorded		
	endIf
	
	if $gSecondRecordLoopLength = 0
				
		addRecordLoop $selectedTrack "Overdub" $gFirstRecordLoopStart $gFirstRecordLoopEnd
		
		print3 addRecordLoop $selectedTrack "Overdub" $gFirstRecordLoopStart $gFirstRecordLoopStart + $gFirstRecordLoopLength
		
		// The next line is to make sure the start of the recording in the middle of the loop will be smooth even if the input already as sound
		armRampUpRecording $lastCreatedRecordLoopID true  // true = ramp immediatly, false (or not provided) = will be 0 until end of the loop then will ramp up
				
				
		if $pUniqueLoopLength
			setLoopJamState $lastCreatedRecordLoopID OverdubMode 

			ifNot $dontUseCustomColors
				setLoopColor $lastCreatedRecordLoopID "Yellow"		
			endIf
		else
			setLoopJamState $lastCreatedRecordLoopID RepeatRecord 
			
			ifNot $dontUseCustomColors
				setLoopColor $lastCreatedRecordLoopID "Red"		
			endIf
		endIf
		
		getLoopEnd	loopEnd $lastCreatedRecordLoopID
		
		globalVariable gSecondRecordLoopLength $gFirstRecordLoopLength  // First time, will be the same length as the first record loop!
		globalVariable gSecondRecordLoopID	 $lastCreatedRecordLoopID  
				
				
		if $pUniqueLoopLength
			exitFunction // We don't create the extent function marker, all loops will be same length
		endIf
		
		variable arguments $lastCreatedRecordLoopID  & " " & $gFirstRecordLoopLength & " " & $dontUseCustomColors

		print gFirstRecordLoopLength : $gFirstRecordLoopLength gSecondRecordLoopLength : $gSecondRecordLoopLength [ $arguments ]
		
		addFunctionMarker $gFirstRecordLoopEnd - aBeforeLoopEnd "Overdub" fctExtendLoopRange $arguments
		
		globalVariable gLooperFunctionMarkerID $lastCreatedMarkerID
		
		setMarkerColor $gLooperFunctionMarkerID #775544


		print2 : gLooperFunctionMarkerID: $gLooperFunctionMarkerID
	else
	
		addRecordLoop $selectedTrack "Overdub" $gFirstRecordLoopStart $gFirstRecordLoopStart + $gSecondRecordLoopLength
		
		print3 addRecordLoop $selectedTrack "Overdub" $gFirstRecordLoopStart $gFirstRecordLoopStart + $gSecondRecordLoopLength
		
		// The next line is to make sure the start of the recording in the middle of the loop will be smooth even if the input already as sound
		armRampUpRecording $lastCreatedRecordLoopID true  // true = ramp immediatly, false (or not provided) = will be 0 until end of the loop then will ramp up
		
		setLoopJamState $lastCreatedRecordLoopID OverdubMode 

		ifNot $dontUseCustomColors
			setLoopColor $lastCreatedRecordLoopID "Yellow"		
		endIf
		
		// We only select the last record loop to be able to use the E shortcut (erase)
		unselectAllLoops
		selectLoop $lastCreatedRecordLoopID  


	endIf
				
}
endFunction

// Creation of the second overdubing loop and other subsequent overdub loops
function fctNewOverdubSecond
{	
	print3 "fctNewOverdubSecond: "  $gLooperState  LooperOverdubFirst LooperOverdubSecond

	//globalVariable gLooperState LooperOverdubFirst
	
	if $nbMarkers > 1
	
		// First time in the second overDub.Since there is a marker that extend the looght length we, continue overbubing but we stop the loop extent!
			
		print3 "fctNewOverdubSecond:   nbMarkers > 1 "

				
	else
	
		// We don't use script markers, it means that it is not the first time we use a second overdub, we change to play!!! 
		
		callFunction fctStopOverdubSecond		 
				
	endIf
				
}
endFunction

// First stop of recording
function fctStopFirstRecording
{
	
	print  "fctStopFirstRecording: " 
	
	// We must compute the next start of the record loop which must be the start of the first record loop plus a integer number of the first record loop length
						
	globalVariable gFirstRecordLoopEnd $songBar
	globalVariable gFirstRecordLoopLength $gFirstRecordLoopEnd - $gFirstRecordLoopStart
	globalVariable gLastEnd $gFirstRecordLoopEnd
	
	print  $lastCreatedRecordLoopID $gFirstRecordLoopStart $gFirstRecordLoopEnd
			
	setLoopStartAndEnd $lastCreatedRecordLoopID $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	print3 setLoopStartAndEnd $lastCreatedRecordLoopID $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	removeCustomGridLine $gFirstRecordLoopStart + $gNbBars
	addCustomGridLine $gFirstRecordLoopEnd		3 	aGridLineColor

	
	setLoopLockState $lastCreatedRecordLoopID LockedState
	
	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Green"  // Green because we are playing back what was recorded		
	endIf
			
	jumpTo $gFirstRecordLoopStart // More accurate than setBar!!!
	
	waitDelta $tempo/5000  // Wait For the jump! Must not be too small because will causes issue with high tempo

	startJamMode $lastCreatedRecordLoopID  
	
	print3 addFunctionToMarker $lastCreatedMarkerID fctExecuteAtJump $lastCreatedMarkerID

	
	addFunctionToMarker $lastCreatedMarkerID fctExecuteAtJump $lastCreatedMarkerID

}
endFunction


// Stopping the extension of loop by deleting the Function marker responsible For extension
function fctStopExtendingSecondOverdub
{
	print  "fctStopExtendingSecondOverdub: nbMarkers"  $nbMarkers
	
	deleteAllMarkers  2049 // delete Function marker 
		
	// Make sure we are overdubbing
	
	setLoopJamState $lastCreatedRecordLoopID OverdubMode
	
	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Yellow"	
	endIf
	
	if $gFirstRecordLoopLength*1.1 < $gSecondRecordLoopLength
		// Second loop is longer thean the first loop, it means that the end of the 
	endIf

}
endFunction

// Stop second overdubbing and subsequent
function fctStopOverdubSecond
{
	print  "fctStopOverdubSecond: " 
	
		
	setLoopLockState $lastCreatedRecordLoopID LockedState true
	
	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Green"  // Green because we are playing back what was recorded		
	endIf
	
}
endFunction

// Determine the looper state based on recording state and loops state
function fctComputeLooperState
{

	print fctComputeLooperState Before : $gLooperState $gSecondRecordLoopID $gSecondRecordLoopLength
	
	variable previousLooperState $gLooperState
	
	globalVariable gLooperState LooperPlay
	
	ifNot $isRecording
		if $nbLoops = 0
			globalVariable gLooperState LooperStoppedAndEmpty
			exitFunction
		endIf
			
		globalVariable gLooperState LooperStopped
				
		exitFunction
	endIf	
	
	
	for loop 1 $nbLoops					// We check all the loops in case the user deleted a loop or did Ctr-Z!
		variable loopID loopID & $loop
		
		getLoopNextJamState loopJamMode $$loopID
		getLoopLockState loopLockState $$loopID
		getLoopType loopType $$loopID

		if $loopType = Record
		
		print2 $gLooperState $loopJamMode $loopLockState $nbMarkers
		
			if $loopLockState = UnLockedState
				if $loopJamMode = OverdubMode		
					if $previousLooperState = LooperOverdubFirst						
						globalVariable gLooperState LooperOverdubSecond																		
						exitFunction //Found, no need to continue searching!
					endIf
					
					if $previousLooperState = LooperOverdubSecond
						globalVariable gLooperState LooperOverdubSecond
						exitFunction //Found, no need to continue searching!
					endIf
					
					if $nbMarkers < 2		// No Function markers, we are in last overdub mode
						globalVariable gLooperState LooperOverdubSecond
						exitFunction //Found, no need to continue searching!
					endIf
					
					globalVariable gLooperState LooperOverdubFirst
					exitFunction //Found, no need to continue searching!
					
				endIf
				
				ifNot  $gFirstRecordLoopID = $lastCreatedRecordLoopID
					globalVariable gLooperState LooperOverdubFirst
					exitFunction //Found, no need to continue searching!
				endIf
				
				globalVariable gLooperState LooperRecord
				exitFunction //Found, no need to continue searching!
				
								
			endIf
		endIf	
					
	endFor
		
}
endFunction


// Set all tracks Play Record and Pause monitoring mode to "In loops or when track is selected"
function setTracksMonitoringMode
{
	print  "setTracksMonitoringMode: " 

	for track 1 $nbTracks
		setChainRecordPlayMonitorMode $track InLoopsOrWhileTrackSelected 				
	endFor
}
endFunction


//////////////////////////////////////////////////////////

alias print print	// We must reset the print aliases because it refers to a functions in the debug library which will noy be accessible from the function 

// This Function is designed to be called by a FunctionMarker
// It does have access to the global variables but not to the othe local variables in this file!!!!

function fctExtendLoopRange // recordLoopID incrementWidth dontUseCustomColors

	//print function fctExtendLoopRange
	
	waitDelta 0.5/$tempo   // This line allows this functions to run outside the audio engine to avoid glitches 


	//ifNot $nbArgs = 3
	//	print fctExtendLoopRange requires 3 arguments [ $nbArgs : recordLoopID "=" $arg1 incrementWidth "=" $arg2 dontUseCustomColor "=" $arg3]
	//	exitFunction
	//endIf
			
	getLoopJamState loopJamMode $arg1
	
	// The first time, the loop will be in record mode, we just set it in overdub mud
	// The second time, the loop will be in overdub, we move the marker and extend the loop!

	if $loopJamMode = OverdubMode
			
		variable newEnd $gFirstRecordLoopStart + $gSecondRecordLoopLength + $arg2
		variable newStart $gLastEnd
		
			
		addPlayLoop $gFirstLoopTrack $gFirstRecordLoopID  $newStart $newEnd 	//Always on first track
		
		globalVariable gLastEnd $newEnd
		

		setLoopStartAndEnd $arg1 $gFirstRecordLoopStart $newEnd
		
		getLoopEnd playLoopEnd $lastCreatedPlayLoopID 
		
		
												
		// Move script markers just before the end 			
		setMarkerBar $gLooperFunctionMarkerID $newEnd - aBeforeLoopEnd
		
	
		globalVariable gSecondRecordLoopLength $newEnd - $gFirstRecordLoopStart
		
		addCustomGridLine $newEnd		3 	aGridLineColor
	
		
	endIf

	setLoopJamState $arg1 OverdubMode
	
	ifNot $arg3
		setLoopColor $arg1 "Yellow"	
	endIf
	
	setMarkerName $gLooperFunctionMarkerID "Extend"
	setMarkerColor $gLooperFunctionMarkerID #335577
	
	// Adjust the view size 
	setUserArgs 0 // argument for next shortcut 1 = zoom
	shortcutByID  116  // horizontal zoom
		
endFunction

function fctExecuteAtJump

	//print function fctExecuteAtJump $arg1 
	
	// Clear the data the first time
	
	ifNot $pUniqueLoopLength
	
		//print clear and arm ramp up  $gSecondRecordLoopID
		
		unselectAllLoops
		selectLoop $gSecondRecordLoopID
		clearSelectedLoops	
		//armRampUpRecording $gSecondRecordLoopID
	endIf
	
	removeFunctionFromMarker $arg1

endFunction


function setParameter // nb nbArgs arg variable g||p
{
	print4 function setParameter $arg1 $arg2 $arg3 $arg4 $arg5

	if $arg3 > 0-1
		if $arg2 > $arg1 - 1
					
			if $arg5 = "g"
				globalVariable $arg4 $arg3
			else
				if $arg5 = "p"
					persistentVariable $arg4 $arg3
				else
					parentVariable $arg4 $arg3
				endIf
			endIf	
			
		endIf
		
		print4 "   " $arg4 set to: $$arg4 
	else
		print4 "   " $arg4 keep default value: $$arg4 
	endIf

}
endFunction