//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2012. All Rights Reserved. -----------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'MIDI 8'
//Author: Chris
//----------------------------------------------------------------------------- 
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 "MIDI 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 (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 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 "MIDI 8";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "MIDI 8";
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogWheelsInScratchMode=[0,0,0,0];
var jogWheelsWasDeckPlaying=[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 MIDI 8 ['+uniqueId+']');// this outputs a string to DebugView app on Win

	/*
	sendMidi(uniqueId,0x90,0,0x34,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x35,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x36,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x37,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x38,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x39,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x3A,0x7F);// onbeat
	
	sendMidi(uniqueId,0x90,0,0x3C,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x3D,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x3E,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x3F,0x7F);// onbeat
	
	sendMidi(uniqueId,0x90,0,0x41,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x42,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x43,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x44,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x45,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x46,0x7F);// onbeat
	sendMidi(uniqueId,0x90,0,0x47,0x7F);// onbeat
*/	
	for(var i=0; i<2; i++)
	{
		
	//deck 1
		sendMidi(uniqueId,0x90,0,0x3B,(getValue('cue', 0)? 0x7F : 0x00));// Cue
		sendMidi(uniqueId,0x90,0,0x4A,(getValue('play', 0) ? 0x7F : 0x00));// PlayPause
		sendMidi(uniqueId,0x90,0,0x40,(getValue('reverse', 0) ? 0x7F : 0x00));// Reverse
		sendMidi(uniqueId,0x90,0,0x33,0x00);// onbeat
		sendMidi(uniqueId,0x90,0,0x48,0x00);// scratch

	//deck 2
	
		sendMidi(uniqueId,0x90,0,0x42,(getValue('cue', 1)? 0x7F : 0x00));// Cue
		sendMidi(uniqueId,0x90,0,0x4C,(getValue('play', 1) ? 0x7F : 0x00));// PlayPause
		sendMidi(uniqueId,0x90,0,0x47,(getValue('reverse', 1) ? 0x7F : 0x00));// Reverse
		sendMidi(uniqueId,0x90,0,0x3C,0x00);// onbeat
		sendMidi(uniqueId,0x90,0,0x35,0x00);// scratch

		
		call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	}
	sendMidi(uniqueId,0xB0,0,0x19,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 MIDI 8 ['+uniqueId+']');
	
	for(var i=0; i<2; i++)
	{
	
	//deck 1	
		sendMidi(uniqueId,0x90,0,0x3B,0x00);// cue
		sendMidi(uniqueId,0x90,0,0x4A,0x00);// play
		sendMidi(uniqueId,0x90,0,0x40,0x00);// reverse
		sendMidi(uniqueId,0x90,0,0x33,0x00);// on beat
		sendMidi(uniqueId,0x90,0,0x48,0x00);// scratch

	//deck 2
	
		sendMidi(uniqueId,0x90,0,0x42,0x00);// cue
		sendMidi(uniqueId,0x90,0,0x4C,0x00);// play
		sendMidi(uniqueId,0x90,0,0x47,0x00);// reverse
		sendMidi(uniqueId,0x90,0,0x3C,0x00);// on beat
		sendMidi(uniqueId,0x90,0,0x35,0x00);// scratch

		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: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xB0:
		switch(data1)
		{
		// global
			case 0x1A: // move track
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('lbMoveCursor', val1);
			break;//library curser up down	
	
		
		case 0x0A: call('setCrossfader', 0x7F-data2); break; //crossfader		
		case 0x17: call('setMasterGain', data2); break; // Cue Mix
		

		// decks
		
		//deck A
		case 0x08: call('setDeckVolume', 0, data2); break; //volume slider 
		case 0x10: call('setDeckEqHigh', 0, data2); break; // eq high
		case 0x14: call('setDeckEqLow', 0, data2); break; // eq low
		case 0x19: // params: (deck, increment, total positions per complete revolution) 
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(jogWheelsInScratchMode[0]) call('scratchDeckJW', 0, val1, 380);else call('moveDeckJogWheel', 0, val1, 380);
			break;

			
		//deck B
		case 0x09: call('setDeckVolume', 1, data2); break; //volume slider 
		case 0x11: call('setDeckEqHigh', 1, data2); break; // eq high
		case 0x15: call('setDeckEqLow', 1, data2); break; // eq low
		case 0x18: // params: (deck, increment, total positions per complete revolution) 
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			if(jogWheelsInScratchMode[1]) call('scratchDeckJW', 1, val1, 375);else call('moveDeckJogWheel', 1, val1, 375);
			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 0x0D:
		case 0x4F: if(data2>0x3F) call('lbToggleSelect', data2); break; //list toggle 
		//case 0x0D: call('record', data2); break;
		

		
		// decks
		

		//deck 1
		case 0x4B: call('deckLBLoad', 0, data2); break; //load deck
		case 0x4A: call('deckPlayPause', 0, data2); break; //play pause
		case 0x3B: call('deckCue', 0, data2); break; //set cue		
		case 0x33: call('deckSync', 0, data2); break; //sync
		case 0x44: call('deckBendDown', 0, data2); break; //pitch bend down
		case 0x43: call('deckBendUp', 0, data2); break; //pitch bend up
		case 0x40: call('deckReverse', 0, data2); break;
		case 0x48: if(data2>0x3F)
					{
						jogWheelsInScratchMode[0] = (jogWheelsInScratchMode[0]+1) % 2; 
						sendMidi(uniqueId,0x90,0,0x48,(jogWheelsInScratchMode[0] ? 0x7F : 0x00)); 
					}
					break;
		//case 0x4D: if(jogWheelsInScratchMode[0]) call('holdDeckJogWheel', 0, data2); break
		//case 0x4D: call('holdDeckJogWheel', 0, data2); break;
			//jogWheelsInScratchMode[0] = (jogWheelsInScratchMode[0]+1) % 2; // keep the remainder to toggle between scratch mode "0" or jog bend mode "1"
			//call('holdDeckJogWheel', 0, jogWheelsInScratchMode[0]);
			//break;
		
		//deck 2
		case 0x34: call('deckLBLoad', 1, data2); break; //load deck
		case 0x4C: call('deckPlayPause', 1, data2); break; //play pause
		case 0x42: call('deckCue', 1, data2); break; //set cue		
		case 0x3C: call('deckSync', 1, data2); break; //sync
		case 0x46: call('deckBendDown', 1, data2); break; //pitch bend down
		case 0x45: call('deckBendUp', 1, data2); break; //pitch bend up
		case 0x47: call('deckReverse', 1, data2); break; //reloop
		case 0x35: if(data2>0x3F)
					{
						jogWheelsInScratchMode[1] = (jogWheelsInScratchMode[1]+1) % 2; 
						sendMidi(uniqueId,0x90,0,0x35,(jogWheelsInScratchMode[1] ? 0x7F : 0x00)); 
					}
					break;
		//case 0x4E: if(jogWheelsInScratchMode[1]) call('holdDeckJogWheel', 1, data2); break
		//case 0x4E: call('holdDeckJogWheel', 1, data2); break;
			//jogWheelsInScratchMode[1] = (jogWheelsInScratchMode[1]+1) % 2; // keep the remainder to toggle between scratch mode "0" or jog bend mode "1"
			//call('holdDeckJogWheel', 1, jogWheelsInScratchMode[1]);
			//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)
{
	//debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);

	if(deck>=2) return; 
	{
			if(name=='cue') sendMidi(uniqueId,0x90,0,(deck==0)?0x3B:0x42,(param1 ? 0x7F : 0x00));
			if(name=='play') sendMidi(uniqueId,0x90,0,(deck==0)?0x4A:0x4C,(param1 ? 0x7F : 0x00));
		{
			//if(deck==0)	sendMidi(uniqueId,0xB0, 0, 19,(param1 ? 0x7F : 0x00));
			//if(deck==1)	sendMidi(uniqueId,0xB0, 1, 20,(param1 ? 0x7F : 0x00));
		}	
			if(name=='reverse') sendMidi(uniqueId,0x90,0,(deck==0)?0x40:0x47,(param1 ? 0x7F : 0x00));
			if(name=='onbeat') sendMidi(uniqueId,0x90,0,(deck==0)?0x33:0x3C,(param1 ? 0x7F : 0x00));
			if(name=='scratch') sendMidi(uniqueId,0x90,0,(deck==0)?0x48:0x35,(param1 ? 0x7F : 0x00));
			{
			//sendMidi(uniqueId,0x90,0,(deck==0)?0x2D:0x5C,(param1 ? 0x7F : 0x00));// loop in led
			//sendMidi(uniqueId,0x90,0,(deck==0)?0x2C:0x5B,(param1 ? 0x7F : 0x00));//loop out led
			}
			
			//if(name=='killHigh') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x62:0x5E,(param1 ? 0x7F : 0x00));
			//if(name=='killMid') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x63:0x60,(param1 ? 0x7F : 0x00));
			//if(name=='killLow') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x64:0x5F,(param1 ? 0x7F : 0x00));
			


		    if(name=='loopSize')
			{
			
			// calculate the new led to power on
				var l2, l4, l8;
				l2 = l4 = l8 = 0;
				switch(param1)
				{
				case  128: l2 = 0x7F; break; //loop 2
				case  256: l4 = 0x7F; break; //loop 4
				case  512: l8 = 0x7F; break; //loop 8
			
			
				}
					if(deck==0)
					{		
					sendMidi(uniqueId,0x90,0,0x16,l2); //loop 2
					sendMidi(uniqueId,0x90,0,0x15,l4); //loop 4 
					sendMidi(uniqueId,0x90,0,0x14,l8); //loop 8
					}
					if(deck==1)
					{	
					sendMidi(uniqueId,0x90,0,0x45,l2); //loop 2
					sendMidi(uniqueId,0x90,0,0x44,l4); //loop 4 
					sendMidi(uniqueId,0x90,0,0x43,l8); //loop 8		
				}			
			}
			// light off the leds
			if((name=='looping')&&(!param1))
			{
				if(deck==0)
				{
				sendMidi(uniqueId,0x90,0,0x16,0); //loop 2
				sendMidi(uniqueId,0x90,0,0x15,0); //loop 4 
				sendMidi(uniqueId,0x90,0,0x14,0); //loop 8
				}
			
				if(deck==1)
				{
				sendMidi(uniqueId,0x90,0,0x45,0); //loop 2
				sendMidi(uniqueId,0x90,0,0x44,0); //loop 4 
				sendMidi(uniqueId,0x90,0,0x43,0); //loop 8
				}
			}
	}
}
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
// 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+']');


	for(var i=0; i<4; i++)
	{
	
	}
}
//----------------------------------------------------------------------------- 
