//-----------------------------------------------------------------------------
//-------- Copyright (c)2003-2013 XYLIO INFO SRL. All Rights Reserved. --------
//-----------------------------------------------------------------------------
// file implementing HID controller 'Gemini CNTRL-7'
//----------------------------------------------------------------------------- 
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 CNTRL-7";
}
//----------------------------------------------------------------------------- 
// 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 'hid';
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// 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 0x23C7;
}
//----------------------------------------------------------------------------- 
function getSupportedHidDeviceVID2(osId)
{
	return 0x23C7;
}
//----------------------------------------------------------------------------- 
function getSupportedHidDevicePID(osId)
{
	return 0x1521;
}
//----------------------------------------------------------------------------- 
function getSupportedHidDevicePID2(osId)
{
	return 0x1421;
}
//----------------------------------------------------------------------------- 
// 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)
{
	//if(osId==1) return "Gemini CNTRL-7";
	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
	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)
{
	// we do NOT use MIDI with this controller since the buttons/knobs/faders appear 
	// to be assignable so the codes reported are not fixed (eg. Cue point 1 Deck A has the exact same code as Cue point 1 Deck B)
	// so we have to use HID
	//if(osId==1) return "Console";
	return false;
}
//----------------------------------------------------------------------------- 
function getSupportedMidiDeviceNameForOutput(osId)
{
	//if(osId==1) return "Console";
	return false;
}
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
//----------------------------------------------------------------------------- 
// this controller accepts 64/65 bytes(in) / 64/65 bytes(out) to it's HID end points
//----------------------------------------------------------------------------- 
// some variables necessary only for this particular script
var jogModeScratch=[0,0,0,0];
var jogModeSearch=[0,0,0,0];
var loopingInBlinkLed=[-1,-1,-1,-1];// -1 means disabled
var effectsSelected=[0,0,0,0];// 4 decks (the selected fx, 0-based index)
var samplerSelected=[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 Hid Gemini CNTRL-7 ['+uniqueId+']');// this outputs a string to DebugView on Win / Console on Mac
	// set all lcd/leds off (this is much faster than 'callSendAllNotifications')
	var initHidData = new Array(65);
	for(var i=0; i<65; i++)	initHidData[i] = 0;
	sendHid(uniqueId, initHidData, 65);
	// defineHidPage(uniqueId, pageName, isInputPage);
	// defineHidPageDetect(uniqueId, pageName, typeName, offset, size, value);
	// defineHidPageAction(uniqueId, pageName, actionName, deck, typeName, offset[,size,min,max,specialTypeName]);
	// define pages, how to detect them and the actions
	//------------------------------------
	// define a new HID page (and specify how to recognize/detect it)
	defineHidPage(uniqueId, 'mainPage', true);

	// deck A
	defineHidPageAction(uniqueId, 'mainPage', 'cue', 0, 'bit', 0x00);
	defineHidPageAction(uniqueId, 'mainPage', 'cueplay', 0, 'bit', 0x01);// actually it's 'PAUSE' on the controller
	defineHidPageAction(uniqueId, 'mainPage', 'playpause', 0, 'bit', 0x02);
	defineHidPageAction(uniqueId, 'mainPage', 'bendup', 0, 'bit', 0x03);
	defineHidPageAction(uniqueId, 'mainPage', 'benddown', 0, 'bit', 0x04);	
	defineHidPageAction(uniqueId, 'mainPage', 'cue1', 0, 'bit', 0x05);
	defineHidPageAction(uniqueId, 'mainPage', 'cue2', 0, 'bit', 0x06);
	defineHidPageAction(uniqueId, 'mainPage', 'cue3', 0, 'bit', 0x07);
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-search-mode', 0, 'bit', 0x08);// search
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-scratch-mode', 0, 'bit', 0x09);// scratch
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-effect', 0, 'bit', 0x0A);// fx select
	defineHidPageAction(uniqueId, 'mainPage', 'pitch-reset', 0, 'bit', 0x0B);
	defineHidPageAction(uniqueId, 'mainPage', 'keylock', 0, 'bit', 0x0C);// Master Tempo
	defineHidPageAction(uniqueId, 'mainPage', 'tap-bpm', 0, 'bit', 0x0D);// BPM
	defineHidPageAction(uniqueId, 'mainPage', 'loopless', 0, 'bit', 0x0E);// loop 1/2
	defineHidPageAction(uniqueId, 'mainPage', 'loopin', 0, 'bit', 0x0F);// loop in
	defineHidPageAction(uniqueId, 'mainPage', 'loopout', 0, 'bit', 0x10);// loop out
	defineHidPageAction(uniqueId, 'mainPage', 'loopmore', 0, 'bit', 0x11);// loop 2x
	//defineHidPageAction(uniqueId, 'mainPage', 'ACTION 11', 0, 'bit', 0x12);//--not-used--
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-play', 0, 'bit', 0x13);
	defineHidPageAction(uniqueId, 'mainPage', 'sync', 0, 'bit', 0x14);
	defineHidPageAction(uniqueId, 'mainPage', 'effect-on', 0, 'bit', 0x15);
	defineHidPageAction(uniqueId, 'mainPage', 'loadtrack', 0, 'bit', 0x16);
	defineHidPageAction(uniqueId, 'mainPage', 'browsertoggle',-1, 'bit', 0x17);// folder button (under track search encoder)
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-play2', 0, 'bit', 0x18);// sampler push
		
	// deck B
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-play2', 1, 'bit', 0x19);// sampler push
	defineHidPageAction(uniqueId, 'mainPage', 'cue', 1, 'bit', 0x1A);
	defineHidPageAction(uniqueId, 'mainPage', 'cueplay', 1, 'bit', 0x1B);// actually it's 'PAUSE' on the controller
	defineHidPageAction(uniqueId, 'mainPage', 'playpause', 1, 'bit', 0x1C);
	defineHidPageAction(uniqueId, 'mainPage', 'bendup', 1, 'bit', 0x1D);
	defineHidPageAction(uniqueId, 'mainPage', 'benddown', 1, 'bit', 0x1E);
	defineHidPageAction(uniqueId, 'mainPage', 'cue1', 1, 'bit', 0x1F);
	defineHidPageAction(uniqueId, 'mainPage', 'cue2', 1, 'bit', 0x20);
	defineHidPageAction(uniqueId, 'mainPage', 'cue3', 1, 'bit', 0x21);
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-search-mode', 1, 'bit', 0x22);// search
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-scratch-mode', 1, 'bit', 0x23);// scratch
	defineHidPageAction(uniqueId, 'mainPage', 'toggle-effect', 1, 'bit', 0x24);// fx select
	defineHidPageAction(uniqueId, 'mainPage', 'pitch-reset', 1, 'bit', 0x25);
	defineHidPageAction(uniqueId, 'mainPage', 'keylock', 1, 'bit', 0x26);// Master Tempo
	defineHidPageAction(uniqueId, 'mainPage', 'tap-bpm', 1, 'bit', 0x27);// BPM
	defineHidPageAction(uniqueId, 'mainPage', 'loopless', 1, 'bit', 0x28);// loop 1/2
	defineHidPageAction(uniqueId, 'mainPage', 'loopin', 1, 'bit', 0x29);// loop in
	defineHidPageAction(uniqueId, 'mainPage', 'loopout', 1, 'bit', 0x2A);// loop out
	defineHidPageAction(uniqueId, 'mainPage', 'loopmore', 1, 'bit', 0x2B);// loop 2x
	//defineHidPageAction(uniqueId, 'mainPage', 'ACTION 26', 1, 'bit', 0x2C);//--not-used--
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-play', 1, 'bit', 0x2D);
	defineHidPageAction(uniqueId, 'mainPage', 'sync', 1, 'bit', 0x2E);
	defineHidPageAction(uniqueId, 'mainPage', 'effect-on', 1, 'bit', 0x2F);
	defineHidPageAction(uniqueId, 'mainPage', 'loadtrack', 1, 'bit', 0x30);
	
	// global
	defineHidPageAction(uniqueId, 'mainPage', 'browsertoggle2',-1, 'bit', 0x31);// track/folder search (encoder with push button)
	defineHidPageAction(uniqueId, 'mainPage', 'monitor', 0, 'bit', 0x32);// USB/Line1
	defineHidPageAction(uniqueId, 'mainPage', 'monitor', 1, 'bit', 0x33);// USB/Line2
	defineHidPageAction(uniqueId, 'mainPage', 'jogwheel-touch', 0, 'bit', 0x34);
	defineHidPageAction(uniqueId, 'mainPage', 'jogwheel-touch', 1, 'bit', 0x35);
	//----------------------------------
	// sliders,knobs,encoders,jog-wheels
	// defineHidPageAction(uniqueId, pageName, actionName, deck, typeName, offset[,size,min,max,specialTypeName]);
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-select', 0, 'ubyte', 0x07, 1, 0, 255, 'encoder');
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-select', 1, 'ubyte', 0x08, 1, 0, 255, 'encoder');
	defineHidPageAction(uniqueId, 'mainPage', 'browser',-1, 'ubyte', 0x09, 1, 0, 255, 'encoder');// track
	
	defineHidPageAction(uniqueId, 'mainPage', 'crossfader',-1, 'ubyte', 0x0A, 1, 0, 255);// inverted
	defineHidPageAction(uniqueId, 'mainPage', 'cfcurve',-1, 'ubyte', 0x0B, 1, 0, 255);
	
	defineHidPageAction(uniqueId, 'mainPage', 'volume', 0, 'ubyte', 0x0C, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'pitch', 0, 'ubyte', 0x0D, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'effect-drywet', 0, 'ubyte', 0x0E, 1, 0, 255);// fx1
	defineHidPageAction(uniqueId, 'mainPage', 'effect-param', 0, 'ubyte', 0x0F, 1, 0, 255);// fx2
	defineHidPageAction(uniqueId, 'mainPage', 'gain', 0, 'ubyte', 0x10, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-high', 0, 'ubyte', 0x11, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-mid', 0, 'ubyte', 0x12, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-low', 0, 'ubyte', 0x13, 1, 0, 255);
	
	defineHidPageAction(uniqueId, 'mainPage', 'mastergain',-1, 'ubyte', 0x14, 1, 0, 255);// master volume

	defineHidPageAction(uniqueId, 'mainPage', 'volume', 1, 'ubyte', 0x15, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'pitch', 1, 'ubyte', 0x16, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'effect-drywet', 1, 'ubyte', 0x17, 1, 0, 255);// fx1
	defineHidPageAction(uniqueId, 'mainPage', 'effect-param', 1, 'ubyte', 0x18, 1, 0, 255);// fx2
	defineHidPageAction(uniqueId, 'mainPage', 'gain', 1, 'ubyte', 0x19, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-high', 1, 'ubyte', 0x1A, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-mid', 1, 'ubyte', 0x1B, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'eq-low', 1, 'ubyte', 0x1C, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-volume', 1, 'ubyte', 0x1D, 1, 0, 255);
	defineHidPageAction(uniqueId, 'mainPage', 'sampler-volume', 0, 'ubyte', 0x1E, 1, 0, 255);
	
	defineHidPageAction(uniqueId, 'mainPage', 'cuepgmmix',-1, 'ubyte', 0x1F, 1, 0, 255);// headphones
	defineHidPageAction(uniqueId, 'mainPage', 'jogwheel', 0, 'ubyte', 0x20, 1, 0, 255, 'jogwheel');// ~140 distinct positions/rotation
	defineHidPageAction(uniqueId, 'mainPage', 'monitorgain',-1, 'ubyte', 0x21, 1, 0, 255);// monitor volume
	defineHidPageAction(uniqueId, 'mainPage', 'jogwheel', 1, 'ubyte', 0x22, 1, 0, 255, 'jogwheel');
	//defineHidPageAction(uniqueId, pageNameBase+'-jw', 'jogwheel', deck, 'uword', 0x03, 1, 0, 65535, 'jogwheel');//~1200 distinct positions/rotation
	//------------------------------------
	//------------------------------------
	//------------------------------------
	// output pages
	defineHidPage(uniqueId, 'mainPageOut', false);// output page
	// deck A
	defineHidPageAction(uniqueId, 'mainPageOut', 'play', 0, 'bit', 0x00);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x01);// pause -- ATTN deck 2
	defineHidPageAction(uniqueId, 'mainPageOut', 'cue', 0, 'bit', 0x02);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x03);// bend up
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x04);// bend down
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos1', 0, 'bit', 0x05);
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos2', 0, 'bit', 0x06);
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos3', 0, 'bit', 0x07);
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-search', 0, 'bit', 0x08);
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-scratch', 0, 'bit', 0x09);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x0A);// fx select
	defineHidPageAction(uniqueId, 'mainPageOut', 'pitchIs0', 0, 'bit', 0x0B);// pitch reset
	defineHidPageAction(uniqueId, 'mainPageOut', 'keyLock', 0, 'bit', 0x0C);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x0D);// BPM
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x0E);// loop 1/2
	defineHidPageAction(uniqueId, 'mainPageOut', 'loopIn', 0, 'bit', 0x0F);// loop in
	defineHidPageAction(uniqueId, 'mainPageOut', 'looping', 0, 'bit', 0x10);// loop out
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x11);// loop 2x
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x12);// button1
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x13);// button2
	defineHidPageAction(uniqueId, 'mainPageOut', 'onbeat', 0, 'bit', 0x14);// sync
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-fx', 0, 'bit', 0x15);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x16);// load
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION',-1, 'bit', 0x17);// folder
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x18);// --not-used--
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x19);// --not-used--
	
	// deck B
	defineHidPageAction(uniqueId, 'mainPageOut', 'play', 1, 'bit', 0x1A);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x1B);// pause -- ATTN deck 1
	defineHidPageAction(uniqueId, 'mainPageOut', 'cue', 1, 'bit', 0x1C);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x1D);// bend up
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x1E);// bend down
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos1', 1, 'bit', 0x1F);
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos2', 1, 'bit', 0x20);
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos3', 1, 'bit', 0x21);
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-search', 1, 'bit', 0x22);
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-scratch', 1, 'bit', 0x23);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x24);// fx select
	defineHidPageAction(uniqueId, 'mainPageOut', 'pitchIs0', 1, 'bit', 0x25);// pitch reset
	defineHidPageAction(uniqueId, 'mainPageOut', 'keyLock', 1, 'bit', 0x26);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x27);// BPM
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x28);// loop 1/2
	defineHidPageAction(uniqueId, 'mainPageOut', 'loopIn', 1, 'bit', 0x29);// loop in
	defineHidPageAction(uniqueId, 'mainPageOut', 'looping', 1, 'bit', 0x2A);// loop out
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x2B);// loop 2x
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x2C);// button1
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x2D);// button2
	defineHidPageAction(uniqueId, 'mainPageOut', 'onbeat', 1, 'bit', 0x2E);// sync
	defineHidPageAction(uniqueId, 'mainPageOut', 'led-fx', 1, 'bit', 0x2F);
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x30);// load
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION',-1, 'bit', 0x31);// enter
	
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler1', 0, 'bit', 0x44);// led 1
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler2', 0, 'bit', 0x45);// led 2
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler3', 0, 'bit', 0x46);// led 3
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler4', 0, 'bit', 0x47);// led 4
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler5', 0, 'bit', 0x48);// led 5
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler6', 0, 'bit', 0x49);// led 6
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler7', 0, 'bit', 0x4A);// led 7
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler8', 0, 'bit', 0x4B);// led 8
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 0, 'bit', 0x4C);// led 9
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos1', 0, 'bit', 0x4D);// led 10
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos2', 0, 'bit', 0x4E);// led 11
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos3', 0, 'bit', 0x4F);// led 12
	 
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler1', 1, 'bit', 0x50);// led 1
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler2', 1, 'bit', 0x51);// led 2
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler3', 1, 'bit', 0x52);// led 3
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler4', 1, 'bit', 0x53);// led 4
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler5', 1, 'bit', 0x54);// led 5
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler6', 1, 'bit', 0x55);// led 6
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler7', 1, 'bit', 0x56);// led 7
	defineHidPageAction(uniqueId, 'mainPageOut', 'sampler8', 1, 'bit', 0x57);// led 8
	//defineHidPageAction(uniqueId, 'mainPageOut', 'ACTION', 1, 'bit', 0x58);// led 9
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos1', 1, 'bit', 0x59);// led 10
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos2', 1, 'bit', 0x5A);// led 11
	defineHidPageAction(uniqueId, 'mainPageOut', 'cuepos3', 1, 'bit', 0x5B);// led 12
	
	// VU-meter led strip LEFT (6 bits, reversed)
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu6', 1, 'bit', 0x38);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu5', 1, 'bit', 0x39);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu4', 1, 'bit', 0x3A);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu3', 1, 'bit', 0x3B);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu2', 1, 'bit', 0x3C);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu1', 1, 'bit', 0x3D);
	// VU-meter led strip RIGHT (6 bits, reversed)
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu6', 0, 'bit', 0x3E);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu5', 0, 'bit', 0x3F);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu4', 0, 'bit', 0x40);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu3', 0, 'bit', 0x41);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu2', 0, 'bit', 0x42);
	defineHidPageAction(uniqueId, 'mainPageOut', 'vu1', 0, 'bit', 0x43);
	// pre-set sampler1 as on
	callHidPageAction(uniqueId, "sampler1", 0, 1);
	callHidPageAction(uniqueId, "sampler1", 1, 1);
	//------------------------------------
	callSendAllNotifications(uniqueId, true);// send all notifications to the controller (so that we don't have to manually init all leds/lcd screens)
}
//----------------------------------------------------------------------------- 
// 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 Hid Gemini CNTRL-7 ['+uniqueId+']');
	//callSendAllNotifications(uniqueId, false);// send all notifications to the controller (so that we don't have to manually de-init all leds/lcd screens)
	// set all lcd/leds off (this is much faster than 'callSendAllNotifications')
	var initHidData = new Array(65);
	for(var i=0; i<65; i++)	initHidData[i] = 0;
	sendHid(uniqueId, initHidData, 65);
}
//----------------------------------------------------------------------------- 
// 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 Midi ['+uniqueId+']');
	// this is not used with HID controllers
	return false;
}
//----------------------------------------------------------------------------- 
// received for both HID/MIDI as/if needed/used
// ATTN: this implementation is 'almost' generic but still includes several XDJ-AERO specific things
function actionReceived(uniqueId,name,deck,value)
{
	//if(name!='jogwheel') debug('actionReceived ['+uniqueId+'] name='+name+' deck='+deck+' value='+value);// return;
	// value is [0..1] or +/-n for encoders/jogwheels
	// ATTN: we multiply by 0x7F almost all the values to simulate MIDI (which our DJ app conforms to)
	switch(name)
	{
	// decks
	case 'loopless': call('deckLoopLess', deck, value*0x7F); break;
	case 'loopmore': call('deckLoopMore', deck, value*0x7F); break;
	case 'looplessmore':
		// since we don't receive press+release notifications for encoders, we need to simulate a fast press+release
		if(value<0) 
		{
			call('deckLoopLess', deck, 0x7F);
			call('deckLoopLess', deck, 0x00);
		}else 
		{
			call('deckLoopMore', deck, 0x7F);
			call('deckLoopMore', deck, 0x00);
		}
		break;
	case 'beat_encoder': // encoder (marked 'beat' on the silkscreen)
	case 'loopprevnext':
		// since we don't receive press+release notifications for encoders, we need to simulate a fast press+release
		if(value<0) 
		{
			call('deckLoopPrev', deck, 0x7F);
			call('deckLoopPrev', deck, 0x00);
		}else 
		{
			call('deckLoopNext', deck, 0x7F);
			call('deckLoopNext', deck, 0x00);
		}
		break;
	case 'pitch': call('setDeckPitch', deck, (1.0-value)*0x7F); break;// reversed slider
	case 'leveldepth_knob': call('setDeckPitchKey', deck, value*0x7F); break;// knob (marked 'level depth' on the silkscreen)
	// buttons
	case 'playpause': call('deckPlayPause', deck, value*0x7F); break;
	case 'cue': call('deckCue', deck, value*0x7F); break;
	case 'cueplay': call('deckCuePlay', deck, value*0x7F); break;
	case 'reverse': call('deckReverse', deck, value*0x7F); break;
	case 'backtotop': call('deckBackToTop', deck, value*0x7F); break;
	case 'sync': call('deckSync', deck, value*0x7F); break;
	case 'keylock': call('deckKeyLock', deck, value*0x7F); break;
	//case 'loopinout': if(getValue('looping', deck)) call('deckLoopExit', deck, value*0x7F);else call('deckLoopInEnd', deck, value*0x7F); break;
	//case 'reloop': if(getValue('looping', deck)) call('deckLoopExit', deck, value*0x7F);else call('deckLoopReloop', deck, value*0x7F); break;
	// the above is not correct since the 'looping' status changes between a press/release cycle so we send the wrong signal so instead we simulate a fast press/release
	case 'loopin': call('deckLoopInEnd', deck, value*0x7F); break;
	case 'loopout': 
		if(value>0)
		{ 
			if(getValue('looping', deck)) 
			{
				call('deckLoopExit', deck, 0x7F);
				call('deckLoopExit', deck, 0x00);
			}else 
			{
				call('deckLoopInEnd', deck, 0x7F);
				call('deckLoopInEnd', deck, 0x00);
			}
		}
		break;
	case 'loopinout': 
		if(value>0)
		{ 
			if(getValue('looping', deck)) 
			{
				call('deckLoopExit', deck, 0x7F);
				call('deckLoopExit', deck, 0x00);
			}else 
			{
				call('deckLoopInEnd', deck, 0x7F);
				call('deckLoopInEnd', deck, 0x00);
			}
		}
		break;
	case 'reloop': 
		if(value>0)
		{ 
			if(getValue('looping', deck)) 
			{
				call('deckLoopExit', deck, 0x7F);
				call('deckLoopExit', deck, 0x00);
			}else 
			{
				call('deckLoopReloop', deck, 0x7F);
				call('deckLoopReloop', deck, 0x00);
			}
		}
		break;
		
	case 'loadtrack': if(value>0) call('deckLBLoad', deck, 1); break;
	case 'pitchrange': 
		// 1 = 4%; 2 = 8%; 3 = 16%; 4 = 24%; 5 = 32%; 6 = 50%;
		if(value>0)
		{ 
			var currentPitchRange = getValue('pitchRange');
			currentPitchRange = currentPitchRange + 1; if(currentPitchRange>6) currentPitchRange = 1;
			call('setPitchRange', currentPitchRange);
		}
		break;
	case 'pitch-reset': call('deckResetPitch', deck, value*0x7F); break;
	case 'tap-bpm': call('deckTapBpm', deck, value*0x7F); break;
	//-------------------------------------
	case 'toggle-scratch-mode':
		if(value>0)
		{
			jogModeScratch[deck] = (jogModeScratch[deck] + 1) % 2;
			callHidPageAction(uniqueId, "led-scratch", deck, jogModeScratch[deck]);
		}
		break;
	case 'toggle-search-mode':
		if(value>0)
		{
			jogModeSearch[deck] = (jogModeSearch[deck] + 1) % 2;
			callHidPageAction(uniqueId, "led-search", deck, jogModeSearch[deck]);
		}
		break;
	//-------------------------------------
	case 'sampler-select':
		samplerSelected[deck] = samplerSelected[deck] + value;
		if(samplerSelected[deck] < 0) samplerSelected[deck] = 7;
		if(samplerSelected[deck] > 7) samplerSelected[deck] = 0;
		for(var i=0; i<8; i++)
		{
			callHidPageAction(uniqueId, "sampler"+(i+1), deck, (samplerSelected[deck]==i)?1:0);
		}
		break;
	case 'sampler-volume': call('samplerVolume', samplerSelected[deck]+1, value*0x7F); break;
	case 'sampler-play':
	case 'sampler-play2': if(value>0) call("samplerPlay", samplerSelected[deck]+1); break;
	//-------------------------------------
	case 'toggle-effect': if(value>0) effectsSelected[deck] = (effectsSelected[deck] + 1) % 3; break;
	case 'effect-on': call('deckReverse', deck, value*0x7F); break;// used as 'reverse'
	case 'effect-drywet':
		//"deckFxPanDW", "deckFxFlangerDW", "deckFxPhaserDW", "deckFxReverbDW", "deckFxEchoDW", "deckFxDelayDW", "deckFxBeatwawDW", "setDeckCutoff"
		//"deckFxPanP1", "deckFxFlangerP1", "deckFxPhaserP1", "deckFxReverbP1", "deckFxEchoP1", "deckFxDelayP1", "deckFxBeatwawP1"
		switch(effectsSelected[deck])
		{
		case 0: call('deckFxFlangerDW', deck, value*0x7F); break;
		case 1: call('deckFxBeatwawDW', deck, value*0x7F); break;
		case 2: call('deckFxReverbDW',  deck, value*0x7F); break;
		}
		break;
	case 'effect-param':
		switch(effectsSelected[deck])
		{
		case 0: call('deckFxFlangerP1', deck, value*0x7F); break;
		//case 1: call('deckFxBeatwawP1', deck, value*0x7F); break;
		//case 2: call('deckFxReverbP1',  deck, value*0x7F); break;
		}
		break;	
	//-------------------------------------
	case 'cue1': call('deckCuePos1', deck, value*0x7F); break;
	case 'cue2': call('deckCuePos2', deck, value*0x7F); break;
	case 'cue3': call('deckCuePos3', deck, value*0x7F); break;
	case 'cue4': call('deckCuePos4', deck, value*0x7F); break;
	case 'cue5': call('deckCuePos5', deck, value*0x7F); break;
	case 'cue6': call('deckCuePos6', deck, value*0x7F); break;
	case 'cue7': call('deckCuePos7', deck, value*0x7F); break;
	case 'cue8': call('deckCuePos8', deck, value*0x7F); break;
	case 'cue9': call('deckCuePos9', deck, value*0x7F); break;
	case 'cue10': call('deckCuePos10', deck, value*0x7F); break;
	
	case 'rev': call('deckSearchLeft', deck, value*0x7F); break;
	case 'fwd': call('deckSearchRight', deck, value*0x7F); break;
	case 'benddown': call('deckBendDown', deck, value*0x7F); break;
	case 'bendup': call('deckBendUp', deck, value*0x7F); break;
	
	// mixer (decks)
	case 'gain': call('setDeckGain', deck, value*0x7F); break;
	case 'eq-high': call('setDeckEqHigh', deck, value*0x7F); break;
	case 'eq-mid': call('setDeckEqMid', deck, value*0x7F); break;
	case 'eq-low': call('setDeckEqLow', deck, value*0x7F); break;
	case 'filter': call('setDeckCutoff', deck, value*0x7F); break;
	case 'volume': call('setDeckVolume', deck, value*0x7F); break;
	// buttons
	case 'monitor': call('deckMonitor', deck, value*0x7F); break;
	
	// mixer (global)
	case 'crossfader': call('setCrossfader', 0x7F - value*0x7F); break;
	case 'cuepgmmix': call('setCuePgmMix', value*0x7F); break;
	case 'mastergain': call('setMasterGain', value*0x7F); break;
	case 'monitorgain': call('setMonitorGain', value*0x7F); break;
	case 'browser': call('lbMoveCursor', value); break;
	case 'cfcurve': call('setCFCurve', value*0x7F); break;
	// buttons
	case 'browsertoggle2':
	case 'browsertoggle': if(value>0) call('lbToggleSelect', 0); break;
	case 'browseup': if(value>0) call('lbMoveCursor', -1); break;
	case 'browsedown': if(value>0) call('lbMoveCursor', +1); break;
	case 'automix': call('setAutoDj', value?0x7F:0x00); break;
	case 'mixnow': call('mixNext', value*0x7F); break;
	
	// jog-wheels
	case 'jogwheel': 
		if(jogModeSearch[deck])
		{
			call('searchDeckJW', deck, value, 140);
		}else
		{
			if(jogModeScratch[deck])
				call('scratchDeckJW', deck, value, 140); 
			else
				call('moveDeckJogWheel', deck, value, 140); 
		}
		break;
	case 'jogwheel-touch': // on-off
		// there is a problem with the touch sensors in HID mode -- a lot of the time the ON signal just hangs and never comes back to OFF
		//if((jogModeScratch[deck])&&(!jogModeSearch[deck])) call('holdDeckJogWheel', deck, value*0x7F); 
		break;
	}
}
//----------------------------------------------------------------------------- 
// 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=='play') 		callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='cue') 		callHidPageAction(uniqueId, name, deck, param1?1:0);	
	if(name=='keyLock') 	callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='onbeat') 		callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='pitchIs0')	callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='monitor') 	callHidPageAction(uniqueId, name, deck, param1?1:0);	
	if(name=='cuepos1') 	callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='cuepos2') 	callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='cuepos3') 	callHidPageAction(uniqueId, name, deck, param1?1:0);
	if(name=='reverse') 	callHidPageAction(uniqueId, 'led-fx', deck, param1?1:0);
	if(name=='loopIn')
	{
		callHidPageAction(uniqueId, 'loopIn', deck, param1?1:0);
		// activate blinking for the LoopIn led (so the user knows to press it again)
		if(param1) loopingInBlinkLed[deck] = 0;else loopingInBlinkLed[deck] = -1;
	}
	if(name=='looping')
	{
		callHidPageAction(uniqueId, 'loopIn', deck, param1?1:0);
		callHidPageAction(uniqueId, 'looping', deck, param1?1:0);
	}	
}
//----------------------------------------------------------------------------- 
function setVuMeter(uniqueId, deck, dbValue)
{
	callHidPageAction(uniqueId, 'vu1', deck, (dbValue>-32)?1:0);
	callHidPageAction(uniqueId, 'vu2', deck, (dbValue>-24)?1:0);
	callHidPageAction(uniqueId, 'vu3', deck, (dbValue>-18)?1:0);
	callHidPageAction(uniqueId, 'vu4', deck, (dbValue>-12)?1:0);
	callHidPageAction(uniqueId, 'vu5', deck, (dbValue>-8)?1:0);
	callHidPageAction(uniqueId, 'vu6', deck, (dbValue>-4)?1:0);
}
//----------------------------------------------------------------------------- 
// 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 Hid ['+uniqueId+']');
	setVuMeter(uniqueId, 0, getValue('vumeterMasterL'));
	setVuMeter(uniqueId, 1, getValue('vumeterMasterR'));
	for(var i=0; i<2; i++)
	{
		// loop in led
		if(loopingInBlinkLed[i]!=-1)
		{
			// actually set the led
			callHidPageAction(uniqueId, 'loopIn', i, (loopingInBlinkLed[i]<5)?1:0);
			loopingInBlinkLed[i]++;
			if(loopingInBlinkLed[i]>=10) loopingInBlinkLed[i] = 0;
		}
	}
}
//----------------------------------------------------------------------------- 
