//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2016. All Rights Reserved. -----------------------
//-----------------------------------------------------------------------------
// file implementing MIDI controller ''
// last revision: 2018-08-27
//Author: Tollen Francisco, 2018-08-27
//
//----------------------------------------------------------------------------- 
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 "MIXTOUR";
}
//----------------------------------------------------------------------------- 
// 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 0x8A39;	
}
//----------------------------------------------------------------------------- 
// 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
	//return '00 01 3F 37 00 19 00 01 00 04 00 7F 7F 7F 7F 4E 31 31 38 30 36 31 38 36 39 30 38 39 34 30 00 F7'; //very long sysex id
	return '00 20 6E 26 2D 00 00 01 08 00 00 F7'; //sysex id
	
}
//----------------------------------------------------------------------------- 
// 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 "MIXTOUR";
	//return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	return "MIXTOUR";
	//return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var shiftButton				=[0,0,0,0];
var samplerBlinkLedStatus   =[0,0,0,0];
var jogWheelsInScratchMode	=[0,0,0,0];
var vuLED                   =[0,0,0,0];

var fxEcho = [0,0,0,0];
var fxFlanger = [0,0,0,0];
var fxBeatwaw = [0,0,0,0];

var fxKnobCurrentValue = 0;
var fxButton = [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)
{
	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,0x00,0x01,0x00);
	sendMidi(uniqueId,0x90,0x01,0x01,0x00);
	
	sendMidi(uniqueId,0x90,0x00,0x12,0x00);
	sendMidi(uniqueId,0x90,0x01,0x12,0x00);
	
	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)
{
	callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
	
	sendMidi(uniqueId,0x90,0x00,0x01,0x00);
	sendMidi(uniqueId,0x90,0x01,0x01,0x00);
	
	sendMidi(uniqueId,0x90,0x00,0x12,0x00);
	sendMidi(uniqueId,0x90,0x01,0x12,0x00);
	
	
	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)
{
	//debug('messageReceived ['+uniqueId+'] - status:'+status+' channel:'+channel+' data1:'+data1+' data2:'+data2);
	var messageNotProcessed=false;
	
    //if(channel==2) channel = 1;else if(channel==1) channel = 2; // use this to switch channel; 2 and 3 instead of multiple if's
	switch(status)
	{
	//-----------------------------------------------
	// controllers: sliders, knobs, jog-wheels, encoders ('moving' things)
	case 0xE0: // call('setDeckPitch', channel, data2); break; //pitch sliders decks 1-4
		break;
	
	case 0xB0:
		switch(data1)
		{
		case 0x00:
			if(channel == 4){
				call('setMasterGain', data2);
			
			} else {
				call('setDeckGain', channel, data2);
			}
			
			break;
		case 0x01: 
			if(channel == 4){
				call('setMonitorVolume', data2);
			} else {
				call('setDeckEqHigh', channel, data2);				 
			}
		break;
		case 0x02: 
			 call('setDeckEqMid', channel, data2);
		break;
		case 0x03: 
			call('setDeckEqLow', channel, data2);
		break;
		case 0x04:
			if(fxButton[channel]){
				call('deckFx1DryWet', channel, data2);
			} else {
				call('setDeckCutoff', channel, data2);	
			}
		break;
		case 0x05:
			call('setDeckVolume', channel, data2);
		break;
		case 0x06: 			
			call('setCuePgmMix', data2);
		break;
		case 0x07: 
			var val1 = (data2 == 0x7F ? 1 : -1);
			call('lbMoveCursor', val1);
		break;
		case 0x08: 
			call('setCrossfader', data2);
		break;
		case 0x09: 
			
		break;
		case 0x0A: 
			
		break;
		case 0x0B: 
			
		break;
		case 0x0C: 
			
		break;
		case 0x0D: 
			
		break;
		case 0x0E: 
		break;
		case 0x0F: 
		
		break;
		case 0x10: 
		break;
		case 0x11: 
		break;
		case 0x12: 
		break;
		case 0x13: 
			
		break;
		case 0x14: 
		break;
		case 0x15: 
		break;
		case 0x16: 
		break;
		case 0x17: 
			
		break;
		case 0x18:
			
		break;
		case 0x19: 
			
		break;
		case 0x1A: 
			
		break;
		case 0x1B: 
		break;
		case 0x1C: 
		break;
		case 0x1D: 
		break;
		case 0x1E: 
		break;
		case 0x1F: 
			
		break;
		case 0x20: 
		break;
		case 0x21: 
			
		break;
		case 0x22:
		case 0x23:		

		break;
		
		case 0x24: 
		break;
		case 0x25: 
		break;
		case 0x26: 
		break;
		case 0x27: 

		break;
		case 0x28: 
		break;
		case 0x29: 
		break;
		case 0x2A: 
		break;
		case 0x2B: 			
		break;
		case 0x2C: 
		break;
		case 0x2D: 
		break;
		case 0x2E: 
		break;
		case 0x2F: 
		break;
		case 0x30: 
		break;
		case 0x31: 
		break;
		case 0x32: 
		break;
		case 0x33: 
		break;
		case 0x34: 
		break;
		case 0x35: 
		break;
		case 0x36: 
		break;
		case 0x37: 
		break;
		case 0x38: 
		break;
		case 0x39: 
		break;
		case 0x3A: 
		break;
		case 0x3B: 
		break;
		case 0x3C: 
		break;
		case 0x3D: 
		break;
		case 0x3E: 
		break;
		case 0x3F:
		break;
		case 0x40:
		break;
		case 0x43:			
		break;
		default: messageNotProcessed = true;
		}
	break;
	//-----------------------------------------------
	// note on/off: buttons, switches ('pressing' things)
	case 0x80:
	case 0x90:
		switch(data1)
		{
		case 0x00:			
			
			break;
		case 0x01:
			//fx button
			if(data2){
				fxButton[channel] = fxButton[channel] ? 0 : 1;
				sendMidi(uniqueId,0x90,channel,0x01,(fxButton[channel] ? 0x7F : 0x00));
			}
			break;
		case 0x02:
			if(data2){
				call('deckLBLoad', channel, data2);
			}
			break;
		case 0x03: 			
			call('deckMonitor', channel, data2);
			break;
		case 0x04: 			
			
			break;
		case 0x05: 			
			
			break;
		case 0x06: 			
			
			break;
		case 0x07: 		
			if(data2)
				call('lbToggleSelect', data2);
			break;
		case 0x08: 
			break;
		case 0x09:
			call('deckLoop4', channel, data2);		
			break;
		case 0x0A:
			call('deckSync', channel, data2);
			break;
		case 0x0B:			
			call('deckCue', channel, data2);
			break;
		case 0x0C:	
			call('deckPlayPause', channel, data2);
			break;
		case 0x0D:		
			call('deckCuePos1', channel, data2);
			break;
		case 0x0E:
			call('deckCuePos2', channel, data2);
			break;
		case 0x0F: 
			call('deckCuePos3', channel, data2);
			break;
		case 0x10:
			call('deckCuePos4', channel, data2);
			break;
		case 0x61:					
			break;
		case 0x62: 
			 
			break;
		case 0x12: 
			
			break;
		case 0x13: 
			
			break;
		case 0x14: 
			
			break;
		case 0x15: 
			
			break;
		case 0x16: 
			
			break;
		case 0x17: 
			
			break;
		case 0x18:		
			break;
		case 0x19:		
			break;
		case 0x1A:	
			
			break;
		case 0x1B: 						
			break;
		case 0x1C: 
			break;
		case 0x1D: 
			break;
		case 0x1E: 
			break;
		case 0x1F: 
			break;
		case 0x20: 
			break;
		case 0x21: 
			break;
		case 0x22: 
			break;
		case 0x23: 
			break;
		case 0x24: 
			break;
		case 0x25: 
			break;
		case 0x26: 
			break;
		case 0x27: 
			break;
		case 0x28: 			
			break;
		case 0x29: 			
			break;
		case 0x2A: 
			break;
		case 0x2B: 			
			break;
		case 0x2C:			
			break;
		case 0x2D: 
			break;
		case 0x2E: 			
			break;
		case 0x2F: 
			break;
		case 0x30: 
			
			break;
		case 0x31: 
			
			break;
		case 0x32: 
			
			break;
		case 0x33: 
			
			break;
		case 0x34: 
			
			break;
		case 0x35: 
			
			break;
		case 0x36: 
			
			break;
		case 0x37: 
			
			break;
		case 0x38: 			
			break;
		case 0x39: 
			break;
		case 0x3A: 
			break;
		case 0x3B: 
			break;
		case 0x3C: 
			break;
		case 0x3D: 
			break;
		case 0x3E: 
			break;
		case 0x3F: 
			break;
		case 0x40:
			
			break;
		case 0x41:			
			call('deckFx1Next', channel, data2);
			break;
		case 0x42:
			call('deckTapBpm', channel, data2);
			break;
		case 0x43:
		
			break;
		case 0x44:
			
			break;
		case 0x45:
			
			break;
		case 0x46:
			
			break;
		case 0x47:
			
			break;
		case 0x48:
			call('deckLoop2', channel, data2);
			break;
		case 0x49:
			call('deckLoop8', channel, data2);	
			break;
		case 0x4B:
			call('deckBackToTop', channel, data2);
			sendMidi(uniqueId,0x90,channel,0x4B,data2);
			break;
		case 0x4D:
			
			break;
		case 0x50:
			
			break;
		case 0x51:
			
			break;
		case 0x52:
			
			break;
		case 0x53:
			
			break;
		case 0x54:
			
			break;
		case 0x55:
			
			break;
		case 0x56:
			
			break;
		case  0x67:
			
			break;
		case 0x58:
			
			break;
		case 0x5F:
			break;
		case 0x60:
			
			break;
		case 0x61:
			break;
		case 0x62:
			break;
		case 0x72:
			
			break;
		case 0x77: 
			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);
	var nameLen = name.length;
	
	
	if(name=='play'){
		sendMidi(uniqueId,0x90,deck,0x0C,(param1 ? 0x7F : 0x00)); //play button		
	}
	
	if(name=='cue') 		sendMidi(uniqueId,0x90,deck,0x0B,(param1 ? 0x7F : 0x00)); //cue
	
	if(name=='onbeat') 		sendMidi(uniqueId,0x90,deck,0x0A,(param1 ? 0x7F : 0x00)); //play
	
	if(name=='cuepos1')		sendMidi(uniqueId,0x90,deck,0x0D,(param1 ? 0x55 : 0x00));
	if(name=='cuepos2')		sendMidi(uniqueId,0x90,deck,0x0E,(param1 ? 0x55 : 0x00));
	if(name=='cuepos3')		sendMidi(uniqueId,0x90,deck,0x0F,(param1 ? 0x55 : 0x00));
	if(name=='cuepos4')		sendMidi(uniqueId,0x90,deck,0x10,(param1 ? 0x55 : 0x00));
	
	if(name=='monitor') 	sendMidi(uniqueId,0x90,deck,0x03,(param1 ? 0x7F : 0x00));//monitor
	
	if(name=='loopSize'){
		debug('notif ['+uniqueId+'] name='+name + ' deck='+deck + ' p1(int)='+param1 + ' p2(float)='+param2 + ' p3(str)='+param3);
		switch(param1){
			case 128: //half loop
				sendMidi(uniqueId,0x90,deck,0x48,0x7F);
				sendMidi(uniqueId,0x90,deck,0x09,0x00);
				sendMidi(uniqueId,0x90,deck,0x49,0x00);
				break;

			case 256: //full loop
				sendMidi(uniqueId,0x90,deck,0x48,0x00);
				sendMidi(uniqueId,0x90,deck,0x09,0x7F);
				sendMidi(uniqueId,0x90,deck,0x49,0x00);
				
				break;
			case 512: //double loop
				sendMidi(uniqueId,0x90,deck,0x48,0x00);
				sendMidi(uniqueId,0x90,deck,0x09,0x00);
				sendMidi(uniqueId,0x90,deck,0x49,0x7F);
				break;
			default:
				sendMidi(uniqueId,0x90,deck,0x48,0x00);
				sendMidi(uniqueId,0x90,deck,0x09,0x00);
				sendMidi(uniqueId,0x90,deck,0x49,0x00);
		}
	}
	
	if(name=='justLoaded')
	{
		
		if(param1!=0 && param1!=32)
		{
			// loading
			sendMidi(uniqueId,0x90,deck,0x02,0x7F);// on
		}else
		{
			// loading finished
			sendMidi(uniqueId,0x90,deck,0x02,0x00);// off
		}
	}
	
	
				
}


//----------------------------------------------------------------------------- 
// 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)
{
	for(var i=0; i<2; i++)
	{	
		var vuDeck = getValue('vumeterDeck', i);// float dB
		sendMidi(uniqueId,0x90,i,0x12,getMIDIValueForVU(vuDeck));
	}
}

function getMIDIValueForVU(vu_val)
{
	// translating VU-meter signal from decibels (dB) to 0..127 MIDI range
	var val = 0;
	var step = 17;
	if(vu_val>-44) val =  1 * step;
	//if(vu_val>-36) val =  2 * step;
	//if(vu_val>-28) val =  3 * step;
	if(vu_val>-20) val =  4 * step;
	//if(vu_val>-16) val =  5 * step;
	if(vu_val>-12) val =  6 * step;
	//if(vu_val> -8) val =  7 * step;
	if(vu_val> -4) val =  8 * step;
	//if(vu_val> -2) val =  9 * step;
	if(vu_val> -1) val = 10 * step;
	return Math.floor(val);
}

//----------------------------------------------------------------------------- 
