//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2012 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Pioneer DDJ-ERGO'
//----------------------------------------------------------------------------- 
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 "DDJ-ERGO MIDI";
}
//----------------------------------------------------------------------------- 
// 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 "PIONEER DDJ-ERGO";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	return "DDJ-ERGO MIDI";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "PIONEER DDJ-ERGO";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	return "DDJ-ERGO MIDI";
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// 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 DDJ-ERGO MIDI ['+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
}
//----------------------------------------------------------------------------- 
// 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)
		{
		// do nothing
		case 0x20: // pitch/master vol
		case 0x33: // volume A
		case 0x34: // volume mic
		case 0x35: // volume B
		case 0x37: // volume C
		case 0x39: // volume D
		case 0x3F: //crossfader
		case 0x2F: //eq low A
		case 0x30: //eq low B
		case 0x31: //eq low C
		case 0x32: //eq low D
		case 0x2B: //eq mid A
		case 0x2C: //eq mid B
		case 0x2D: //eq mid C
		case 0x2E: //eq mid D
		case 0x28: //eq high B
		case 0x29: //eq high C
		case 0x2A: //eq high D
		case 0x3B: //filter A
		case 0x3C: //filter B
		case 0x3D: //filter C
		case 0x3E: //filter D
		case 0x24: //gain B
		case 0x25: //gain C
			break;
		
		// global
		case 0x1F: if(channel==6) call('setCrossfader', data2); break;
		case 0x01: if(channel==6) call('setCuePgmMix', data2); break;
		case 0x02: if(channel==6) call('setMonitorGain', data2);
				   if(channel==4) call('deckFxBeatwawDW', 0, data2); 
				   if(channel==5) call('deckFxBeatwawDW', 1, data2); 
				   break;	
		case 0x14: 
				if(channel==6) call('setMicGain', data2); 
				if(channel==4) call('deckFxEchoDW', 2, data2);
				if(channel==5) call('deckFxEchoDW', 3, data2);
				break;
		case 0x40: 
			if(channel==6) 
			{
				var val1 = (data2>0x40 ? data2-0x80 : data2);
				call('lbMoveCursor', val1);
			}
			break;

		case 0x00: 
			if(channel<4) 
			{
				call('setDeckPitch', channel, 0x7F - data2); // volume
			}else
			{
				if(channel==4) call('deckFxFlangerDW', 0, data2);
				if(channel==5) call('deckFxFlangerDW', 1, data2);
				if(channel==6) call('setMasterGain', data2);	
			}
			break;
		
		// decks
		case 0x0F: if(channel==6) call('setDeckEqLow', 0, data2); break; // eq low A
		case 0x10: if(channel==6) call('setDeckEqLow', 1, data2);
				   if(channel==4) call('deckFxFlangerDW', 2, data2);
				   if(channel==5) call('deckFxFlangerDW', 3, data2);
				   break;
		case 0x11: if(channel==6) call('setDeckEqLow', 2, data2); break; // eq low C
		case 0x12: if(channel==6) call('setDeckEqLow', 3, data2); 
				   if(channel==4) call('deckFxBeatwawDW', 2, data2); 
				   if(channel==5) call('deckFxBeatwawDW', 3, data2);
					break;
		case 0x0B: if(channel==6) call('setDeckEqMid', 0, data2); break; // eq mid A
		case 0x0C: if(channel==6) call('setDeckEqMid', 1, data2); break; // eq mid B
		case 0x0D: if(channel==6) call('setDeckEqMid', 2, data2); break; // eq mid C
		case 0x0E: if(channel==6) call('setDeckEqMid', 3, data2); break; // eq mid D
		case 0x07: if(channel==6) call('setDeckEqHigh', 0, data2); break; // eq high A
		case 0x08: if(channel==6) call('setDeckEqHigh', 1, data2); break; // eq high B
		case 0x09: if(channel==6) call('setDeckEqHigh', 2, data2); break; // eq high C
		case 0x0A: if(channel==6) call('setDeckEqHigh', 3, data2); break; // eq high D
		case 0x03: if(channel==6) call('setDeckGain', 0, data2); break; // gain A 
		// pitch key encoder
		case 0x44: var val1 = (data2>0x40 ? data2-0x80 : data2);
					pitchKeyValue[channel] += val1*2;
					if(pitchKeyValue[channel]<0) pitchKeyValue[channel] = 0;
					if(pitchKeyValue[channel]>127) pitchKeyValue[channel] = 127;
					call('setDeckPitchKey', channel, pitchKeyValue[channel]); 
					break;
		case 0x04: if(channel==6) call('setDeckGain', 1, data2);
				   if(channel==4) call('deckFxEchoDW', 0, data2);
				   if(channel==5) call('deckFxEchoDW', 1, data2); 
				   break;		
		case 0x05: if(channel==6) call('setDeckGain', 2, data2); break; // gain C
		case 0x06: if(channel==6) call('setDeckGain', 3, data2);
				   if(channel==4) call('deckFxPanDW', 0, data2);
				   if(channel==5) call('deckFxPanDW', 1, data2); 
				   break;
		case 0x16: if(channel==4) call('deckFxPanDW', 2, data2);
				   if(channel==5) call('deckFxPanDW', 3, data2); 
				   break;
		case 0x1B: if(channel==6) call('setDeckCutoff', 0, data2); break; // filter A
		case 0x1C: if(channel==6) call('setDeckCutoff', 1, data2); break; // filter B
		case 0x1D: if(channel==6) call('setDeckCutoff', 2, data2); break; // filter C
		case 0x1E: if(channel==6) call('setDeckCutoff', 3, data2); break; // filter D
		case 0x13:
			if(channel==6) 
			{
				call('setDeckVolume', 0, data2); 
			}else
			{
				if(data2>0x40) call('deckLoopLess', channel, data2); else call('deckLoopMore', channel, data2);
			}
			break; // volume A
		case 0x15: if(channel==6) call('setDeckVolume', 1, data2); break; // volume B
		case 0x17: if(channel==6) call('setDeckVolume', 2, data2); break; // volume C
		case 0x19: if(channel==6) call('setDeckVolume', 3, data2); break; // volume D
				
		// JOG-WHEEL
		// search
		case 0x26: // also gain D extra byte
		case 0x27: // pressed (also eq high A extra byte)
			if(channel<4)
			{
				var val1 = data2-0x40;
				if(val1<0)
				{
					jwSearchCountLeft[channel]++;
					jwSearchCountRight[channel]=0;
					if(jwSearchCountLeft[channel]>8)
					{
						call('deckSkipBarPrev', channel, 0x7F);
						call('deckSkipBarPrev', channel, 0x00);
						jwSearchCountLeft[channel]=0;
					}
				}else
				{
					jwSearchCountRight[channel]++;
					jwSearchCountLeft[channel]=0;
					if(jwSearchCountRight[channel]>8)
					{
						call('deckSkipBarNext', channel, 0x7F);
						call('deckSkipBarNext', channel, 0x00);
						jwSearchCountRight[channel]=0;
					}
				}
			}
			break;
		// bend
		case 0x21: // params: (deck, increment, total positions per complete revolution) 
			if(channel<4)
			{
				var val1 = data2-0x40;
				call('moveDeckJogWheel', channel, val1, 2450);
			}
			// also pfl mix (extra byte)
			break;
		// scratch
		case 0x23: // also gain A extra byte
		case 0x22: // pressed // params: (deck, increment, total positions per complete revolution); also monitor vol extra byte
			if(channel<4)
			{
				var val1 = data2-0x40;
				call('scratchDeckJW', channel, val1, 2450);
			}
			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 0x41: if(data2>0x3F) call('lbToggleSelect', data2); break;
		case 0x65: if(channel==6) call('record', data2);
				   if(channel==4) call('deckFxPan', 2, data2);
				   if(channel==5) call('deckFxPan', 3, data2);
				   break;
		// decks
		case 0x0B: call('deckPlayPause', channel, data2); break;
		case 0x0C: call('deckCue', channel, data2); break;
		case 0x48:
			if(channel<4) call('deckCuePlay', channel, data2);
			if(data2>0x3F) if(channel==6) call('deckLBLoad', 2, data2);
			if(channel==4) call('deckFxEcho', 0, data2);
			if(channel==5) call('deckFxEcho', 1, data2);
			break;
		case 0x58: call('deckSync', channel, data2); break;
		case 0x10: call('deckLoopInEnd', channel, data2); break;
		case 0x11: call('deckLoopExit', channel, data2); break;
		case 0x4C: call('deckLoopPrev', channel, data2); break;
		case 0x4D: call('deckLoopNext', channel, data2); break;
		case 0x2E: call('deckCuePos1', channel, data2); break;
		case 0x2F: call('deckCuePos2', channel, data2); break;
		case 0x30: call('deckCuePos3', channel, data2); break;
		case 0x31: call('deckCuePos4', channel, data2); break;
		case 0x1A: call('deckKeyLock', channel, data2);	break;			
		//case 0x15: call('deckAnalogIn', channel, data2); break;// disabled as this controls the jog-wheel behaviour
		case 0x36:
		case 0x37: call('holdDeckJogWheel', channel, data2); break;
		// sampler
		case 0x3C: if(channel==0) if(data2>0x3F) call('samplerPlay', 1);
				   if(channel==1) if(data2>0x3F) call('samplerPlay', 5);
				   break;
		case 0x3E: if(channel==0) if(data2>0x3F) call('samplerPlay', 2);
				   if(channel==1) if(data2>0x3F) call('samplerPlay', 6);
				   break;
		case 0x40: if(channel==0) if(data2>0x3F) call('samplerPlay', 3);
				   if(channel==1) if(data2>0x3F) call('samplerPlay', 7);
				   // effects
				   if(channel==4) call('deckFxFlanger', 2, data2);
				   if(channel==5) call('deckFxFlanger', 3, data2);
				   break;
		case 0x42: if(channel==0) if(data2>0x3F) call('samplerPlay', 4);
				   if(channel==1) if(data2>0x3F) call('samplerPlay', 8);
				   break;
		// effects
		case 0x43: if(channel==4) call('deckFxFlanger', 0, data2);
				   if(channel==5) call('deckFxFlanger', 1, data2);
				   break;
		case 0x63: if(channel==4) call('deckFxBeatwaw', 2, data2);
				   if(channel==5) call('deckFxBeatwaw', 3, data2);
				   break;
		case 0x64: if(channel==4) call('deckFxEcho', 2, data2);
				   if(channel==5) call('deckFxEcho', 3, data2);
				   break;
		case 0x54: if(channel==6) call('deckMonitor', 0, data2); break;
		case 0x55: if(channel==6) call('deckMonitor', 1, data2); break;
		case 0x56: if(channel==6) call('deckMonitor', 2, data2); break;
		case 0x57: if(channel==6) call('deckMonitor', 3, data2); break;
		case 0x46: if(data2>0x3F) if(channel==6) call('deckLBLoad', 0, data2); break;
		case 0x47: if(channel<4)  call('deckReverse', channel, data2);
				   if(channel==4) call('deckFxBeatwaw', 0, data2);
				   if(channel==5) call('deckFxBeatwaw', 1, data2);
				   if(data2>0x3F) if(channel==6) call('deckLBLoad', 1, data2);
				   break;
		case 0x49: if(channel==4) call('deckFxPan', 0, data2);
				   if(channel==5) call('deckFxPan', 1, data2);
				   if(data2>0x3F) if(channel==6) call('deckLBLoad', 3, data2);
				   break;
		case 0x14: if(!getValue('looping', channel)) call('deckLoopInEnd', channel, data2);else call('deckLoopExit', channel, 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));
			}
		}
	}
}
//----------------------------------------------------------------------------- 
