//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2013. All Rights Reserved. -----------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller ' Numark NS6'
//Author: Brandon James 2013 08 05
//----------------------------------------------------------------------------- 
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 "Numark Ns6";
}
//----------------------------------------------------------------------------- 
// 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 (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 "00013F7900";
	//full string:
	//00  F0 7E 00 06 02 00 01 3F  79 00 19 00 01 01 03 00 
	//10  7F 7F 7F 7F 00 4E 01 01  02 00 03 01 08 07 05 01
	// 20  05 08 07 09 F7
	//return false;
}
//----------------------------------------------------------------------------- 
// 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 "Midi port name ";// !!! 
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//return " midi port name ";// !!! MAKE SURE THIS IS INDEED OK !!!
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var delCue=[0,0,0,0];
var loopingInBlinkLed=[-1,-1,-1,-1];// -1 means disabled
var jogWheelsInScratchMode=[0,0,0,0];
var loopAuto=[0,0,0,0] // 0 = manual = 1 autoloop
var deckLayer=[0,0]; //layer 1/3 & 2/4
var sampleLoopMode=[0,0,0,0]; //loop control button toggle sampler or loop control 0==loop 1=sampler 1-4 or 5-8
var flanP1Level=[63]; //flange P1 level
var flanP2Level=[63]; //flange P2 level
var echoP1Level=[63]; //echo P1 level
var echoP2Level=[63]; //echo P2 level

var lastJWSignificantByte=[0,0,0,0];
var lastJWValue=[-1,-1,-1,-1];// [0..16383]
//----------------------------------------------------------------------------- 
// 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 ns6 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	callSendAllNotifications(uniqueId, true);
	for(var i=0; i<4; i++)
	{
		sendMidi(uniqueId,0xB0,i+1,24,0x02); //set auto loop to manual (white)
		sendMidi(uniqueId,0xB0,0,17,0x01); //set layer 1/3 to 1 white
		sendMidi(uniqueId,0xB0,0,40,0x01); //set layer 2/4 to 2 white
		sendMidi(uniqueId,0xB0,0,0x50,0x00); // set left side controls to deck 1
		sendMidi(uniqueId,0xB0,0,0x51,0x00); // set right side controls to deck 2
		sendMidi(uniqueId,0xB0,i+1,18,0x00); //scratch led's off
		sendMidi(uniqueId,0xB0,i+1,21,0x00); // loop  / sampler mode control off
		// set jog-wheel default mode
		sendMidi(uniqueId,0xB0,i+1,0x3B,0x02);// 0 load; 1 play; 2 scratch; // TEST !!!
		//sendMidi(uniqueId,0xB0,1,0x3A,0x01);// 0 all off; 1-21 led; >22 all leds on
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
}
//----------------------------------------------------------------------------- 
// 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 ns6 ['+uniqueId+']');
	callSendAllNotifications(uniqueId, false);
	for(var i=0; i<4; i++)
	{
		
		sendMidi(uniqueId,0xB0,i+1,24,0x00); //set auto loop to off (off)
		sendMidi(uniqueId,0xB0,i+1,78,0x00); //strip led's
		sendMidi(uniqueId,0xB0,0,54,0x00); //bpm strip off
		sendMidi(uniqueId,0xB0,0,17,0x00); //layer 1/3 off
		sendMidi(uniqueId,0xB0,0,40,0x00); //layer 2/4 off
		sendMidi(uniqueId,0xB0,i+1,18,0x00); //scratch led's off
		sendMidi(uniqueId,0xB0,i+1,21,0x00); // loop control off
		sendMidi(uniqueId,0xB0,i+1,0x3B,0x00); //platter LED pattern off
		sendMidi(uniqueId,0xB0,i+1,0x3A,0x00); //platter LED index off

		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
}
// some variables necessary only for this particular script


