//-----------------------------------------------------------------------------
//------------ Copyright (c)2003-2018 Xylio. All Rights Reserved. -------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Reloop Mixage CE/IE' (script v3)
//-----------------------------------------------------------------------------
function getLanguageVersion()
{
	return 1;// do not modify this, this should be 1 for all scripts
}
//-----------------------------------------------------------------------------
function getFileVersion()
{
	return 3;// update this as needed
}
//-----------------------------------------------------------------------------
// return a user friendly name for the controller supported
function getControllerUserFriendlyName()
{
	return "Reloop Mixage CE/IE";
}
//-----------------------------------------------------------------------------
// 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 (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 0x200C;
}
//-----------------------------------------------------------------------------
function getSupportedMidiDevicePID(osId)
{
	return 0x0015;// Mixage CE (Controller Edition)
}
//-----------------------------------------------------------------------------
function getSupportedMidiDeviceVID2(osId)
{
	return 0x200C;
}
//-----------------------------------------------------------------------------
function getSupportedMidiDevicePID2(osId)
{
	return 0x1017;// Mixage IE (Interface Edition)
}
//-----------------------------------------------------------------------------
// 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 "002079200C0015";// Reloop Mixage CE
}
//-----------------------------------------------------------------------------
function getSupportedMidiSysExIdString2(osId)
{
	//return "002079200C101701";// a bit longer 8-bytes sysex id -- old one (1 byte longer)
	return "002079200C1017";// Reloop Mixage IE
}
//-----------------------------------------------------------------------------
// 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 "Reloop Mixage IE";
	//return "Reloop MACEA";// for the CE version
	return false;
}
//-----------------------------------------------------------------------------
function getSupportedMidiDeviceNameForOutput(osId)
{
	//return "Reloop Mixage IE";
	//return "Reloop MACEA";// for the CE version
	return false;
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// some variables necessary only for this particular script
var fxParams=[0,0,0,0,0,0,0,0];
var jogWheelsInSearchMode=[0,0,0,0];
var jogWheelsInScratchMode=[0,0,0,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 Reloop Mixage CE/IE ['+uniqueId+']');// this outputs a string to DebugView app on Win

	// setting audio (the actual routing is done automatically for this controller so
	// we don't need to manually set "RoutingOutHeadphones", "RoutingOutDeckA", etc
	// ATTN: we first try to set ASIO mode, and only then regular CoreAudio, DirectSound audio/WDM/Wasapi
	if(setAudioDevice("Mixage Interface Edition|||Reloop Mixage IE|||Speakers (Mixage Interface Edition WDM Audio 2.9.53)|||Speakers (Reloop Mixage IE)|||Speakers (Mixage Interface Edition)"))
	{
		//debug('AudioDevice was set OK');
		setSetting('AudioDevice2', "NO AUDIO");
	}

	//deck A
	//sendMidi(uniqueId,0x90,0,0x09,0x00);// Sync
	//sendMidi(uniqueId,0x90,0,0x0A,0x00);// Cueplay
	//sendMidi(uniqueId,0x90,0,0x0B,(getValue('cue', 0)? 0x7F : 0x00));// Cue
	//sendMidi(uniqueId,0x90,0,0x0C,(getValue('play', 0) ? 0x7F : 0x00));// PlayPause
	sendMidi(uniqueId,0x90,0,0x01,0x00);// Pitchbend -
	sendMidi(uniqueId,0x90,0,0x02,0x00);// Pitchbend +
	sendMidi(uniqueId,0x90,0,0x03,0x00);// Search LED
	sendMidi(uniqueId,0x90,0,0x04,0x00);// Scratch LED
	//sendMidi(uniqueId,0x90,0,0x05,(getValue('loopIn', 0) ? 0x7F : 0x00));// Loop
	//sendMidi(uniqueId,0x90,0,0x06,0x00);// Reloop
	sendMidi(uniqueId,0x90,0,0x07,0x00);// Fx Sel
	//sendMidi(uniqueId,0x90,0,0x08,(getValue('keyLock', 0) ? 0x7F : 0x00));// Keylock
	sendMidi(uniqueId,0x90,0,0x0D,0x00);// Load
	//sendMidi(uniqueId,0x90,0,0x0E,(getValue('monitor', 0) ? 0x7F : 0x00));// Monitor
	//sendMidi(uniqueId,0x90,0,0x1D,(getValue('volume', 0) ? 0x7F : 0x00)); ??

	//deck B
	//sendMidi(uniqueId,0x90,0,0x17,0x00);// Sync
	//sendMidi(uniqueId,0x90,0,0x18,0x00);// Cueplay
	//sendMidi(uniqueId,0x90,0,0x19,(getValue('cue', 1) ? 0x7F : 0x00));// Cue
	//sendMidi(uniqueId,0x90,0,0x1A,(getValue('play', 1) ? 0x7F : 0x00));// PlayPause
	sendMidi(uniqueId,0x90,0,0x0F,0x00);// Pitchbend -
	sendMidi(uniqueId,0x90,0,0x10,0x00);// Pitchbend +
	sendMidi(uniqueId,0x90,0,0x11,0x00);// Search LED
	sendMidi(uniqueId,0x90,0,0x12,0x00);// Scratch LED
	//sendMidi(uniqueId,0x90,0,0x13,(getValue('loopIn', 1) ? 0x7F : 0x00));// Loop
	//sendMidi(uniqueId,0x90,0,0x14,0x00);// Reloop
	sendMidi(uniqueId,0x90,0,0x15,0x00);// Fx Sel
	//sendMidi(uniqueId,0x90,0,0x16,(getValue('keyLock', 1) ? 0x7F : 0x00));// Keylock
	sendMidi(uniqueId,0x90,0,0x1B,0x00);// Load
	//sendMidi(uniqueId,0x90,0,0x1C,(getValue('monitor', 1) ? 0x7F : 0x00));// Monitor
	//sendMidi(uniqueId,0x90,0,0x1E,(getValue('volume', 0) ? 0x7F : 0x00)); ??
	//------------------------------------
	callSendAllNotifications(uniqueId, true);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
}
//-----------------------------------------------------------------------------
// called just before the controller will be deinitialized and the control will go away from the script
// use to power off any powered leds, etc
function controllerDeinit(uniqueId)
{
	debug('controllerDeinit Reloop Mixage CE/IE ['+uniqueId+']');

	//------------------------------------
	callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually de-init all leds/lcd screens)

	//deck A
	//sendMidi(uniqueId,0x90,0,0x09,0x00);// Sync
	//sendMidi(uniqueId,0x90,0,0x0A,0x00);// Cueplay
	//sendMidi(uniqueId,0x90,0,0x0B,0x00);// Cue
	//sendMidi(uniqueId,0x90,0,0x0C,0x00);// PlayPause
	sendMidi(uniqueId,0x90,0,0x01,0x00);// Pitchbend -
	sendMidi(uniqueId,0x90,0,0x02,0x00);// Pitchbend +
	sendMidi(uniqueId,0x90,0,0x03,0x00);// Search LED
	sendMidi(uniqueId,0x90,0,0x04,0x00);// Scratch LED
	//sendMidi(uniqueId,0x90,0,0x05,0x00);// Loop
	//sendMidi(uniqueId,0x90,0,0x06,0x00);// Reloop
	sendMidi(uniqueId,0x90,0,0x07,0x00);// Fx Sel
	//sendMidi(uniqueId,0x90,0,0x08,0x00);// Keylock
	sendMidi(uniqueId,0x90,0,0x0D,0x00);// Load
	//sendMidi(uniqueId,0x90,0,0x0E,0x00);// Monitor
	sendMidi(uniqueId,0x90,0,0x1D,0x00);// VU-meter

	//deck B
	//sendMidi(uniqueId,0x90,0,0x17,0x00);// Sync
	//sendMidi(uniqueId,0x90,0,0x18,0x00);// Cueplay
	//sendMidi(uniqueId,0x90,0,0x19,0x00);// Cue
	//sendMidi(uniqueId,0x90,0,0x1A,0x00);// PlayPause
	sendMidi(uniqueId,0x90,0,0x0F,0x00);// Pitchbend -
	sendMidi(uniqueId,0x90,0,0x10,0x00);// Pitchbend +
	sendMidi(uniqueId,0x90,0,0x11,0x00);// Search LED
	sendMidi(uniqueId,0x90,0,0x12,0x00);// Scratch LED
	//sendMidi(uniqueId,0x90,0,0x13,0x00);// Loop
	//sendMidi(uniqueId,0x90,0,0x14,0x00);// Reloop
	sendMidi(uniqueId,0x90,0,0x15,0x00);// Fx Sel
	//sendMidi(uniqueId,0x90,0,0x16,0x00);// Keylock
	sendMidi(uniqueId,0x90,0,0x1B,0x00);// Load
	//sendMidi(uniqueId,0x90,0,0x1C,0x00);// Monitor
	sendMidi(uniqueId,0x90,0,0x1E,0x00);// VU-meter
}
//-----------------------------------------------------------------------------
// 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
		if(channel==0) call('setDeckPitch', 0, data2);
		if(channel==1) call('setDeckPitch', 1, data2);
		break;
	//-----------------------------------------------
	// controllers: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1)
		{
		//global

		case 0x31: call('setCrossfader', data2); break;
		case 0x32: call('setCuePgmMix', data2); break;
		//case 0x17: call('setMasterGain', data2); break; Nu trimite semnal
		//case 0x16: call('setCuePgmMix', data2); break; Nu trimite semnal
		case 0x1F: call('lbMoveCursor', data2-0x40); break;

		//per deck
		//deck A
		case 0x38: call('setDeckVolume', 0, data2); break;
		case 0x37: call('setDeckEqLow', 0, data2); break;
		case 0x36: call('setDeckEqMid', 0, data2); break;
		case 0x35: call('setDeckEqHigh', 0, data2); break;
		case 0x34: call('setDeckCutoff', 0, data2); break;
		case 0x73: call('setDeckPitchKey', 0, data2); break;
		case 0x33: call('setDeckGain', 0, data2); break;
		case 0x20: if(data2==0x3F) call('deckLoopLess', 0, data2); else call('deckLoopMore', 0, data2); break; //loop knob x2 or /2
		case 0x5F: if(data2==0x3F) call('deckLoopPrev', 0, data2); else call('deckLoopNext', 0, data2); break; //loop knob prev/next
		case 0x24: // params: (deck, increment, total positions per complete revolution)
			var val1 = data2-0x40;
			if(jogWheelsInSearchMode[0])
			{
				call('searchDeckJW', 0, val1, 600);
			}else
			{
				if(jogWheelsInScratchMode[0]) call('scratchDeckJW', 0, val1, 600);else call('moveDeckJogWheel', 0, val1, 600);
			}
			break;
		case 0x21: // fx dry-wet
			var val1 = data2-0x40;
			fxParams[0] += val1*8; if(fxParams[0]<0) fxParams[0] = 0; if(fxParams[0]>127) fxParams[0] = 127;
			call('deckFxFlangerDW', 0, fxParams[0]);
			//debug('flange '+fxParams[0]);
			break;
		case 0x60: // fx dry-wet
			var val1 = data2-0x40;
			fxParams[2] += val1*8; if(fxParams[2]<0) fxParams[2] = 0; if(fxParams[2]>127) fxParams[2] = 127;
			call('deckFxBeatwawDW', 0, fxParams[2]);
			//debug('bw '+fxParams[2]);
			break;

		//deck B
		case 0x3E: call('setDeckVolume', 1, data2); break;
		case 0x3D: call('setDeckEqLow', 1, data2); break;
		case 0x3C: call('setDeckEqMid', 1, data2); break;
		case 0x3B: call('setDeckEqHigh', 1, data2); break;
		case 0x3A: call('setDeckCutoff', 1, data2); break;
		case 0x79: call('setDeckPitchKey', 1, data2); break;
		case 0x39: call('setDeckGain', 1, data2); break;
		case 0x22: if(data2==0x3F) call('deckLoopLess', 1, data2); else call('deckLoopMore', 1, data2); break; //loop knob x2 or /2
		case 0x61: if(data2==0x3F) call('deckLoopPrev', 1, data2); else call('deckLoopNext', 1, data2); break; //loop knob prev/next
		case 0x25: // params: (deck, increment, total positions per complete revolution)
			var val1 = data2-0x40;
			if(jogWheelsInSearchMode[1])
			{
				call('searchDeckJW', 1, val1, 600);
			}else
			{
				if(jogWheelsInScratchMode[1]) call('scratchDeckJW', 1, val1, 600);else call('moveDeckJogWheel', 1, val1, 600);
			}
			break;
		case 0x23: // fx dry-wet
			var val1 = data2-0x40;
			fxParams[1] += val1*8; if(fxParams[1]<0) fxParams[1] = 0; if(fxParams[1]>127) fxParams[1] = 127;
			call('deckFxFlangerDW', 1, fxParams[1]);
			//debug('flange '+fxParams[1]);
			break;
		case 0x62: // fx dry-wet
			var val1 = data2-0x40;
			fxParams[3] += val1*8; if(fxParams[3]<0) fxParams[3] = 0; if(fxParams[3]>127) fxParams[3] = 127;
			call('deckFxBeatwawDW', 1, fxParams[3]);
			//debug('bw '+fxParams[1]);
			break;

		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		//global
		case 0x1F: if(data2>0x3F) call('lbToggleSelect', data2); break;

		//per deck
		//deck A
		case 0x09: call('deckSync', 0, data2); break;
		case 0x0B: call('deckCue', 0, data2); break;
		case 0x0A: call('deckCuePlay', 0, data2); break;
		case 0x0C: call('deckPlayPause', 0, data2); break;
		case 0x48: call('deckCuePos1', 0, data2); break;
		case 0x49: call('deckCuePos2', 0, data2); break;
		case 0x4A: call('deckCuePos3', 0, data2); break;
		case 0x4B: call('deckCuePos4', 0, data2); break;
		case 0x40: call('deckSearchLeft', 0, data2); break;
		case 0x41: call('deckSearchRight', 0, data2); break;
		case 0x01: call('deckBendDown', 0, data2); sendMidi(uniqueId,0x90,0,0x01,data2); break;
		case 0x02: call('deckBendUp', 0, data2); sendMidi(uniqueId,0x90,0,0x02,data2); break;
		case 0x05: call('deckLoopInEnd', 0, data2); break;
		case 0x44: call('deckLoopMore', 0, data2); break;
		case 0x06: call('deckLoopExit', 0, data2); break;
		case 0x45: call('deckLoopReloop', 0, data2); break;
		case 0x08: call('deckKeyLock', 0, data2); break;
		case 0x07: call('deckFxSel', 0, data2); break;
		case 0x0D: if(data2>0x3F) call('deckLBLoad', 0, data2); break;
		case 0x0E: call('deckMonitor', 0, data2); break;
		case 0x20: if(!getValue('looping', 0)) call('deckLoopInEnd', 0, data2);else call('deckLoopExit', 0, data2); break; //Loop (deckLoopReloop)
		case 0x03:
			if(data2>0x3F)
			{
				jogWheelsInSearchMode[0] = (jogWheelsInSearchMode[0]+1) % 2;
				sendMidi(uniqueId,0x90,0,0x03,jogWheelsInSearchMode[0]?0x7F:0x00);
			}
			break;
		//case 0x04: call('deckScratch', 0, data2); break;
		case 0x04:
			if(data2>0x3F)
			{
				jogWheelsInScratchMode[0] = (jogWheelsInScratchMode[0]+1) % 2; // keep the remainder to toggle between scratch mode "0" or jog bend mode "1"
				sendMidi(uniqueId,0x90,0,0x04,jogWheelsInScratchMode[0]?0x7F:0x00);
			}
			break;
		case 0x24: call('holdDeckJogWheel', 0, data2); break;
		case 0x21: // fx dry-wet
			if(data2>0x3F)
			{
				if(fxParams[0]>63) fxParams[0] = 0;else fxParams[0] = 127;
				call('deckFxFlangerDW', 0, fxParams[0]);
			}
			break;
		case 0x60: // fx dry-wet
			if(data2>0x3F)
			{
				if(fxParams[2]>63) fxParams[2] = 0;else fxParams[2] = 127;
				call('deckFxBeatwawDW', 0, fxParams[2]);
			}
			break;

		//deck B
		case 0x17: call('deckSync', 1, data2); break;
		case 0x19: call('deckCue', 1, data2); break;
		case 0x18: call('deckCuePlay', 1, data2); break;
		case 0x1A: call('deckPlayPause', 1, data2); break;
		case 0x56: call('deckCuePos1', 1, data2); break;
		case 0x57: call('deckCuePos2', 1, data2); break;
		case 0x58: call('deckCuePos3', 1, data2); break;
		case 0x59: call('deckCuePos4', 1, data2); break;
		case 0x4E: call('deckSearchLeft', 1, data2); break;
		case 0x4F: call('deckSearchRight', 1, data2); break;
		case 0x0F: call('deckBendDown', 1, data2); sendMidi(uniqueId,0x90,0,0x0F,data2); break;
		case 0x10: call('deckBendUp', 1, data2); sendMidi(uniqueId,0x90,0,0x10,data2); break;
		case 0x13: call('deckLoopInEnd', 1, data2); break;
		case 0x52: call('deckLoopMore', 1, data2); break;
		case 0x14: call('deckLoopExit', 1, data2); break;
		case 0x53: call('deckLoopReloop', 1, data2); break;
		case 0x16: call('deckKeyLock', 1, data2); break;
		case 0x15: call('deckFxSel', 1, data2); break;
		case 0x1B: if(data2>0x3F) call('deckLBLoad', 1, data2); break;
		case 0x1C: call('deckMonitor', 1, data2); break;
		case 0x22: if(!getValue('looping', 1)) call('deckLoopInEnd', 1, data2);else call('deckLoopExit', 1, data2); break; //Loop (deckLoopReloop)

		case 0x11:
			if(data2>0x3F)
			{
				jogWheelsInSearchMode[1] = (jogWheelsInSearchMode[1]+1) % 2;
				sendMidi(uniqueId,0x90,0,0x11,jogWheelsInSearchMode[1]?0x7F:0x00);
			}
			break;
		//case 0x12: call('deckScratch', 1, data2); break;
		case 0x12:
			if(data2>0x3F)
			{
				jogWheelsInScratchMode[1] = (jogWheelsInScratchMode[1]+1) % 2; // keep the remainder to toggle between scratch mode "0" or jog bend mode "1"
				sendMidi(uniqueId,0x90,0,0x12,jogWheelsInScratchMode[1]?0x7F:0x00);
			}
			break;
		case 0x25: call('holdDeckJogWheel', 1, data2); break;

		case 0x23: // fx dry-wet
			if(data2>0x3F)
			{
				if(fxParams[1]>63) fxParams[1] = 0;else fxParams[1] = 127;
				call('deckFxFlangerDW', 1, fxParams[1]);
			}
			break;
		case 0x62: // fx dry-wet
			if(data2>0x3F)
			{
				if(fxParams[3]>63) fxParams[3] = 0;else fxParams[3] = 127;
				call('deckFxBeatwawDW', 1, fxParams[3]);
			}
			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);
	if(name=='cue') 		 sendMidi(uniqueId,0x90,0,(deck==0)?0x0B:0x19,(param1 ? 0x7F : 0x00));
	if(name=='play') 		 sendMidi(uniqueId,0x90,0,(deck==0)?0x0C:0x1A,(param1 ? 0x7F : 0x00));
	//if(name=='fxBeatwaw')  { sendMidi(uniqueId,0x90,0,(deck==0)?0x33:0x44,(param1 ? 0x7F : 0x00)); fxParams[4*deck + 0] = 127*param1;}
	//if(name=='fxFlanger')  { sendMidi(uniqueId,0x90,0,(deck==0)?0x31:0x45,(param1 ? 0x7F : 0x00)); fxParams[4*deck + 1] = 127*param1;}
	//if(name=='fxPan') 	   { sendMidi(uniqueId,0x90,0,(deck==0)?0x32:0x46,(param1 ? 0x7F : 0x00)); fxParams[4*deck + 2] = 127*param1;}
	//if(name=='fxEcho') 	   { sendMidi(uniqueId,0x90,0,(deck==0)?0x30:0x47,(param1 ? 0x7F : 0x00)); fxParams[4*deck + 3] = 127*param1;}
	if(name=='monitor') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x0E:0x1C,(param1 ? 0x7F : 0x00));
	if(name=='onbeat') 		 sendMidi(uniqueId,0x90,0,(deck==0)?0x09:0x17,(param1 ? 0x7F : 0x00));
	if(name=='keyLock') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x08:0x16,(param1 ? 0x7F : 0x00));

	// justLoaded: 1,2 (loading in progress), 4 (loading ended), 8 (progress), 16 (detection started), 32 (detection finished);
	if(name=='justLoaded')
	{
		if(param1!=0 && param1!=32)
		{
			// loading
			sendMidi(uniqueId,0x90,0,(deck==0)?0x0D:0x1B,0x7F);// on
		}else
		{
			// loading finished
			sendMidi(uniqueId,0x90,0,(deck==0)?0x0D:0x1B,0x00);// off
		}
	}

	/*
	if(name=='loopBlink')
	{
		// 'loopBlink' = off (no loopIn, no looping); blink (loopIn, no looping yet); on (no loopIn, looping);
		if(getValue('loopIn', deck))
		{
			sendMidi(uniqueId,0xB0,deck+1,0x1B,(param1 ? 0x0C : 0x0D));// alternate the 2 dots
		}else
		{
			if(!getValue('looping', deck))
			{
				sendMidi(uniqueId,0xB0,deck+1,0x1B,0x05);// we first set it to loop 1 so that the dot will disappear
				sendMidi(uniqueId,0xB0,deck+1,0x1C,0x00);
				sendMidi(uniqueId,0xB0,deck+1,0x1D,0x00);
			}
		}
	}
	*/

	if(name=='loopBlink')
	{
		// buttons leds
		sendMidi(uniqueId,0x90,0,(deck==0)?0x05:0x13,(param1 ? 0x7F : 0x00));// loop in // deckLoopInEnd
		sendMidi(uniqueId,0x90,0,(deck==0)?0x06:0x14,(param1 ? 0x7F : 0x00));// loop exit(out) // deckLoopExitOrReloop
	}
}
//-----------------------------------------------------------------------------
// 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)
{
	//debug('timerTick ['+uniqueId+']');
	// VU-meters
	for(var i=0; i<2; i++)
	{
		var vu_val = getValue('vumeterDeck', i);// float dB
		var val = 0;
		if(vu_val>-36) val = 1;
		if(vu_val>-28) val = 2;
		if(vu_val>-20) val = 3;
		if(vu_val>-16) val = 4;
		if(vu_val>-12) val = 5;
		if(vu_val> -8) val = 6;
		if(vu_val> -4) val = 7;
		sendMidi(uniqueId, 0x90, 0, (i==0)?0x1D:0x1E, val);
	}
}
//-----------------------------------------------------------------------------
