//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2015 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Reloop Terminal Mix 8'
//----------------------------------------------------------------------------- 
function getLanguageVersion()
{
	return 1;// do not modify this, this should be 1 for all scripts
}
//----------------------------------------------------------------------------- 
function getFileVersion()
{
	return 2;// update this as needed
}
//----------------------------------------------------------------------------- 
// return a user friendly name for the controller supported
function getControllerUserFriendlyName()
{
	return "Reloop Terminal Mix 8";
}
//----------------------------------------------------------------------------- 
// 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 0x26AD;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID(osId)
{
	return 0x6DF4;// Terminal Mix 8
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceVID2(osId)
{
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDevicePID2(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 '00207926AD6DF4'; // full sysex: F07E7F0602 00207926AD6DF430313230F7
}
//----------------------------------------------------------------------------- 
// 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 "Terminal Mix 8";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	return "Terminal Mix 8";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "Terminal Mix 8";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	return "Terminal Mix 8";
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogWheelsInScratchMode=[0,0,0,0];
var currentSampler=1;
// color constants
var cCueOff=0x00;// off
var cCueOn=0x10;// red
var cLoopOff=0x05;// aqua
var cLoopOn=0x03;// blue
var cSamplerOff=0x00;// off
var cSamplerOn=0x14;// orange
var cSliceOff=0x1C;// lime 
var cSliceOn=0x7F;// white
//----------------------------------------------------------------------------- 
// 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 Terminal Mix 8 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	// send sysex init (see below - from the manual)
	// Pick up SysEx message 0xf0, 0x7e, 0x7f, 0x56, 0x44, 0x4a, 0x20, 0x69, 0x6e, 0x69, 0x74, 0xf7	
	//var sysex1=[0xF0, 0x7E, 0x7F, 0x56, 0x44, 0x4A, 0x20, 0x69, 0x6E, 0x69, 0x74, 0xF7];// F07E7F56444A20696E6974F7
	//sendMidiSysEx(uniqueId, sysex1, sysex1.length);// on
	// send sysex init (send all controls)
	var sysex2=[0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7];
	sendMidiSysEx(uniqueId, sysex2, sysex2.length);// on
	//call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	//------------------------------------
	callSendAllNotifications(uniqueId, true);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
	//------------------------------------
	/*
	// test colors (they don't seem to corespond to what's listed in the manual)
	for(var i=0; i<32; i++) 
	{
		sendMidi(uniqueId, 0x90, 4, i, i);
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
	*/
}
//----------------------------------------------------------------------------- 
// called just before the controller will be deinitialized and the control will go away from the script
// use to power off any powered leds, etc
function controllerDeinit(uniqueId)
{
	debug('controllerDeinit Reloop Terminal Mix 8 ['+uniqueId+']');
	//------------------------------------
	callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually de-init all leds/lcd screens)
	//------------------------------------
	for(var deck=0; deck<4; deck++)
	{
		sendMidi(uniqueId, 0xB0, deck, 0x01, 0x00);// VU Led off
		// set to off all pad leds
		for(var i=0; i<0x20; i++) // 0x40 (for all modes)
		{
			sendMidi(uniqueId, 0x90, deck+4, i, 0x00);
			if(i % 5 == 0) 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, 0x7F-data2);
		break;
	//-----------------------------------------------
	// controllers: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1)
		{
		// jog-wheel has a normal and a scratch mode (also add 0x40 if SHIFT is also pressed)
		// params: (deck, increment, total positions per complete revolution) 
		case 0x06: // normal (scratch button off) - pitch bend while playing, scratch while paused;
			var val1 = data2-0x40;
			if(channel<4) call('moveDeckJogWheel', channel, val1, 800);
			/*
			if(channel<4)
			{
				if(jogWheelsInScratchMode[channel]) 
					call('scratchDeckJW', channel, val1, 800);
				else 
					call('moveDeckJogWheel', channel, val1, 800);
			}
			*/
			break;
		case 0x07: // always scratch mode
			var val1 = data2-0x40;
			if(channel<4) call('scratchDeckJW', channel, val1, 800);
			break;
		case 0x08: // press and hold the Scratch/JOG/Slip button while moving the jog-wheel
		case 0x46:
		case 0x47: // Shift + jog-wheel
			var val1 = data2-0x40;
			if(channel<4) call('searchDeckJW', channel, val1, 800);// skip +/- 1 bar for every 15degrees the jog-wheel moves
			break;
		//-------------
		case 0x09: if(channel<4) call('setDeckGain', channel, data2); break;
		case 0x0A: if(channel<4) call('setDeckEqHigh', channel, data2); break;
		case 0x0B: if(channel<4) call('setDeckEqMid', channel, data2); break; 
		case 0x0C: if(channel<4) call('setDeckEqLow', channel, data2); break;
		case 0x0D: if(channel<4) call('setDeckCutoff', channel, data2); break;
		case 0x0E: break;// no control sends this
		case 0x0F: if(channel<4) call('setDeckVolume', channel, data2); break;

		// 3 effect knobs
		case 0x1A: if(channel==0) call('deckFxFlangerDW', 0, data2);
				   if(channel==1) call('deckFxFlangerDW', 1, data2);
				   break;
		case 0x5A: if(channel==0) call('deckFxFlangerDW', 2, data2);// using Shift
				   if(channel==1) call('deckFxFlangerDW', 3, data2);
				   break;
		case 0x1B: if(channel==0) call('deckFxBeatwawDW', 0, data2);
				   if(channel==1) call('deckFxBeatwawDW', 1, data2);
				   break;
		case 0x5B: if(channel==0) call('deckFxBeatwawDW', 2, data2);// using Shift
				   if(channel==1) call('deckFxBeatwawDW', 3, data2);
				   break;
		case 0x1C: if(channel==0) call('deckFxEchoDW', 0, data2);
				   if(channel==1) call('deckFxEchoDW', 1, data2);
				   break;
		case 0x5C: if(channel==0) call('deckFxEchoDW', 2, data2);// using Shift
				   if(channel==1) call('deckFxEchoDW', 3, data2);
				   break;
		
		// 1 encoder + press (on the right of the 3 effect knobs)
		case 0x1D: // loop knob x2 or /2 
			if(channel<2)
			{
				if(data2 < 0x40) 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopLess', channel, 0x7F); 
					call('deckLoopLess', channel, 0x00); 
				}else 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopMore', channel, 0x7F); 
					call('deckLoopMore', channel, 0x00); 
				}
			}
			break;
		case 0x5D: // loop knob x2 or /2 // using Shift
			if(channel<2)
			{
				if(data2 < 0x40) 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopLess', channel+2, 0x7F); 
					call('deckLoopLess', channel+2, 0x00); 
				}else 
				{
					// simulate a fast button press (a note on/off)
					call('deckLoopMore', channel+2, 0x7F); 
					call('deckLoopMore', channel+2, 0x00); 
				}
			}
			break;
		
		case 0x28: call('lbMoveCursor', data2 - 0x40); break;
		case 0x29: call('setCuePgmMix', data2); break;
		case 0x2A: call('samplerVolume', currentSampler, data2); break;// per sampler
		//case 0x2A: call('setSamplerMasterVolume', currentSampler, data2); break;// general
		case 0x2B: call('setCrossfader', data2); break;
		case 0x2C: call('setCFCurve', data2); break;
				
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		//-------------
		// Cue mode
		case 0x00: if(channel>=4) call('deckCuePos1', channel-4, data2); 
				   break;
		case 0x01: if(channel<4) jogWheelsInScratchMode[channel] = data2;// this is not used
				   if(channel>=4) call('deckCuePos2', channel-4, data2); 
				   break;
		case 0x02: if(channel<4) call('deckSync', channel, data2); 
				   if(channel>=4) call('deckCuePos3', channel-4, data2);
				   break;
		case 0x03: if(channel<4) call('deckCuePlay', channel, data2); 
				   if(channel>=4) call('deckCuePos4', channel-4, data2); 
				   break;
		case 0x04: if(channel<4) call('deckCue', channel, data2);// also "fader start cue"
				   if(channel>=4) call('deckCuePos5', channel-4, data2); 
				   break;
		case 0x05: if(channel<4) call('deckPlayPause', channel, data2);// also "fader start play"
				   if(channel>=4) call('deckCuePos6', channel-4, data2); 
				   break;
		case 0x06: if(channel>=4) call('deckCuePos7', channel-4, data2); 
				   break;
		case 0x07: if(channel<4) call('holdDeckJogWheel', channel, data2); 
				   if(channel>=4) call('deckCuePos8', channel-4, data2); 
				   break;
				   
		//-------------
		// Loop mode
		case 0x08: if(channel>=4) call('deckLoop1_16', channel-4, data2); break; 
		case 0x09: if(channel>=4) call('deckLoop1_8', channel-4, data2); break;
		case 0x0A: if(channel>=4) call('deckLoop1_4', channel-4, data2); break;
		case 0x0B: if(channel>=4) call('deckLoop1_2', channel-4, data2); break;
		case 0x0C: if(channel>=4) call('deckLoop1', channel-4, data2); break;
		case 0x0D: if(channel>=4) call('deckLoop2', channel-4, data2); break;
		case 0x0E: if(channel>=4) call('deckLoop4', channel-4, data2);
				   if(channel<4) call('deckMonitor', channel, data2);
				   break;
		case 0x0F: if(channel>=4) call('deckLoop8', channel-4, data2); break;

		//-------------
		// Sampler mode (channel>=4) / Select/change mode (channel<4)
		case 0x10: if(channel<4) if(data2>0x3F) call('deckLBLoad', channel, data2);
				   if(channel>=4) call('samplerInstant', 1, data2);
				   break;
		case 0x11: if(channel<4) ;// Mode 1 (Hot Cue)
				   if(channel>=4) call('samplerInstant', 2, data2);
				   break;
		case 0x12: if(channel<4) ;// Mode 2 (Loop)
				   if(channel>=4) call('samplerInstant', 3, data2);
				   break;
		case 0x13: if(channel<4) ;// Mode 3 (Sampler)
				   if(channel>=4) call('samplerInstant', 4, data2);
				   break;				   
		case 0x14: if(channel<4) ; break;// Mode 4 (Slice)
				   if(channel>=4) call('samplerInstant', 5, data2);
				   break;
		case 0x15: if(channel<4) ; break;// Mode Mix 1 (Cue + Loop)
				   if(channel>=4) call('samplerInstant', 6, data2);
				   break;
		case 0x16: if(channel<4) ; break;// Mode Mix 2 (Cue + Sampler)
				   if(channel>=4) call('samplerInstant', 7, data2);
				   break;
		case 0x17: if(channel<4) ; break;// Mode Mix 3 (Loop + Sampler)
				   if(channel>=4) call('samplerInstant', 8, data2);
				   break;
		
		//-------------
		// Slice mode
		case 0x18: 
			if(channel<4) 
			{
				call('deckBendDown', channel, data2);// deck fx assign1
				sendMidi(uniqueId,0x90,channel,data1,data2);
				//sendMidi(uniqueId,0x90,channel,0x30,data2);// test "load sequence"
			}
			if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:4);// 1/16 beat
			break;
		case 0x19: 
			if(channel<4) 
			{
				call('deckBendUp', channel, data2);// deck fx assign2
				sendMidi(uniqueId,0x90,channel,data1,data2);
			}
			if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:8);// 1/8 beat
			break;
		case 0x1A: if(channel<4) call('deckFxFlanger', channel, data2); 
				   if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:16);// 1/4 beat
				   break;
		case 0x1B: if(channel<4) call('deckFxBeatwaw', channel, data2); 
				   if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:32);// 1/2 beat
				   break;
		case 0x1C: if(channel<4) call('deckFxEcho', channel, data2); 
				   if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:64);// 1 beat
				   break;
		case 0x1D: 
			if(channel<4) 
			{
				// beats/tap -- used for in/out/exit looping
				if(data2>0x3F)
				{
					if(!getValue('looping', channel)) 
					{
						// simulate a fast button press (a note on/off)
						call('deckLoopInEnd', channel, 0x7F); 
						call('deckLoopInEnd', channel, 0x00); 
					}else 
					{
						// simulate a fast button press (a note on/off)
						call('deckLoopExit', channel, 0x7F); 
						call('deckLoopExit', channel, 0x00); 
					}
				}
			}
			if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:128);// 2 beat
			break;
		case 0x1E:
			if(channel<4) // TAP / LoopRoll
			{
				// beats/tap -- used for in/out/exit looping
				if(data2>0x3F)
				{
					if(!getValue('looping', channel)) 
					{
						// simulate a fast button press (a note on/off)
						call('deckLoopInEnd', channel, 0x7F); 
						call('deckLoopInEnd', channel, 0x00); 
					}else 
					{
						// simulate a fast button press (a note on/off)
						call('deckLoopExit', channel, 0x7F); 
						call('deckLoopExit', channel, 0x00); 
					}
				}
			}
			if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:256);// 4 beat
			break;
		case 0x1F: if(channel>=4) call('deckLoopInstant64ths', channel-4, (data2==0)?-1:512); break;// 8 beat
				   
		//-------------
		//-------------
		//-------------
		// Cue mode 2 (ch>=4)
		case 0x20: 
			if(channel<4) ;// deck selection (1/3, 2/4)
			if(channel>=4) call('deckCuePos1Clear', channel-4, data2);
			break;
		// the 4 small switches on the front side (under the crossfader) -- each for one deck with 3 positions (A/THRU/B)
		case 0x21: 
			if(channel<4) ;// CF A
			if(channel>=4) call('deckCuePos2Clear', channel-4, data2);
			break;
		case 0x22: 
			if(channel<4) ;// CF THRU
			if(channel>=4) call('deckCuePos3Clear', channel-4, data2);
			break;
		case 0x23: 
			if(channel<4) ;// CF B
			if(channel>=4) call('deckCuePos4Clear', channel-4, data2);
			break;
		case 0x24: 
			if(channel<4) call('mixNext', data2);// Area
			if(channel>=4) call('deckCuePos5Clear', channel-4, data2);
			break;
		case 0x25: 
			if(channel<4) call('setAutoDj', data2);// View
			if(channel>=4) call('deckCuePos6Clear', channel-4, data2);
			break;
		case 0x26: 
			if(channel<4) call('micOnAir', data2);// Back
			if(channel>=4) call('deckCuePos7Clear', channel-4, data2);
			break;
		case 0x27: 
			if(channel<4) call('micTalkOver', data2);// Prep
			if(channel>=4) call('deckCuePos8Clear', channel-4, data2);
			break;
		//-------------				   
		// Loop mode 2 (ch>=4)
		case 0x28: 
			if(channel<4) if(data2==0x7F) call('lbToggleSelect', data2); 
			if(channel>=4) call('deckLoopPoint1', channel-4, data2); 
			break;				   
		case 0x29: 
			if(channel>=4) call('deckLoopPoint2', channel-4, data2); 
			break;
		case 0x2A: 
			if((channel<4)&&(data2>0x3F))
			{
				currentSampler = currentSampler + 1;
				if(currentSampler>8) currentSampler=1;
				//debug('sampler channel is '+currentSampler);
			}
			if(channel>=4) call('deckLoopPoint3', channel-4, data2); 
			break;
		case 0x2B: 
			if(channel>=4) call('deckLoopPoint4', channel-4, data2); 
			break;
		case 0x2C: 
			if(channel>=4) call('deckLoopLess', channel-4, data2); 
			break;
		case 0x2D: 
			if(channel>=4) call('deckLoopMore', channel-4, data2); 
			break;
		case 0x2E: 
			if(channel>=4) call('deckLoopPrev', channel-4, data2); 
			break;
		case 0x2F: 
			if(channel>=4) call('deckLoopNext', channel-4, data2); 
			break;
		//-------------				   
		// Sampler mode 2 (ch>=4)
			// play
		case 0x30: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerPlay', 1); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerPlay', 5); 
			break;
		case 0x31: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerPlay', 2); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerPlay', 6); 
			break;
		case 0x32: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerPlay', 3); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerPlay', 7); 
			break;
		case 0x33: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerPlay', 4); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerPlay', 8); 
			break;
			// stop
		case 0x34: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerStop', 1); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerStop', 5); 
			break;
		case 0x35: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerStop', 2); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerStop', 6); 
			break;
		case 0x36: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerStop', 3); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerStop', 7); 
			break;
		case 0x37: 
			if((channel==4)||(channel==6)) if(data2>0x3F) call('samplerStop', 4); 
			if((channel==5)||(channel==7)) if(data2>0x3F) call('samplerStop', 8); 
			break;
		//-------------
		// Slice mode 2 (ch>=4)
		/*
		case 0x38: if(channel>=4) ; break;
		case 0x39: if(channel>=4) ; break;
		case 0x3A: if(channel>=4) ; break;
		case 0x3B: if(channel>=4) ; break;
		case 0x3C: if(channel>=4) ; break;
		case 0x3D: if(channel>=4) ; break;
		case 0x3E: if(channel>=4) ; break;
		case 0x3F: if(channel>=4) ; break;
		*/
		//-------------
		//-------------
		//-------------
		// Shift +				   
		case 0x42: if(channel<4) call('deckMatch', channel, data2); break;// sync
		case 0x43: if(channel<4) call('deckBrake', channel, data2); break;// stutter (CUP)
		case 0x44: if(channel<4) call('deckBackToTop', channel, data2); break;// cue
		case 0x45: if(channel<4) call('deckReverse', channel, data2); break;// play-pause
		case 0x46: // Shift + hold jog-wheel (touch) - scratch off
		case 0x47: // Shift + hold jog-wheel (touch) - scratch on
		case 0x48: // Shift + hold jog-wheel (touch) - scratch HOLD (pressed continuously)
			break;
		
		// no Shift here
		case 0x51: break;// activate Cue mode 2
		case 0x52: break;// activate Loop mode 2
		case 0x53: break;// activate Sampler mode 2
		case 0x54: break;// activate Slice mode 2
				   
		// Shift +
		case 0x58: 
			if(channel<4) 
			{
				// 1 = 4%; 2 = 8%; 3 = 16%; 4 = 24%; 5 = 32%; 6 = 50%;
				if(data2>0x3F)
				{ 
					var currentPitchRange = getValue('pitchRange');
					currentPitchRange = currentPitchRange + 1; if(currentPitchRange>6) currentPitchRange = 1;
					call('setPitchRange', currentPitchRange);
				}
			}
			break;// bend - (deck fx assign1)
		case 0x59: if(channel<4) call('deckKeyLock', channel, data2); break;// bend + (deck fx assign2)
		case 0x5E: if(channel<4) call('deckTapBpm', channel, data2);// TAP / LoopRoll
				   
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	default: messageNotProcessed = true;
	}
	if(messageNotProcessed) debug('messageReceived ['+uniqueId+'] - status:'+status+' channel:'+channel+' data1:'+data1+' data2:'+data2);
	return !messageNotProcessed;
}
//----------------------------------------------------------------------------- 
// this is called by the software whenever something important changes (eg. play status, song changed, etc)
// depending on the notification type it may refer to a global event (deck is -1) or a specific deck (deck >= 0)
// and can contain any/all of the parameters: param 1 is an integer, param 2 is a float, param 3 is a string
function notificationReceived(uniqueId,name,deck,param1,param2,param3)
{
	//debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
	if(name=='onbeat') 		
	{
		sendMidi(uniqueId,0x90,deck,0x02,(param1 ? 0x7F : 0x00));
		sendMidi(uniqueId,0x90,deck,0x5E,(param1 ? 0x7F : 0x00));// Shift + TAP/LoopRoll
	}
	//if(name=='none') 		sendMidi(uniqueId,0x90,deck,0x03,(param1 ? 0x7F : 0x00));// the stutter (CUP) led
	if(name=='cue') 		sendMidi(uniqueId,0x90,deck,0x04,(param1 ? 0x7F : 0x00));	
	if(name=='play') 		sendMidi(uniqueId,0x90,deck,0x05,(param1 ? 0x7F : 0x00));	
	
	if(name=='monitor') 	sendMidi(uniqueId,0x90,deck,0x0E,(param1 ? 0x7F : 0x00));
	
	// justLoaded: 1,2 (loading in progress), 4 (loading ended), 8 (progress), 16 (detection started), 32 (detection finished);
	if(name=='justLoaded') 	
	{
		// set led on during loading
		sendMidi(uniqueId,0x90,deck,0x10,((param1!=0 && param1!=32) ? 0x7F : 0x00));// load button
		// 0x30 is "Load sequence" -- the pads light in different colors
		//sendMidi(uniqueId,0x90,deck,0x30,((param1!=0 && param1!=32) ? 0x7F : 0x00));
		if(param1<=4) sendMidi(uniqueId,0x90,deck,0x30,((param1!=0 && param1!=4) ? 0x7F : 0x00));
	}
	if(name=='brake') 		sendMidi(uniqueId,0x90,deck,0x43,(param1 ? 0x7F : 0x00));// Shift + Stutter (CUP)
	if(name=='reverse')		sendMidi(uniqueId,0x90,deck,0x45,(param1 ? 0x7F : 0x00));// Shift + PlayPause
	
	if(name=='fxFlanger') 	sendMidi(uniqueId,0x90,deck,0x1A,(param1 ? 0x7F : 0x00));
	if(name=='fxBeatwaw') 	sendMidi(uniqueId,0x90,deck,0x1B,(param1 ? 0x7F : 0x00));
	if(name=='fxEcho') 		sendMidi(uniqueId,0x90,deck,0x1C,(param1 ? 0x7F : 0x00));

	if(name=='loopBlink') 	sendMidi(uniqueId,0x90,deck,0x1E,(param1 ? 0x7F : 0x00));// TAP / LoopRoll
	if(name=='keyLock') 	sendMidi(uniqueId,0x90,deck,0x59,(param1 ? 0x7F : 0x00));// 2/KEY (pitch bend+)

	//if(name=='none') 		sendMidi(uniqueId,0x90,0,0x24,(param1 ? 0x7F : 0x00));// Area (mixNext)
	if(name=='autoDj') 		sendMidi(uniqueId,0x90,0,0x25,(param1 ? 0x7F : 0x00));// View (setAutoDj)
	if(name=='onAir') 		sendMidi(uniqueId,0x90,0,0x26,(param1 ? 0x7F : 0x00));// Back (micOnAir)
	if(name=='talkOver') 	sendMidi(uniqueId,0x90,0,0x27,(param1 ? 0x7F : 0x00));// Prep (micTalkOver)
	
	// PADS
	//-------------
	// cue
	if(name=='cuepos1') 	sendMidi(uniqueId,0x90,deck+4,0x00,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos2') 	sendMidi(uniqueId,0x90,deck+4,0x01,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos3') 	sendMidi(uniqueId,0x90,deck+4,0x02,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos4') 	sendMidi(uniqueId,0x90,deck+4,0x03,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos5') 	sendMidi(uniqueId,0x90,deck+4,0x04,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos6') 	sendMidi(uniqueId,0x90,deck+4,0x05,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos7') 	sendMidi(uniqueId,0x90,deck+4,0x06,(param1 ? cCueOn : cCueOff));
	if(name=='cuepos8') 	sendMidi(uniqueId,0x90,deck+4,0x07,(param1 ? cCueOn : cCueOff));
	//-------------
	// loop
	if(name=='loopSize') // normal loops
	{
		sendMidi(uniqueId,0x90,deck+4,0x08,((param1==4)   ? cLoopOn : cLoopOff));// loop 1/16
		sendMidi(uniqueId,0x90,deck+4,0x09,((param1==8)   ? cLoopOn : cLoopOff));// loop 1/8
		sendMidi(uniqueId,0x90,deck+4,0x0A,((param1==16)  ? cLoopOn : cLoopOff));// loop 1/4
		sendMidi(uniqueId,0x90,deck+4,0x0B,((param1==32)  ? cLoopOn : cLoopOff));// loop 1/2
		sendMidi(uniqueId,0x90,deck+4,0x0C,((param1==64)  ? cLoopOn : cLoopOff));// loop 1
		sendMidi(uniqueId,0x90,deck+4,0x0D,((param1==128) ? cLoopOn : cLoopOff));// loop 2
		sendMidi(uniqueId,0x90,deck+4,0x0E,((param1==256) ? cLoopOn : cLoopOff));// loop 4
		sendMidi(uniqueId,0x90,deck+4,0x0F,((param1==512) ? cLoopOn : cLoopOff));// loop 8
	}
	//-------------
	// sampler
	if(name=='sampler1') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x10,(param1 ? cSamplerOn : cSamplerOff));// 'sampler1' getValue(sampler2loaded)
	if(name=='sampler2') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x11,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler3') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x12,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler4') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x13,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler5') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x14,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler6') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x15,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler7') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x16,(param1 ? cSamplerOn : cSamplerOff));
	if(name=='sampler8') for(var d=0; d<4; d++) sendMidi(uniqueId,0x90,d+4,0x17,(param1 ? cSamplerOn : cSamplerOff));
	//-------------
	// slice
	if(name=='loopSize') // instant loops
	{
		sendMidi(uniqueId,0x90,deck+4,0x18,((param1==4)   ? cSliceOn : cSliceOff));// loop 1/16
		sendMidi(uniqueId,0x90,deck+4,0x19,((param1==8)   ? cSliceOn : cSliceOff));// loop 1/8
		sendMidi(uniqueId,0x90,deck+4,0x1A,((param1==16)  ? cSliceOn : cSliceOff));// loop 1/4
		sendMidi(uniqueId,0x90,deck+4,0x1B,((param1==32)  ? cSliceOn : cSliceOff));// loop 1/2
		sendMidi(uniqueId,0x90,deck+4,0x1C,((param1==64)  ? cSliceOn : cSliceOff));// loop 1
		sendMidi(uniqueId,0x90,deck+4,0x1D,((param1==128) ? cSliceOn : cSliceOff));// loop 2
		sendMidi(uniqueId,0x90,deck+4,0x1E,((param1==256) ? cSliceOn : cSliceOff));// loop 4
		sendMidi(uniqueId,0x90,deck+4,0x1F,((param1==512) ? cSliceOn : cSliceOff));// loop 8
	}
	//-------------
}
//----------------------------------------------------------------------------- 
var vuCurrent=[-36, -28, -20, -16, -12, -8, -6, -4, -2, -1];// VU series 1
//var vuCurrent=[-24, -15, -10,  -5,  -3, -1,  0,  1,  2,  4];// VU series 2
function setVUValueForDeck(uniqueId, deck, dbValue)
{
	var param1=0;
	//dbValue += 8;// correct the way we measure RMS (only when using VU series 2)
	for(var i=9; i>=0; i--)	if(dbValue >= vuCurrent[i]){ param1 = i+1; break; }
	sendMidi(uniqueId, 0xB0, deck, 0x01, param1);// VU Led (instant)
}
//----------------------------------------------------------------------------- 
// this is called from time to time by the software (several times per second)
// (it is guaranteed that 'timerTick' will get executed ALWAYS right after notificationReceived)
//var timer1=0;
function timerTick(uniqueId)
{
	//debug('timerTick ['+uniqueId+']');
	// limit the amount of time this gets executed
	//timer1++; if(timer1<2) return;else timer1=0;
	for(var deck=0; deck<4; deck++)
	{
		var dbValue = getValue('vumeterDeck', deck);// float dB
		setVUValueForDeck(uniqueId, deck, dbValue);
	}
}
//----------------------------------------------------------------------------- 