//----------------------------------------------------------------------------- 
// 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 0x44: call('lbMoveCursor', data2==0x01 ? 1:-1); break; //library curser up down	
		case 0x07: call('setCrossfader', data2); sendMidi(uniqueId,0xB0,0,54,(data2/11));  break; //crossfader bpm grid
		case 0x12: call('setCuePgmMix', data2); break; //cue/pgm mix
		case 0x42: call('setMonitorGain', data2); break; // monitor gain
		case 0x55: call('setCFCurve', data2); break; // monitor mix
		case 0x43: call('setMasterGain', data2); break; // master
		case 0x56: 
				{
				if(data2==0x7F) flanP1Level = flanP1Level - 2;// to left
				if(data2==0x01) flanP1Level = flanP1Level + 2;// to right
				if(flanP1Level<0) flanP1Level = 0;
				if(flanP1Level>0x7F) flanP1Level = 0x7F;
				call('deckFxFlangerP1',0, flanP1Level); 
				call('deckFxFlangerP1',1, flanP1Level);
				call('deckFxFlangerP1',2, flanP1Level);
				call('deckFxFlangerP1',3, flanP1Level);
				}break; // FX A Parameter sets all decks flanger P1
		case 0x57:
				{
				call('deckFxFlangerDW',0, data2); 
				call('deckFxFlangerDW',1, data2);
				call('deckFxFlangerDW',2, data2);
				call('deckFxFlangerDW',3, data2);
				}break; // FX A Parameter sets all decks flanger D/W		
		case 0x5A: 
				{
				if(data2==0x7F) flanP2Level = flanP2Level - 2;// to left
				if(data2==0x01) flanP2Level = flanP2Level + 2;// to right
				if(flanP1Level<0) flanP2Level = 0;
				if(flanP1Level>0x7F) flanP2Level = 0x7F;
				call('deckFxFlangerP2',0, flanP2Level); 
				call('deckFxFlangerP2',1, flanP2Level);
				call('deckFxFlangerP2',2, flanP2Level);
				call('deckFxFlangerP2',3, flanP2Level);
				}break; // FX A Parameter sets all decks flanger P2
		
		case 0x58: 
				{
				if(data2==0x7F) echoP1Level = echoP1Level - 2;// to left
				if(data2==0x01) echoP1Level = echoP1Level + 2;// to right
				if(flanP1Level<0) echoP1Level = 0;
				if(flanP1Level>0x7F) echoP1Level = 0x7F;
				call('deckFxEchoP1',0, echoP1Level); 
				call('deckFxEchoP1',1, echoP1Level);
				call('deckFxEchoP1',2, echoP1Level);
				call('deckFxEchoP1',3, echoP1Level);
				}break; // FX B Parameter sets all decks echo P1
		case 0x59:
				{
				call('deckFxEchoDW',0, data2); 
				call('deckFxEchoDW',1, data2);
				call('deckFxEchoDW',2, data2);
				call('deckFxEchoDW',3, data2);
				}break; // FX B Parameter sets all decks echo D/W		
		case 0x5A: 
				{
				if(data2==0x7F) echoP2Level = echoP2Level - 2;// to left
				if(data2==0x01) echoP2Level = echoP2Level + 2;// to right
				if(flanP1Level<0) echoP2Level = 0;
				if(flanP1Level>0x7F) echoP2Level = 0x7F;
				call('deckFxEchoP2',0, echoP2Level); 
				call('deckFxEchoP2',1, echoP2Level);
				call('deckFxEchoP2',2, echoP2Level);
				call('deckFxEchoP2',3, echoP2Level);
				}break; // FX B Parameter sets all decks echo P2		
		
		// decks
		case 0x01: call('setDeckPitch', channel-1, 0x7F-data2); break; //deck pitch
		
		case 0x00: // this contains the most significant 7-bits (this gets sent first)
			lastJWSignificantByte[channel-1] = data2;
			break;
		case 0x20: // this contains the least significant 7-bits
			var deck=channel-1;
			// params: (deck, increment, total positions per complete revolution) 
			var currentValue = (lastJWSignificantByte[deck] * 128) + data2;// now we have val1 in [0..16383]
			var val1 = 0;
			if(lastJWValue[deck]!=-1)
			{
				// eg. 1. prev value was 2345 and current value is 2367 => moved to the right 22
				// eg. 2. prev value was 2367 and current value is 2345 => moved to the left -22
				// eg. 3. prev value was 16382 and current value is 5 => moved to the right 7 (-16377)
				// eg. 4. prev value was 5 and current value is 16382 => moved to the left -7 (16377)
				val1 = currentValue - lastJWValue[deck];
				// correct for wrap-around
				if(val1<-8192) val1 = val1 + 16384;
				if(val1>8192) val1 = val1 - 16384;
			}
			lastJWValue[deck] = currentValue;// save value
			if(jogWheelsInScratchMode[deck]) call('scratchDeckJW', deck, val1, 3600);else call('moveDeckJogWheel', deck, val1, 3600); break;
			
		case 0x02: call('setDeckPos', channel-1, data2); break; //strip search
		case 0x50: if(data2==0x00) sendMidi(uniqueId,0xB0,0,17,0x01);else sendMidi(uniqueId,0xB0,0,17,0x02); break; //layer 1/3 notification
		case 0x51: if(data2==0x00) sendMidi(uniqueId,0xB0,0,40,0x01);else sendMidi(uniqueId,0xB0,0,40,0x02); break; //layer 2/4 notification
		
		//Mixer per deck inside out config on Mixer

		//deck A

			case 0x08: call('setDeckVolume', 0, data2); break;  // volume
			case 0x0C: call('setDeckGain', 0, data2); break;  // gain
			case 0x0B: call('setDeckEqHigh', 0, data2); break; //EQ Hi
			case 0x0A: call('setDeckEqMid', 0, data2); break; //EQ Mid
			case 0x09: call('setDeckEqLow', 0, data2); break; //EQ Low
		
		//deck B
		
			case 0x0D: call('setDeckVolume', 1, data2); break;	// volume
			case 0x11: call('setDeckGain', 1, data2); break;  // gain
			case 0x10: call('setDeckEqHigh', 1, data2); break; //EQ Hi
			case 0x0F: call('setDeckEqMid', 1, data2); break; //EQ Mid
			case 0x0E: call('setDeckEqLow', 1, data2); break; //EQ Low
		
		//deck C
			case 0x13: call('setDeckVolume', 2, data2); break;	// volume	
			case 0x17: call('setDeckGain', 2, data2); break;  // gain
			case 0x16: call('setDeckEqHigh', 2, data2); break; //EQ Hi
			case 0x15: call('setDeckEqMid', 2, data2); break; //EQ Mid
			case 0x14: call('setDeckEqLow', 2, data2); break; //EQ Low
			
		//deck D
			case 0x18: call('setDeckVolume', 3, data2); break;	// volume
			case 0x1C: call('setDeckGain', 3, data2); break;  // gain
			case 0x1B: call('setDeckEqHigh', 3, data2); break; //EQ Hi
			case 0x1A: call('setDeckEqMid', 3, data2); break; //EQ Mid
			case 0x19: call('setDeckEqLow', 3, data2); break; //EQ Low
				

		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		//if(status==0x90) data2 = 0x7F;
		//if(status==0x80) data2 = 0;
		switch(data1)
		{
		// global
		case 0x06: call('lbBrowserSelect', data2); break; //back button
		case 0x07: call('lbListSelect', data2); break; //fwd button
		case 0x08: call('lbToggleSelect', data2); break; //slection knob press
		case 0x00: call('phonesSplit', 0x7F); // TODO: no set phone split actions as of 4/30/13-> this toggles no matter current state
				   call('phonesSplit', 0x00); 
				   break; //phones split

		
		
		// decks
		case 0x0C: call('deckLBLoad', channel-1, data2); break; //load deck B/D
		case 0x0E: call('deckLBLoad', channel-1, data2); break; //load deck A/C
		case 0x11: call('deckPlayPause', channel-1, data2); break; //play pause all
		case 0x1C: if(loopAuto[channel-1]==0) call('deckReverse', channel-1, data2);else call('deckBrake', channel-1, data2); break; //reverse play / brake
		
		case 0x1A: if(data2>0x3F)
			{ 
				var currentPitchRange = getValue('pitchRange');
				currentPitchRange = currentPitchRange + 1; if(currentPitchRange>6) currentPitchRange = 2;
				call('setPitchRange', currentPitchRange);
			}
			break;
		
		case 0x33: call('setDeckMonitor', 2, data2); break; //deck C PFL
		case 0x31: call('setDeckMonitor', 0, data2); break; //deck A PFL
		case 0x32: call('setDeckMonitor', 1, data2); break; //deck B PFL
		case 0x34: call('setDeckMonitor', 3, data2); break; //deck D PFL		
		
		case 0x10: call('deckCue', channel-1, data2); break; //Cue all
		case 0x0F: call('deckSync', channel-1, data2); break; //sync all
		case 0x12: delCue[channel-1] = data2; break; //shift 
		case 0x27: if(data2>0x3F) loopAuto[channel-1] = (loopAuto[channel-1]+1)%2; sendMidi(uniqueId,0xB0,channel,24,(loopAuto[channel-1] ? 0x01 : 0x02)); break; //manual or auto loop mode 
		case 0x24: if(data2>0x3F) sampleLoopMode[channel-1] = (sampleLoopMode[channel-1]+1)%2; sendMidi(uniqueId,0xB0,channel,21,(sampleLoopMode[channel-1] ? 0x7F : 0x00)); break; //loop control or sampler
		case 0x28: if(loopAuto[channel-1]==0) call('deckLoopInEnd', channel-1, data2);else call('deckLoop1', channel-1, data2); break; //loop in/end or loop 1			
		case 0x29: if(loopAuto[channel-1]==0)
					{
					if(!getValue('looping', channel-1)) call('deckLoopInEnd', channel-1, data2);else call('deckLoopExit', channel-1, data2); //Loop //loop end or exit
					}else
					{
					call('deckLoop2', channel-1, data2);
					} break; 
		case 0x2A: if(loopAuto[channel-1]==1) call('deckLoop4', channel-1, data2); break; //Loop 4
		case 0x2B: if(loopAuto[channel-1]==0) call('deckLoopReloop', channel-1, data2);else call('deckLoop8', channel-1, data2); break; //reloop / loop 8
		case 0x22: if(sampleLoopMode[channel-1]==0) call('deckLoopLess', channel-1, data2);else call('samplerPlay', 1); break; // loop /2 / sampler 1 play
		case 0x23: if(sampleLoopMode[channel-1]==0) call('deckLoopMore', channel-1, data2);else call('samplerPlay', 2); break; // loop x2 or sampler 2 play
		case 0x25: if(sampleLoopMode[channel-1]==0) call('deckLoopNext', channel-1, data2);else call('samplerPlay', 3); break; //ask for loop previous / or sampler 3 play
		case 0x26: if(sampleLoopMode[channel-1]==0) call('deckLoopNext', channel-1, data2);else call('samplerPlay', 4); break; // loop next or sampler 4 play
		
		case 0x13: if(delCue[0]<0x7F) call('deckCuePos1', channel-1, data2);else
					  call('deckCuePos1Clear', channel-1, data2); break; // Cue 2 / delete cue 2
		
		case 0x14: if(delCue[0]<0x7F) call('deckCuePos2', channel-1, data2);else
					  call('deckCuePos2Clear', channel-1, data2); break; // Cue 2 / delete cue 2
		
		case 0x15: if(delCue[0]<0x7F) call('deckCuePos3', channel-1, data2);else
					  call('deckCuePos3Clear', channel-1, data2); break; // Cue3 / delete cue 3	
		
		case 0x16: if(delCue[0]<0x7F) call('deckCuePos4', channel-1, data2);else
					  call('deckCuePos4Clear', channel-1, data2); break; // Cue 4 / delete cue 4	
		
		case 0x17: if(delCue[0]<0x7F) call('deckCuePos5', channel-1, data2);else
					  call('deckCuePos5Clear', channel-1, data2); break; // Cue 5 / delete cue 5
		case 0x18: call('deckBendDown', channel-1, data2); break; //deck pitch bend down
		case 0x19: call('deckBendUp', channel-1, data2); break; //deck pitch bend up
		case 0x1F: call('deckSkipBeatPrev', channel-1, data2); break; //beat grid buttons->skip beat prev
		case 0x20: call('deckSkipBeatNext', channel-1, data2); break; //beat grid buttons->skip beat next
		case 0x1D: call('deckSkipBarNext', channel-1, data2); break; //skip button->skip bar
		case 0x1B: call('deckKeyLock', channel-1, data2); break; //MT
		case 0x1E: call('deckTapBpm', channel-1, data2); break; //Tap BPM
		case 0x21: if(data2>0x3F) 
						{
						jogWheelsInScratchMode[channel-1] = (jogWheelsInScratchMode[channel-1]+1)%2; sendMidi(uniqueId,0xB0,channel,18,(jogWheelsInScratchMode[channel-1] ? 0x7F : 0x00)); 
						}
						break;
		case 0x2C: if(jogWheelsInScratchMode[channel-1]) call('holdDeckJogWheel', channel-1, data2); break;
					
		//sampler Fx buttons A, B above each channel slider activate flanger or delay per deck effect
		
		case 0x3D: call('deckFxFlanger', 0, data2);  break; //flanger deck 1 (fx A button channel 1)
		case 0x3E: call('deckFxEcho', 0, data2);  break; // echo deck 1 (fx B button channel 1)
		
		case 0x3F: call('deckFxFlanger', 1, data2);  break; //flanger deck 2 (fx A button channel 2)
		case 0x40: call('deckFxEcho', 1, data2);  break; // echo deck 2 (fx B button channel 2)
		
		case 0x41: call('deckFxFlanger', 2, data2);  break; //flanger deck 3 (fx A button channel 3)
		case 0x42: call('deckFxEcho', 2, data2);  break; // echo deck 3 (fx B button channel 3)
		
		case 0x43: call('deckFxFlanger', 3, data2);  break; //flanger deck 4 (fx A button channel 4)
		case 0x44: call('deckFxEcho', 3, data2);  break; // echo deck 4 (fx B button channel 4)	
		
		//fx buttons A / B control for all decks
		//case 0x2D: 


		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<4)
	{
		if(name=='cue') 		 sendMidi(uniqueId,0xb0,deck+1,8,(param1 ? 0x7F : 0x00)); // cue
		if(name=='play') 		 sendMidi(uniqueId,0xB0,deck+1,9,(param1 ? 0x7F : 0x00)); //play 
		if(name=='onbeat') 		 sendMidi(uniqueId,0xB0,deck+1,7,(param1 ? 0x7F : 0x00)); //onbeat
		if(name=='reverse') 	 sendMidi(uniqueId,0xB0,deck+1,22,(param1 ? 0x7F : 0x00)); //reverse
		if(name=='brake') 	 	 sendMidi(uniqueId,0xB0,deck+1,22,(param1 ? 0x7F : 0x00)); //brake 
		if(name=='keyLock') 	 sendMidi(uniqueId,0xB0,deck+1,16,(param1 ? 0x7F : 0x00)); //mt
		if(name=='pitchIs0') 	 sendMidi(uniqueId,0xB0,deck+1,55,(param1 ? 0x7F : 0x00)); //0 pitch
		if(name=='cuepos1') 	 sendMidi(uniqueId,0xB0,deck+1,11,(param1 ? 0x7F : 0x00)); //cue 1
		if(name=='cuepos2') 	 sendMidi(uniqueId,0xB0,deck+1,12,(param1 ? 0x7F : 0x00)); //cue 2
		if(name=='cuepos3') 	 sendMidi(uniqueId,0xB0,deck+1,13,(param1 ? 0x7F : 0x00)); //cue 3
		if(name=='cuepos4') 	 sendMidi(uniqueId,0xB0,deck+1,14,(param1 ? 0x7F : 0x00)); //cue 4
		if(name=='cuepos5') 	 sendMidi(uniqueId,0xB0,deck+1,15,(param1 ? 0x7F : 0x00)); //cue 5
		if(name=='loopIn')
			{
			sendMidi(uniqueId,0xB0,deck+1,25,(param1 ? 0x02 : 0x00));// Loop In (on or off)
			// activate blinking for the LoopIn led (so the user knows to press it again)
			if(param1) loopingInBlinkLed[deck] = 0;else loopingInBlinkLed[deck] = -1;
			}
		
		if(name=='looping')
			{ 
					sendMidi(uniqueId,0xB0,deck+1,25,0x00);// Loop In (off)		
					sendMidi(uniqueId,0xB0,deck+1,26,(param1 ? 0x02 : 0x00));// Loop Out (on or off)
					sendMidi(uniqueId,0xB0,deck+1,28,(param1 ? 0x02 : 0x00));// Reloop (on or off)
			}
		if(name=='loopSize')
			{
							// calculate the new led to power on
				var l1, l2, l4, l8;
				l1 = l2 = l4 = l8 = 0;
				switch(param1)
				{
				case  64: l1 = 0x01; break; //loop 1
				case  128: l2 = 0x01; break; //loop 2
				case  256: l4 = 0x01; break; //loop 4
				case  512: l8 = 0x01; break; //loop 8		
				}
				
				sendMidi(uniqueId,0xB0,deck+1,25,l1); //loop 1	
				sendMidi(uniqueId,0xB0,deck+1,26,l2); //loop 2
				sendMidi(uniqueId,0xB0,deck+1,27,l4); //loop 4 
				sendMidi(uniqueId,0xB0,deck+1,28,l8); //loop 8

			}	
		if((name=='looping')&&(!param1))
			{
				sendMidi(uniqueId,0xB0,deck+1,25,0x00); //loop 1	
				sendMidi(uniqueId,0xB0,deck+1,26,0x00); //loop 2
				sendMidi(uniqueId,0xB0,deck+1,27,0x00); //loop 4 
				sendMidi(uniqueId,0xB0,deck+1,28,0x00); //loop 8	
				
			}		
		if(name=='fxFlanger') 
			{	 
				if(deck==0){
					sendMidi(uniqueId,0xB0,0,68,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,23,(param1 ? 0x7F : 0x00));
				}
				if(deck==1){
					sendMidi(uniqueId,0xB0,0,70,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,23,(param1 ? 0x7F : 0x00));
				}
				if(deck==2){
					sendMidi(uniqueId,0xB0,0,72,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,23,(param1 ? 0x7F : 0x00));
				}
				if(deck==3){
					sendMidi(uniqueId,0xB0,0,74,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,23,(param1 ? 0x7F : 0x00));
				}
			}
		if(name=='fxEcho') 
			{	 
				if(deck==0){
					sendMidi(uniqueId,0xB0,0,69,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,46,(param1 ? 0x7F : 0x00));
				}
				if(deck==1){
					sendMidi(uniqueId,0xB0,0,71,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,46,(param1 ? 0x7F : 0x00));
				}
				if(deck==2){
					sendMidi(uniqueId,0xB0,0,73,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,46,(param1 ? 0x7F : 0x00));
				}
				if(deck==3){
					sendMidi(uniqueId,0xB0,0,75,(param1 ? 0x7F : 0x00));
					sendMidi(uniqueId,0xB0,0,46,(param1 ? 0x7F : 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)
var timer1=0;
function timerTick(uniqueId)
{
	timer1++; if(timer1>15) timer1 = 0;
	//debug('timerTick ['+uniqueId+']');
	for(var i=0; i<4; i++)
	{
		if(timer1 % 4 == 0)
		{
			//progress led strips
			var jwAngle = getValue('jogWheelAngle', i);// float degrees
			var timeElapsed = getValue('timeElapsed', i);// float seconds
			var timeRemain = getValue('timeRemain', i);// float seconds
			//led progress strip
			var tempTime = timeElapsed / (timeElapsed+timeRemain);// this will result in [0..1]
			sendMidi(uniqueId,0xB0,i+1,78, 1 + tempTime*14);// 1..14
			// jog-wheel play/scratch leds move
			var finalLed = Math.round(jwAngle/360.0 * 20.0 + 1.0);
			if(finalLed<1) finalLed = 1;
			if(finalLed>21) finalLed = 21;
			//sendMidi(uniqueId,0xB0,i+1,0x3A, finalLed);// 0 all off; 1-21 led; >22 all leds on	
		}
		if(loopingInBlinkLed[i]!=-1)
		{
			// actually set the led
			sendMidi(uniqueId,0xB0,i+1,25,((loopingInBlinkLed[i]<2) ? 0x02 : 0x00));// Loop In (on or off)
			loopingInBlinkLed[i]++;
			if(loopingInBlinkLed[i]>=4) loopingInBlinkLed[i] = 0;
		}
	}
}
//----------------------------------------------------------------------------- 
