//-----------------------------------------------------------------------------
//------------ Copyright (c)2003-2016 Xylio. All Rights Reserved. -------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Hercules DJControl Instinct P8'
//----------------------------------------------------------------------------- 
function getLanguageVersion()
{
	return 1;// do not modify this, this should be 1 for all scripts
}
//----------------------------------------------------------------------------- 
function getFileVersion()
{
	return 1;// update this as needed
}
//----------------------------------------------------------------------------- 
// return a user friendly name for the controller supported
function getControllerUserFriendlyName()
{
	return "Hercules DJControl Instinct P8";
}
//----------------------------------------------------------------------------- 
// 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 getSupportedMidiDeviceVID(osId)
{
	return 0x06F8;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID(osId)
{
	return 0xB122;
}
//----------------------------------------------------------------------------- 
/*
function getSupportedMidiDeviceVID2(osId)
{
	return 0x06F8;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID2(osId)
{
	return 0x0000;
}
*/
//----------------------------------------------------------------------------- 
// 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 "00014E020018";
	// F0 7E 00 06 02 00 01 4E 02 00 02 00 01 00 00 00 F7 -- Hercules DJ Console MK2 complete sysex
	// F0 7E 00 06 02 00 01 4E 01 00 03 00 01 00 00 00 F7 -- Hercules DJ Control MP3 complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 04 00 01 00 00 00 F7 -- Hercules DJ Console RMX complete sysex
	// F0 7E 00 06 02 00 01 4E 01 00 05 00 01 00 00 00 F7 -- Hercules DJ Control Steel complete sysex	
	// F0 7E 00 06 02 00 01 4E 01 00 07 00 01 00 00 00 F7 -- Hercules DJ Control MP3e2 complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 08 00 01 00 00 00 F7 -- Hercules DJ Console MK4 complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 0B 00 01 00 00 00 F7 -- Hercules DJ Control Air complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 0C 00 01 00 00 00 F7 -- Hercules DJ Control Instinct complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 18 00 01 00 00 00 F7 -- Hercules DJControl Instinct P8 complete sysex
}
//----------------------------------------------------------------------------- 
// 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)
{
	//if(osId==1) return "DJControl Instinct P8";
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//if(osId==1) return "DJControl Instinct P8";
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogWheelsInScratchMode=0;
var previousAutoLoopLightLed=[-1,-1,-1,-1];// 4 decks leds
var cutoffValue=[63,63,63,63];// filter value for setDeckCutoff (63 is at the middle so it means disabled)
//----------------------------------------------------------------------------- 
// value is 0x7F for left (-1); 0x01 for right(+1);
function trimEncoderValue(value, increment, initialValue)
{
	var outValue = 0;
	var outIncrement = 0;
	if(value>0x40) // left (decrease)
		outIncrement = increment * (value - 0x80);
	else // left (increase)
		outIncrement = increment * (value);
	outValue = initialValue + outIncrement;
	if(outValue<0) outValue = 0;
	if(outValue>0x7F) outValue = 0x7F;
	return outValue;
}
//----------------------------------------------------------------------------- 
// 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 Hercules DJControl Instinct P8 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	// setting audio (the actual routing is done automatically for this controller so 
	// we don't need to manually set "RoutingOutHeadphones", "RoutingOutDeckA", etc	
	if(setAudioDevice("Hercules DJControl Instinct P8 ASIO|||DJControl Instinct P8 ASIO|||Hercules DJControl Instinct P8|||DJControl Instinct P8|||DJ Control Instinct|||Speakers (Hercules DJControl Instinct P8)|||Speakers (DJControl Instinct P8)"))
	{
		//debug('AudioDevice was set OK');
		setSetting('AudioDevice2', "NO AUDIO");	
	}else
	{
		//debug('AudioDevice not set (we are not allow to set it or the device either does not exist or it has a different name)');
	}
	//sendMidi(uniqueId, status, channel, data1, data2);
	sendMidi(uniqueId,0x90,0,0x2D,(jogWheelsInScratchMode ? 0x7F : 0x00));// scratch mode
	//------------------------------------
	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 ['+uniqueId+']');
	// set leds off
	sendMidi(uniqueId,0x90,0,0x2D,0x00);// scratch mode
	//------------------------------------
	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: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1)
		{
		// global
		case 0x56: call('setCrossfader', data2); break;
		case 0x38: 
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('lbMoveCursor', val1); 
			break;


		// deck A
		case 0x40: call('setDeckVolume', 0, data2); break;
		case 0x44: call('setDeckEqLow', 0, data2); break;
		case 0x46: call('setDeckEqMid', 0, data2); break;
		case 0x48: call('setDeckEqHigh', 0, data2); break;
		//case 0x34: call('moveDeckPitch', 0, -(data2>0x40 ? data2-0x80 : data2)); break;// increment mode		

		// jog-wheel
		// params: (deck, increment, total positions per complete revolution) 
		case 0x30: // simple move
		case 0x69: // move + press (hold/touch)
		case 0x6A: // move + press (hold/touch) + SHIFT
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(jogWheelsInScratchMode) call('scratchDeckJW', 0, val1, 256);else call('moveDeckJogWheel', 0, val1, 256);
			break;
		case 0x31: // simple move + SHIFT
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('searchDeckJW', 0, val1, 256);
			break;

		case 0x34: // Loop encoder
			if(data2>0x40) // to the left (0x7F = -1)
			{
				call('deckLoopLess', 0, 0x7F);
				call('deckLoopLess', 0, 0x00);
			}else // to the right (0x01 = +1)
			{
				call('deckLoopMore', 0, 0x7F);
				call('deckLoopMore', 0, 0x00);
			}
			break;
		case 0x35: // Filter encoder (Loop encoder + SHIFT)
			{
				//var val1 = (data2>0x40 ? data2-0x80 : data2);
				cutoffValue[0] = trimEncoderValue(data2, 2, cutoffValue[0]);
				call('setDeckCutoff', 0, cutoffValue[0]);
				break;
			}


		// deck B
		case 0x42: call('setDeckVolume', 1, data2); break;		
		case 0x50: call('setDeckEqLow', 1, data2); break;
		case 0x52: call('setDeckEqMid', 1, data2); break;
		case 0x54: call('setDeckEqHigh', 1, data2); break;
		//case 0x35: call('moveDeckPitch', 1, -(data2>0x40 ? data2-0x80 : data2)); break;// increment mode		

		// jog-wheel
		// params: (deck, increment, total positions per complete revolution) 
		case 0x32: // simple move
		case 0x6B: // move + press (hold/touch)
		case 0x6C: // move + press (hold/touch) + SHIFT
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(jogWheelsInScratchMode) call('scratchDeckJW', 1, val1, 256);else call('moveDeckJogWheel', 1, val1, 256);
			break;
		case 0x33: // simple move + SHIFT
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('searchDeckJW', 1, val1, 256);
			break;

		case 0x36: // Loop encoder
			if(data2>0x40) // to the left (0x7F = -1)
			{
				call('deckLoopLess', 1, 0x7F);
				call('deckLoopLess', 1, 0x00);
			}else // to the right (0x01 = +1)
			{
				call('deckLoopMore', 1, 0x7F);
				call('deckLoopMore', 1, 0x00);
			}
			break;
		case 0x37: // Filter encoder (Loop encoder + SHIFT)
			{
				//var val1 = (data2>0x40 ? data2-0x80 : data2);
				cutoffValue[1] = trimEncoderValue(data2, 2, cutoffValue[1]);
				call('setDeckCutoff', 1, cutoffValue[1]);
				break;
			}
		
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		// global
		case 0x5D:// headphone volume -/+
		case 0x5E:		
			if(data2>0x3F) 
			{
				var monValue = getValue('monitorGain');
				if(data1==0x5D) monValue -= 2;else monValue += 2;
				if(monValue<-40) monValue = -40;
				if(monValue>0) monValue = 0;
				// we need to convert from -40..0dB to 0..127 (MIDI)
				call('setMonitorGain', Math.round((monValue+40)*3.175));
			}
			break;
		case 0x2B: if(data2>0x3F) call('lbToggleSelect', 1); break;
		case 0x2C: call('mixNext', data2); break;// above + Shift
		//case 0x2C: call('setAutoDj', data2); break;
		case 0x2D: // scratch on/off
			if(data2>0x3F)
			{ 
				jogWheelsInScratchMode = (jogWheelsInScratchMode + 1) % 2; 
				sendMidi(uniqueId,0x90,0,0x2D,(jogWheelsInScratchMode ? 0x7F : 0x00));
			} 
			break;

		// deck A
		// PADs (4 modes x (4 pads + 4 Shift pads))
		// cues
		case 0x01: call('deckCuePos1', 0, data2); break;
		case 0x02: call('deckCuePos2', 0, data2); break;
		case 0x03: call('deckCuePos3', 0, data2); break;
		case 0x04: call('deckCuePos4', 0, data2); break;
		case 0x05: call('deckCuePos5', 0, data2); break;// cue 1 + Shift
		case 0x06: call('deckCuePos6', 0, data2); break;// --//--
		case 0x07: call('deckCuePos7', 0, data2); break;// --//--
		case 0x08: call('deckCuePos8', 0, data2); break;// --//--
		// fx
		case 0x09: call('deckFxFlanger', 0, data2); break;
		case 0x0A: call('deckFxEcho', 0, data2); break;
		case 0x0B: call('deckFxBeatwaw', 0, data2); break;
		case 0x0C: call('deckFxReverb', 0, data2); break;	
		case 0x0D: call('deckBendDown', 0, data2); break;// fx 1 + Shift
		case 0x0E: call('deckBendUp', 0, data2); break;// --//--
		case 0x0F: call('deckReverse', 0, data2); break;// --//--
		case 0x10: call('deckBrake', 0, data2); break;// --//--
		// sampler
		case 0x11: call('sampler1', data2); break;
		case 0x12: call('sampler2', data2); break;
		case 0x13: call('sampler3', data2); break;
		case 0x14: call('sampler4', data2); break;
		case 0x15: call('sampler5', data2); break;// sampler 1 + Shift
		case 0x16: call('sampler6', data2); break;// --//--
		case 0x17: call('sampler7', data2); break;// --//--
		case 0x18: call('sampler8', data2); break;// --//--
		// loop
		case 0x19: call('deckLoop1', 0, data2); break;
		case 0x1A: call('deckLoop2', 0, data2); break;
		case 0x1B: call('deckLoop4', 0, data2); break;
		case 0x1C: call('deckLoop8', 0, data2); break;
		case 0x1D: call('deckLoop1_16', 0, data2); break;// loop 1 + Shift
		case 0x1E: call('deckLoop1_8', 0, data2); break;// --//--
		case 0x1F: call('deckLoop1_4', 0, data2); break;// --//--
		case 0x20: call('deckLoop1_2', 0, data2); break;// --//--
	
		// transport		
		case 0x21: call('deckPlayPause', 0, data2); break;
		case 0x22: call('deckCue', 0, data2); break;
		case 0x23: call('deckSync', 0, data2); break;
		case 0x24: call('deckReverse', 0, data2); break;// play + Shift
		case 0x25: call('deckCuePlay', 0, data2); break;// cue + Shift
		case 0x26: call('deckMatch', 0, data2); break;// sync + Shift
		
		case 0x57:
			if(data2>0x40)
			{ 
				if(getValue('looping', 0)) 
				{
					call('deckLoopExit', 0, 0x7F);
					call('deckLoopExit', 0, 0x00);
				}else 
				{
					call('deckLoopInEnd', 0, 0x7F);
					call('deckLoopInEnd', 0, 0x00);
					//call('deckLoopReloop', 0, 0x7F);
					//call('deckLoopReloop', 0, 0x00);
				}
			}
			break;		
		case 0x5B: call('deckMonitor', 0, data2); break;
		case 0x5F: if(data2>0x3F) call('deckLBLoad', 0, data2); break;
		case 0x61: call('holdDeckJogWheel', 0, data2); break;
		//case 0x13: call('deckKeyLock', 0, data2); break;

		// deck B
		// PADs (4 modes x (4 pads + 4 Shift pads))
		// cues
		case 0x31: call('deckCuePos1', 1, data2); break;
		case 0x32: call('deckCuePos2', 1, data2); break;
		case 0x33: call('deckCuePos3', 1, data2); break;
		case 0x34: call('deckCuePos4', 1, data2); break;
		case 0x35: call('deckCuePos5', 1, data2); break;// cue 1 + Shift
		case 0x36: call('deckCuePos6', 1, data2); break;// --//--
		case 0x37: call('deckCuePos7', 1, data2); break;// --//--
		case 0x38: call('deckCuePos8', 1, data2); break;// --//--
		// fx
		case 0x39: call('deckFxFlanger', 1, data2); break;
		case 0x3A: call('deckFxEcho', 1, data2); break;
		case 0x3B: call('deckFxBeatwaw', 1, data2); break;
		case 0x3C: call('deckFxReverb', 1, data2); break;
		case 0x3D: call('deckBendDown', 1, data2); break;// fx 1 + Shift
		case 0x3E: call('deckBendUp', 1, data2); break;// --//--
		case 0x3F: call('deckReverse', 1, data2); break;// --//--
		case 0x40: call('deckBrake', 1, data2); break;// --//--
		// sampler
		case 0x41: call('sampler5', data2); break;
		case 0x42: call('sampler6', data2); break;
		case 0x43: call('sampler7', data2); break;
		case 0x44: call('sampler8', data2); break;
		case 0x45: call('sampler1', data2); break;// sampler 1 + Shift
		case 0x46: call('sampler2', data2); break;// --//--
		case 0x47: call('sampler3', data2); break;// --//--
		case 0x48: call('sampler4', data2); break;// --//--
		// loop
		case 0x49: call('deckLoop1', 1, data2); break;
		case 0x4A: call('deckLoop2', 1, data2); break;
		case 0x4B: call('deckLoop4', 1, data2); break;
		case 0x4C: call('deckLoop8', 1, data2); break;
		case 0x4D: call('deckLoop1_16', 1, data2); break;// loop 1 + Shift
		case 0x4E: call('deckLoop1_8', 1, data2); break;// --//--
		case 0x4F: call('deckLoop1_4', 1, data2); break;// --//--
		case 0x50: call('deckLoop1_2', 1, data2); break;// --//--
		
		// transport		
		case 0x51: call('deckPlayPause', 1, data2); break;
		case 0x52: call('deckCue', 1, data2); break;
		case 0x53: call('deckSync', 1, data2); break;
		case 0x54: call('deckReverse', 1, data2); break;// play + Shift
		case 0x55: call('deckCuePlay', 1, data2); break;// cue + Shift
		case 0x56: call('deckMatch', 1, data2); break;// sync + Shift
	
		case 0x58:
			if(data2>0x40)
			{ 
				if(getValue('looping', 1)) 
				{
					call('deckLoopExit', 1, 0x7F);
					call('deckLoopExit', 1, 0x00);
				}else 
				{
					call('deckLoopInEnd', 1, 0x7F);
					call('deckLoopInEnd', 1, 0x00);
					//call('deckLoopReloop', 1, 0x7F);
					//call('deckLoopReloop', 1, 0x00);
				}
			}
			break;		
		case 0x5C: call('deckMonitor', 1, data2); break;
		case 0x60: if(data2>0x3F) call('deckLBLoad', 1, data2); break;
		case 0x62: call('holdDeckJogWheel', 1, data2); break;
		//case 0x27: call('deckKeyLock', 1, data2); break;
				
		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);
	if(deck>=2) return;
	var nameLen = name.length;
	
	if(name=='play') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x21:0x51,(param1 ? 0x7F : 0x00));
	if(name=='cue') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x22:0x52,(param1 ? 0x7F : 0x00));
	if(name=='onbeat') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x23:0x53,(param1 ? 0x7F : 0x00));
	if(name=='monitor') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x5B:0x5C,(param1 ? 0x7F : 0x00));

	//if(name=='keyLock') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x13:0x27,(param1 ? 0x7F : 0x00));
	//if(name=='autoDj') 		sendMidi(uniqueId,0x90,0,0x2E,(param1 ? 0x7F : 0x00));// automix

	if(name=='reverse') 	
	{
		sendMidi(uniqueId,0x90,0,(deck==0)?0x24:0x54,(param1 ? 0x7F : 0x00));// play + Shift
		sendMidi(uniqueId,0x90,0,(deck==0)?0x0F:0x3F,(param1 ? 0x7F : 0x00));// fx pad + Shift (pad 3)
	}
	if(name=='brake') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x10:0x40,(param1 ? 0x7F : 0x00));// fx pad + Shift (pad 4)	

	// justLoaded: 1,2 (loading in progress), 4 (loading ended), 8 (progress), 16 (detection started), 32 (detection finished);
	if(name=='justLoaded') 	 
	{
		if(param1!=0 && param1!=32)
		{
			// loading
			sendMidi(uniqueId,0x90,0,(deck==0)?0x5F:0x60,0x7F);
		}else
		{
			// loading finished
			sendMidi(uniqueId,0x90,0,(deck==0)?0x5F:0x60,0x00);
		}
	}
	
	// PADs
	// we use different color on the PADs: red - cues and sampler; blue - loop; purple - fx;
	// 7D = Blue, 7E = Red, 7F = Blue + Red (purple)

	// cues
	if(name=='cuepos1') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x01:0x31,(param1 ? 0x7E : 0x00));
	if(name=='cuepos2') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x02:0x32,(param1 ? 0x7E : 0x00));
	if(name=='cuepos3') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x03:0x33,(param1 ? 0x7E : 0x00));
	if(name=='cuepos4') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x04:0x34,(param1 ? 0x7E : 0x00));			
	if(name=='cuepos5') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x05:0x35,(param1 ? 0x7E : 0x00));			
	if(name=='cuepos6') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x06:0x36,(param1 ? 0x7E : 0x00));			
	if(name=='cuepos7') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x07:0x37,(param1 ? 0x7E : 0x00));			
	if(name=='cuepos8') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x08:0x38,(param1 ? 0x7E : 0x00));			
	
	// fx
	if(name=='fxFlanger') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x09:0x39,(param1 ? 0x7F : 0x00));
	if(name=='fxEcho') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x0A:0x3A,(param1 ? 0x7F : 0x00));
	if(name=='fxBeatwaw') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x0B:0x3B,(param1 ? 0x7F : 0x00));
	if(name=='fxReverb') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x0C:0x3C,(param1 ? 0x7F : 0x00));
	// fx with Shift (eg. deck A: 0D, 0E, 0F, 10; deck B: 3D, 3E, 3F, 40;) - not used (actually, 0F,10 and 3F,40 are used above for reverse and brake)

	// loop
	if(name=='loopSize')
	{
		// turn off last led (if any is on)
		if(previousAutoLoopLightLed[deck]>-1)
			sendMidi(uniqueId,0x90,0,previousAutoLoopLightLed[deck],0x00);
		// calculate the new led to power on
		switch(param1)
		{
		case   64: previousAutoLoopLightLed[deck] = (deck==0)?0x19:0x49; break;// 1 beat
		case  128: previousAutoLoopLightLed[deck] = (deck==0)?0x1A:0x4A; break;// 2 beats
		case  256: previousAutoLoopLightLed[deck] = (deck==0)?0x1B:0x4B; break;// 4 beats
		case  512: previousAutoLoopLightLed[deck] = (deck==0)?0x1C:0x4C; break;// 8 beats
		// with Shift
		case    4: previousAutoLoopLightLed[deck] = (deck==0)?0x1D:0x4D; break;// 1/16 beat
		case    8: previousAutoLoopLightLed[deck] = (deck==0)?0x1E:0x4E; break;// 1/8 beat
		case   16: previousAutoLoopLightLed[deck] = (deck==0)?0x1F:0x4F; break;// 1/4 beat
		case   32: previousAutoLoopLightLed[deck] = (deck==0)?0x20:0x50; break;// 1/2 beat
		default:   previousAutoLoopLightLed[deck] = -1;
		}
		// actually light the led
		if(previousAutoLoopLightLed[deck]>-1)	
			sendMidi(uniqueId,0x90,0,previousAutoLoopLightLed[deck],0x7D);
	}
	
	// sampler
	if(nameLen==13)
	{
		var name1 = name.substr(0, nameLen-1);
		if(name1=='samplerBlink')
		{
			// deck A
			if(name=='samplerBlink1') sendMidi(uniqueId,0x90,0,0x11,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink2') sendMidi(uniqueId,0x90,0,0x12,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink3') sendMidi(uniqueId,0x90,0,0x13,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink4') sendMidi(uniqueId,0x90,0,0x14,(param1 ? 0x7E : 0x00));
			// with Shift
			if(name=='samplerBlink5') sendMidi(uniqueId,0x90,0,0x15,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink6') sendMidi(uniqueId,0x90,0,0x16,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink7') sendMidi(uniqueId,0x90,0,0x17,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink8') sendMidi(uniqueId,0x90,0,0x18,(param1 ? 0x7E : 0x00));

			// deck B
			if(name=='samplerBlink5') sendMidi(uniqueId,0x90,0,0x41,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink6') sendMidi(uniqueId,0x90,0,0x42,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink7') sendMidi(uniqueId,0x90,0,0x43,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink8') sendMidi(uniqueId,0x90,0,0x44,(param1 ? 0x7E : 0x00));
			// with Shift
			if(name=='samplerBlink1') sendMidi(uniqueId,0x90,0,0x45,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink2') sendMidi(uniqueId,0x90,0,0x46,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink3') sendMidi(uniqueId,0x90,0,0x47,(param1 ? 0x7E : 0x00));
			if(name=='samplerBlink4') sendMidi(uniqueId,0x90,0,0x48,(param1 ? 0x7E : 0x00));
		}
	}
}
//----------------------------------------------------------------------------- 
// 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)
{
	//debug('timerTick ['+uniqueId+']');
}
//----------------------------------------------------------------------------- 
