//-----------------------------------------------------------------------------
//----------------- (c)2003-2016 Xylio. All Rights Reserved. ------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Reloop RMP4'
//----------------------------------------------------------------------------- 
function getLanguageVersion()
{
	return 1;// do not modify this, this should be 1 for all scripts
}
//----------------------------------------------------------------------------- 
function getFileVersion()
{
	return 2;// update this as needed
}
//----------------------------------------------------------------------------- 
// return a user friendly name for the controller supported
function getControllerUserFriendlyName()
{
	return "Reloop RMP4";
}
//----------------------------------------------------------------------------- 
// return the communication type that the controller supports 
// this can be either 'midi' or 'hid' (please return only one of them in case the controller supports both)
function getControllerType()
{
	return 'midi';
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// preferred way to identify the controller (using the USB device VID and PID -- vendor and product id)
// return false if the controller does not support this kind of identification
// osId -- 0 Windows; 1 MacOSX; 2 Linux; -1 unknown
function getSupportedHidDeviceVID(osId)
{
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedHidDevicePID(osId)
{
	return false;
}
//----------------------------------------------------------------------------- 
// this is NOT the preferred way to identify the controller but you should use
// it if the controller does not support standard USB VID and PID identification
// return false if the controller does not support this kind of identification
// osId -- 0 Windows; 1 MacOSX; 2 Linux; -1 unknown
function getSupportedHidDeviceName(osId)
{
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// preferred way to identify the controller (using the USB device VID and PID -- vendor and product id)
// return false if the controller does not support this kind of identification
// osId -- 0 Windows; 1 MacOSX; 2 Linux; -1 unknown
function getSupportedMidiDeviceVID(osId)
{
	return 0x200C;// RMP-4
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID(osId)
{
	return 0x837E;// RMP-4
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceVID2(osId)
{
	//return 0x26AD;
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID2(osId)
{
	//return 0x726F;
	return false;
}
//----------------------------------------------------------------------------- 
// preferred way to identify the controller (if it supports MIDI SysEx)
// return false if the controller does not support this kind of identification
function getSupportedMidiSysExIdString(osId)
{
	// sysex response to 'F0 7E 7F 06 01 F7' (identification request sysex)
	// please note that the response contains 5 bytes in hex format containing
	// the Manufacturer ID (3 bytes) and Model Number (2 bytes)
	// ATTN: the returned value should omit the standard 'F0 7E 00 06 02' message start
	//if(osId==1) return false;
	//return '00206E7270';// BeatMix 4
	return false;// SysEx ID is not supported by this controller
}
//----------------------------------------------------------------------------- 
function getSupportedMidiSysExIdString2(osId)
{
	//return '00206E726F';// BeatMix 2
	return false;// SysEx ID is not supported by this controller
}
//----------------------------------------------------------------------------- 
// this is NOT the preferred way to identify the controller but you should use
// it if the controller does not support standard MIDI SysEx identification
// return false if the controller does not support this kind of identification
// osId -- 0 Windows; 1 MacOSX; 2 Linux; -1 unknown
function getSupportedMidiDeviceNameForInput(osId)
{
	return "RMP-4";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	//return "Reloop RMP4";
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "RMP-4";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	//return "Reloop RMP4";
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogWheelsInScratchMode=[0,0,0,0];// Vinyl is ON or off
//var lastPoweredJWled=[0,0,0,0];
var lastSearchPosAbsolute=[0,0,0,0];
//----------------------------------------------------------------------------- 
// this is called when the controller is initialized and the control is passed to this script
// use this to initialize any variables you might need, the controller' leds, etc
// uniqueId is a unique integer between 0..15 that is guaranteed not to change for 
// a certain opened controller -- please note that there can be many controllers
// of the same type in use at the same time ! Use uniqueId to identify between them
function controllerInit(uniqueId)
{
	debug('controllerInit Reloop RMP4 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	//------------------------------------
	/*
	Both Beatmix units needs to activate the memorization first to remember the PAD LED status. 
	This is done by sending a specific MIDI Note OFF message order to the device:

	09 91 30 00/09 91 34 00/09 91 38 00/09 91 3C 00/09 92 30 00/09 92 34 00/09 92 38 00/09 92 3C 00

	Please note that this should be sent 2 seconds after the device has powered up.

	sendMidi(uniqueId, 0x90, 1, 0x30, 0x00);
	sendMidi(uniqueId, 0x90, 1, 0x34, 0x00);
	sendMidi(uniqueId, 0x90, 1, 0x38, 0x00);
	sendMidi(uniqueId, 0x90, 1, 0x3C, 0x00);
	//
	sendMidi(uniqueId, 0x90, 2, 0x30, 0x00);
	sendMidi(uniqueId, 0x90, 2, 0x34, 0x00);
	sendMidi(uniqueId, 0x90, 2, 0x38, 0x00);
	sendMidi(uniqueId, 0x90, 2, 0x3C, 0x00);
	*/
	for(var deck=0; deck<4; deck++)
	{
		sendMidi(uniqueId,0x90,deck,0x46,(jogWheelsInScratchMode[deck] ? 0x7F : 0x00));// Vinyl
	}
	//------------------------------------
	callSendAllNotifications(uniqueId, true);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
}
//----------------------------------------------------------------------------- 
// called just before the controller will be deinitialized and the control will go away from the script
// use to power off any powered leds, etc
function controllerDeinit(uniqueId)
{
	debug('controllerDeinit Reloop RMP4 ['+uniqueId+']');
	for(var deck=0; deck<4; deck++)
	{
		//sendMidi(uniqueId, 0x90, deck+1, 0x30 + lastPoweredJWled[deck], 0x00);// power off the last powered jog-wheel led
		sendMidi(uniqueId,0x90,deck,0x46,(jogWheelsInScratchMode[deck] ? 0x7F : 0x00));// Vinyl
	}
	//------------------------------------
	callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually de-init all leds/lcd screens)
}
//----------------------------------------------------------------------------- 
// this is your main target function to implement the controller -- this is called 
// for each and every MIDI message that comes from the controller itself
// return true if the message was processed by the script and false to let it 
// pass thru the software (eg. so it can be assigned by the user using the LEARN function)
function messageReceived(uniqueId,status,channel,data1,data2)
{
	var messageNotProcessed=false;
	switch(status)
	{
	//-----------------------------------------------
	// controllers: pitch sliders ('moving' things)
	case 0xE0:
		// attn: we're only using 7bit (we use only data2, we should use data1 as well)
		call('setDeckPitch', channel, data2);
		break;
	//-----------------------------------------------
	// controllers: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1)
		{
		// ATTN: jog-wheel has a different mode when SHIFT is also pressed
		// params: (deck, increment, total positions per complete revolution) 
		case 0x01: // jog-wheel (normal mode)
			var val1 = data2-0x40;
			if(jogWheelsInScratchMode[channel]) 
				call('scratchDeckJW', channel, val1, 1024);
			else 
				call('moveDeckJogWheel', channel, val1, 1024);
			break;
		case 0x02: // jog-wheel + Shift (normal mode)
			var val1 = data2-0x40;
			call('searchDeckJW', channel, val1, 1024);// skip +/- 1 bar for every 15degrees the jog-wheel moves
			break;

		case 0x03: // Enter/Select
		case 0x04: // Enter/Select + Shift
			var val1 = data2-0x40;
			call('lbMoveCursor', val1);
			break;
			
		case 0x06: // << Search >>
			var val1 = data2-0x40;
			// modify the position only on increasing (in absolute terms)
			var val1abs = Math.abs(val1);
			if(val1abs > lastSearchPosAbsolute[channel])
			{
				//debug('val1='+val1+', val1abs='+val1abs+', last='+lastSearchPosAbsolute[channel]);
				call('searchDeckJW', channel, val1, 1024);
			}
			lastSearchPosAbsolute[channel] = val1abs;
			break;
		case 0x07: 	call('setDeckCutoff', channel, data2); 	break;// << Search >> + Shift

		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		//-----------------
		// these buttons should not be dealt with (the hardware/firmware uses them directly)
		// data2 is either 0x00 (off) or 0x7F (on) -- these buttons do NOT send a regular note on/off on every press
		//case 0x7C: call('deckCuePos1', channel, data2); break;// Hot Cue
		//case 0x7D: call('deckCuePos1', channel, data2); break;// Hot Loop
		//case 0x7E: call('deckCuePos1', channel, data2); break;// Loop Roll
		//case 0x7F: call('deckCuePos1', channel, data2); break;// Sampler
		//-----------------
		// ATTN: for all buttons add 0x20 when Shift is pressed too (eg. 0x04 turns into 0x24)
		// hot cues
		case 0x00: call('deckCuePos1', channel, data2); break;
		case 0x01: call('deckCuePos2', channel, data2); break;
		case 0x02: call('deckCuePos3', channel, data2); break;
		case 0x03: call('deckCuePos4', channel, data2); break;
		case 0x04: call('deckCuePos5', channel, data2); break;
		case 0x05: call('deckCuePos6', channel, data2); break;
		case 0x06: call('deckCuePos7', channel, data2); break;
		case 0x07: call('deckCuePos8', channel, data2); break;
		// +Shift
		case 0x20: call('deckCuePos1Clear', channel, data2); break;
		case 0x21: call('deckCuePos2Clear', channel, data2); break;
		case 0x22: call('deckCuePos3Clear', channel, data2); break;
		case 0x23: call('deckCuePos4Clear', channel, data2); break;
		case 0x24: call('deckCuePos5Clear', channel, data2); break;
		case 0x25: call('deckCuePos6Clear', channel, data2); break;
		case 0x26: call('deckCuePos7Clear', channel, data2); break;
		case 0x27: call('deckCuePos8Clear', channel, data2); break;

		// hot loops
		case 0x08: call('deckLoopPoint1', channel, data2); break;
		case 0x09: call('deckLoopPoint2', channel, data2); break;
		case 0x0A: call('deckLoopPoint3', channel, data2); break;
		case 0x0B: call('deckLoopPoint4', channel, data2); break;
		case 0x0C: call('deckLoopPoint5', channel, data2); break;
		case 0x0D: call('deckLoopPoint6', channel, data2); break;
		case 0x0E: call('deckLoopPoint7', channel, data2); break;
		case 0x0F: call('deckLoopPoint8', channel, data2); break;

		// sampler
		case 0x10: call('samplerInstant', 1, data2); break;
		case 0x11: call('samplerInstant', 2, data2); break;
		case 0x12: call('samplerInstant', 3, data2); break;
		case 0x13: call('samplerInstant', 4, data2); break;
		case 0x14: call('samplerInstant', 5, data2); break;
		case 0x15: call('samplerInstant', 6, data2); break;
		case 0x16: call('samplerInstant', 7, data2); break;
		case 0x17: call('samplerInstant', 8, data2); break;

		// loop roll
		// from user's manual: Loop Roll: A loop is set with the number of beats assigned to the respective pad: 
		//		1/32 (Pad1) 1/16 (Pad 2) 1/8 (Pad2) 1/4 (Pad3) 1/2 (Pad4) 1/1 (Pad5) 2/1(Pad6) 4/1 (Pad7) 8/1 (Pad8). 
		//		During loop roll playback the normal playback will be continued in the background (autmatically activated SLIP mode).
		case 0x18: call('deckLoopInstant64ths', channel, (data2==0)?-1:4);   break; // 1/16 beat
		case 0x19: call('deckLoopInstant64ths', channel, (data2==0)?-1:8);   break; // 1/8 beat
		case 0x1A: call('deckLoopInstant64ths', channel, (data2==0)?-1:16);  break; // 1/4 beat
		case 0x1B: call('deckLoopInstant64ths', channel, (data2==0)?-1:32);  break; // 1/2 beat
		case 0x1C: call('deckLoopInstant64ths', channel, (data2==0)?-1:64);  break; // 1 beat
		case 0x1D: call('deckLoopInstant64ths', channel, (data2==0)?-1:128); break; // 2 beats
		case 0x1E: call('deckLoopInstant64ths', channel, (data2==0)?-1:256); break; // 4 beats
		case 0x1F: call('deckLoopInstant64ths', channel, (data2==0)?-1:512); break; // 8 beats
		//-----------------
		
		case 0x40: call('deckLoopInEnd', channel, data2); break;// Loop In
		case 0x41: // Loop Out
			if(data2>0x3F)
			{
				if(!getValue('looping', channel)) 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopInEnd', channel, 0x7F); 
					call('deckLoopInEnd', channel, 0x00); 
				}else 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopMore', channel, 0x7F); 
					call('deckLoopMore', channel, 0x00); 
				}
			}
			break;
		case 0x42: call('deckLoopExitOrReloop', channel, data2); break;// Reloop/Exit
		case 0x43: call('deckLoopPrev', channel, data2); break;// Save
		case 0x44: call('deckLoopNext', channel, data2); break;// Call
		case 0x45: call('deckLoopMode', channel, data2); break;// Slip
		case 0x46: // Vinyl
			if(data2>0x3F)
			{
				jogWheelsInScratchMode[channel] = (jogWheelsInScratchMode[channel] + 1) % 2;
				sendMidi(uniqueId,0x90,channel,0x46,(jogWheelsInScratchMode[channel] ? 0x7F : 0x00));
			}
			break;
		case 0x47: call('deckLoadNext', channel, data2); break;// Eject
		//case 0x47: if(data2>0x3F) call('deckLBLoad', channel, data2); break;// Eject
		case 0x48: call('deckSync', channel, data2); break;
		case 0x68: call('deckMonitor', channel, data2); break;// Shift + Sync
		case 0x49: call('deckKeyLock', channel, data2); break;
		case 0x4A: call('deckResetPitch', channel, data2); break;// Pitch Reset
		case 0x4B: call('deckCue', channel, data2); break;
		case 0x6B: call('deckCuePlay', channel, data2); break;// Cue + Shift
		case 0x4C: call('deckPlayPause', channel, data2); break;
		case 0x6C: call('deckBrake', channel, data2); break; // Play + Shift

		case 0x4D: call('deckBackToTop', channel, data2); break;// Back (on the left of the screen)
		case 0x6D: call('deckReverse', channel, data2); break; // Back + Shift
		case 0x4E: if(data2>0x3F) call('lbToggleSelect', data2); break;// Info/Root (on the right of the screen)
		
		case 0x4F: call('deckLoop1_8', channel, data2); break; 
		case 0x50: call('deckLoop1_4', channel, data2); break; 
		case 0x51: call('deckLoop1_2', channel, data2); break; 
		case 0x52: call('deckLoop1', channel, data2); break; 
		case 0x53: call('deckLoop2', channel, data2); break; 
		case 0x54: call('deckLoop4', channel, data2); break; 
		case 0x55: call('deckLoop8', channel, data2); break; 

		case 0x56: call('deckSearchLeft',  channel, data2); break;// Prev Track
		case 0x57: call('deckSearchRight', channel, data2); break;// Next Track
		case 0x58: call('deckBendDown', channel, data2); break;
		case 0x59: call('deckBendUp', channel, data2); break;
		case 0x5A: if(data2>0x3F) call('deckLBLoad', channel, data2); break;// Enter/Select
		case 0x7A: if(data2>0x3F) call('lbToggleSelect', data2); break;// Enter/Select + Shift
		case 0x5B: if(jogWheelsInScratchMode[channel]) call('holdDeckJogWheel', channel, data2); break;// Touch/JOG
		case 0x5C: call('deckTapBpm', channel, data2); break;
		//case 0x5D: call('setAutoDj', data2); break;// Time
		case 0x5D: call('mixNext', data2); break;// Time
		case 0x5E: // Pitch Range
			if(data2>0x3F) 
			{
				// on the controller: 4%, 8%, 16%, 100%
				var currentPitchRange = getValue('pitchRange');// 1 = 4%; 2 = 8%; 3 = 16%; 4 = 24%; 5 = 32%; 6 = 50%;
				currentPitchRange = currentPitchRange + 1; if(currentPitchRange>6) currentPitchRange = 1;
				// do not allow 24% or 32%, go straight to 50% instead
				if((currentPitchRange==4)||(currentPitchRange==5)) currentPitchRange = 6;
				call('setPitchRange', currentPitchRange); 
			}
			break;
		case 0x5F: call('showCfg', data2); break;// Utility
		
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	default: messageNotProcessed = true;
	}
	if(messageNotProcessed) debug('messageReceived ['+uniqueId+'] - status:'+status+' channel:'+channel+' data1:'+data1+' data2:'+data2);
	return !messageNotProcessed;
}
//----------------------------------------------------------------------------- 
// this is called by the software whenever something important changes (eg. play status, song changed, etc)
// depending on the notification type it may refer to a global event (deck is -1) or a specific deck (deck >= 0)
// and can contain any/all of the parameters: param 1 is an integer, param 2 is a float, param 3 is a string
function notificationReceived(uniqueId,name,deck,param1,param2,param3)
{
	//debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
	//-----------------
	// ATTN: for all buttons add 0x20 when Shift is pressed too (eg. 0x04 turns into 0x24)
	// hot cues
	if(name=='cuepos1')	 		sendMidi(uniqueId,0x90,deck,0x00,(param1 ? 0x7F : 0x00));
	if(name=='cuepos2')	 		sendMidi(uniqueId,0x90,deck,0x01,(param1 ? 0x7F : 0x00));
	if(name=='cuepos3')	 		sendMidi(uniqueId,0x90,deck,0x02,(param1 ? 0x7F : 0x00));
	if(name=='cuepos4')	 		sendMidi(uniqueId,0x90,deck,0x03,(param1 ? 0x7F : 0x00));
	if(name=='cuepos5')	 		sendMidi(uniqueId,0x90,deck,0x04,(param1 ? 0x7F : 0x00));
	if(name=='cuepos6')	 		sendMidi(uniqueId,0x90,deck,0x05,(param1 ? 0x7F : 0x00));
	if(name=='cuepos7')	 		sendMidi(uniqueId,0x90,deck,0x06,(param1 ? 0x7F : 0x00));
	if(name=='cuepos8')	 		sendMidi(uniqueId,0x90,deck,0x07,(param1 ? 0x7F : 0x00));
	
	// hot loops
	if(name=='looppos1')	 	sendMidi(uniqueId,0x90,deck,0x08,(param1 ? 0x7F : 0x00));
	if(name=='looppos2')	 	sendMidi(uniqueId,0x90,deck,0x09,(param1 ? 0x7F : 0x00));
	if(name=='looppos3')	 	sendMidi(uniqueId,0x90,deck,0x0A,(param1 ? 0x7F : 0x00));
	if(name=='looppos4')	 	sendMidi(uniqueId,0x90,deck,0x0B,(param1 ? 0x7F : 0x00));
	if(name=='looppos5')	 	sendMidi(uniqueId,0x90,deck,0x0C,(param1 ? 0x7F : 0x00));
	if(name=='looppos6')	 	sendMidi(uniqueId,0x90,deck,0x0D,(param1 ? 0x7F : 0x00));
	if(name=='looppos7')	 	sendMidi(uniqueId,0x90,deck,0x0E,(param1 ? 0x7F : 0x00));
	if(name=='looppos8')	 	sendMidi(uniqueId,0x90,deck,0x0F,(param1 ? 0x7F : 0x00));

	// sampler
	if(name=='sampler1') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x10,(param1 ? 0x7F : 0x00));// 'sampler1' getValue(sampler2loaded)
	if(name=='sampler2') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x11,(param1 ? 0x7F : 0x00));
	if(name=='sampler3') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x12,(param1 ? 0x7F : 0x00));
	if(name=='sampler4') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x13,(param1 ? 0x7F : 0x00));
	if(name=='sampler5') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x14,(param1 ? 0x7F : 0x00));
	if(name=='sampler6') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x15,(param1 ? 0x7F : 0x00));
	if(name=='sampler7') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x16,(param1 ? 0x7F : 0x00));
	if(name=='sampler8') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x17,(param1 ? 0x7F : 0x00));

	// loop roll -- leds not used
	//case 0x18: call('deckLoopInstant64ths', channel, (data2==0)?-1:4);   break; // 1/16 beat
	//-----------------
	if(name=='onbeat')	 		sendMidi(uniqueId,0x90,deck,0x48,(param1 ? 0x7F : 0x00));// sync
	if(name=='keyLock')	 		sendMidi(uniqueId,0x90,deck,0x49,(param1 ? 0x7F : 0x00));
	if(name=='cue')	 			sendMidi(uniqueId,0x90,deck,0x4B,(param1 ? 0x7F : 0x00));
	if(name=='play')	 		sendMidi(uniqueId,0x90,deck,0x4C,(param1 ? 0x7F : 0x00));
	if(name=='loopSize')
	{
		sendMidi(uniqueId,0x90,deck,0x4F,((param1==8)   ? 43 : 0x00));// loop 1/8
		sendMidi(uniqueId,0x90,deck,0x50,((param1==16)  ? 43 : 0x00));// loop 1/4
		sendMidi(uniqueId,0x90,deck,0x51,((param1==32)  ? 43 : 0x00));// loop 1/2
		sendMidi(uniqueId,0x90,deck,0x52,((param1==64)  ? 43 : 0x00));// loop 1
		sendMidi(uniqueId,0x90,deck,0x53,((param1==128) ? 43 : 0x00));// loop 2
		sendMidi(uniqueId,0x90,deck,0x54,((param1==256) ? 43 : 0x00));// loop 4
		sendMidi(uniqueId,0x90,deck,0x55,((param1==512) ? 43 : 0x00));// loop 8
	}	
	if(name=='loopBlink')	 
	{
		sendMidi(uniqueId,0x90,deck,0x40,(param1 ? 0x7F : 0x00));// deckLoopInEnd
		//sendMidi(uniqueId,0x90,deck,0x41,(param1 ? 0x7F : 0x00));// loop out
		sendMidi(uniqueId,0x90,deck,0x42,(param1 ? 0x7F : 0x00));// deckLoopExitOrReloop
	}
	if(name=='loopMode')	 	for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d,0x45,(param1 ? 0x7F : 0x00));// Slip // 0 vinyl mode, 1 slip mode
	if(name=='monitor')	 		sendMidi(uniqueId,0x90,deck,0x68,(param1 ? 0x7F : 0x00));// Sync + Shift
	if(name=='brake')	 		sendMidi(uniqueId,0x90,deck,0x6C,(param1 ? 0x7F : 0x00));// Play + Shift
	if(name=='reverse')	 		sendMidi(uniqueId,0x90,deck,0x6D,(param1 ? 0x7F : 0x00));// Back + Shift
	// justLoaded: 1,2 (loading in progress), 4 (loading ended), 8 (progress), 16 (detection started), 32 (detection finished);
	if(name=='justLoaded') 	 	sendMidi(uniqueId,0x90,deck,0x47,((param1!=0 && param1!=32) ? 0x7F : 0x00));// set led on during loading // Eject	
	if(name=='pitchIs0')
	{
		sendMidi(uniqueId,0x90,deck,0x4A,(param1 ? 0x00 : 0x7F));// pitch reset led (turned on when the pitch is non-zero)
		sendMidi(uniqueId,0x90,deck,0x5B,(param1 ? 0x7F : 0x00));// 0x5A red, 0x5B green - pitch fader led
		// ATTN: use the RED led to let the use know when the current deck value is different than the one on the fader itself (eg. Sync was used)
	}
	if(name=='pitchRange')
	{
		// 1 = 4%; 2 = 8%; 3 = 16%; 4 = 24%; 5 = 32%; 6 = 50%;
		for(var d=0; d<4; d++)	sendMidi(uniqueId,0x90,d,0x56,((param1>=4) ? 0x7F : 0x00));// 100%
		for(var d=0; d<4; d++)	sendMidi(uniqueId,0x90,d,0x57,((param1==3) ? 0x7F : 0x00));// 16%
		for(var d=0; d<4; d++)	sendMidi(uniqueId,0x90,d,0x58,((param1==2) ? 0x7F : 0x00));// 8%
		for(var d=0; d<4; d++)	sendMidi(uniqueId,0x90,d,0x59,((param1==1) ? 0x7F : 0x00));// 4%
	}
}
//----------------------------------------------------------------------------- 
// this is called from time to time by the software (several times per second)
// (it is guaranteed that 'timerTick' will get executed ALWAYS right after notificationReceived)
function timerTick(uniqueId)
{
	//var t_elapsed = getValue('timeElapsed', channel);// float seconds
	//var t_remain = getValue('timeRemain', channel);
	//var t_total = t_elapsed + t_remain;
	//debug('t_elapsed='+t_elapsed+', t_remain='+t_remain+', t_total='+t_total);
	
	//debug('timerTick ['+uniqueId+']');
	/*
	var totalJwLeds = 16;
	for(var deck=0; deck<4; deck++)
	{
		// get the jog-wheel angle and map to the corresponding led (the closest one to that angle)
		var jwAngle = getValue('jogWheelAngle', deck);// float degrees
		var finalLed = Math.round(totalJwLeds * jwAngle/360.0);
		if(finalLed<0) finalLed = 0;
		if(finalLed>=totalJwLeds) finalLed = totalJwLeds-1;
		// reverse the led number (since it's counter-clockwise)
		finalLed = (totalJwLeds-1) - finalLed;
		//debug('led='+finalLed+', last='+lastPoweredJWled[deck]);
		// actually light on/off the leds
		if(lastPoweredJWled[deck] != finalLed)
		{
			// set to off prev led
			sendMidi(uniqueId, 0x90, deck+1, 0x30 + lastPoweredJWled[deck], 0x00);
			// set to on next led
			sendMidi(uniqueId, 0x90, deck+1, 0x30 + finalLed, 0x7F);
			// update last led
			//debug('2led='+finalLed+', last='+lastPoweredJWled[deck]);
			lastPoweredJWled[deck] = finalLed;
		}
	}
	*/
}
//----------------------------------------------------------------------------- 
