//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2014 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Hercules DJ Control Wave'
//----------------------------------------------------------------------------- 
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 "DJControl Wave";
}
//----------------------------------------------------------------------------- 
// 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
	//if(osId==1) return false;
	return "00014E020011";
	// 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 10 00 01 00 00 00 F7 -- Hercules DJ Control Air+ complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 11 00 01 00 00 00 F7 -- Hercules DJ Control Wave complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 0A 00 01 00 00 00 F7 -- Hercules DJ4Set complete sysex
	// F0 7E 00 06 02 00 01 4E 02 00 09 00 01 00 00 00 F7 -- Hercules DJ Console 4-Mx
}
//----------------------------------------------------------------------------- 
// 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 "DJControlWave";
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//if(osId==1) return "DJControlWave";
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
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;
//----------------------------------------------------------------------------- 
// 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 DJ Control Wave ['+uniqueId+']');// this outputs a string to DebugView app on Win	
	//sendMidi(uniqueId, status, channel, data1, data2);
	for(var deck=0; deck<2; deck++)
	{
		// stop spinning the jog-wheels' leds
		setJogWheelSpinLeds_Special(uniqueId, deck, 2);
	}
	sendMidi(uniqueId,0xB0,0,0x7F, 0x7F);// request all analog controls' current positions
	//------------------------------------
	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
	for(var deck=0; deck<2; deck++)
	{
		// stop spinning the jog-wheels' leds
		setJogWheelSpinLeds_Special(uniqueId, deck, 2);
		//sendMidi(uniqueId,0x90,0,0x0A, 0x02);// SPIN_LED_A
		//sendMidi(uniqueId,0x90,0,0x1C, 0x02);// SPIN_LED_B
		// reset VU-meters
		setVUValueForDeck(uniqueId, deck, -90);
		//setVUValueForDeck(uniqueId, 1, -90);
	}
	setMasterVolumeLeds(uniqueId, 0);
	//------------------------------------
	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 0x01: call('setCrossfader', data2); break;
		/*
		case 0x14: // move track A
		case 0x15: // move track B
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('lbMoveCursor', val1);
			break;//library curser up down
		*/
		case 0x06: // master volume (global)
			call('setMasterGain', data2);
			setMasterVolumeLeds(uniqueId, 8*data2/0x7F);
			break;
		
		// per deck
		// deck A
		case 0x02: call('setDeckPitch', 0, 0x7F - data2); break;
		case 0x04: call('setDeckVolume', 0, data2); break;
		case 0x09: call('setDeckEqLow', 0, data2); break;
		case 0x08: call('setDeckEqMid', 0, data2); break;
		case 0x07: call('setDeckEqHigh', 0, data2); break;
		case 0x10: // move (bend when play / scratch when pause) // params: (deck, increment, total positions per complete revolution)  
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('moveDeckJogWheel', 0, val1, 512);
			break;
		case 0x12: // grab/scratch (always) // params: (deck, increment, total positions per complete revolution)  
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('scratchDeckJW', 0, val1, 512);
			break;
		case 0x14: // resize track A
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(val1<0)
			{
				call('deckLoopLess', 0, 0x7F);
				call('deckLoopLess', 0, 0x00);
			}else
			{
				call('deckLoopMore', 0, 0x7F);
				call('deckLoopMore', 0, 0x00);
			}
			break;

		// deck B
		case 0x03: call('setDeckPitch', 1, 0x7F - data2); break;
		case 0x05: call('setDeckVolume', 1, data2); break;		
		case 0x0C: call('setDeckEqLow', 1, data2); break;
		case 0x0B: call('setDeckEqMid', 1, data2); break;
		case 0x0A: call('setDeckEqHigh', 1, data2); break;
		case 0x11: // move (bend when play / scratch when pause) // params: (deck, increment, total positions per complete revolution)  
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('moveDeckJogWheel', 1, val1, 512);
			break;
		case 0x13: // grab/scratch (always) // params: (deck, increment, total positions per complete revolution)  
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('scratchDeckJW', 1, val1, 512);
			break;
		case 0x15: // resize track B
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(val1<0)
			{
				call('deckLoopLess', 1, 0x7F);
				call('deckLoopLess', 1, 0x00);
			}else
			{
				call('deckLoopMore', 1, 0x7F);
				call('deckLoopMore', 1, 0x00);
			}
			break;
				
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		/*
		// these are now used as Monitor (PFL) buttons
		case 0x10: // A
		case 0x22: // B
			if(data2>0x3F) call('lbToggleSelect', data2); 
			sendMidi(uniqueId,0x90,0,data1,data2);// enable led temporary (while pressed)
			break;
		*/

		// deck A
		case 0x11: 
			if(data2>0x3F) 
			{
				if(getValue('looping', 0)) 
				{
					call('deckLoopExit', 0, 0x7F);
					call('deckLoopExit', 0, 0x00);
				}else 
				{
					call('deckLoop4', 0, 0x7F);
					call('deckLoop4', 0, 0x00);
				}
			}
			break;
		//case 0x11: if(data2>0x3F) call('deckLBLoad', 0, data2); sendMidi(uniqueId,0x90,0,data1,data2); break;
		case 0x12: call('holdDeckJogWheel', 0, data2); break;
		case 0x0D: call('deckPlayPause', 0, data2); break;
		case 0x0F: call('deckCue', 0, data2); break;
		case 0x0E: call('deckSync', 0, data2); break;
		
		case 0x01: if(data2>0x3F) call('samplerPlay', 1, data2); break;
		case 0x02: if(data2>0x3F) call('samplerPlay', 2, data2); break;
		case 0x03: if(data2>0x3F) call('samplerPlay', 3, data2); break;
		case 0x04: call('deckFxFlanger', 0, data2); break;
		case 0x05: call('deckFxEcho', 0, data2); break;
		case 0x06: call('deckFxBeatwaw', 0, data2); break;
		case 0x07: call('deckCuePos1', 0, data2); break;
		case 0x08: call('deckCuePos2', 0, data2); break;
		case 0x09: call('deckCuePos3', 0, data2); break;
		case 0x10: call('deckMonitor', 0, data2); break;

		// deck B
		case 0x23: 
			if(data2>0x3F) 
			{
				if(getValue('looping', 1)) 
				{
					call('deckLoopExit', 1, 0x7F);
					call('deckLoopExit', 1, 0x00);
				}else 
				{
					call('deckLoop4', 1, 0x7F);
					call('deckLoop4', 1, 0x00);
				}
			}
			break;
		//case 0x23: if(data2>0x3F) call('deckLBLoad', 1, data2); sendMidi(uniqueId,0x90,0,data1,data2); break;
		case 0x24: call('holdDeckJogWheel', 1, data2); break;
		case 0x1F: call('deckPlayPause', 1, data2); break;
		case 0x21: call('deckCue', 1, data2); break;
		case 0x20: call('deckSync', 1, data2); break;

		case 0x13: if(data2>0x3F) call('samplerPlay', 5, data2); break;
		case 0x14: if(data2>0x3F) call('samplerPlay', 6, data2); break;
		case 0x15: if(data2>0x3F) call('samplerPlay', 7, data2); break;
		case 0x16: call('deckFxFlanger', 1, data2); break;
		case 0x17: call('deckFxEcho', 1, data2); break;
		case 0x18: call('deckFxBeatwaw', 1, data2); break;
		case 0x19: call('deckCuePos1', 1, data2); break;
		case 0x1A: call('deckCuePos2', 1, data2); break;
		case 0x1B: call('deckCuePos3', 1, data2); break;
		case 0x22: call('deckMonitor', 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=='beatPos'){ setBeatPosLed(uniqueId, deck, param1); return;}
	if(name=='play') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x0D:0x1F,(param1 ? 0x7F : 0x00));
	if(name=='cue') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x0F:0x21,(param1 ? 0x7F : 0x00));
	if(name=='onbeat') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x0E:0x20,(param1 ? 0x7F : 0x00));// sync
	if(name=='monitor')		sendMidi(uniqueId,0x90,0,(deck==0)?0x10:0x22,(param1 ? 0x7F : 0x00));// 4-squares PFL button
	if(name=='looping')		sendMidi(uniqueId,0x90,0,(deck==0)?0x11:0x23,(param1 ? 0x7F : 0x00));// loop

	if(name=='fxFlanger') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x04:0x16,(param1 ? 0x7F : 0x00));
	if(name=='fxEcho') 		sendMidi(uniqueId,0x90,0,(deck==0)?0x05:0x17,(param1 ? 0x7F : 0x00));
	if(name=='fxBeatwaw')   sendMidi(uniqueId,0x90,0,(deck==0)?0x06:0x18,(param1 ? 0x7F : 0x00));

	if(name=='cuepos1') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x07:0x19,(param1 ? 0x7F : 0x00));
	if(name=='cuepos2') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x08:0x1A,(param1 ? 0x7F : 0x00));
	if(name=='cuepos3') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x09:0x1B,(param1 ? 0x7F : 0x00));
	
	if(name=='killLow') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x5A:0x5D,(param1 ? 0x7F : 0x00));
	if(name=='killMid') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x59:0x5C,(param1 ? 0x7F : 0x00));
	if(name=='killHigh') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x58:0x5B,(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) 
			if(param2<=0)
			{
				samplerBlinkLedStatus[samplerIdx] = 0;
				if(name=='sampler1') sendMidi(uniqueId,0x90,0,0x01,0x00);
				if(name=='sampler2') sendMidi(uniqueId,0x90,0,0x02,0x00);
				if(name=='sampler3') sendMidi(uniqueId,0x90,0,0x03,0x00);
				//if(name=='sampler4') sendMidi(uniqueId,0x90,0,0x4B,0x00);
				if(name=='sampler5') sendMidi(uniqueId,0x90,0,0x13,0x00);
				if(name=='sampler6') sendMidi(uniqueId,0x90,0,0x14,0x00);
				if(name=='sampler7') sendMidi(uniqueId,0x90,0,0x15,0x00);
				//if(name=='sampler8') sendMidi(uniqueId,0x90,0,0x53,0x00);
				// instead of Math.floor(19/4), parseInt(19/4) = 4 can also be used
			}else
			{
				if(name=='sampler1') sendMidi(uniqueId,0x90,0,0x01,0x7F);
				if(name=='sampler2') sendMidi(uniqueId,0x90,0,0x02,0x7F);
				if(name=='sampler3') sendMidi(uniqueId,0x90,0,0x03,0x7F);
				//if(name=='sampler4') sendMidi(uniqueId,0x90,0,0x4B,0x7F);
				if(name=='sampler5') sendMidi(uniqueId,0x90,0,0x13,0x7F);
				if(name=='sampler6') sendMidi(uniqueId,0x90,0,0x14,0x7F);
				if(name=='sampler7') sendMidi(uniqueId,0x90,0,0x15,0x7F);
				//if(name=='sampler8') sendMidi(uniqueId,0x90,0,0x53,0x7F);
				if(param2>0) samplerBlinkLedStatus[samplerIdx] = 2;else samplerBlinkLedStatus[samplerIdx] = 1;
			}
		}
	}
}
//----------------------------------------------------------------------------- 
var startLed = 0x08;
var totalLeds = 0x03;
// mode - 1 pause/unpause; 2 turn off everything;
function setJogWheelSpinLeds_Special(uniqueId, deck, mode)
{
	if(mode==1)
	{
		var sysex1=[0xF0, 0x00, 0x01, 0x4E, 0x11, 0x02, 0x1B, 0x00, deck, 0x00, startLed, totalLeds, 0x7F, 0x3F, 0xF7];
		sendMidiSysEx(uniqueId, sysex1, sysex1.length);
	}
	if(mode==2)
	{
		var sysex1=[0xF0, 0x00, 0x01, 0x4E, 0x11, 0x02, 0x1B, 0x00, deck, 0x00, startLed, totalLeds, 0, 0, 0xF7];
		sendMidiSysEx(uniqueId, sysex1, sysex1.length);
	}
}
//----------------------------------------------------------------------------- 
function setJogWheelSpinLeds(uniqueId, deck, rpm, reverse)
{
/*
	SYSEX Packet Format
	The packet format is as follows:
	F0 00 01 4E DID OP PROP0 PROP1 SEQ0 SEQ1 D0 D1 D2 D3 F7

	Where:
	00 01 4E: Hercules manufacturer ID
	DID: Device ID. The device ID for the DJControl Wave is 17 ( 0x11 )
	OP: Operation. (01 get; 02 set; 03 reportget; 04 report error; 05 report success; 06 changed property value;)
	PROP0-PROP1: Property of interest.
	SEQ0-SEQ1: Sequence number of property.
	D0-D3: Data bytes of property of interest, where applicable (They are ìdonít caresî otherwise).
	
	//---------------	
	D0.0 ñ D0.3 Start LED : 0-F maps to LED 1- 16
	D0.6 Direction : 1 is CCW, 0 is CW
	D1 ñ Number of LEDs : 01-0F Number of LEDs which will spin at the requested rate 
	D2 ñ D3 Step delay in mS : 13 bit number 0 ñ 1FFF encoded in the last 7 bits of each byte, little endian (7F 3F would be the maximum value of 1FFF encoded in D2-D3). 
		Values 0 and 1FFF are special cases, where 0 turns off spin and the LEDís, while 1FFF pauses and restarts the spin pattern.
*/
	// send sysex init
	reverse = reverse << 6;
	// D2 is the least significant 7 bits, and D3 is the most significant 7 bits
	var d2d3 = 3750 / rpm;
	var d2 = d2d3 % 0x80;
	var d3 = d2d3 / 0x80;
	var sysex1=[0xF0, 0x00, 0x01, 0x4E, 0x11, 0x02, 0x1B, 0x00, deck, 0x00, startLed | reverse, totalLeds, d2, d3, 0xF7];
	// F0 00 01 4E 11 02 1B 00 00 00 08 04 7F 3F F7 // pause
	// F0 00 01 4E 11 02 1B 00 00 00 08 04 7F 3F F7 // un-pause
	// F0 00 01 4E 11 02 1B 00 00 00 48 04 2A 01 F7 // reverse
	// D2-D3 = 3750 / RPM
	sendMidiSysEx(uniqueId, sysex1, sysex1.length);// on
}
//----------------------------------------------------------------------------- 
// 'value' is 0..8 (0 -- all are off)
var masterLast=[0,0,0,0,0,0,0,0];// used to save the last state
function setMasterVolumeLeds(uniqueId, value)
{
	for(var i=0; i<8; i++)
	{
		var masterCurrent = (value>i)?0x7F:0x00;
		if(masterLast[i] != masterCurrent)
		{
			masterLast[i] = masterCurrent;
			sendMidi(uniqueId,0x90,0,0x50+i,masterLast[i]);// 0x50 left .. 0x57 right
		}
	}	
	/*
	sendMidi(uniqueId,0x90,0,0x50, (value>0?0x7F:0x00));// VOL_LEV_1
	sendMidi(uniqueId,0x90,0,0x51, (value>1?0x7F:0x00));// VOL_LEV_2
	sendMidi(uniqueId,0x90,0,0x52, (value>2?0x7F:0x00));// VOL_LEV_3
	sendMidi(uniqueId,0x90,0,0x53, (value>3?0x7F:0x00));// VOL_LEV_4
	sendMidi(uniqueId,0x90,0,0x54, (value>4?0x7F:0x00));// VOL_LEV_5
	sendMidi(uniqueId,0x90,0,0x55, (value>5?0x7F:0x00));// VOL_LEV_6
	sendMidi(uniqueId,0x90,0,0x56, (value>6?0x7F:0x00));// VOL_LEV_7
	sendMidi(uniqueId,0x90,0,0x57, (value>7?0x7F:0x00));// VOL_LEV_8
	*/
}
//----------------------------------------------------------------------------- 
var vuLast=[[0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0]];// used to save the last state
//-----------------------------------------------------------------------------
function setVUValueForDeck(uniqueId, deck, dbValue)
{
	var vuCurrent=[0,0,0,0,0,0,0,0];// temp
	if(dbValue>-36) vuCurrent[0] = 0x7F;
	if(dbValue>-20) vuCurrent[1] = 0x7F;
	if(dbValue>-12) vuCurrent[2] = 0x7F;
	if(dbValue>-8)  vuCurrent[3] = 0x7F;
	if(dbValue>-4)  vuCurrent[4] = 0x7F;
	if(dbValue>-1)  vuCurrent[5] = 0x7F;
	for(var i=0; i<6; i++)
	{
		if(vuLast[deck][i] != vuCurrent[i])
		{
			vuLast[deck][i] = vuCurrent[i];
			sendMidi(uniqueId,0x90,0,((deck==0)?0x24:0x2A)+i,vuLast[deck][i]);// 0x24 bottom .. 0x29 top
		}
	}	
}
//----------------------------------------------------------------------------- 
// 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)
var lastPitch=[0,0,0,0];
var lastPlay=[0,0,0,0];
var lastReverse=[0,0,0,0];
function timerTick(uniqueId)
{
	//debug('timerTick ['+uniqueId+']');
	// VU-meters
	for(var deck=0; deck<2; deck++)
	{
		var dbValue = getValue('vumeterDeck', deck);// float dB
		setVUValueForDeck(uniqueId, deck, dbValue);
		//
		var pitch = getValue('pitch', deck);// pitch (100th of percents)
		var play = getValue('play', deck);
		var reverse = getValue('reverse', deck);
		if((pitch!=lastPitch[deck])||(play!=lastPlay[deck])||(reverse!=lastReverse[deck]))
		{
			var rpm = 33.333 * (10000.0 + pitch)/10000.0;
			//if(deck==0) debug("pitch="+((10000.0 + pitch)/10000.0)+" rpm="+rpm);
			//function setJogWheelSpinLeds(uniqueId, deck, rpm, reverse)
			if(play!=lastPlay[deck])
			{
				setJogWheelSpinLeds_Special(uniqueId, deck, 1);// pause/unpause spinning
			}
			if(play) setJogWheelSpinLeds(uniqueId, deck, rpm, reverse);
			// save new values
			lastPitch[deck] = pitch;
			lastPlay[deck] = play;
			lastReverse[deck] = reverse;
		}
	}
	/*
	// 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<8; i++) 
	{
		// test if blinking is active
		if(samplerBlinkLedStatus[i]>1)
		{
			if(samplerBlinkLedStatus[i]==2) samplerBlinkLedStatus[i] = 3;else samplerBlinkLedStatus[i] = 2;
			switch(i)
			{
			case 0: sendMidi(uniqueId,0x90,0,0x01,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			case 1: sendMidi(uniqueId,0x90,0,0x02,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			case 2: sendMidi(uniqueId,0x90,0,0x03,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			//case 3: sendMidi(uniqueId,0x90,0,0x4B,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;			
			case 4: sendMidi(uniqueId,0x90,0,0x13,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			case 5: sendMidi(uniqueId,0x90,0,0x14,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			case 6: sendMidi(uniqueId,0x90,0,0x15,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			//case 7: sendMidi(uniqueId,0x90,0,0x53,((samplerBlinkLedStatus[i]==2) ? 0x7F : 0x00)); break;
			}
		}
	}
	*/
}
//----------------------------------------------------------------------------- 
