//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2013 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'M-Audio Xponent'
//----------------------------------------------------------------------------- 
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 "M-Audio Xponent";
}
//----------------------------------------------------------------------------- 
// 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 "002079200C";// short 5-bytes sysex id (we don't use this since it's same as 'Zomo MC1000')
	//return "002079200C101701";// a bit longer 8-bytes sysex id
	// F0 7E 00 06 02 00 20 08 63 0E 16 40 30 31 30 30 F7 -- full sysex reply
	//return false;
	return "002008630E";
	/*
	-- xfd: in  '2- Xponent Audio   In [2]' VID:PID=0763:2016
	-- xfd: in  '2- Xponent MIDI In (Control)' VID:PID=0763:2016 -- this should be used
	-- xfd: out 'Microsoft GS Wavetable Synth' VID:PID=0000:0000
	-- xfd: out '2- Xponent MIDI Out (Control)' VID:PID=0763:2016 -- this should be used
	-- xfd: out '2- Xponent MIDI Out (External)' VID:PID=0763:2016
	F0 7E 00 06 02 00 20 08 63 0E 16 40 30 31 30 30 F7 
	*/
}
//----------------------------------------------------------------------------- 
// 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 "M-Audio Xponent";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	if(osId==0) return "2- Xponent MIDI In (Control)";
	return "Xponent";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "M-Audio Xponent";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	if(osId==0) return "2- Xponent MIDI Out (Control)";
	return "Xponent";
	//return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// preferred way to identify the controller (using the USB device VID and PID -- vendor and product id)
