//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2013. All Rights Reserved. -----------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Gemini FirstMIX' -- ATTN: differs completely from 'Gemini FirstMIX I/O'
//----------------------------------------------------------------------------- 
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 "Gemini FirstMIX";
}
//----------------------------------------------------------------------------- 
// 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; 3 iOS; -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==3) return false;// if using "Network Session 1"
	return false;// doesn't have a sysex
}
//----------------------------------------------------------------------------- 
// 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)
{
	//if(osId==3) return "Network Session 1";
	return "firstmix";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForInput2(osId)
{
	//if(osId==3) return "Network Session 1";
	return " firstmix  ";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//if(osId==3) return "Network Session 1";
	return "firstmix";
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput2(osId)
{
	//if(osId==3) return "Network Session 1";
	return " firstmix  ";
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogWheelsInScratchMode=[0,0,0,0];
var effectsSelected=[0,0,0,0];// 4 decks (the selected fx, 0-based index)
//----------------------------------------------------------------------------- 
// 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 FirstMIX ['+uniqueId+']');// this outputs a string to DebugView app on Win
	callSendAllNotifications(uniqueId, true);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
	sendMidi(uniqueId,0x90,0,0x0D,0x00);// preview
	// manually power off the scratch leds
	sendMidi(uniqueId,0x90,0,0x48,0x00);// scratch A
	sendMidi(uniqueId,0x90,0,0x35,0x00);// scratch B
/*	
	// power on ALL the leds
	for(var i=0; i<=127; i++)
	{
		sendMidi(uniqueId,0x90,0,i,0x7F);
		call('sleep', 5);// delay for 5ms
	}
	// test for half of the interval
	for(var i=64; i<=127; i++) // we still need to test for 0..63
	{
		sendMidi(uniqueId,0x90,0,i,0x7F);
		call('sleep', 5);// delay for 5ms
	}
*/
}
//----------------------------------------------------------------------------- 
// 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 FirstMIX ['+uniqueId+']');
	callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually de-init all leds/lcd screens)
	// manually power off the scratch leds
	sendMidi(uniqueId,0x90,0,0x48,0x00);// scratch A
	sendMidi(uniqueId,0x90,0,0x35,0x00);// scratch B
}
//----------------------------------------------------------------------------- 
// 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)
		{
		case 0x0A: call('setCrossfader', 0x7F-data2); break; //crossfader		
		case 0x17: call('setMasterGain', data2); break; // Cue Mix
		case 0x1A: // browse encoder
			var val1 = (data2<0x40) ? data2 : data2-0x80;
			call('lbMoveCursor', val1);
			break;
		
		//deck A
		case 0x08: call('setDeckGain', 0, data2); break; //volume slider 
		case 0x10: call('setDeckEqHigh', 0, data2); break; // eq high
		case 0x14: call('setDeckEqLow', 0, data2); break; // eq low
		//case 0x03: call('setDeckPitch', 0, data2); break; //pitch -- no pitch for FirstMix
		case 0x19: // sends jog-wheel data completely different than FirstMix I/O
			var val1 = (data2<0x40) ? data2 : data2-0x80;
			if(jogWheelsInScratchMode[0]) call('scratchDeckJW', 0, val1, 700);else call('moveDeckJogWheel', 0, val1, 700);
			break;
			// effect knob
		case 0x16:
			switch(effectsSelected[0])
			{
			case 0: call('setDeckCutoff', 0, data2); break;
			case 1: call('deckFxFlangerDW', 0, data2); break;// deckFxDelayDW, deckFxReverbDW, deckFxPhaserDW, deckFxPanDW, deckFxBeatwawDW
			case 2: call('deckFxReverbDW', 0, data2); break;// deckFxEchoDW deckFxReverbDW
			}
			break;

		//deck B
		case 0x09: call('setDeckGain', 1, data2); break; //volume slider 
		case 0x11: call('setDeckEqHigh', 1, data2); break; // eq high
		case 0x15: call('setDeckEqLow', 1, data2); break; // eq low
		//case 0x04: call('setDeckPitch', 1, data2); break; //pitch -- no pitch for FirstMix
		case 0x18: // sends jog-wheel data completely different than FirstMix I/O
			var val1 = (data2<0x40) ? data2 : data2-0x80;
			if(jogWheelsInScratchMode[1]) call('scratchDeckJW', 1, val1, 700);else call('moveDeckJogWheel', 1, val1, 700);
			break;
			// effect knob
		case 0x1C:
			switch(effectsSelected[1])
			{
			case 0: call('setDeckCutoff', 1, data2); break;
			case 1: call('deckFxFlangerDW', 1, data2); break;// deckFxDelayDW, deckFxReverbDW, deckFxPhaserDW, deckFxPanDW, deckFxBeatwawDW
			case 2: call('deckFxReverbDW', 1, data2); break;// deckFxEchoDW deckFxReverbDW
			}
			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 0x4F: if(data2>0x3F) call('lbToggleSelect', data2); break; //list toggle 
		case 0x0D: call('previewSong', data2); break;// 'previewSong' 'mixNext'
		
		//deck A
		case 0x4B: if(data2>0x3F) 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 0x40: call('deckReverse', 0, data2); break;
		case 0x43: call('deckKeyLock', 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
		// cycle thru the effects
		case 0x44: 
			if(data2==0x7F)
			{
				effectsSelected[0] = effectsSelected[0] + 1;
				if(effectsSelected[0]>=3) effectsSelected[0] = 0;
			}
			break;

		//deck B
		case 0x34: if(data2>0x3F) 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 0x47: call('deckReverse', 1, data2); break;
		case 0x45: call('deckKeyLock', 1, data2); break;
		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
		// cycle thru the effects
		case 0x46: 
			if(data2==0x7F)
			{
				effectsSelected[1] = effectsSelected[1] + 1;
				if(effectsSelected[1]>=3) effectsSelected[1] = 0;
			}
			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(name=='onbeat') 	sendMidi(uniqueId,0x90,0,(deck==0)?0x33:0x3C,(param1 ? 0x7F : 0x00));
	if(name=='reverse') sendMidi(uniqueId,0x90,0,(deck==0)?0x40:0x47,(param1 ? 0x7F : 0x00));
	if(name=='keyLock') sendMidi(uniqueId,0x90,0,(deck==0)?0x43:0x45,(param1 ? 0x7F : 0x00));
	//if(name=='scratch') sendMidi(uniqueId,0x90,0,(deck==0)?0x48:0x35,(param1 ? 0x7F : 0x00));
}
//----------------------------------------------------------------------------- 
// 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+']');
}
//----------------------------------------------------------------------------- 
