//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2012 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'American Audio DJ DP2 (DigitalProducer2)'
//----------------------------------------------------------------------------- 
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 "American Audio DP2";
}
//----------------------------------------------------------------------------- 
// 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 (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
	return false;
	//return "0011EE2200";// this controller doesn't support sysex id
}
//----------------------------------------------------------------------------- 
// 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 "ADJ-DP2";else return "ADJ-DP2 MIDI";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	if(osId==1) return "ADJ-DP2";else return "ADJ-DP2 MIDI";
	//return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var previousAutoLoopLightLed=[-1,-1,-1,-1];// 4 decks leds
var loopingInBlinkLed=[-1,-1,-1,-1];// 4 decks leds
var loopingInBlinkLedStatus=[0,0,0,0];// 4 decks leds
var samplerBlinkLedStatus=[0,0,0,0,0,0,0,0];// 2 decks leds, each with 4 samplers // 0 means off; 1 means on; 2 means blink on; 3 means blink off;
var jogWheelStatus=[0,0,0,0];// 0 means normal mode, 1 scratch mode, 2 seek mode
var pitchStatus=[1,1,1,1];// 1 means enabled, 0 disabled
var effectsSelected=[0,0];// 2 decks (the selected fx, 0-based index)
var effectsStatus=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];// 2 decks leds, each with 8 effects -- 1 means enabled, 0 disabled
var timer1=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 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	//sendMidi(uniqueId, status, channel, data1, data2);
	for(var deck=0; deck<2; deck++)
	{
		// cue pos
		sendMidi(uniqueId,0x90,deck,0x09,(getValue('cuepos1', deck) ? 0x7F : 0x00));// cuepos1
		sendMidi(uniqueId,0x90,deck,0x0A,(getValue('cuepos2', deck) ? 0x7F : 0x00));// cuepos2
		sendMidi(uniqueId,0x90,deck,0x0B,(getValue('cuepos3', deck) ? 0x7F : 0x00));// cuepos3
		sendMidi(uniqueId,0x90,deck,0x0C,(getValue('cuepos4', deck) ? 0x7F : 0x00));// cuepos4
		
		// auto-loop
		var loopSize = getValue('loopSize', deck);
		var looping = getValue('looping', deck);
		//var loopIn = getValue('loopIn', deck);
		//sendMidi(uniqueId,0x90,deck,0x0D,0x7F);// autoloop <-
		sendMidi(uniqueId,0x90,deck,0x0E,(loopSize == 16 ? 0x7F : 0x00));// 1/4 beat
		sendMidi(uniqueId,0x90,deck,0x0F,(loopSize == 32 ? 0x7F : 0x00));// 1/2 beat
		sendMidi(uniqueId,0x90,deck,0x10,(loopSize == 64 ? 0x7F : 0x00));// 1 beat
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x11,(loopSize ==128 ? 0x7F : 0x00));// 2 beats
		sendMidi(uniqueId,0x90,deck,0x12,(loopSize ==256 ? 0x7F : 0x00));// 4 beats
		sendMidi(uniqueId,0x90,deck,0x13,(loopSize ==512 ? 0x7F : 0x00));// 8 beats
		sendMidi(uniqueId,0x90,deck,0x14,(loopSize==1024 ? 0x7F : 0x00));// 16 beats
		//sendMidi(uniqueId,0x90,deck,0x15,0x7F);// autoloop ->
		sendMidi(uniqueId,0x90,deck,0x16,(looping ? 0x7F : 0x00));// in
		sendMidi(uniqueId,0x90,deck,0x17,(looping ? 0x7F : 0x00));// out
		sendMidi(uniqueId,0x90,deck,0x18,0x00);// reloop
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		
		// transport
		sendMidi(uniqueId,0x90,deck,0x19,(getValue('cue', deck) ? 0x7F : 0x00));// cue
		sendMidi(uniqueId,0x90,deck,0x1A,(getValue('play', deck) ? 0x7F : 0x00));// play
		// effects
		//sendMidi(uniqueId,0x90,deck,0x1B,0x7F);// x-param
		//sendMidi(uniqueId,0x90,deck,0x1C,0x7F);// y-param
		//sendMidi(uniqueId,0x90,deck,0x1D,0x7F);// select
		//sendMidi(uniqueId,0x90,deck,0x33,0x00);// effect on -- moved below
		//
		sendMidi(uniqueId,0x90,deck,0x34,0x00);// scratch mode
		sendMidi(uniqueId,0x90,deck,0x35,(getValue('monitor', deck) ? 0x7F : 0x00));// monitor
		sendMidi(uniqueId,0x90,deck,0x36,0x00);// seek mode
		sendMidi(uniqueId,0x90,deck,0x37,0x00);// shift
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x38,(getValue('onbeat', deck) ? 0x7F : 0x00));// onbeat/sync
		sendMidi(uniqueId,0x90,deck,0x39,(getValue('keyLock', deck) ? 0x7F : 0x00));// keylock
		sendMidi(uniqueId,0x90,deck,0x3A,0x7F);// pitch on
		//sendMidi(uniqueId,0x90,deck,0x3B,0x00);// pitch bend -
		//sendMidi(uniqueId,0x90,deck,0x3C,0x00);// pitch bend +
		sendMidi(uniqueId,0x90,deck,0x3D,0x00);// to deck
		
		sendMidi(uniqueId,0x90,deck,0x41,0x00);// save to
		sendMidi(uniqueId,0x90,deck,0x42,0x00);// sampler
		sendMidi(uniqueId,0x90,deck,0x43,0x00);// bpm
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x44,0x00);// tap
		if(deck==0)
		{
			sendMidi(uniqueId,0x90,deck,0x45,(getValue('sampler1loaded', deck) ? 0x7F : 0x00));// sampler 1
			sendMidi(uniqueId,0x90,deck,0x46,(getValue('sampler2loaded', deck) ? 0x7F : 0x00));// sampler 2
			sendMidi(uniqueId,0x90,deck,0x47,(getValue('sampler3loaded', deck) ? 0x7F : 0x00));// sampler 3
			sendMidi(uniqueId,0x90,deck,0x48,(getValue('sampler4loaded', deck) ? 0x7F : 0x00));// sampler 4
		}else
		{
			sendMidi(uniqueId,0x90,deck,0x45,(getValue('sampler5loaded', deck) ? 0x7F : 0x00));// sampler 1
			sendMidi(uniqueId,0x90,deck,0x46,(getValue('sampler6loaded', deck) ? 0x7F : 0x00));// sampler 2
			sendMidi(uniqueId,0x90,deck,0x47,(getValue('sampler7loaded', deck) ? 0x7F : 0x00));// sampler 3
			sendMidi(uniqueId,0x90,deck,0x48,(getValue('sampler8loaded', deck) ? 0x7F : 0x00));// sampler 4
		}
		// effects leds
		sendMidi(uniqueId,0x90,deck,0x2B,0x7F);
		sendMidi(uniqueId,0x90,deck,0x2C,0x00);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x2D,0x00);
		sendMidi(uniqueId,0x90,deck,0x2E,0x00);
		sendMidi(uniqueId,0x90,deck,0x2F,0x00);
		sendMidi(uniqueId,0x90,deck,0x30,0x00);
		sendMidi(uniqueId,0x90,deck,0x31,0x00);
		sendMidi(uniqueId,0x90,deck,0x32,0x00);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		
		// get the effects status
		effectsStatus[deck*8 + 0] = getValue('fxFlanger', deck);
		effectsStatus[deck*8 + 1] = getValue('fxEcho', deck);
		effectsStatus[deck*8 + 2] = getValue('fxDelay', deck);
		effectsStatus[deck*8 + 3] = getValue('fxReverb', deck);
		effectsStatus[deck*8 + 4] = getValue('fxPan', deck);
		effectsStatus[deck*8 + 5] = getValue('fxPhaser', deck);
		effectsStatus[deck*8 + 6] = 0;
		effectsStatus[deck*8 + 7] = 0;		
		sendMidi(uniqueId,0x90,deck,0x33,(effectsStatus[deck*8 + 0] ? 0x7F : 0x00));// effect on
	}
	//sendMidi(uniqueId,0x90,deck,0x35,(param1 ? 0x7F : 0x00));// monitor			
}
//----------------------------------------------------------------------------- 
// 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+']');
	for(var deck=0; deck<2; deck++)
	{
		// cue pos
		sendMidi(uniqueId,0x90,deck,0x09,0x00);// cuepos1
		sendMidi(uniqueId,0x90,deck,0x0A,0x00);// cuepos2
		sendMidi(uniqueId,0x90,deck,0x0B,0x00);// cuepos3
		sendMidi(uniqueId,0x90,deck,0x0C,0x00);// cuepos4
		// auto-loop
		//sendMidi(uniqueId,0x90,deck,0x0D,0x00);// autoloop <-
		sendMidi(uniqueId,0x90,deck,0x0E,0x00);
		sendMidi(uniqueId,0x90,deck,0x0F,0x00);
		sendMidi(uniqueId,0x90,deck,0x10,0x00);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x11,0x00);
		sendMidi(uniqueId,0x90,deck,0x12,0x00);
		sendMidi(uniqueId,0x90,deck,0x13,0x00);
		sendMidi(uniqueId,0x90,deck,0x14,0x00);
		//sendMidi(uniqueId,0x90,deck,0x15,0x00);// autoloop ->
		sendMidi(uniqueId,0x90,deck,0x16,0x00);// in
		sendMidi(uniqueId,0x90,deck,0x17,0x00);// out
		sendMidi(uniqueId,0x90,deck,0x18,0x00);// reloop
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		// transport
		sendMidi(uniqueId,0x90,deck,0x19,0x00);// cue
		sendMidi(uniqueId,0x90,deck,0x1A,0x00);// play
		// effects
		//sendMidi(uniqueId,0x90,deck,0x1B,0x00);// x-param
		//sendMidi(uniqueId,0x90,deck,0x1C,0x00);// y-param
		//sendMidi(uniqueId,0x90,deck,0x1D,0x00);// select
		sendMidi(uniqueId,0x90,deck,0x33,0x00);// effect on
		//
		sendMidi(uniqueId,0x90,deck,0x34,0x00);// scratch mode
		sendMidi(uniqueId,0x90,deck,0x35,0x00);// monitor
		sendMidi(uniqueId,0x90,deck,0x36,0x00);// seek mode
		sendMidi(uniqueId,0x90,deck,0x37,0x00);// shift
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x38,0x00);// onbeat/sync
		sendMidi(uniqueId,0x90,deck,0x39,0x00);// keylock
		sendMidi(uniqueId,0x90,deck,0x3A,0x00);// pitch on
		//sendMidi(uniqueId,0x90,deck,0x3B,0x00);// pitch bend -
		//sendMidi(uniqueId,0x90,deck,0x3C,0x00);// pitch bend +
		sendMidi(uniqueId,0x90,deck,0x3D,0x00);// to deck
		
		sendMidi(uniqueId,0x90,deck,0x41,0x00);// save to
		sendMidi(uniqueId,0x90,deck,0x42,0x00);// sampler
		sendMidi(uniqueId,0x90,deck,0x43,0x00);// bpm
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x44,0x00);// tap
		sendMidi(uniqueId,0x90,deck,0x45,0x00);// sampler 1
		sendMidi(uniqueId,0x90,deck,0x46,0x00);// sampler 2
		sendMidi(uniqueId,0x90,deck,0x47,0x00);// sampler 3
		sendMidi(uniqueId,0x90,deck,0x48,0x00);// sampler 4
		
		// effects leds
		sendMidi(uniqueId,0x90,deck,0x2B,0x00);
		sendMidi(uniqueId,0x90,deck,0x2C,0x00);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		sendMidi(uniqueId,0x90,deck,0x2D,0x00);
		sendMidi(uniqueId,0x90,deck,0x2E,0x00);
		sendMidi(uniqueId,0x90,deck,0x2F,0x00);
		sendMidi(uniqueId,0x90,deck,0x30,0x00);
		sendMidi(uniqueId,0x90,deck,0x31,0x00);
		sendMidi(uniqueId,0x90,deck,0x32,0x00);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
}
//----------------------------------------------------------------------------- 
// 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 0x05: if(channel==2) call('setCrossfader', data2); break;
		//case 0x3D: call('setCuePflMix', data2); break;
		case 0x01: if(channel==2) call('lbMoveCursor', data2-0x40); break;
		case 0x02: if(channel==2) call('setCuePgmMix', data2); break;
		case 0x03: if(channel==2) call('setMonitorGain', data2); break;
		case 0x04: if(channel==2) call('setCFCurve', data2); break;
		case 0x13: if(channel==0) call('setMicGain', data2);else call('setMasterGain', data2); break;
		// per deck
		case 0x11: 
			var tmpc = channel%2;
			// light off the previous led
			sendMidi(uniqueId,0x90,channel,0x2B+effectsSelected[tmpc],0x00);
			// move next
			if(data2<0x40)
			{
				effectsSelected[tmpc] = effectsSelected[tmpc] - 1; if(effectsSelected[tmpc]<0) effectsSelected[tmpc] = 5;// only 6 fx enabled
				//effectsSelected[tmpc] = effectsSelected[tmpc] - 1; if(effectsSelected[tmpc]<0) effectsSelected[tmpc] += 8;
			}else
			{
				effectsSelected[tmpc] = (effectsSelected[tmpc] + 1) % 6;// only 6 fx enabled
				//effectsSelected[tmpc] = (effectsSelected[tmpc] + 1) % 8;
			}
			// light up the new led
			sendMidi(uniqueId,0x90,channel,0x2B+effectsSelected[tmpc],0x7F);
			// modify the led state depending on the selected fx
			sendMidi(uniqueId,0x90,channel,0x33,(effectsStatus[tmpc*8 + effectsSelected[tmpc]] ? 0x7F : 0x00));// effect on
			break;
		
		case 0x16: call('setDeckVolume', channel, data2); break;
		case 0x12: if(pitchStatus[channel]) call('setDeckPitch', channel, data2); break;// increment mode
		case 0x15: call('setDeckEqLow', channel, data2); break;
		case 0x14: call('setDeckEqHigh', channel, data2); break;
		case 0x19: 
			//var jogWheelStatus=[0,0,0,0];// 0 means normal mode, 1 scratch mode, 2 seek mode
			var tmpIncrement = data2-0x40;
			switch(jogWheelStatus[channel])
			{
			case 1: // scratch mode only (no matter if it's playing or not)
				call('scratchDeckJW', channel, data2-0x40, 75); // params: (deck, increment, total positions per complete revolution)
				break;
			case 2: // jog seek mode only (no matter if it's playing or not)
				for(var i=tmpIncrement; i<0; i++) call('deckSkipBeatPrev', channel);
				for(var i=0; i<tmpIncrement; i++) call('deckSkipBeatNext', channel);
				break;
			default:// normal mode (bend when playing / scratch when paused)
				call('moveDeckJogWheel', channel, data2-0x40, 75); // params: (deck, increment, total positions per complete revolution)
			}
			break;
		
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		case 0x42: if(data2>0x3F) call('samplesSel', 1); break; // global
		// all are per deck
		case 0x01: if((channel==2)&&(data2>0x3F)) call('lbToggleSelect', data2); break; // global		
		case 0x09: call('deckCuePos1', channel, data2); break;
		case 0x0A: call('deckCuePos2', channel, data2); break;
		case 0x0B: call('deckCuePos3', channel, data2); break;
		case 0x0C: call('deckCuePos4', channel, data2); break;		
		case 0x0D: call('deckLoopLess', channel, data2); break;
		case 0x15: call('deckLoopMore', channel, data2); break;
		case 0x16: call('deckLoopInEnd', channel, data2); break;
		case 0x17: call('deckLoopExit', channel, data2); break;
		case 0x18: call('deckLoopReloop', channel, data2); break;
		case 0x19: call('deckCue', channel, data2); break;
		case 0x1A: call('deckPlayPause', channel, data2); break;
		
		case 0x33: 
			switch(effectsSelected[channel%2])
			{
			case 0: call('deckFxFlanger', channel, data2); break;
			case 1: call('deckFxEcho', channel, data2); break;
			case 2: call('deckFxDelay', channel, data2); break;
			case 3: call('deckFxReverb', channel, data2); break;
			case 4: call('deckFxPan', channel, data2); break;
			case 5: call('deckFxPhaser', channel, data2); break;
			//case 6: call('deckFxNone', channel, data2); break;
			//case 7: call('deckFxNone', channel, data2); break;
			}
			break;
		
		case 0x34: // JW Scratch
			//var jogWheelStatus=[0,0,0,0];// 0 means normal mode, 1 scratch mode, 2 seek mode
			if(data2>0x3F) // only on button press
			{
				// test if we're already in this mode and if so reset it to default
				if(jogWheelStatus[channel]==1)
				{
					jogWheelStatus[channel] = 0;
				}else
				{
					if(jogWheelStatus[channel]==2) // see if we were in seek mode (so light off that led)
						sendMidi(uniqueId,0x90,channel,0x36,0x00);
					jogWheelStatus[channel] = 1;
				}
				sendMidi(uniqueId,0x90,channel,0x34,((jogWheelStatus[channel]==1) ? 0x7F : 0x00));
			}
			break;
			
		case 0x35: call('deckMonitor', channel, data2); break;
			
		case 0x36: // JW Seek Mode
			if(data2>0x3F) // only on button press
			{
				// test if we're already in this mode and if so reset it to default
				if(jogWheelStatus[channel]==2)
				{
					jogWheelStatus[channel] = 0;
				}else
				{
					if(jogWheelStatus[channel]==1) // see if we were in scratch mode (so light off that led)
						sendMidi(uniqueId,0x90,channel,0x34,0x00);
					jogWheelStatus[channel] = 2;
				}
				sendMidi(uniqueId,0x90,channel,0x36,((jogWheelStatus[channel]==2) ? 0x7F : 0x00));
			}
			break;

		case 0x38: call('deckSync', channel, data2); break;
		case 0x39: call('deckKeyLock', channel, data2); break;			
		case 0x3A: // Pitch ON
			if(data2>0x3F) // only on button press
			{
				pitchStatus[channel] = (pitchStatus[channel] + 1) % 2;// toggle state between 0 and 1
				sendMidi(uniqueId,0x90,channel,0x3A,(pitchStatus[channel] ? 0x7F : 0x00));
			}
			break;				
		case 0x3B: call('deckBendDown', channel, data2); break;
		case 0x3C: call('deckBendUp', channel, data2); break;
		case 0x3D: if((channel<2)&&(data2>0x3F)) call('deckLBLoad', channel, data2); break;

		case 0x41: call('deckSaveBpm', channel, data2); break;
		case 0x43: call('deckEditBpm', channel, data2); break;
		case 0x44: call('deckTapBpm', channel, data2); break;
		
		case 0x45: if(data2>0x3F){ if(channel%2==0) call('samplerPlay', 1);else call('samplerPlay', 5);} break;
		case 0x46: if(data2>0x3F){ if(channel%2==0) call('samplerPlay', 2);else call('samplerPlay', 6);} break;
		case 0x47: if(data2>0x3F){ if(channel%2==0) call('samplerPlay', 3);else call('samplerPlay', 7);} break;
		case 0x48: if(data2>0x3F){ if(channel%2==0) call('samplerPlay', 4);else call('samplerPlay', 8);} 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);
	var nameLen = name.length;
	if(deck>=2) return;
	if(name=='cue') 	sendMidi(uniqueId,0x90,deck,0x19,(param1 ? 0x7F : 0x00));
	if(name=='play') 	sendMidi(uniqueId,0x90,deck,0x1A,(param1 ? 0x7F : 0x00));
	if(name=='keyLock')	sendMidi(uniqueId,0x90,deck,0x39,(param1 ? 0x7F : 0x00));
	//if(name=='pitchIs0')sendMidi(uniqueId,0x90,deck,0x3A,(param1 ? 0x7F : 0x00));
	if(name=='loopSize')
	{
		// turn off last led (if any is on)
		if(previousAutoLoopLightLed[deck]>-1)
			sendMidi(uniqueId,0x90,deck,previousAutoLoopLightLed[deck],0x00);
		// calculate the new led to power on
		switch(param1)
		{
		case   16: previousAutoLoopLightLed[deck] = 0x0E; break;// 1/4 beat
		case   32: previousAutoLoopLightLed[deck] = 0x0F; break;// 1/2 beat
		case   64: previousAutoLoopLightLed[deck] = 0x10; break;// 1 beat
		case  128: previousAutoLoopLightLed[deck] = 0x11; break;// 2 beats
		case  256: previousAutoLoopLightLed[deck] = 0x12; break;// 4 beats
		case  512: previousAutoLoopLightLed[deck] = 0x13; break;// 8 beats
		case 1024: previousAutoLoopLightLed[deck] = 0x14; break;// 16 beats
		default:   previousAutoLoopLightLed[deck] = -1;
		}
		// actually light the led
		if(previousAutoLoopLightLed[deck]>-1)	
			sendMidi(uniqueId,0x90,deck,previousAutoLoopLightLed[deck],0x7F);
	}
	if(name=='loopIn')
	{
		sendMidi(uniqueId,0x90,deck,0x16,(param1 ? 0x7F : 0x00));// in
		// activate blinking for the LoopIn led (so the user knows to press it again)
		if(param1) loopingInBlinkLed[deck] = 0x16;else loopingInBlinkLed[deck] = -1;
		loopingInBlinkLedStatus[deck] = 0;
	}
	if(name=='looping')
	{
		sendMidi(uniqueId,0x90,deck,0x16,(param1 ? 0x7F : 0x00));// in
		sendMidi(uniqueId,0x90,deck,0x17,(param1 ? 0x7F : 0x00));// out
	}
	if(name=='monitor')	sendMidi(uniqueId,0x90,deck,0x35,(param1 ? 0x7F : 0x00));
	if(name=='cuepos1')	sendMidi(uniqueId,0x90,deck,0x09,(param1 ? 0x7F : 0x00));
	if(name=='cuepos2')	sendMidi(uniqueId,0x90,deck,0x0A,(param1 ? 0x7F : 0x00));
	if(name=='cuepos3')	sendMidi(uniqueId,0x90,deck,0x0B,(param1 ? 0x7F : 0x00));
	if(name=='cuepos4')	sendMidi(uniqueId,0x90,deck,0x0C,(param1 ? 0x7F : 0x00));
	if(name=='onbeat')	sendMidi(uniqueId,0x90,deck,0x38,(param1 ? 0x7F : 0x00));
	
	//var samplerBlinkLedStatus=[0,0,0,0,0,0,0,0];// 2 decks leds, each with 4 samplers // 0 means off; 1 means on; 2 means blink on; 3 means blink off;
	if(nameLen==8)
	{
		var name1 = name.substr(0, nameLen-1);
		if(name1=='sampler')
		{
			var samplerIdx = parseInt(name.charAt(nameLen-1))-1;
			//debug('notif sampler strLen='+nameLen+' idx='+samplerIdx + ' char='+name.charAt(nameLen-1));
			if(!param1) 
			{
				samplerBlinkLedStatus[samplerIdx] = 0;
				sendMidi(uniqueId,0x90,Math.floor(samplerIdx/4),0x45+(samplerIdx%4),0x00);
				// instead of Math.floor(19/4), parseInt(19/4) = 4 can also be used
			}else
			{
				sendMidi(uniqueId,0x90,Math.floor(samplerIdx/4),0x45+(samplerIdx%4),0x7F);
				if(param2>0) samplerBlinkLedStatus[samplerIdx] = 2;else samplerBlinkLedStatus[samplerIdx] = 1;
			}
		}
	}	
	// effects
	if(deck<2)
	{
		var fxChanged=-1;
		if(name=='fxFlanger')	{ fxChanged = 0; effectsStatus[deck*8 + fxChanged] = param1; }
		if(name=='fxEcho')		{ fxChanged = 1; effectsStatus[deck*8 + fxChanged] = param1; }
		if(name=='fxDelay')		{ fxChanged = 2; effectsStatus[deck*8 + fxChanged] = param1; }
		if(name=='fxReverb')	{ fxChanged = 3; effectsStatus[deck*8 + fxChanged] = param1; }
		if(name=='fxPan')		{ fxChanged = 4; effectsStatus[deck*8 + fxChanged] = param1; }
		if(name=='fxPhaser')	{ fxChanged = 5; effectsStatus[deck*8 + fxChanged] = param1; }
		//if(name=='fxNone')	{ fxChanged = 6; effectsStatus[deck*8 + fxChanged] = param1; }
		//if(name=='fxNone')	{ fxChanged = 7; effectsStatus[deck*8 + fxChanged] = param1; }
		// modify the led state depending on the selected fx
		if(effectsSelected[deck]==fxChanged) sendMidi(uniqueId,0x90,deck,0x33,(effectsStatus[deck*8 + fxChanged] ? 0x7F : 0x00));// effect on
	}	
}
//----------------------------------------------------------------------------- 
// 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)
{
	// limit the amount of time this gets executed
	timer1++; if(timer1<4) return;else timer1 = 0;
	//debug('timerTick ['+uniqueId+']');
	for(var deck=0; deck<2; deck++)
	{
		if(loopingInBlinkLed[deck]!=-1)
		{
			if(loopingInBlinkLedStatus[deck]==0) loopingInBlinkLedStatus[deck] = 0x7F;else loopingInBlinkLedStatus[deck] = 0;
			sendMidi(uniqueId,0x90,deck,0x16,loopingInBlinkLedStatus[deck]);// in
		}
		// sampler leds
		//var samplerBlinkLedStatus=[0,0,0,0,0,0,0,0];// 2 decks leds, each with 4 samplers // 0 means off; 1 means on; 2 means blink on; 3 means blink off;		
		for(var i=0; i<4; i++) 
		{
			var ledIdx = deck*4+i;
			// test if blinking is active
			if(samplerBlinkLedStatus[ledIdx]>1)
			{
				if(samplerBlinkLedStatus[ledIdx]==2) samplerBlinkLedStatus[ledIdx] = 3;else samplerBlinkLedStatus[ledIdx] = 2;
				sendMidi(uniqueId,0x90,deck,0x45+i,((samplerBlinkLedStatus[ledIdx]==2) ? 0x7F : 0x00));
			}
		}
	}
}
//----------------------------------------------------------------------------- 