// return false if the controller does not support this kind of identification
// osId -- 0 Windows; 1 MacOSX; 2 Linux; -1 unknown
function getSupportedMidiDeviceVID(osId)
{	
	return 0x0763;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID(osId)
{	
	return 0x2016;	
}
// some variables necessary only for this particular script
var shiftMode = [0,0,0,0];
var loopBlink 	= [0,0,0,0];//0=off, 1=blink, 2=on

var timer1=0;
var loopInPulse=0;
var loopInEnabled=[0,0];
var fxParams=[0,0,0,0,0,0,0,0];
var jogWheelsInScratchMode=[1,1,1,1];
var jogWheelsWasDeckPlaying=[0,0,0,0];
var crossfaderValue = 0x3F;
var gainValue = [63,63]; //07-29-2015: Set Default Gain Values, used by Gain Kill buttons.
var gainKillStatus = [0,0];


var currentFXDW = [0,0,0,0];
var cutoffValue			=[63,63,63,63];
var flangerValue		=[127,127,127,127];
var delayValue			=[127,127,127,127];
var echoValue			=[127,127,127,127];
var fxEnabled = [[false,false,false],[false,false,false],[false,false,false]];

//----------------------------------------------------------------------------- 
// 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 M-Audio Xponent ['+uniqueId+']');// this outputs a string to DebugView app on Win
	
	sendMidi(uniqueId,0x90,0,0x15,0x7F);//scratch button deck 1
	sendMidi(uniqueId,0x90,1,0x15,0x7F);//scratch button deck 2
	
	
	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)
{
	sendMidi(uniqueId,0x90,0,0x15,0x00);//scratch button deck 1
	sendMidi(uniqueId,0x90,1,0x15,0x00);//scratch button deck 2
	
	//deck 1
	sendMidi(uniqueId,0x90,0,0x17,0x00);
	sendMidi(uniqueId,0x90,0,0x18,0x00);
	sendMidi(uniqueId,0x90,0,0x19,0x00);
	sendMidi(uniqueId,0x90,0,0x1A,0x00);
	sendMidi(uniqueId,0x90,0,0x1B,0x00);
	//deck 2
	sendMidi(uniqueId,0x90,1,0x17,0x00);
	sendMidi(uniqueId,0x90,1,0x18,0x00);
	sendMidi(uniqueId,0x90,1,0x19,0x00);
	sendMidi(uniqueId,0x90,1,0x1A,0x00);
	sendMidi(uniqueId,0x90,1,0x1B,0x00);
	//debug('controllerDeinit M-Audio Xponent ['+uniqueId+']');
	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: pitch sliders ('moving' things)
	case 0xE0:
		// attn: we're only using 7bit	
		call('setDeckPitch', channel, data2);
		break;
	//-----------------------------------------------
	// controllers: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1){
			// volumes, crossfader, eqs, gain
			case  0x07: //07-30-2015: Reimplemented, Tested, Verified.
				if(channel==2){
					crossfaderValue = data2;
					call('setCrossfader', data2);					
				} else {
					call('setDeckVolume', channel, data2);
				}				
				break;//0x07	
				
			case 0x08: //07-30-2015: Modified, Tested, Verified.
				call('setDeckEqLow', channel, data2); 
				break;//0x08
				
			case 0x09: //07-30-2015: Modified, Tested, Verified.
				call('setDeckEqMid', channel, data2); 
				break;//0x09
				
			case 0x0A: //07-30-2015: Modified, Tested, Verified.			
				call('setDeckEqHigh', channel, data2); 
				break;//0x00A
				
			case 0x0B: //07-29-2015: Reimplemented, Tested, and Verified.
				gainValue[channel] 		= data2; //07-29-2015: Save this value in case we invoke Gain Kill button.
				gainKillStatus[channel] = 0;
				call('setDeckGain', channel, gainValue[channel]);			
				break;//0x0B
		
			// the 4 knobs/4buttons group under each jog-wheel		
			case 0x0C: 
				echoValue[channel] = data2;
				fxEnabled[channel]['echo'] = echoValue[channel] ? true : false;
				echoValue[channel] ? sendMidi(uniqueId,0x90,channel,0x0C,0x7F) : sendMidi(uniqueId,0x90,channel,0x0C,0x00);
				call('deckFxEchoDW', channel, echoValue[channel]);
				break;//0X0C
				
			case 0x0D: //07-30-2015: Tested, and Verified.
				if(channel==2) {
					call('setCuePgmMix', data2);	
				} else {
					delayValue[channel] = data2;
					fxEnabled[channel]['delay'] = delayValue[channel] ? true : false;
					delayValue[channel] ? sendMidi(uniqueId,0x90,channel,0x0D,0x7F) : sendMidi(uniqueId,0x90,channel,0x0D,0x00);
					call('deckFxDelayDW', channel, delayValue[channel]);
				}
				break;//0X0D
			
			
			case 0x0E:
				flangerValue[channel] = data2;
				//debug('Set Flanger Value: ' + (flangerValue[channel]).toString());
				fxEnabled[channel]['flanger'] = flangerValue[channel] ? true : false;
				flangerValue[channel] ? sendMidi(uniqueId,0x90,channel,0x0E,0x7F) : sendMidi(uniqueId,0x90,channel,0x0E,0x00);
				call('deckFxFlangerDW', channel, flangerValue[channel]);
				break;//0X0E deck 4 knob		
				
			case 0x16: //07-30-2015: Reimplemented, Tested, Verified.  
				var val1 = data2-0x40;			
				if(jogWheelsInScratchMode[channel]){			
					call('scratchDeckJW', channel, val1, 300); //params: (deck, increment, total positions per complete revolution)
				} else {
					if(shiftMode[channel]){					
						call('searchDeckJW', channel, val1, 600);
					}else{
						call('moveDeckJogWheel', channel, val1/2, 600);				
					}
							
				}				
				break;//0X16
				
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80://Deck 1 Button Release
		status 	= 0x90;
		data2 	= 0x00;
	case 0x81://Deck 2 Button Release
		status 	= 0x91;
		data2 	= 0x00;
	case 0x90:
	case 0x91:
		switch(data1)
		{
		// mixer section		
		case 0x02: //07-29-2015: Syncs Deck 1 or Deck 2
			call('deckSync', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x02,data2);//Sync Button
			break; //0x02
			
		case  0x07: //07-29-2015: Implemented
			var newVal = 0x00;	//07-29-2015: Initialize default value.
			if(channel==1){		//07-29-2015: If channel 1, transform  right, if not transform left.				
				newVal = 0x7F;
			}
			call('setCrossfader', (data2 ? newVal : crossfaderValue)); 
			sendMidi(uniqueId,0x90,channel,0x07,data2);//hardfade button
			break;//0x07 Left/Right transform buttons (the ones on each side of the crossfader)		
		
		case 0x08: 
			call('deckEqLowKill', channel, data2); 
			break; 	//0x08 07-29-2015: Tested and Verified Working
			
		case 0x09: 
			call('deckEqMidKill', channel, data2); 
			break; // 0x09 07-29-2015: Tested and Verified Working
			
		case 0x0A: 
			call('deckEqHighKill', channel, data2); 
			break; 	//07-29-2015: Tested and Verified Working
			
		case 0x0B: //07-29-2015: Implemented
			if(data2){
				gainKillStatus[channel] = (gainKillStatus[channel] ? 0 : 1);
				if(gainKillStatus[channel]){
					call('setDeckGain', channel, 0x00);
				} else {
					call('setDeckGain', channel, gainValue[channel]);
				}
			}
			 break;//0x0B gain button; ATTN: on channel 2 we also have 'foot pedal' for 11
		case 0x0C: 
			debug('deckFxEchoDW' + (channel).toString() + '/' + (echoValue[channel]).toString());
			if(data2){
				if(!fxEnabled[channel]['echo']){ //If Echo is not currently enabled, enable it.
				fxEnabled[channel]['echo'] = true; 				//Update the state of Echo effect to 'on/true'.
				currentFXDW[channel] 		= 'deckFxEchoDW'; 		//Set the currently selected effect to Echo.
				call('deckFxEchoDW', channel, echoValue[channel]);	//Enable the Echo effect in software.
				//sendMidi(uniqueId,0x90,channel,0x07,0x7F); 		//Enable FX 1 LED on controller.
				} else { //If Echo is currently enabled, then disable it.
					fxEnabled[channel]['echo'] = false;				//Update the state of the Echo effect to 'off/false'.
					call('deckFxEchoDW', channel, 0x00);				//Disable the Echo effect in software.
					currentFXDW[channel] 		= '';					//Unset the currently selected effect.							
					//sendMidi(uniqueId,0x90,channel,0x07,0x00); 		//Disable FX 1 LED on controller.					
				}			
			}			
		break;//0x0C
		
		case 0x0D:
			if(channel!=2){
				if(data2){//Only concerned about button presses, not button releases.
					if(!fxEnabled[channel]['delay']){ //If Delay is not currently enabled, enable it.
						fxEnabled[channel]['delay'] = true; //Update the state of Delay effect to 'on/true'.		
						currentFXDW[channel] = 'deckFxDelayDW'; //Set the currently selected effect to Delay.					
						call(currentFXDW[channel], channel, delayValue[channel]); //Enable the Delay effect in software.
						sendMidi(uniqueId,0x90,channel,0x0D,0x7F);//Enable FX 2 LED on controller.
					} else { //If Delay is currently enabled, then disable it.
						fxEnabled[channel]['delay'] = false;			//Update the state of the Delay effect to 'off/false'.						
						call('deckFxDelayDW', channel, 0x00); 			//Disable the Delay effect in software.						
						currentFXDW[channel] = '';             		//Unset the currently selected effect.
						sendMidi(uniqueId,0x90,channel,0x0D,0x00); 	//Disable FX 2 LED on controller.
					}
				}
			}
		break;//0x0D
		
		case 0x0E:
			if(data2){//Only concerned about button presses, not button releases.
				if(!fxEnabled[channel]['flanger']){ //If Delay is not currently enabled, enable it.
					fxEnabled[channel]['flanger'] = true; //Update the state of Delay effect to 'on/true'.		
					currentFXDW['flanger'] = 'deckFxFlangerDW'; //Set the currently selected effect to Delay.					
					//debug('Use Flanger Value: ' + (flangerValue[channel]).toString());
					call('deckFxFlangerDW', channel, flangerValue[channel]); //Enable the Delay effect in software.
					sendMidi(uniqueId,0x90,channel,0x0D,0x7F);//Enable FX 2 LED on controller.
				} else { //If Delay is currently enabled, then disable it.
					//debug('Disable Flanger: ' + (flangerValue[channel]).toString());
					fxEnabled[channel]['flanger'] = false;			//Update the state of the Delay effect to 'off/false'.						
					call('deckFxFlangerDW', channel, 0x00); 			//Disable the Delay effect in software.						
					currentFXDW[channel] = '';             		//Unset the currently selected effect.
					sendMidi(uniqueId,0x90,channel,0x0D,0x00); 	//Disable FX 2 LED on controller.
				}
			}
			break;//0x0E
		
		
		
		case 0x15: 
			debug('Scratch button Pressed');
			if(data2){ 
				
				jogWheelsInScratchMode[channel] = (jogWheelsInScratchMode[channel]+1) % 2; // keep the remainder to toggle between scratch mode "1" or jog bend mode "0"
				debug('Scratch button Pressed');
				if(jogWheelsInScratchMode[channel]){
					debug('Turn Scratch Button LED On');
					sendMidi(uniqueId,0x90,channel,0x15,0x7F);//scratch button deck x
				} else {
					debug('Turn Scratch Button LED OFF');
					sendMidi(uniqueId,0x90,channel,0x15,0x00);//scratch button deck x
				}
				
				//call('holdDeckJogWheel', channel, jogWheelsInScratchMode[channel]);
			}
			break;//0x15
		
		case 0x16: // scratch wheel-touch (hold scratch); ATTN: you can lock the scratch mode using the special touch button NEAR (not on the) jog-wheel
			if(jogWheelsInScratchMode[channel]){
				call('holdDeckJogWheel', channel, data2);
			}
			break;//0x16
			
		// we use the shift buttons to load the decks
		case 0x2C: 
			call('deckLBLoad', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x2C,data2);//Track Load button
		break;//0x2C left/right SHIFT buttons (the ones above the gain / on each side of the mouse buttons; they look like an "up arrow")
	
		case 0x10: 
			call('deckBendDown', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x10,data2);//bend down button
			break;//0x10 small '<'
		case 0x11: 
			call('deckBendUp', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x11,data2);//bend up button
			break;//0x11 small '>'		
		
		case 0x12: 
			shiftMode[channel] = data2; 
			sendMidi(uniqueId,0x90,channel,0x12,data2); 
			sendMidi(uniqueID,0x90,channel,0x12,data2);
			break;//0x12
		case 0x13://not defined
			sendMidi(uniqueId,0x90,channel,0x13,data2);//undefined big '-' button.
			break;
		
		case 0x14: 
			call('deckMonitor', channel, data2); 
			break;//0x14 large headphone button
		

		// transport
		case 0x17: 
			//debug('debug cue button');
			 if(shiftMode[channel]) {
				call('deckCuePos1Clear', channel, data2); 
			 } else {
				call('deckCuePos1', channel, data2); 
			 }
		 break;//0x17
		
		
		case 0x18: 
			if(shiftMode[channel]){
				call('deckCuePos2Clear', channel, data2); 
			}else{ 
				call('deckCuePos2', channel, data2);
			} 
		break;//0x18
		
		case 0x19: 
			if(shiftMode[channel]) {
				call('deckCuePos3Clear', channel, data2); 
			}else{ 
				call('deckCuePos3', channel, data2);
			} 
		break;//0x19
		
		case 0x1A: 
			if(shiftMode[channel]) {
				call('deckCuePos4Clear', channel, data2); 
			}else{
				call('deckCuePos4', channel, data2);
			}
		break;
		
		case 0x1B: 
		if(shiftMode[channel]) {
			call('deckCuePos5Clear', channel, data2); 
		}else{
			call('deckCuePos5', channel, data2);
		}			
		break;
		

		// the 5 small buttons under the 1..5 cue point small buttons
		case 0x1C: 		
		call('deckLoopPrev', channel, data2); 
		sendMidi(uniqueId,0x90,channel,0x1C,data2);//loop prev button
		break;// small '|<' button
		case 0x1D: 
		call('deckLoopNext', channel, data2); 
		sendMidi(uniqueId,0x90,channel,0x1D,data2);//loop next button
		break;// small '>|' button
		
		case 0x1E: 
		call('deckKeyLock', channel, data2); 
		if(getValue('keyLock', channel)){
			sendMidi(uniqueId,0x90,channel,0x1E,0x7F);//loop next button		
		} else {
			sendMidi(uniqueId,0x90,channel,0x1E,0x00);//loop next button		
		}
		break;// small lock button		
		case 0x20: 
		call('deckLoopLess', channel, data2); 
		sendMidi(uniqueId,0x90,channel,0x20,data2);//loop less button
		break;// small '+' button		 
		case 0x1F:
		call('deckLoopMore', channel, data2); 
		sendMidi(uniqueId,0x90,channel,0x1F,data2);//loop more button
		break;// small '-' button

		case 0x21: 
		call('deckSearchLeft', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x21,data2);//search left button
		break;// big '<<'
		case 0x22: 
		call('deckSearchRight', channel, data2); 
			sendMidi(uniqueId,0x90,channel,0x22,data2);//search right button
		break;// big '>>'
		case 0x23: 
			if(shiftMode[channel]){						//If Shift Button IS pressed, the Deck will Cue at the beginning of the Track.
				call('deckBackToTop', channel, data2); 	//Cue to beginning of Track.
			} else { 									//If Shift Button IS NOT pressed, the Deck will Cue at the Cue-Point.
				call('deckCue', channel, data2); 			//Cue to Cue-Point
			}
		break;
		case 0x24: 
		call('deckPlayPause', channel, data2); 
		break;
//		case 0x0A: call('deckCuePlay', channel, data2); break;
		
		// loop
		case 0x25: 
		call('deckLoop1', channel, data2); 
		break;//1
		case 0x26: 
		call('deckLoop2', channel, data2); 
		break;//2
		case 0x27: 
		call('deckLoop4', channel, data2); 
		break;//4
		case 0x28: 
		call('deckLoop8', channel, data2); 
		break;//8		
		
		
		case 0x29: /*call('deckLoopInEnd', channel, data2);*/ //loopin button		
			if(!getValue('looping', channel) && loopBlink[channel] != 1){ 
				call('deckLoopInEnd', channel, data2);	//this will trigger loopInOut. Cant seem to track the complete in/out state					
				loopBlink[channel]=1; //loop in; no loop out; not looping;
				sendMidi(uniqueId,0x90,channel,0x29,0x7F);
				//turn on loop in LED.
				debug('Enable Loop-In LED');
				//sendMidi(uniqueId,0x90,channel,0x2A,0x00);
				//sendMidi(uniqueId,0x90,channel,0x2B,0x00);
				
			}
			break;//in
		//case 0x2A: call('deckLoopMore', channel, data2); break;//loop
		//case 0x2B: call('deckLoopExit', channel, data2); break;//out
		case 0x2A: //reloop button		
			if(data2>0x3F){ 
				if(getValue('looping', channel)){
					call('deckLoopExit', channel, 0x7F);
					call('deckLoopExit', channel, 0x00);
					loopBlink[channel] = 0; //no loop in; not looping;
					sendMidi(uniqueId,0x90,channel,0x29,0x00);												
					sendMidi(uniqueId,0x90,channel,0x2B,0x00);										
					sendMidi(uniqueId,0x90,channel,0x2A,0x00);
					
					
				}else{/*if(loopBlink[deck] = 0)*/	
					call('deckLoopReloop', channel, 0x7F);
					call('deckLoopReloop', channel, 0x00);
					if(getValue('looping', channel)){
						loopBlink[channel] = 2; //no loop in; looping;
						sendMidi(uniqueId,0x90,channel,0x29,0x7F);												
						sendMidi(uniqueId,0x90,channel,0x2B,0x7F);										
						sendMidi(uniqueId,0x90,channel,0x2A,0x7F);								
					}						
				}
			}	
			break;
		
		//loop
		case 0x2B: //loop out button		
			if(!getValue('looping', channel) && loopBlink[channel] == 1){
						call('deckLoopInEnd', channel, data2);	
						loopBlink[channel] = 2; //no loop in; looping;
						sendMidi(uniqueId,0x90,channel,0x29,0x7F);												
						sendMidi(uniqueId,0x90,channel,0x2B,0x7F);										
						sendMidi(uniqueId,0x90,channel,0x2A,0x7F);
						
					}

		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)
{
	if(deck>=2) return;
	debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
	if(name=='play'){
		sendMidi(uniqueId,0x90,deck,0x23,(param1 ? 0x00 : 0x7F));
		sendMidi(uniqueId,0x90,deck,0x24,(param1 ? 0x7F : 0x00));
	}
	if(name=='loopSize') {
		/*
		0x25
		0x26
		0x27
		0x28
		*/
		sendMidi(uniqueId,0x90,deck,0x25,0x00);
		sendMidi(uniqueId,0x90,deck,0x26,0x00);
		sendMidi(uniqueId,0x90,deck,0x27,0x00);
		sendMidi(uniqueId,0x90,deck,0x28,0x00);
		//debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
		switch(param1){
			case 64: sendMidi(uniqueId,0x90,deck,0x25,0x7F); break;
			case 128: sendMidi(uniqueId,0x90,deck,0x26,0x7F); break;
			case 256: sendMidi(uniqueId,0x90,deck,0x27,0x7F); break;
			case 512: sendMidi(uniqueId,0x90,deck,0x28,0x7F); break;
		}
	}
	if(name=='killHigh') {
		sendMidi(uniqueId,0x90,deck,0x0A,(param1 ? 0x7F : 0x00));
	}
	
	if(name=='killMid'){
		sendMidi(uniqueId,0x90,deck,0x09,(param1 ? 0x7F : 0x00))
	}
	
	if(name=='killLow'){
		sendMidi(uniqueId,0x90,deck,0x08,(param1 ? 0x7F : 0x00))
	}
	//sync
	if(name=='onbeat') 	   {	sendMidi(uniqueId,0x90,deck,0x02,(param1 ? 0x7F : 0x00));}
	
	if(name=='cuepos1')		sendMidi(uniqueId,0x90,deck,0x17,(param1 ? 0x7F : 0x00));
	if(name=='cuepos2')		sendMidi(uniqueId,0x90,deck,0x18,(param1 ? 0x7F : 0x00));
	if(name=='cuepos3')		sendMidi(uniqueId,0x90,deck,0x19,(param1 ? 0x7F : 0x00));
	if(name=='cuepos4')		sendMidi(uniqueId,0x90,deck,0x1A,(param1 ? 0x7F : 0x00));
	if(name=='cuepos5')		sendMidi(uniqueId,0x90,deck,0x1B,(param1 ? 0x7F : 0x00));
	
	if(name=='monitor') 	sendMidi(uniqueId,0x90,deck,0x14,(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)
function timerTick(uniqueId){
	
}
//----------------------------------------------------------------------------- 
