//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2015 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing MIDI controller 'Numark/Ion DJ2Go'
//-----------------------------------------------------------------------------
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 "Numark/Ion DJ2Go";
}
//-----------------------------------------------------------------------------
// 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 0x15E4;// Numark DJ2Go
}
//-----------------------------------------------------------------------------
function getSupportedMidiDevicePID(osId)
{
	return 0x0027;// Numark DJ2Go
}
//-----------------------------------------------------------------------------
/*
function getSupportedMidiDeviceVID2(osId)
{
	return 0x15E4;// Ion DJ2Go
}
//-----------------------------------------------------------------------------
function getSupportedMidiDevicePID2(osId)
{
	return 0x0027;// Ion DJ2Go
}
*/
//-----------------------------------------------------------------------------
// 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 "00013F2100";
	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; 3 iOS; 4 Android; -1 unknown
function getSupportedMidiDeviceNameForInput(osId)
{
	//if(osId==3) return "Network Session 1";
	return "Numark DJ2Go";
}
//-----------------------------------------------------------------------------
function getSupportedMidiDeviceNameForInput2(osId)
{
	return "DJ2Go";
}
//-----------------------------------------------------------------------------
function getSupportedMidiDeviceNameForOutput(osId)
{
	//if(osId==3) return "Network Session 1";
	return "Numark DJ2Go";
}
//-----------------------------------------------------------------------------
function getSupportedMidiDeviceNameForOutput2(osId)
{
	return "DJ2Go";
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// DEBUG USE ONLY -- no use for this particular script/controller
// tests array communication in both ways: [JS -> C++] and [C++ -> JS]
function isArray(obj){return toString.call(obj) === "[object Array]";}
function printObject(obj)
{
	if(isArray(obj))
	{
		debug('array object (size '+obj.length+'):');
		for(var i=0; i<obj.length; i++) printObject(obj[i]);
	}else // normal object
	{
		debug('item='+obj);
	}
}
function testArrays(uniqueId)
{
//	asd} -- used to simulate a compile error
	debug('------- testArrays START ------- ['+uniqueId+']');
	// prepare data (array contains various data types)
	var tmpArray = new Array(3);
	tmpArray[0] = 28;
	tmpArray[1] = 'str28';
	tmpArray[2] = 28.02;
	var testData = new Array(4);
	testData[0] = 15;
	testData[1] = 30.3;
	testData[2] = tmpArray;// array inside array
	testData[3] = 'str60';
	// call C++ defined function 'testArraysDebug'
	var resultArray = testArraysDebug(uniqueId, testData, 4, 1.2345, "testStr");
	// see what we get back
	debug('------- testArrays RESULT ------- ['+uniqueId+']');
	if(isArray(resultArray)) debug('result IS an array');else debug('result is NOT an array');
	printObject(resultArray);
	debug('------- testArrays STOP ------- ['+uniqueId+']');
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// 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 DJ2Go ['+uniqueId+']');// this outputs a string to DebugView app on Win
	sendMidi(uniqueId,0x90,0,0x33,(getValue('cue', 0) ? 0x7F : 0x00));// cue A
	sendMidi(uniqueId,0x90,0,0x3B,(getValue('play', 0) ? 0x7F : 0x00));// play-pause A
	sendMidi(uniqueId,0x90,0,0x40,0x00);// sync A
	sendMidi(uniqueId,0x90,0,0x65,(getValue('monitor', 0) ? 0x7F : 0x00));// monitor A
	call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	sendMidi(uniqueId,0x90,0,0x3C,(getValue('cue', 1) ? 0x7F : 0x00));// cue B
	sendMidi(uniqueId,0x90,0,0x42,(getValue('play', 1) ? 0x7F : 0x00));// play-pause B
	sendMidi(uniqueId,0x90,0,0x47,0x00);// sync B
	sendMidi(uniqueId,0x90,0,0x66,(getValue('monitor', 1) ? 0x7F : 0x00));// monitor B

	//--------------------
	//testArrays(uniqueId);// debug use only -- no use for this particular script/controller
	/*
	// test extra screens - Duet screen appears as "unknown screen"
	if(openExtraScreen("extraWindow1", "DELL U2312HM|||unknown***|||DELL U2412M"))
	{
		debug('openExtraScreen was set OK');
		//setSetting('AudioDevice2', "NO AUDIO");
	}else
	{
		debug('error: openExtraScreen was NOT set OK');
	}
	*/
}
//-----------------------------------------------------------------------------
// 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 DJ2Go ['+uniqueId+']');
	sendMidi(uniqueId,0x90,0,0x33,0x00);// cue A
	sendMidi(uniqueId,0x90,0,0x3B,0x00);// play-pause A
	sendMidi(uniqueId,0x90,0,0x40,0x00);// sync A
	sendMidi(uniqueId,0x90,0,0x65,0x00);// monitor A
	call('sleep', 10);// delay for 10ms to allow the MIDI out buffer to flush
	sendMidi(uniqueId,0x90,0,0x3C,0x00);// cue B
	sendMidi(uniqueId,0x90,0,0x42,0x00);// play-pause B
	sendMidi(uniqueId,0x90,0,0x47,0x00);// sync B
	sendMidi(uniqueId,0x90,0,0x66,0x00);// monitor B
	closeExtraScreen("extraWindow1");
}
//-----------------------------------------------------------------------------
// 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 0x0A: call('setCrossfader', data2); break;
		case 0x17: call('setMasterGain', data2/2); break;
		case 0x0B: call('setMonitorGain', data2); break;
		case 0x1A: // move track
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('lbMoveCursor', val1);
			break;

		// deck A
		case 0x08: call('setDeckVolume', 0, data2); break;
		case 0x0D: call('setDeckPitch', 0, data2); break;
		case 0x19: // params: (deck, increment, total positions per complete revolution)
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('moveDeckJogWheel', 0, val1, 64);
			break;

		// deck B
		case 0x09: call('setDeckVolume', 1, data2); break;
		case 0x0E: call('setDeckPitch', 1, data2); break;
		case 0x18: // params: (deck, increment, total positions per complete revolution)
			var val1 = (data2>0x40 ? data2-0x80 : data2);
			call('moveDeckJogWheel', 1, val1, 64);
			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 0x00: if((status==0x90)&&(data2>0x3F)) call('lbToggleSelect', data2); break;
		case 0x59: if(data2>0x3F) call('lbBrowserSelect', data2); break;
		case 0x5A: if(data2>0x3F) call('lbListSelect', data2); break;
		case 0x4B: if(data2>0x3F) call('deckLBLoad', 0, data2); break;
		case 0x34: if(data2>0x3F) call('deckLBLoad', 1, data2); break;

		// deck A
		case 0x33: call('deckCue', 0, data2); break;
		case 0x3B: call('deckPlayPause', 0, data2); break;
		case 0x40: call('deckSync', 0, data2); break;
		case 0x65: call('deckMonitor', 0, data2); break;
		case 0x44: call('deckBendDown', 0, data2); break;
		case 0x43: call('deckBendUp', 0, data2); break;
		//case 0x43: call('deckTapBpm', 0, data2); break;//test only

		// deck B
		case 0x3C: call('deckCue', 1, data2); break;
		case 0x42: call('deckPlayPause', 1, data2); break;
		case 0x47: call('deckSync', 1, data2); break;
		case 0x66: call('deckMonitor', 1, data2); break;
		case 0x46: call('deckBendDown', 1, data2); break;
		case 0x45: call('deckBendUp', 1, data2); 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)?0x33:0x3C,(param1 ? 0x7F : 0x00));
	if(name=='play') 		 sendMidi(uniqueId,0x90,0,(deck==0)?0x3B:0x42,(param1 ? 0x7F : 0x00));
	if(name=='onbeat') 		 sendMidi(uniqueId,0x90,0,(deck==0)?0x40:0x47,(param1 ? 0x7F : 0x00));
	if(name=='monitor') 	 sendMidi(uniqueId,0x90,0,(deck==0)?0x65:0x66,(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+']');
}
//-----------------------------------------------------------------------------
