//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2012. All Rights Reserved. -----------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Vestax VCI-100MKII'
//----------------------------------------------------------------------------- 
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 "VCI-100MKII DJ-Controller";
}
//----------------------------------------------------------------------------- 
// 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 "0040022001";// short 5-bytes sysex id (we don't use this since it's the same as 'Vestax Typhoon')
	return "0040022001000000290013";// the 'almost' full sysex id

	// ATTN: normally we will only use 5 bytes (10 hexa characters) but there are cases when 2 otherwise 
	// very different controllers (even from different companies) have the exact same sysex id for the first 5 bytes
	// example:
	//return "0040022001000000290020F7";// full sysex id reply from 'Vestax Typhoon'
	//return "0040022001000000290013F7";// full sysex id reply from 'Vestax VCI-100 MK2'
	//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 "VCI-100MKII DJ-Controller";
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//return "VCI-100MKII DJ-Controller";
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// 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 VCI100MK2 ['+uniqueId+']');// this outputs a string to DebugView app on Win
	for(var i=0; i<4; i++)
	{
		
		sendMidi(uniqueId,0x90,i,0x22,(getValue('play', i) ? 0x7F : 0x00)); // play-pause
		sendMidi(uniqueId,0x90,i,0x23,(getValue('cue', i) ? 0x7F : 0x00)); // cue
		sendMidi(uniqueId,0x90,i,0x2A,(getValue('cuepos1', i) ? 0x7F : 0x00)); // cue 1
		sendMidi(uniqueId,0x90,i,0x2B,(getValue('cuepos2', i) ? 0x7F : 0x00)); // cue 2
		sendMidi(uniqueId,0x90,i,0x24,(getValue('cuepos2', i) ? 0x7F : 0x00)); //sync
		sendMidi(uniqueId,0x90,i,0x36,(getValue('monitor', i) ? 0x7F : 0x00));// monitor
		sendMidi(uniqueId,0x90,i,0x2D,(getValue('keyLock', i) ? 0x7F : 0x00));// key lock

		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 VCI100MK2 ['+uniqueId+']');
	
	for(var i=0; i<4; i++)
	{
		
		sendMidi(uniqueId,0x90,i,0x22,0x00);// play-pause
		sendMidi(uniqueId,0x90,i,0x23,0x00);// cue
		
		sendMidi(uniqueId,0x90,i,0x2A,0x00);// cue 1
		sendMidi(uniqueId,0x90,i,0x2B,0x00);// cue 2
		sendMidi(uniqueId,0x90,i,0x24,0x00);//sync

		sendMidi(uniqueId,0x90,i,0x36,0x00);// headphone
		sendMidi(uniqueId,0x90,i,0x2D,0x00);// keylock
		sendMidi(uniqueId,0x90,i,0x3A,0x00);// reverse
		sendMidi(uniqueId,0x90,i,0x38,0x00);// brake
		
		sendMidi(uniqueId,0x90,i,0x26,0x00);// loop / loop more decks 1/3
		sendMidi(uniqueId,0x90,i,0x33,0x00);// loop / loop more deck 2/4
		sendMidi(uniqueId,0x90,i,0x2C,0x00);// flanger deck 1 / echo deck 2
		sendMidi(uniqueId,0x90,i,0x28,0x00);// flanger deck 2 / 
		sendMidi(uniqueId,0x90,i,0x25,0x00);// phaser deck 1/ 2
		sendMidi(uniqueId,0x90,i,0x27,0x00);// reverb deck 1/ 2
		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 0x14: if(channel==4) call('setMasterGain', data2);else 
			 if((channel==0)||(channel==2)) call('deckFxPanDW', channel, data2);else
			 if((channel==1)||(channel==3)) call('setDeckEqHigh', channel, data2); break; //master volume/ deck 1/3 pan / deck 2/4 eq high
		
		case 0x10: // params: (deck, increment, total positions per complete revolution) 
			if(channel==4) 
			{
				call('setCrossfader', data2); //crossfader
			}else
			{
				var val1 = data2-0x40;
				if(jogWheelsInScratchMode[channel]) call('scratchDeckJW', channel, val1, 2150);else call('moveDeckJogWheel', channel, val1, 2150); break;			
			}
			break;
			
		case 0x11: if(channel==4) call('setCFCurve', data2);else
			 if((channel==0)||(channel==2)) call('setDeckEqHigh', channel, data2);else
			 if((channel==1)||(channel==3)) call('setDeckPitch', channel, 0x7F-data2); break; //crossfader curve / deck 1/3 high eq / deck 2/4 pitch
			
		case 0x13: if(channel==4) call('setCuePgmMix', data2);else call('setDeckEqLow', channel, data2); break; //cue mix / decks 1-3 eq low 
			
		case 0x12: if(channel==4) call('setMonitorGain', data2);else
			 if((channel==0)||(channel==2)) call('setDeckEqMid', channel, data2);else
			 if((channel==1)||(channel==3)) call('deckFxPanDW', channel, data2); break; //heaphone gain / decks 1/3 eq mid / decks 2/4 pan
		
		
		// decks 
		case 0x1C: if((channel==0)||(channel==2)) call('setDeckVolume', channel, data2);else
			 		if((channel==1)||(channel==3)) call('setDeckEqMid', channel, data2); break; //volume slider deck 1/3 / deck 2/4 EQ Mid
			
		case 0x1B: if((channel==0)||(channel==2)) call('setDeckPitch', channel, 0x7F-data2);else 
				   if((channel==1)||(channel==3)) call('setDeckCutoff', channel, data2); break; //pitch slider decks 1/3 / HP filter decks 2/4
		
		case 0x16: if((channel==1)||(channel==3)) call('setDeckVolume', channel, data2);else
					if(channel==0) call('deckFxFlangerP1', 0, data2); break; //volume slider deck 2/4 / flanger P1 deck 1
		
		case 0x1A: if((channel==0)||(channel==2)) call('setDeckCutoff', channel, data2);else
					if(channel==1) call('deckFxEchoP1', 1, data2); break; //hp filter decks 1/3 / echo P1 deck 2
		
		
		case 0x15: call('setDeckGain', channel, data2); break; //deck gain decks 1-4
		case 0x17: if(channel==1) call('deckFxFlangerP1', 1, data2);else
					if(channel==0) call('deckFxPhaserP1', 0, data2); break; //flanger P1 deck 2 / phaser P1 deck 1
					
		case 0x18: if(channel==1) call('deckFxPhaserP1', 1, data2);else
					if(channel==0) call('deckFxReverbP1', 0, data2); break; // phaser P1 deck 2 / reverb P1 deck 1
					
		case 0x19: if(channel==1) call('deckFxReverbP1', 1, data2);else
					if(channel==0) call('deckFxEchoP1', 0, data2); break; //reverb P1 deck 1 / echo P1 deck 2 
		
		default: messageNotProcessed = true;
		}
		break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	
	case 0x90:
		//if(status==0x90) data2 = 0x7F;
		//if(status==0x80) data2 = 0;
		switch(data1)
		{
		// global
		
		case 0x37: if((channel==4)&&(data2>0x3F)) call('lbMoveCursor', -1);else if(channel<=3) call('deckLBLoad', channel, data2); break; //load deck break; // lb curser up
		case 0x38: if((channel==4)&&(data2>0x3F)) call('lbMoveCursor', +1);else call('deckBrake', channel, data2); break; //lb curser down // deck brake
		

		
		// decks
	
		
		case 0x22: call('deckPlayPause', channel, data2); break; //play pause deck
		case 0x23: call('deckCue', channel, data2); break; // cue deck 
		case 0x36: if(channel==4) call('lbToggleSelect', data2);else call('deckMonitor', channel, data2); break; // deck headphone cue
	
		case 0x24: if(channel<4) call('deckSync', channel, data2); break; //sync
		case 0x2A: call('deckCuePos1', channel, data2); break; //cue1
		case 0x2B: call('deckCuePos2', channel, data2); break; //cue2
		
		case 0x2D: call('deckKeyLock', channel, data2); break; // key lock
		
		case 0x26: 
			if(channel==0)
				{
					if(!getValue('looping', 0)) call('deckLoopInEnd', 0, data2);else call('deckLoopExit', 0, data2); //loop deck 1
				}
			if(channel==2)
				{
					if(!getValue('looping', 2)) call('deckLoopInEnd', 2, data2);else call('deckLoopExit', 2, data2); //loop deck 3
				}
			if(channel==1)
				{
					call('deckLoopMore', 1, data2); // loop more deck 2
				}
			if(channel==3)
				{
					call('deckLoopMore', 3, data2); // loop more deck 4
				}
				break;

		
		case 0x33: 
		
			if(channel==0)
				{
					call('deckLoopLess', 0, data2); //loop less deck 1
					
				}
			if(channel==2)
				{
					call('deckLoopLess', 2, data2); //loop less deck 3
				}
			if(channel==1)
				{
					if(!getValue('looping', 1)) call('deckLoopInEnd', 1, data2);else call('deckLoopExit', 1, data2); // loop deck 2
				}
			if(channel==3)
				{
					if(!getValue('looping', 3)) call('deckLoopInEnd', 3, data2);else call('deckLoopExit', 3, data2); //loop deck 4
				}
				break;
				
		case 0x29:
		
			if(channel==0)
				{
					call('deckLoopMore', 0, data2); //loop more deck 1
					
				}
			if(channel==2)
				{
					call('deckLoopMore', 2, data2); //loop more deck 3
				}
			if(channel==1)
				{
					call('deckLoopLess', 1, data2); //loop less deck 2
				}
			if(channel==3)
				{
					call('deckLoopLess', 3, data2); //loop less deck 4
				}
				break;
		
		case 0x3A: call('deckReverse', channel, data2); // FX1 button= deck reverse
		case 0x49: if((channel==1)||(channel==3)) call('deckLoopPrev', channel, data2);else
					if((channel==0)||(channel==2)) call('deckLoopNext', channel, data2); break; // shift + loop less = loop next (1/3) / loop prev (2/4)
		
		case 0x53: if((channel==0)||(channel==2)) call('deckLoopPrev', channel, data2); break;	//shift + loop less = prev (1/3)
 		case 0x46: if((channel==1)||(channel==3)) call('deckLoopNext', channel, data2); break   //shift + Loop More = loop next (2/4)
 		
 		case 0x2C: if(channel==0) call('deckFxFlanger', 0, data2);else
 					if(channel==1) call('deckFxEcho', 1, data2); break; //flanger deck 1 / echo deck 2
 					
		case 0x28: if(channel==1) call('deckFxFlanger', 1, data2);else
					if(channel==0) call('deckFxEcho', 0, data2); break; //flanger deck 2 / echo deck 1
					
		case 0x25: if(channel<3) call('deckFxPhaser', channel, data2); break; //phazer deck 1/2
		case 0x27: if(channel<3) call('deckFxReverb', channel, data2); break; //reverb deck 1/2
		
		case 0x3B: 
			jogWheelsInScratchMode[channel] = (jogWheelsInScratchMode[channel]+1) % 2; // keep the remainder to toggle between scratch mode "0" or jog bend mode "1"
			call('holdDeckJogWheel', channel, jogWheelsInScratchMode[channel]);	

		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<4)
	{
		if(name=='cue') 		 sendMidi(uniqueId,0x90,deck,0x23,(param1 ? 0x7F : 0x00)); // cue
		if(name=='play') 		 sendMidi(uniqueId,0x90,deck,0x22,(param1 ? 0x7F : 0x00)); //play
	
		
		
		if(name=='cuepos1') 	 sendMidi(uniqueId,0x90,deck,0x2A,(param1 ? 0x7F : 0x00)); //cue 1
		if(name=='cuepos2') 	 sendMidi(uniqueId,0x90,deck,0x2B,(param1 ? 0x7F : 0x00)); //cue 2
		if(name=='onbeat')		 sendMidi(uniqueId,0x90,deck,0x24,(param1 ? 0x7F : 0x00)); // sync 
		if(name=='monitor')		 sendMidi(uniqueId,0x90,deck,0x36,(param1 ? 0x7F : 0x00)); // headphone
		if(name=='keyLock')		 sendMidi(uniqueId,0x90,deck,0x2D,(param1 ? 0x7F : 0x00)); // keylock
		if(name=='reverse')		 sendMidi(uniqueId,0x90,deck,0x3A,(param1 ? 0x7F : 0x00)); // reverse
		if(name=='brake')		 sendMidi(uniqueId,0x90,deck,0x38,(param1 ? 0x7F : 0x00)); // brake

		if(name=='looping') 	
			{
			if(deck==0)  		sendMidi(uniqueId,0x90,0,0x26,(param1 ? 0x7F : 0x00));
			if(deck==2)			sendMidi(uniqueId,0x90,2,0x26,(param1 ? 0x7F : 0x00));
			if(deck==1)			sendMidi(uniqueId,0x90,1,0x33,(param1 ? 0x7F : 0x00));
			if(deck==3)			sendMidi(uniqueId,0x90,3,0x33,(param1 ? 0x7F : 0x00)); 	
			}
					
		if(name=='fxFlanger')
			{
			if(deck==0)			sendMidi(uniqueId,0x90,0,0x2C,(param1 ? 0x7F : 0x00));
			if(deck==1)			sendMidi(uniqueId,0x90,1,0x28,(param1 ? 0x7F : 0x00));
			}
		if(name=='fxPhaser')	sendMidi(uniqueId,0x90,deck,0x25,(param1 ? 0x7F : 0x00));
		if(name=='fxReverb')	sendMidi(uniqueId,0x90,deck,0x27,(param1 ? 0x7F : 0x00));
		if(name=='fxEcho')
			{
			if(deck==0)			sendMidi(uniqueId,0x90,0,0x28,(param1 ? 0x7F : 0x00));
			if(deck==1)			sendMidi(uniqueId,0x90,1,0x2C,(param1 ? 0x7F : 0x00));
			}		
		
//		if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,21,(param1 ? 0x7F : 0x00)); //loop 4 ask ionut
//		if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,22,(param1 ? 0x7F : 0x00)); //loop 8
//		if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,23,(param1 ? 0x7F : 0x00)); //loop 16
//		if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,24,(param1 ? 0x7F : 0x00)); //loop 32 
		
		//if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,0x03,(param1 ? 0x7F : 0x00)); //Dex FX 1
		//if(name=='looping') 	 sendMidi(uniqueId,0x90,2+deck,0x04,(param1 ? 0x7F : 0x00)); //Dex FX 2
		
		

	}
}
//----------------------------------------------------------------------------- 

//----------------------------------------------------------------------------- 
// 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++)
	{
	
	}
}
//----------------------------------------------------------------------------- 
