// Example of a one button standard looper. First loop length will be the length of all other loops  		
//
// Author: LoopToGo
//
// Arguments or user arguments : 
// 		1 : (optional) gFirstTrack, track number to start the looping, default is 1. If equal to -1, selected track is used
// 		2 : (optional) gNbBars, number of bars for the first recording, default is 10
//		3 : (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

if $isPaused * $isRecording
	record
	endScriptDynamic
endIf	

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

// Note see debugUtilities.ltgl For details on how to use debugging


loadScript ..\libs\debugUtilities.ltgl	// To uses debugging prints

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

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

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

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

// Do not run the script without a track
if $nbTracks < 1
	setUserArgs  // Reset the users args just in case!
	endScriptDynamic
endIf

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

variable deltaTime $sysTime - $gLastExecutionTime
globalVariable gLastExecutionTime $sysTime


/////////////////////////////////////////////////////////
///////////// 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

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

alias true 1
alias false 0

// Locked state value For loops
alias UnLockedState 0
alias LockedState 3
alias OverdubMode 6

// Looper States
alias LooperStoppedAndEmpty 0
alias LooperStopped 1
alias LooperRecord 2
alias LooperPlay 3
alias LooperOverdub 4

// Track monitoring mode
alias InLoopsOrWhileTrackSelected 3


// If this script is called a second time within 200 ms, the script is not executed
if  $deltaTime < 200
	//print "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 "Start of script: "

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


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



// If we are not starting from scratch, just make sure we have a jam marker
if $nbMarkers < 1
	//print2 startJamMode $gFirstRecordLoopID
	startJamMode $gFirstRecordLoopID		
endIf 



// Execute actions upon Looper State value
if $gLooperState = LooperStoppedAndEmpty	// First time


	globalVariable gNbBars aDefaultNbBars
	globalVariable gFirstTrack	aDefaultFirstTrack
	
	if $pNbMaxSecs
		globalVariable gNbBars $pNbMaxSecs*60/$tempo
	endIf
		
	if $arg3 // 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
		
			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			
		endIf


	//print gFirstTrack: $gFirstTrack gNbBars: $gNbBars

	// Let's init global variables and start recording
	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	

else
	// Script called but not first time

	setUserArgs  // reset the users args just in case!

	print LooperState : $gLooperState
	
	
	if $nbArgs
		ifNot $arg1 = $gFirstTrack   // The user called the script and asked for another track
			globalVariable gFirstTrack $arg1
			if $gFirstTrack > 0 
				selectTrack $gFirstTrack
			else
				if $selectedTrack = 0
					selectTrack aDefaultFirstTrack
				endIf
			endIf
		endIf
	endIf
	
	//print "New LooperState:" $gLooperState "dontLockCurrentOverDub:" $dontLockCurrentOverDub

	// Let's do action upon looper state value
	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
		
		endScriptDynamic
																
	endIf
			
	if $gLooperState = LooperPlay	

		callFunction fctNewOverdub 
		endScriptDynamic
	endIf
				
	if $gLooperState = LooperOverdub
		callFunction fctStopOverdub
		endScriptDynamic
	endIf
	
	if $gLooperState = LooperStopped
		
		callFunction fctStopOverdub
		
		setBar $gFirstRecordLoopStart
		
		shortcutByID 39 // Start recording
	endIf
		
	
endIf



// All initialization and start of recording
function fctInitAndStartRecording
{
	
	print  "fctInitAndStartRecording: " 
	
	globalVariable gFirstTime true
	globalVariable gInRecordLoop true
	globalVariable gLooperState LooperRecord
	globalVariable gFirstRecordLoopStart $songBar
	
	setUserArgs 1		// Arg1 to for next shortcut 1: vertically zoomed
	shortcutByID 9		// Set vertical zomm mode

	if $gFirstTrack > 0 
		selectTrack $gFirstTrack
	else
		if $selectedTrack = 0
			selectTrack aDefaultFirstTrack
		endIf
	endIf
	
	ifNot $dontChangeMonitoring
		callFunction setTracksMonitoringMode
	endIf
	// First record loop	
	
	addRecordLoop $selectedTrack FirstLoop $gFirstRecordLoopStart $gFirstRecordLoopStart + $gNbBars
	
	globalVariable gFirstRecordLoopID	$lastCreatedRecordLoopID

	
	// Since we are not sync with any tempo, let's remove the grid lines and add our own grid lines
	setGridLinesVisibility 0
	
	removeAllCustomGridLines	// In case there are older grid lines
	
	addCustomGridLine $gFirstRecordLoopStart				3	aGridLineColor
	addCustomGridLine $gFirstRecordLoopStart + $gNbBars		3 	aGridLineColor

		
	record // Start recording

	print 3: $sysTime $gLastExecutionTime $sysTime - $gLastExecutionTime

	startJamMode $lastCreatedRecordLoopID

	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Red"	
	endIf	

	// Adjust the view size 
	setUserArgs 0 // argument for next shortcut 1 = zoom 0 = unzoom
	shortcutByID  116  // horizontal zoom
	
}
endFunction

// Add a new record loop and set it in overdub mode. 
function fctNewOverdub 
{	
	print "fctNewOverdub: " 
	
	setLoopLockState $lastCreatedRecordLoopID LockedState
				
	addRecordLoop $selectedTrack "Overdub" $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	// 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
		
	jamMode // Starts jam mode
	
	setLoopJamState $lastCreatedRecordLoopID OverdubMode
	
	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Yellow"	
	endIf

		
}
endFunction

// Stop the first recordin and lock the loop
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
	
	//print  $lastCreatedRecordLoopID $gFirstRecordLoopStart $gFirstRecordLoopEnd
			
	setLoopStartAndEnd $lastCreatedRecordLoopID $gFirstRecordLoopStart $gFirstRecordLoopEnd
	
	setLoopLockState $lastCreatedRecordLoopID LockedState 
			
	jumpTo $gFirstRecordLoopStart // More accurate than setBar!!!
	
	print 2: $sysTime
		
	waitDelta $tempo/5000  // Wait For the jump! Must not be too small because will causes issue with high tempo
	startJamMode $lastCreatedRecordLoopID // Make sure we stay in Jam Mode

	ifNot $dontUseCustomColors
		setLoopColor $lastCreatedRecordLoopID "Green"  // Green because we are playing back what was recorded		
	endIf
}
endFunction

// Lock the last overdub loop
function fctStopOverdub
{
	print  "fctStopOverdub: " 
							
	setLoopLockState $lastCreatedRecordLoopID LockedState true // true = do a ramp down of input data  
	
	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: " 

	globalVariable gLooperState LooperPlay
				
	ifNot $isRecording
		if $nbLoops = 0
			globalVariable gLooperState LooperStoppedAndEmpty
		else
			globalVariable gLooperState LooperStopped
		endIf
		
		exitFunction	// The state has been set, exit!!!
	endIf
	
	for loop 1 $nbLoops
		variable loopID loopID & $loop
		
		getLoopJamState loopJamMode $$loopID
		getLoopLockState loopLockState $$loopID

		if $loopLockState = UnLockedState
			
			if $loopJamMode = OverdubMode				
				globalVariable gLooperState LooperOverdub
			else
				globalVariable gLooperState LooperRecord
			endIf
							
			exitFunction			// The state has been set, exit!!!

		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

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


