//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2012 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Faderfox DJ3'
//----------------------------------------------------------------------------- 
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 "Faderfox DJ3";
}
//----------------------------------------------------------------------------- 
// 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 "00013F2100";
	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 "Faderfox DJ3";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	return "Faderfox DJ3";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "Faderfox DJ3";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	return "Faderfox DJ3";
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
//var jwSearchCountLeft=[0,0,0,0];
//var jwSearchCountRight=[0,0,0,0];
//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 pitchKeyValue=[63,63,63,63];
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 Faderfox DJ3 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	//sendMidi(uniqueId,0x90,0,0x33,(getValue('cue', 0) ? 0x7F : 0x00));// cue A
	//sendMidi(uniqueId,0x90,0,0x3B,(getValue('play', 0) ? 0x7F : 0x00));// play-pause A
	//sendMidi(uniqueId,0x90,0,0x40,0x00);// sync A
	//sendMidi(uniqueId,0x90,0,0x65,(getValue('monitor', 0) ? 0x7F : 0x00));// monitor A
	//call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	//sendMidi(uniqueId,0x90,0,0x3C,(getValue('cue', 1) ? 0x7F : 0x00));// cue B
	//sendMidi(uniqueId,0x90,0,0x42,(getValue('play', 1) ? 0x7F : 0x00));// play-pause B
	//sendMidi(uniqueId,0x90,0,0x47,0x00);// sync B
	//sendMidi(uniqueId,0x90,0,0x66,(getValue('monitor', 1) ? 0x7F : 0x00));// monitor B	
	// per deck
	for(var i=0; i<4; i++)
	{
		sendMidi(uniqueId,0x90,i,11,(getValue('play', i) ? 0x7F : 0x00));// play
		sendMidi(uniqueId,0x90,i,12,(getValue('cue', i) ? 0x7F : 0x00));// cue
		sendMidi(uniqueId,0x90,i,88, 0x00);// sync (off by default)
		sendMidi(uniqueId,0x90,i,26,(getValue('keyLock', i) ? 0x7F : 0x00));
		sendMidi(uniqueId,0x90,i,16,(getValue('loopIn', i) ? 0x7F : 0x00));
		sendMidi(uniqueId,0x90,i,17,(getValue('loopExit', i) ? 0x7F : 0x00));
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		if(i==0)
		{
			sendMidi(uniqueId,0x90,i,0x3C,(getValue('sampler1loaded', i) ? 0x7F : 0x00));// sampler 1
			sendMidi(uniqueId,0x90,i,0x3E,(getValue('sampler2loaded', i) ? 0x7F : 0x00));// sampler 2
			sendMidi(uniqueId,0x90,i,0x40,(getValue('sampler3loaded', i) ? 0x7F : 0x00));// sampler 3
			sendMidi(uniqueId,0x90,i,0x42,(getValue('sampler4loaded', i) ? 0x7F : 0x00));// sampler 4
		}
		if(i==1)
		{
			sendMidi(uniqueId,0x90,i,0x3C,(getValue('sampler5loaded', i) ? 0x7F : 0x00));// sampler 5
			sendMidi(uniqueId,0x90,i,0x3E,(getValue('sampler6loaded', i) ? 0x7F : 0x00));// sampler 6
			sendMidi(uniqueId,0x90,i,0x40,(getValue('sampler7loaded', i) ? 0x7F : 0x00));// sampler 7
			sendMidi(uniqueId,0x90,i,0x42,(getValue('sampler8loaded', i) ? 0x7F : 0x00));// sampler 8
		}
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
	// monitor (headphones
	sendMidi(uniqueId,0x90,6,84,(getValue('monitor', 0) ? 0x7F : 0x00));
	sendMidi(uniqueId,0x90,6,85,(getValue('monitor', 1) ? 0x7F : 0x00));
	sendMidi(uniqueId,0x90,6,86,(getValue('monitor', 2) ? 0x7F : 0x00));
	sendMidi(uniqueId,0x90,6,87,(getValue('monitor', 3) ? 0x7F : 0x00));	
}
//----------------------------------------------------------------------------- 
// 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+']');
	// per deck
	for(var i=0; i<4; i++)
	{
		sendMidi(uniqueId,0x90,i,11,0x00);// play
		sendMidi(uniqueId,0x90,i,12,0x00);// cue
		sendMidi(uniqueId,0x90,i,88,0x00);// sync
		sendMidi(uniqueId,0x90,i,26,0x00);// keylock
		sendMidi(uniqueId,0x90,i,16,0x00);// loop in
		sendMidi(uniqueId,0x90,i,17,0x00);// loop exit
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
		if(i==0)
		{
			sendMidi(uniqueId,0x90,i,0x3C,0x00);// sampler 1
			sendMidi(uniqueId,0x90,i,0x3E,0x00);// sampler 2
			sendMidi(uniqueId,0x90,i,0x40,0x00);// sampler 3
			sendMidi(uniqueId,0x90,i,0x42,0x00);// sampler 4
		}
		if(i==1)
		{
			sendMidi(uniqueId,0x90,i,0x3C,0x00);// sampler 5
			sendMidi(uniqueId,0x90,i,0x3E,0x00);// sampler 6
			sendMidi(uniqueId,0x90,i,0x40,0x00);// sampler 7
			sendMidi(uniqueId,0x90,i,0x42,0x00);// sampler 8
		}
		sendMidi(uniqueId,0xB0,6,0x1B+i, 0x40);// jog-wheel leds rotate
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
	// monitor (headphones
	sendMidi(uniqueId,0x90,6,84,0x00);// A
	sendMidi(uniqueId,0x90,6,85,0x00);// B
	sendMidi(uniqueId,0x90,6,86,0x00);// C
	sendMidi(uniqueId,0x90,6,87,0x00);// D
}
//----------------------------------------------------------------------------- 
var MasterGain=0x3F;// start from middle
var MonitorGain=0x3F;
var CuePgmMix=0x3F;
var DeckGain=0x3F;
var DeckPitch=0x3F;
var FxFlangerDW=[0x00,0x00,0x00,0x00];
var FxBeatwawDW=[0x00,0x00,0x00,0x00];
var FxEchoDW=[0x00,0x00,0x00,0x00];
var FxPhaserDW=[0x00,0x00,0x00,0x00]; //inainte era pan
var FxFlangerP1=[0x00,0x00,0x00,0x00];
var FxBeatwawP1=[0x00,0x00,0x00,0x00];
var FxEchoP1=[0x00,0x00,0x00,0x00];
var FxPhaserP1=[0x00,0x00,0x00,0x00]; //inainte era pan
// 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 0x78: call('setCrossfader', data2); break;
		case 0x61:
			{	
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				CuePgmMix = CuePgmMix + val1; if(CuePgmMix<0) CuePgmMix = 0; if(CuePgmMix>0x7F) CuePgmMix = 0x7F;
				call('setCuePgmMix', CuePgmMix); 
			}	
			break;
		case 0x62:  
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				MonitorGain = MonitorGain + val1; if(MonitorGain<0) MonitorGain = 0; if(MonitorGain>0x7F) MonitorGain = 0x7F;
				call('setMonitorGain', MonitorGain);
			}
			break;	
		case 0x63: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				MasterGain = MasterGain + val1; if(MasterGain<0) MasterGain = 0; if(MasterGain>0x7F) MasterGain = 0x7F;
				call('setMasterGain', MasterGain);
			}
			break;
		case 0x60: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				call('lbMoveCursor', val1);
			}
			break;
		case 0x40: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 0, DeckGain);
			}
			break;
		case 0x50: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 0, DeckGain);
			}
			break;
		case 0x41: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 2, DeckGain);
			}
			break;
		case 0x51: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 2, DeckGain);
			}
			break;
		case 0x48: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 1, DeckGain);
			}
			break;
		case 0x58: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 1, DeckGain);
			}
			break;
		case 0x49: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 3, DeckGain);
			}
			break;
		case 0x59: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckGain = DeckGain + val1; if(DeckGain<0) DeckGain = 0; if(DeckGain>0x7F) DeckGain = 0x7F;
				call('setDeckGain', 3, DeckGain);
			}
			break;
		case 0x42: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 0, DeckPitch);
			}
			break;
		case 0x52: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 0, DeckPitch);
			}
			break;
		case 0x43: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 2, DeckPitch);
			}
			break;
		case 0x53: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 2, DeckPitch);
			}
			break;
		case 0x4A: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 1, DeckPitch);
			}
			break;
		case 0x5A: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 1, DeckPitch);
			}
			break;
		case 0x4B: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 3, DeckPitch);
			}
			break;
		case 0x5B: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				DeckPitch = DeckPitch + val1; if(DeckPitch<0) DeckPitch = 0; if(DeckPitch>0x7F) DeckPitch = 0x7F;
				call('setDeckPitch', 3, DeckPitch);
			}
			break;
		case 0x20: 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerDW[0] = FxFlangerDW[0] + val1; if(FxFlangerDW[0]<0) FxFlangerDW[0] = 0; if(FxFlangerDW[0]>0x7F) FxFlangerDW[0] = 0x7F;
				call('deckFxFlangerDW', 0, FxFlangerDW[0]);
			}
			break;
		case 0x30:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerDW[2] = FxFlangerDW[2] + val1; if(FxFlangerDW[2]<0) FxFlangerDW[2] = 0; if(FxFlangerDW[2]>0x7F) FxFlangerDW[2] = 0x7F;
				call('deckFxFlangerDW', 2, FxFlangerDW[2]);
			}
			break;
		case 0x28:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerDW[1] = FxFlangerDW[1] + val1; if(FxFlangerDW[1]<0) FxFlangerDW[1] = 0; if(FxFlangerDW[1]>0x7F) FxFlangerDW[1] = 0x7F;
				call('deckFxFlangerDW', 1, FxFlangerDW[1]);
			}
			break;
		case 0x38:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerDW[3] = FxFlangerDW[3] + val1; if(FxFlangerDW[3]<0) FxFlangerDW[3] = 0; if(FxFlangerDW[3]>0x7F) FxFlangerDW[3] = 0x7F;
				call('deckFxFlangerDW', 3, FxFlangerDW[3]);
			}
			break;
		case 0x21:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawDW[0] = FxBeatwawDW[0] + val1; if(FxBeatwawDW[0]<0) FxBeatwawDW[0] = 0; if(FxBeatwawDW[0]>0x7F) FxBeatwawDW[0] = 0x7F;
				call('deckFxBeatwawDW', 0, FxBeatwawDW[0]);
			}
			break;
		case 0x31:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawDW[2] = FxBeatwawDW[2] + val1; if(FxBeatwawDW[2]<0) FxBeatwawDW[2] = 0; if(FxBeatwawDW[2]>0x7F) FxBeatwawDW[2] = 0x7F;
				call('deckFxBeatwawDW', 2, FxBeatwawDW[2]);
			}
			break;
		case 0x29:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawDW[1] = FxBeatwawDW[1] + val1; if(FxBeatwawDW[1]<0) FxBeatwawDW[1] = 0; if(FxBeatwawDW[1]>0x7F) FxBeatwawDW[1] = 0x7F;
				call('deckFxBeatwawDW', 1, FxBeatwawDW[1]);
			}
			break;
		case 0x39:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawDW[3] = FxBeatwawDW[3] + val1; if(FxBeatwawDW[3]<0) FxBeatwawDW[3] = 0; if(FxBeatwawDW[3]>0x7F) FxBeatwawDW[3] = 0x7F;
				call('deckFxBeatwawDW', 3, FxBeatwawDW[3]);
			}
			break;
		case 0x22:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoDW[0] = FxEchoDW[0] + val1; if(FxEchoDW[0]<0) FxEchoDW[0] = 0; if(FxEchoDW[0]>0x7F) FxEchoDW[0] = 0x7F;
				call('deckFxEchoDW', 0, FxEchoDW[0]);
			}
			break;
		case 0x32:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoDW[2] = FxEchoDW[2] + val1; if(FxEchoDW[2]<0) FxEchoDW[2] = 0; if(FxEchoDW[2]>0x7F) FxEchoDW[2] = 0x7F;
				call('deckFxEchoDW', 2, FxEchoDW[2]);
			}
			break;
		case 0x2A:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoDW[1] = FxEchoDW[1] + val1; if(FxEchoDW[1]<0) FxEchoDW[1] = 0; if(FxEchoDW[1]>0x7F) FxEchoDW[1] = 0x7F;
				call('deckFxEchoDW', 1, FxEchoDW[1]);
			}
			break;
		case 0x3A:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoDW[3] = FxEchoDW[3] + val1; if(FxEchoDW[3]<0) FxEchoDW[3] = 0; if(FxEchoDW[3]>0x7F) FxEchoDW[3] = 0x7F;
				call('deckFxEchoDW', 3, FxEchoDW[3]);
			}
			break;
		case 0x23:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPhaserDW[0] = FxPhaserDW[0] + val1; if(FxPhaserDW[0]<0) FxPhaserDW[0] = 0; if(FxPhaserDW[0]>0x7F) FxPhaserDW[0] = 0x7F;
				call('deckFxPhaserDW', 0, FxPhaserDW[0]); // era pan inainte
			}
			break;
		case 0x33:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPhaserDW[2] = FxPhaserDW[2] + val1; if(FxPhaserDW[2]<0) FxPhaserDW[2] = 0; if(FxPhaserDW[2]>0x7F) FxPhaserDW[2] = 0x7F;
				call('deckFxPhaserDW', 2, FxPhaserDW[2]); // era pan inainte
			}
			break;
		case 0x2B:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPanDW[1] = FxPanDW[1] + val1; if(FxPanDW[1]<0) FxPanDW[1] = 0; if(FxPanDW[1]>0x7F) FxPanDW[1] = 0x7F;
				call('deckFxPanDW', 1, FxPanDW[1]);
			}
			break;
		case 0x3B:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPanDW[3] = FxPanDW[3] + val1; if(FxPanDW[3]<0) FxPanDW[3] = 0; if(FxPanDW[3]>0x7F) FxPanDW[3] = 0x7F;
				call('deckFxPanDW', 3, FxPanDW[3]);
			}
			break;
		case 0x24:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerP1[0] = FxFlangerP1[0] + val1; if(FxFlangerP1[0]<0) FxFlangerP1[0] = 0; if(FxFlangerP1[0]>0x7F) FxFlangerP1[0] = 0x7F;
				call('deckFxFlangerP1', 0, FxFlangerP1[0]);
			}
			break;
		case 0x34:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerP1[2] = FxFlangerP1[2] + val1; if(FxFlangerP1[2]<0) FxFlangerP1[2] = 0; if(FxFlangerP1[2]>0x7F) FxFlangerP1[2] = 0x7F;
				call('deckFxFlangerP1', 2, FxFlangerP1[2]);
			}
			break;
		case 0x2C:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerP1[1] = FxFlangerP1[1] + val1; if(FxFlangerP1[1]<0) FxFlangerP1[1] = 0; if(FxFlangerP1[1]>0x7F) FxFlangerP1[1] = 0x7F;
				call('deckFxFlangerP1', 1, FxFlangerP1[1]);
			}
			break;
		case 0x3C:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxFlangerP1[3] = FxFlangerP1[3] + val1; if(FxFlangerP1[3]<0) FxFlangerP1[3] = 0; if(FxFlangerP1[3]>0x7F) FxFlangerP1[3] = 0x7F;
				call('deckFxFlangerP1', 3, FxFlangerP1[3]);
			}
			break;
		case 0x25:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawP1[0] = FxBeatwawP1[0] + val1; if(FxBeatwawP1[0]<0) FxBeatwawP1[0] = 0; if(FxBeatwawP1[0]>0x7F) FxBeatwawP1[0] = 0x7F;
				call('deckFxBeatwawP1', 0, FxBeatwawP1[0]);
			}
			break;
		case 0x35:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawP1[2] = FxBeatwawP1[2] + val1; if(FxBeatwawP1[2]<0) FxBeatwawP1[2] = 0; if(FxBeatwawP1[2]>0x7F) FxBeatwawP1[2] = 0x7F;
				call('deckFxBeatwawP1', 2, FxBeatwawP1[2]);
			}
			break;
		case 0x2D:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawP1[1] = FxBeatwawP1[1] + val1; if(FxBeatwawP1[1]<0) FxBeatwawP1[1] = 0; if(FxBeatwawP1[1]>0x7F) FxBeatwawP1[1] = 0x7F;
				call('deckFxBeatwawP1', 1, FxBeatwawP1[1]);
			}
			break;
		case 0x3D:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxBeatwawP1[3] = FxBeatwawP1[3] + val1; if(FxBeatwawP1[3]<0) FxBeatwawP1[3] = 0; if(FxBeatwawP1[3]>0x7F) FxBeatwawP1[3] = 0x7F;
				call('deckFxBeatwawP1', 3, FxBeatwawP1[3]);
			}
			break;
		case 0x26:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoP1[0] = FxEchoP1[0] + val1; if(FxEchoP1[0]<0) FxEchoP1[0] = 0; if(FxEchoP1[0]>0x7F) FxEchoP1[0] = 0x7F;
				call('deckFxEchoP1', 0, FxEchoP1[0]);
			}
			break;
		case 0x36:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoP1[2] = FxEchoP1[2] + val1; if(FxEchoP1[2]<0) FxEchoP1[2] = 0; if(FxEchoP1[2]>0x7F) FxEchoP1[2] = 0x7F;
				call('deckFxEchoP1', 2, FxEchoP1[2]);
			}
			break;
		case 0x2E:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoP1[1] = FxEchoP1[1] + val1; if(FxEchoP1[1]<0) FxEchoP1[1] = 0; if(FxEchoP1[1]>0x7F) FxEchoP1[1] = 0x7F;
				call('deckFxEchoP1', 1, FxEchoP1[1]);
			}
			break;
		case 0x3E:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxEchoP1[3] = FxEchoP1[3] + val1; if(FxEchoP1[3]<0) FxEchoP1[3] = 0; if(FxEchoP1[3]>0x7F) FxEchoP1[3] = 0x7F;
				call('deckFxEchoP1', 3, FxEchoP1[3]);
			}
			break;
		case 0x27:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPhaserP1[0] = FxPhaserP1[0] + val1; if(FxPhaserP1[0]<0) FxPhaserP1[0] = 0; if(FxPhaserP1[0]>0x7F) FxPhaserP1[0] = 0x7F;
				call('deckFxPhaserP1', 0, FxPhaserP1[0]); //era pan inainte
			}
			break;
		case 0x37:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPhaserP1[2] = FxPhaserP1[2] + val1; if(FxPhaserP1[2]<0) FxPhaserP1[2] = 0; if(FxPhaserP1[2]>0x7F) FxPhaserP1[2] = 0x7F;
				call('deckFxPhaserP1', 2, FxPhaserP1[2]); //era pan inainte
			}
			break;
		case 0x2F:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPanP1[1] = FxPanP1[1] + val1; if(FxPanP1[1]<0) FxPanP1[1] = 0; if(FxPanP1[1]>0x7F) FxPanP1[1] = 0x7F;
				call('deckFxPanP1', 1, FxPanP1[1]);
			}
			break;
		case 0x3F:
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				FxPanP1[3] = FxPanP1[3] + val1; if(FxPanP1[3]<0) FxPanP1[3] = 0; if(FxPanP1[3]>0x7F) FxPanP1[3] = 0x7F;
				call('deckFxPanP1', 3, FxPanP1[3]);
			}
			break;

		// decks
		
		// deck A
            case 0x44:
                if(data2>0x40)
                {
                    // simulate a fast press-release (like a button)
                    call('deckLoopLess', 0, 0x7F); call('deckLoopLess', 0, 0x00);
                }else
                {
                    call('deckLoopMore', 0, 0x7F); call('deckLoopMore', 0, 0x00);
                }
                break;
            case 0x45:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 0, 0x7F); call('deckLoopPrev', 0, 0x00);
                }else
                {
                    call('deckLoopNext', 0, 0x7F); call('deckLoopNext', 0, 0x00);
                }
                break;
            case 0x54:
                if(data2>0x40)
                {
                    call('deckLoopLess', 0, 0x7F); call('deckLoopLess', 0, 0x00);
                }else
                {
                    call('deckLoopMore', 0, 0x7F); call('deckLoopMore', 0, 0x00);
                }
                break;
            case 0x55:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 0, 0x7F); call('deckLoopPrev', 0, 0x00);
                }else
                {
                    call('deckLoopNext', 0, 0x7F); call('deckLoopNext', 0, 0x00);
                }
                break;
		case 0x00: call('setDeckCutoff', 0, data2); break;
		case 0x01: call('setDeckEqHigh', 0, data2); break;
		case 0x02: call('setDeckEqMid', 0, data2); break;
		case 0x03: call('setDeckEqLow', 0, data2); break;
		case 0x70: call('setDeckVolume', 0, data2); break; 
		case 0x68: call('deckMonitor', 0, data2); break;
					
		//deck B
            case 0x4C:
                if(data2>0x40)
                {
                    // simulate a fast press-release (like a button)
                    call('deckLoopLess', 1, 0x7F); call('deckLoopLess', 1, 0x00);
                }else
                {
                    call('deckLoopMore', 1, 0x7F); call('deckLoopMore', 1, 0x00);
                }
                break;
            case 0x4D:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 1, 0x7F); call('deckLoopPrev', 1, 0x00);
                }else
                {
                    call('deckLoopNext', 1, 0x7F); call('deckLoopNext', 1, 0x00);
                }
                break;
            case 0x5C:
                if(data2>0x40)
                {
                    call('deckLoopLess', 1, 0x7F); call('deckLoopLess', 1, 0x00);
                }else
                {
                    call('deckLoopMore', 1, 0x7F); call('deckLoopMore', 1, 0x00);
                }
                break;
            case 0x5D:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 1, 0x7F); call('deckLoopPrev', 1, 0x00);
                }else
                {
                    call('deckLoopNext', 1, 0x7F); call('deckLoopNext', 1, 0x00);
                }
                break;
		case 0x04: call('setDeckCutoff', 1, data2); break;
		case 0x05: call('setDeckEqHigh', 1, data2); break;
		case 0x06: call('setDeckEqMid', 1, data2); break;
		case 0x07: call('setDeckEqLow', 1, data2); break;
		case 0x71: call('setDeckVolume', 1, data2); break;
		case 0x69: call('deckMonitor', 1, data2); break;
		
		//deck C
            case 0x46:
                if(data2>0x40)
                {
                    // simulate a fast press-release (like a button)
                    call('deckLoopLess', 2, 0x7F); call('deckLoopLess', 2, 0x00);
                }else
                {
                    call('deckLoopMore', 2, 0x7F); call('deckLoopMore', 2, 0x00);
                }
                break;
            case 0x47:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 2, 0x7F); call('deckLoopPrev', 2, 0x00);
                }else
                {
                    call('deckLoopNext', 2, 0x7F); call('deckLoopNext', 2, 0x00);
                }
                break;
            case 0x56:
                if(data2>0x40)
                {
                    call('deckLoopLess', 2, 0x7F); call('deckLoopLess', 2, 0x00);
                }else
                {
                    call('deckLoopMore', 2, 0x7F); call('deckLoopMore', 2, 0x00);
                }
                break;
            case 0x57:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 2, 0x7F); call('deckLoopPrev', 2, 0x00);
                }else
                {
                    call('deckLoopNext', 2, 0x7F); call('deckLoopNext', 2, 0x00);
                }
                break;
		case 0x08: call('setDeckCutoff', 2, data2); break;
		case 0x09: call('setDeckEqHigh', 2, data2); break;
		case 0x0A: call('setDeckEqMid', 2, data2); break;
		case 0x0B: call('setDeckEqLow', 2, data2); break;
		case 0x72: call('setDeckVolume', 2, data2); break;
		case 0x6C: call('deckMonitor', 2, data2); break;
		
		//deck D
            case 0x4E:
                if(data2>0x40)
                {
                    // simulate a fast press-release (like a button)
                    call('deckLoopLess', 3, 0x7F); call('deckLoopLess', 3, 0x00);
                }else
                {
                    call('deckLoopMore', 3, 0x7F); call('deckLoopMore', 3, 0x00);
                }
                break;
            case 0x4F:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 3, 0x7F); call('deckLoopPrev', 3, 0x00);
                }else
                {
                    call('deckLoopNext', 3, 0x7F); call('deckLoopNext', 3, 0x00);
                }
                break;
            case 0x5E:
                if(data2>0x40)
                {
                    call('deckLoopLess', 3, 0x7F); call('deckLoopLess', 3, 0x00);
                }else
                {
                    call('deckLoopMore', 3, 0x7F); call('deckLoopMore', 3, 0x00);
                }
                break;
            case 0x5F:
                if(data2>0x40)
                {
                    call('deckLoopPrev', 3, 0x7F); call('deckLoopPrev', 3, 0x00);
                }else
                {
                    call('deckLoopNext', 3, 0x7F); call('deckLoopNext', 3, 0x00);
                }
                break;
		case 0x0C: call('setDeckCutoff', 3, data2); break;
		case 0x0D: call('setDeckEqHigh', 3, data2); break;
		case 0x0E: call('setDeckEqMid', 3, data2); break;
		case 0x0F: call('setDeckEqLow', 3, data2); break;
		case 0x73: call('setDeckVolume', 3, data2); break;
		case 0x6D: call('deckMonitor', 3, data2); break;
				
		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 0x40: if(data2>0x3F) call('lbToggleSelect', data2); break;
		case 0x41: if(data2>0x3F) call('record', data2); break;
		
		// deck A
		case 0x20: if(data2>0x3F) call('deckLBLoad', 0, data2); break;
		case 0x30: if(data2>0x3F) call('deckLBLoad', 0, data2); break;
		case 0x59: call('deckPlayPause', 0, data2); break;
		case 0x5A: call('deckCue', 0, data2); break;
		case 0x5B: call('deckCuePlay', 0, data2); break;
		case 0x58: call('deckSync', 0, data2); break;
		case 0x48: call('deckBendDown', 0, data2); break;
		case 0x49: call('deckBendUp', 0, data2); break;
		case 0x4C: call('deckCuePos1', 0, data2); break;
		case 0x4D: call('deckCuePos2', 0, data2); break;
		case 0x62: call('deckCuePos3', 0, data2); break;
		case 0x63: call('deckCuePos4', 0, data2); break;
		case 0x22: call('deckKeyLock', 0, data2); break;
		case 0x32: call('deckKeyLock', 0, data2); break;
		case 0x00: call('deckReverse', 0, data2); break;
		case 0x01: call('deckBrake', 0, data2); break;
		case 0x02: call('deckSkipBeatNext', 0, data2); break;
		case 0x03: call('deckResetPitch', 0, data2); break;
		case 0x24: call('deckLoopInEnd', 0, data2); break;
		case 0x34: call('deckLoopInEnd', 0, data2); break;
		case 0x25: call('deckLoopExit', 0, data2); break;
		case 0x35: call('deckLoopExit', 0, data2); break;
		
		// deck B
		case 0x28: if(data2>0x3F) call('deckLBLoad', 1, data2); break;
		case 0x38: if(data2>0x3F) call('deckLBLoad', 1, data2); break;
		case 0x5D: call('deckPlayPause', 1, data2); break;
		case 0x5E: call('deckCue', 1, data2); break;
		case 0x5F: call('deckCuePlay', 1, data2); break;
		case 0x5C: call('deckSync', 1, data2); break;
		case 0x4A: call('deckBendDown', 1, data2); break;
		case 0x4B: call('deckBendUp', 1, data2); break;
		case 0x4E: call('deckCuePos1', 1, data2); break;
		case 0x4F: call('deckCuePos2', 1, data2); break;
		case 0x66: call('deckCuePos3', 1, data2); break;
		case 0x67: call('deckCuePos4', 1, data2); break;
		case 0x2A: call('deckKeyLock', 1, data2); break;
		case 0x3A: call('deckKeyLock', 1, data2); break;
		case 0x08: call('deckReverse', 1, data2); break;
		case 0x09: call('deckBrake', 1, data2); break;
		case 0x0A: call('deckSkipBeatNext', 1, data2); break;
		case 0x0B: call('deckResetPitch', 1, data2); break;
		case 0x2C: call('deckLoopInEnd', 1, data2); break;
		case 0x3C: call('deckLoopInEnd', 1, data2); break;
		case 0x2D: call('deckLoopExit', 1, data2); break;
		case 0x3D: call('deckLoopExit', 1, data2); break;
	
		// deck C
		case 0x21: if(data2>0x3F) call('deckLBLoad', 2, data2); break;
		case 0x31: if(data2>0x3F) call('deckLBLoad', 2, data2); break;
		case 0x69: call('deckPlayPause', 2, data2); break;
		case 0x6A: call('deckCue', 2, data2); break;
		case 0x6B: call('deckCuePlay', 2, data2); break;
		case 0x68: call('deckSync', 2, data2); break;
		case 0x50: call('deckBendDown', 2, data2); break;
		case 0x51: call('deckBendUp', 2, data2); break;
		case 0x54: call('deckCuePos1', 2, data2); break;
		case 0x55: call('deckCuePos2', 2, data2); break;
		case 0x72: call('deckCuePos3', 2, data2); break;
		case 0x73: call('deckCuePos4', 2, data2); break;
		case 0x23: call('deckKeyLock', 2, data2); break;
		case 0x33: call('deckKeyLock', 2, data2); break;
		case 0x10: call('deckReverse', 2, data2); break;
		case 0x11: call('deckBrake', 2, data2); break;
		case 0x12: call('deckSkipBeatNext', 2, data2); break;
		case 0x13: call('deckResetPitch', 2, data2); break;
		case 0x26: call('deckLoopInEnd', 2, data2); break;
		case 0x36: call('deckLoopInEnd', 2, data2); break;
		case 0x27: call('deckLoopExit', 2, data2); break;
		case 0x37: call('deckLoopExit', 2, data2); break;
		
		// deck D
		case 0x29: if(data2>0x3F) call('deckLBLoad', 3, data2); break;
		case 0x39: if(data2>0x3F) call('deckLBLoad', 3, data2); break;
		case 0x6D: call('deckPlayPause', 3, data2); break;
		case 0x6E: call('deckCue', 3, data2); break;
		case 0x6F: call('deckCuePlay', 3, data2); break;
		case 0x6C: call('deckSync', 3, data2); break;
		case 0x52: call('deckBendDown', 3, data2); break;
		case 0x53: call('deckBendUp', 3, data2); break;
		case 0x56: call('deckCuePos1', 3, data2); break;
		case 0x57: call('deckCuePos2', 3, data2); break;
		case 0x76: call('deckCuePos3', 3, data2); break;
		case 0x77: call('deckCuePos4', 3, data2); break;
		case 0x2B: call('deckKeyLock', 3, data2); break;
		case 0x3B: call('deckKeyLock', 3, data2); break;
		case 0x18: call('deckReverse', 3, data2); break;
		case 0x19: call('deckBrake', 3, data2); break;
		case 0x1A: call('deckSkipBeatNext', 3, data2); break;
		case 0x1B: call('deckResetPitch', 3, data2); break;
		case 0x2E: call('deckLoopInEnd', 3, data2); break;
		case 0x3E: call('deckLoopInEnd', 3, data2); break;
		case 0x2F: call('deckLoopExit', 3, data2); break;
		case 0x3F: call('deckLoopExit', 3, 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)
{
	//if(deck>=2) return;
	//debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
	var nameLen = name.length;
	if(name=='play')
	{
		sendMidi(uniqueId,0x90,deck,11,(param1 ? 0x7F : 0x00));
		// jog-wheels light display (rotate leds)
		if(param1)
		{
			if(getValue('reverse', deck))
				sendMidi(uniqueId,0xB0,6,0x1B+deck, 0x3F);// to left
			else
				sendMidi(uniqueId,0xB0,6,0x1B+deck, 0x41);// to right
		}else
		{
			sendMidi(uniqueId,0xB0,6,0x1B+deck, 0x40);// off
		}
	}
	if(name=='reverse')
	{
		if(getValue('play', deck)) 
		{
			if(param1)
				sendMidi(uniqueId,0xB0,6,0x1B+deck, 0x3F);// to left
			else
				sendMidi(uniqueId,0xB0,6,0x1B+deck, 0x41);// to right
		}
	}
	if(name=='cue') 		 sendMidi(uniqueId,0x90,deck,12,(param1 ? 0x7F : 0x00));
	if(name=='onbeat') 		 sendMidi(uniqueId,0x90,deck,88,(param1 ? 0x7F : 0x00));
	if(name=='keyLock')      sendMidi(uniqueId,0x90,deck,26,(param1 ? 0x7F : 0x00));
	if(name=='loopIn')       sendMidi(uniqueId,0x90,deck,16,(param1 ? 0x7F : 0x00));
	if(name=='loopExit')     sendMidi(uniqueId,0x90,deck,17,(param1 ? 0x7F : 0x00));
	if(name=='monitor')		 
	{
		if(deck==0)	sendMidi(uniqueId,0x90,6,84,(param1 ? 0x7F : 0x00));
		if(deck==1)	sendMidi(uniqueId,0x90,6,85,(param1 ? 0x7F : 0x00));
		if(deck==2)	sendMidi(uniqueId,0x90,6,86,(param1 ? 0x7F : 0x00));
		if(deck==3)	sendMidi(uniqueId,0x90,6,87,(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),0x3C+(samplerIdx%4)*2,0x00);
				// instead of Math.floor(19/4), parseInt(19/4) = 4 can also be used
			}else
			{
				sendMidi(uniqueId,0x90,Math.floor(samplerIdx/4),0x3C+(samplerIdx%4)*2,0x7F);
				if(param2>0) samplerBlinkLedStatus[samplerIdx] = 2;else samplerBlinkLedStatus[samplerIdx] = 1;
			}
		}
	}	
}
//----------------------------------------------------------------------------- 
// 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 DDJErgo ['+uniqueId+']');
	for(var deck=0; deck<2; deck++)
	{
		// 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,0x3C+i*2,((samplerBlinkLedStatus[ledIdx]==2) ? 0x7F : 0x00));
			}
		}
	}
}
//----------------------------------------------------------------------------- 
