function LPD8RK() {}
LPD8RK.debug=false;

//set defaults - don't change these
LPD8RK.oldHotcueBank=0;//storage for the last active hotcue bank - used for bank indicator lights
LPD8RK.LEDinterval=300;//interval in milliseconds for LED update
LPD8RK.hotcueClear=false;//if true, hitting hotcue button clears it.
LPD8RK.loopbuttonDown=false;//if true, special loop functions with knob modifiers are enabled.
LPD8RK.looplen=0x40;//default position of looplength dial - active when loop buttons are held down
LPD8RK.looptype="beatloop";//default looptype - beatloop if <64, beatlooproll otherwise
LPD8RK.loopmove=0.0125;//default loop move distance in seconds
LPD8RK.doreloop=true;//don't change this
LPD8RK.beatjumpstep=1;//default beat jump step in beats
LPD8RK.vol=new Array();//array of volumes to return to after mute - don't change
LPD8RK.hotcueBank=1;//default hotcue bank to show on PAD setting, adjustable by knob


//array of valid LED addresses
LPD8RK.validLEDS = new Array();
LPD8RK.validLEDS[0x90]={0x2b : true,0x27 : true,0x2a : true,0x26 : true,0x29 : true,0x25 : true,0x28 : true,0x24 : true};
LPD8RK.validLEDS[0x91]={0x2c : true,0x27 : true,0x2e : true,0x2a : true,0x26 : true,0x24 : true,0x25 : true,0x23 : true};
LPD8RK.validLEDS[0x92]={0x48 : true,0x41 : true,0x47 : true,0x40 : true,0x45 : true,0x3e : true,0x43 : true,0x3c : true};
LPD8RK.validLEDS[0x93]={0x30 : true,0x29 : true,0x2f : true,0x28 : true,0x2d : true,0x26 : true,0x2b : true,0x24 : true};
LPD8RK.validLEDS[0xb0]={0x01 : true,0x09 : true,0x04 : true,0x08 : true,0x03 : true,0x06 : true,0x03 : true,0x05 : true};
LPD8RK.validLEDS[0xb1]={0x01 : true,0x09 : true,0x04 : true,0x08 : true,0x03 : true,0x06 : true,0x03 : true,0x05 : true};
LPD8RK.validLEDS[0xb2]={0x01 : true,0x09 : true,0x04 : true,0x08 : true,0x03 : true,0x06 : true,0x03 : true,0x05 : true};
LPD8RK.validLEDS[0xb3]={0x01 : true,0x09 : true,0x04 : true,0x08 : true,0x03 : true,0x06 : true,0x03 : true,0x05 : true};


//map hotcue pads and leds
LPD8RK.hotcues = new Array();
//preset 1 (group, cuenum, status, ctrl)
//initialize
LPD8RK.hotcues["902b"] = new Array();
LPD8RK.hotcues["9027"] = new Array();
LPD8RK.hotcues["902a"] = new Array();
LPD8RK.hotcues["9026"] = new Array();
LPD8RK.hotcues["9029"] = new Array();
LPD8RK.hotcues["9025"] = new Array();
//bank 1
LPD8RK.hotcues["902b"][1] = new Array("[Channel1]", "1", 0x90, 0x2b);
LPD8RK.hotcues["9027"][1] = new Array("[Channel1]", "2", 0x90, 0x27);
LPD8RK.hotcues["902a"][1] = new Array("[Channel1]", "3", 0x90, 0x2a);
LPD8RK.hotcues["9026"][1] = new Array("[Channel1]", "4", 0x90, 0x26);
LPD8RK.hotcues["9029"][1] = new Array("[Channel1]", "5", 0x90, 0x29);
LPD8RK.hotcues["9025"][1] = new Array("[Channel1]", "6", 0x90, 0x25);
//bank 2
LPD8RK.hotcues["902b"][2] = new Array("[Channel1]", "7", 0x90, 0x2b);
LPD8RK.hotcues["9027"][2] = new Array("[Channel1]", "8", 0x90, 0x27);
LPD8RK.hotcues["902a"][2] = new Array("[Channel1]", "9", 0x90, 0x2a);
LPD8RK.hotcues["9026"][2] = new Array("[Channel1]", "10", 0x90, 0x26);
LPD8RK.hotcues["9029"][2] = new Array("[Channel1]", "11", 0x90, 0x29);
LPD8RK.hotcues["9025"][2] = new Array("[Channel1]", "12", 0x90, 0x25);
//bank 3
LPD8RK.hotcues["902b"][3] = new Array("[Channel1]", "13", 0x90, 0x2b);
LPD8RK.hotcues["9027"][3] = new Array("[Channel1]", "14", 0x90, 0x27);
LPD8RK.hotcues["902a"][3] = new Array("[Channel1]", "15", 0x90, 0x2a);
LPD8RK.hotcues["9026"][3] = new Array("[Channel1]", "16", 0x90, 0x26);
LPD8RK.hotcues["9029"][3] = new Array("[Channel1]", "17", 0x90, 0x29);
LPD8RK.hotcues["9025"][3] = new Array("[Channel1]", "18", 0x90, 0x25);
//bank 4
LPD8RK.hotcues["902b"][4] = new Array("[Channel1]", "19", 0x90, 0x2b);
LPD8RK.hotcues["9027"][4] = new Array("[Channel1]", "20", 0x90, 0x27);
LPD8RK.hotcues["902a"][4] = new Array("[Channel1]", "21", 0x90, 0x2a);
LPD8RK.hotcues["9026"][4] = new Array("[Channel1]", "22", 0x90, 0x26);
LPD8RK.hotcues["9029"][4] = new Array("[Channel1]", "23", 0x90, 0x29);
LPD8RK.hotcues["9025"][4] = new Array("[Channel1]", "24", 0x90, 0x25);
//bank 5
LPD8RK.hotcues["902b"][5] = new Array("[Channel1]", "25", 0x90, 0x2b);
LPD8RK.hotcues["9027"][5] = new Array("[Channel1]", "26", 0x90, 0x27);
LPD8RK.hotcues["902a"][5] = new Array("[Channel1]", "27", 0x90, 0x2a);
LPD8RK.hotcues["9026"][5] = new Array("[Channel1]", "28", 0x90, 0x26);
LPD8RK.hotcues["9029"][5] = new Array("[Channel1]", "29", 0x90, 0x29);
LPD8RK.hotcues["9025"][5] = new Array("[Channel1]", "30", 0x90, 0x25);

//##################
//preset 2 (group, cuenum, status, ctrl)
//initialize
LPD8RK.hotcues["912c"] = new Array();
LPD8RK.hotcues["9127"] = new Array();
LPD8RK.hotcues["912e"] = new Array();
LPD8RK.hotcues["912a"] = new Array();
LPD8RK.hotcues["9126"] = new Array();
LPD8RK.hotcues["9124"] = new Array();
//bank 1
LPD8RK.hotcues["912c"][1] = new Array("[Channel2]", "1", 0x91, 0x2c);
LPD8RK.hotcues["9127"][1] = new Array("[Channel2]", "2", 0x91, 0x27);
LPD8RK.hotcues["912e"][1] = new Array("[Channel2]", "3", 0x91, 0x2e);
LPD8RK.hotcues["912a"][1] = new Array("[Channel2]", "4", 0x91, 0x2a);
LPD8RK.hotcues["9126"][1] = new Array("[Channel2]", "5", 0x91, 0x26);
LPD8RK.hotcues["9124"][1] = new Array("[Channel2]", "6", 0x91, 0x24);
//bank 2
LPD8RK.hotcues["912c"][2] = new Array("[Channel2]", "7", 0x91, 0x2c);
LPD8RK.hotcues["9127"][2] = new Array("[Channel2]", "8", 0x91, 0x27);
LPD8RK.hotcues["912e"][2] = new Array("[Channel2]", "9", 0x91, 0x2e);
LPD8RK.hotcues["912a"][2] = new Array("[Channel2]", "10", 0x91, 0x2a);
LPD8RK.hotcues["9126"][2] = new Array("[Channel2]", "11", 0x91, 0x26);
LPD8RK.hotcues["9124"][2] = new Array("[Channel2]", "12", 0x91, 0x24);
//bank 3
LPD8RK.hotcues["912c"][3] = new Array("[Channel2]", "13", 0x91, 0x2c);
LPD8RK.hotcues["9127"][3] = new Array("[Channel2]", "14", 0x91, 0x27);
LPD8RK.hotcues["912e"][3] = new Array("[Channel2]", "15", 0x91, 0x2e);
LPD8RK.hotcues["912a"][3] = new Array("[Channel2]", "16", 0x91, 0x2a);
LPD8RK.hotcues["9126"][3] = new Array("[Channel2]", "17", 0x91, 0x26);
LPD8RK.hotcues["9124"][3] = new Array("[Channel2]", "18", 0x91, 0x24);
//bank 4
LPD8RK.hotcues["912c"][4] = new Array("[Channel2]", "19", 0x91, 0x2c);
LPD8RK.hotcues["9127"][4] = new Array("[Channel2]", "20", 0x91, 0x27);
LPD8RK.hotcues["912e"][4] = new Array("[Channel2]", "21", 0x91, 0x2e);
LPD8RK.hotcues["912a"][4] = new Array("[Channel2]", "22", 0x91, 0x2a);
LPD8RK.hotcues["9126"][4] = new Array("[Channel2]", "23", 0x91, 0x26);
LPD8RK.hotcues["9124"][4] = new Array("[Channel2]", "24", 0x91, 0x24);
//bank 5
LPD8RK.hotcues["912c"][5] = new Array("[Channel2]", "25", 0x91, 0x2c);
LPD8RK.hotcues["9127"][5] = new Array("[Channel2]", "26", 0x91, 0x27);
LPD8RK.hotcues["912e"][5] = new Array("[Channel2]", "27", 0x91, 0x2e);
LPD8RK.hotcues["912a"][5] = new Array("[Channel2]", "28", 0x91, 0x2a);
LPD8RK.hotcues["9126"][5] = new Array("[Channel2]", "29", 0x91, 0x26);
LPD8RK.hotcues["9124"][5] = new Array("[Channel2]", "30", 0x91, 0x24);

//##################
//preset 3 (group, cuenum, status, ctrl)
//initialize
LPD8RK.hotcues["9248"] = new Array();
LPD8RK.hotcues["9241"] = new Array();
LPD8RK.hotcues["9247"] = new Array();
LPD8RK.hotcues["9240"] = new Array();
LPD8RK.hotcues["9245"] = new Array();
LPD8RK.hotcues["923e"] = new Array();
//bank 1
LPD8RK.hotcues["9248"][1] = new Array("[Sampler1]", "1", 0x92, 0x48);
LPD8RK.hotcues["9241"][1] = new Array("[Sampler1]", "2", 0x92, 0x41);
LPD8RK.hotcues["9247"][1] = new Array("[Sampler1]", "3", 0x92, 0x47);
LPD8RK.hotcues["9240"][1] = new Array("[Sampler1]", "4", 0x92, 0x40);
LPD8RK.hotcues["9245"][1] = new Array("[Sampler1]", "5", 0x92, 0x45);
LPD8RK.hotcues["923e"][1] = new Array("[Sampler1]", "6", 0x92, 0x3e);
//bank 2
LPD8RK.hotcues["9248"][2] = new Array("[Sampler1]", "7", 0x92, 0x48);
LPD8RK.hotcues["9241"][2] = new Array("[Sampler1]", "8", 0x92, 0x41);
LPD8RK.hotcues["9247"][2] = new Array("[Sampler1]", "9", 0x92, 0x47);
LPD8RK.hotcues["9240"][2] = new Array("[Sampler1]", "10", 0x92, 0x40);
LPD8RK.hotcues["9245"][2] = new Array("[Sampler1]", "11", 0x92, 0x45);
LPD8RK.hotcues["923e"][2] = new Array("[Sampler1]", "12", 0x92, 0x3e);
//bank 3
LPD8RK.hotcues["9248"][3] = new Array("[Sampler1]", "13", 0x92, 0x48);
LPD8RK.hotcues["9241"][3] = new Array("[Sampler1]", "14", 0x92, 0x41);
LPD8RK.hotcues["9247"][3] = new Array("[Sampler1]", "15", 0x92, 0x47);
LPD8RK.hotcues["9240"][3] = new Array("[Sampler1]", "16", 0x92, 0x40);
LPD8RK.hotcues["9245"][3] = new Array("[Sampler1]", "17", 0x92, 0x45);
LPD8RK.hotcues["923e"][3] = new Array("[Sampler1]", "18", 0x92, 0x3e);
//bank 4
LPD8RK.hotcues["9248"][4] = new Array("[Sampler1]", "19", 0x92, 0x48);
LPD8RK.hotcues["9241"][4] = new Array("[Sampler1]", "20", 0x92, 0x41);
LPD8RK.hotcues["9247"][4] = new Array("[Sampler1]", "21", 0x92, 0x47);
LPD8RK.hotcues["9240"][4] = new Array("[Sampler1]", "22", 0x92, 0x40);
LPD8RK.hotcues["9245"][4] = new Array("[Sampler1]", "23", 0x92, 0x45);
LPD8RK.hotcues["923e"][4] = new Array("[Sampler1]", "24", 0x92, 0x3e);
//bank 5
LPD8RK.hotcues["9248"][5] = new Array("[Sampler1]", "25", 0x92, 0x48);
LPD8RK.hotcues["9241"][5] = new Array("[Sampler1]", "26", 0x92, 0x41);
LPD8RK.hotcues["9247"][5] = new Array("[Sampler1]", "27", 0x92, 0x47);
LPD8RK.hotcues["9240"][5] = new Array("[Sampler1]", "28", 0x92, 0x40);
LPD8RK.hotcues["9245"][5] = new Array("[Sampler1]", "29", 0x92, 0x45);
LPD8RK.hotcues["923e"][5] = new Array("[Sampler1]", "30", 0x92, 0x3e);

//##################
//preset 4 (group, cuenum, status, ctrl)
//initialize
LPD8RK.hotcues["9330"] = new Array();
LPD8RK.hotcues["9329"] = new Array();
LPD8RK.hotcues["932f"] = new Array();
LPD8RK.hotcues["9328"] = new Array();
LPD8RK.hotcues["932d"] = new Array();
LPD8RK.hotcues["9326"] = new Array();
//bank 1
LPD8RK.hotcues["9330"][1] = new Array("[Sampler2]", "1", 0x93, 0x30);
LPD8RK.hotcues["9329"][1] = new Array("[Sampler2]", "2", 0x93, 0x29);
LPD8RK.hotcues["932f"][1] = new Array("[Sampler2]", "3", 0x93, 0x2f);
LPD8RK.hotcues["9328"][1] = new Array("[Sampler2]", "4", 0x93, 0x28);
LPD8RK.hotcues["932d"][1] = new Array("[Sampler2]", "5", 0x93, 0x2d);
LPD8RK.hotcues["9326"][1] = new Array("[Sampler2]", "6", 0x93, 0x26);
//bank 2
LPD8RK.hotcues["9330"][2] = new Array("[Sampler2]", "7", 0x93, 0x30);
LPD8RK.hotcues["9329"][2] = new Array("[Sampler2]", "8", 0x93, 0x29);
LPD8RK.hotcues["932f"][2] = new Array("[Sampler2]", "9", 0x93, 0x2f);
LPD8RK.hotcues["9328"][2] = new Array("[Sampler2]", "10", 0x93, 0x28);
LPD8RK.hotcues["932d"][2] = new Array("[Sampler2]", "11", 0x93, 0x2d);
LPD8RK.hotcues["9326"][2] = new Array("[Sampler2]", "12", 0x93, 0x26);
//bank 3
LPD8RK.hotcues["9330"][3] = new Array("[Sampler2]", "13", 0x93, 0x30);
LPD8RK.hotcues["9329"][3] = new Array("[Sampler2]", "14", 0x93, 0x29);
LPD8RK.hotcues["932f"][3] = new Array("[Sampler2]", "15", 0x93, 0x2f);
LPD8RK.hotcues["9328"][3] = new Array("[Sampler2]", "16", 0x93, 0x28);
LPD8RK.hotcues["932d"][3] = new Array("[Sampler2]", "17", 0x93, 0x2d);
LPD8RK.hotcues["9326"][3] = new Array("[Sampler2]", "18", 0x93, 0x26);
//bank 4
LPD8RK.hotcues["9330"][4] = new Array("[Sampler2]", "19", 0x93, 0x30);
LPD8RK.hotcues["9329"][4] = new Array("[Sampler2]", "20", 0x93, 0x29);
LPD8RK.hotcues["932f"][4] = new Array("[Sampler2]", "21", 0x93, 0x2f);
LPD8RK.hotcues["9328"][4] = new Array("[Sampler2]", "22", 0x93, 0x28);
LPD8RK.hotcues["932d"][4] = new Array("[Sampler2]", "23", 0x93, 0x2d);
LPD8RK.hotcues["9326"][4] = new Array("[Sampler2]", "24", 0x93, 0x26);
//bank 5
LPD8RK.hotcues["9330"][5] = new Array("[Sampler2]", "25", 0x93, 0x30);
LPD8RK.hotcues["9329"][5] = new Array("[Sampler2]", "26", 0x93, 0x29);
LPD8RK.hotcues["932f"][5] = new Array("[Sampler2]", "27", 0x93, 0x2f);
LPD8RK.hotcues["9328"][5] = new Array("[Sampler2]", "28", 0x93, 0x28);
LPD8RK.hotcues["932d"][5] = new Array("[Sampler2]", "29", 0x93, 0x2d);
LPD8RK.hotcues["9326"][5] = new Array("[Sampler2]", "30", 0x93, 0x26);




//map hotcue loop and leds
LPD8RK.loops = new Array();
//preset 1 (group, beatloop_len, status, ctrl)
LPD8RK.loops["b09"] = new Array("[Channel1]", "1", 0xB0, 0x09);
LPD8RK.loops["b04"] = new Array("[Channel1]", "2", 0xB0, 0x04);
LPD8RK.loops["b08"] = new Array("[Channel1]", "4", 0xB0, 0x08);
LPD8RK.loops["b03"] = new Array("[Channel1]", "8", 0xB0, 0x03);

//preset 2 (group, beatloop_len, status, ctrl)
LPD8RK.loops["b19"] = new Array("[Channel2]", "1", 0xB1, 0x09);
LPD8RK.loops["b14"] = new Array("[Channel2]", "2", 0xB1, 0x04);
LPD8RK.loops["b18"] = new Array("[Channel2]", "4", 0xB1, 0x08);
LPD8RK.loops["b13"] = new Array("[Channel2]", "8", 0xB1, 0x03);

//preset 3 (group, beatloop_len, status, ctrl)
LPD8RK.loops["b29"] = new Array("[Sampler1]", "1", 0xB2, 0x09);
LPD8RK.loops["b24"] = new Array("[Sampler1]", "2", 0xB2, 0x04);
LPD8RK.loops["b28"] = new Array("[Sampler1]", "4", 0xB2, 0x08);
LPD8RK.loops["b23"] = new Array("[Sampler1]", "8", 0xB2, 0x03);

//preset 4 (group, beatloop_len, status, ctrl)
LPD8RK.loops["b39"] = new Array("[Sampler2]", "1", 0xB3, 0x09);
LPD8RK.loops["b34"] = new Array("[Sampler2]", "2", 0xB3, 0x04);
LPD8RK.loops["b38"] = new Array("[Sampler2]", "4", 0xB3, 0x08);
LPD8RK.loops["b33"] = new Array("[Sampler2]", "8", 0xB3, 0x03);



LPD8RK.init = function (id, debug) { // called when the device is opened & set up
	if (LPD8RK.debug){print("###init##############")};
	//soft takeovers
	engine.softTakeover("[Master]","crossfader",true);
	engine.softTakeover("[Channel1]","volume",true);
	engine.softTakeover("[Channel1]","rate",true);
	engine.softTakeover("[Channel2]","volume",true);
	engine.softTakeover("[Channel2]","rate",true);
	engine.softTakeover("[Sampler1]","volume",true);
	engine.softTakeover("[Sampler1]","rate",true);
	engine.softTakeover("[Sampler2]","volume",true);
	engine.softTakeover("[Sampler2]","rate",true);
	
	//set LED timer
	LPD8RK.ledTimer = engine.beginTimer(LPD8RK.LEDinterval, "LPD8RK.setLeds()");
};

LPD8RK.shutdown = function () {
	engine.stopTimer(LPD8RK.ledTimer);
};

LPD8RK.resetLEDTimer = function () {
	engine.stopTimer(LPD8RK.ledTimer);
	LPD8RK.setLeds()
	LPD8RK.ledTimer = engine.beginTimer(LPD8RK.LEDinterval, "LPD8RK.setLeds()");
};

LPD8RK.setLeds = function () {
	//runs repeatedly on a timer set in init()
	//has to run on a timer because you apparently can only set LEDs on the current prog selection on the LPD8
	//ie: leds on a PAD or CC other than the one you're currently using can't be set.
	//and no midi messages are sent when you change a PROG or pad.  No way of telling MIXXX which LEDs are currently active
	//so, this runs 4x a second to make sure LEDs are updated.  Kludge, but so it goes.

	//hotcues
	for (var id in LPD8RK.hotcues){
		for (var bank in LPD8RK.hotcues[id]){
			//iterate through hotcues for current bank, set hotcue leds
			var status = LPD8RK.hotcues[id][LPD8RK.hotcueBank][2];
			var ctrl = LPD8RK.hotcues[id][LPD8RK.hotcueBank][3];
			var state = engine.getValue(LPD8RK.hotcues[id][LPD8RK.hotcueBank][0], "hotcue_"+LPD8RK.hotcues[id][LPD8RK.hotcueBank][1]+"_enabled");

			//if (LPD8RK.debug){print("midi.sendShortMsg("+status+", "+ctrl+", "+state+")")};
			
			LPD8RK.lightLED(status, ctrl, state);
			};
		};
	
	//loops
	for (var id in LPD8RK.loops){
		//iterate through hotcues, set hotcue leds
		var status = LPD8RK.loops[id][2];
		var ctrl = LPD8RK.loops[id][3];
		var state = engine.getValue(LPD8RK.loops[id][0], "beatloop_"+LPD8RK.loops[id][1]+"_enabled");

		//if (LPD8RK.debug){print("midi.sendShortMsg("+status+", "+ctrl+", "+state+")")};
	
		LPD8RK.lightLED(status, ctrl, state);
		};
	
	//reloop buttons
	LPD8RK.lightLED(0xb0, 0x01, engine.getValue("[Channel1]", "loop_enabled"));	
	LPD8RK.lightLED(0xb1, 0x01, engine.getValue("[Channel2]", "loop_enabled"));	
	LPD8RK.lightLED(0xb2, 0x01, engine.getValue("[Sampler1]", "loop_enabled"));	
	LPD8RK.lightLED(0xb3, 0x01, engine.getValue("[Sampler2]", "loop_enabled"));	
	};

LPD8RK.lightLED = function (status, ctrl, state){
	//function to check for valid LED lighting messages - LPD8 seems to go into a weird nonresponsive mode when some unknown code is sent to it
	//don't know what the messed code is, but this function checks for valid LED addresses.  Hopefully this will prevent problems.
	if (LPD8RK.validLEDS[status][ctrl] !== true){
		print("######## INVALID STATUS ########");
		return false;
		} else {
		if (state > 0 || state === true){state=1;}//make sure state is valid
		midi.sendShortMsg(status, ctrl, state);
		}
	};	
	
LPD8RK.clear = function (){//enables hotcue clearing
	if (LPD8RK.debug){print("###hotcueclear##############")};
	LPD8RK.hotcueClear=true;
	};

LPD8RK.noclear = function (){//disables hotcue clearing
	LPD8RK.hotcueClear=false;
	};

LPD8RK.hotcueButton = function (channel, control, value, status, group) {
	//weird status bug workaround
	if (channel==0 && status != 0x90){status = 0x90};
	if (channel==1 && status != 0x91){status = 0x91};
	if (channel==2 && status != 0x92){status = 0x92};
	if (channel==3 && status != 0x93){status = 0x93};

	if (LPD8RK.debug){print("###hotcueButton##############")};
	if (LPD8RK.debug){print("status:"+status)};
	if (LPD8RK.debug){print("channel:"+channel)};
	if (LPD8RK.debug){print("control:"+control)};
	if (LPD8RK.debug){print("hotcuebank:"+LPD8RK.hotcueBank)};
	if (LPD8RK.debug){print("phrase:#"+status.toString(16).toLowerCase()+control.toString(16).toLowerCase()+"#")};
	//activate or clear depending on whether clear button is pressed
	var thecue = LPD8RK.hotcues[status.toString(16).toLowerCase()+control.toString(16).toLowerCase()][LPD8RK.hotcueBank];
	if (LPD8RK.hotcueClear){
		engine.setValue(thecue[0], "hotcue_"+thecue[1]+"_clear", 1);
		engine.setValue(thecue[0], "hotcue_"+thecue[1]+"_clear", 0);
		if (LPD8RK.debug){print("cleared")};
		} else {
		engine.setValue(thecue[0], "hotcue_"+thecue[1]+"_activate", 1);
		engine.setValue(thecue[0], "hotcue_"+thecue[1]+"_activate", 0);
		if (LPD8RK.debug){print("###"+status.toString(16).toLowerCase()+control.toString(16).toLowerCase()+"--activated")};
		};

	};

LPD8RK.loopButton = function (channel, control, value, status, group) {
	if (LPD8RK.debug){print(LPD8RK.looplen+"len");}
	if (LPD8RK.debug){print(LPD8RK.looptype+"type");}
	//activate beatloop
	var theloop = LPD8RK.loops[status.toString(16).toLowerCase()+control.toString(16).toLowerCase()];
	if (value>0){//button was pressed
		LPD8RK.loopbuttonDown=true;
		engine.setValue(group, LPD8RK.looptype+"_"+theloop[1]+"_activate", 1);
		} else {//button was released
		LPD8RK.loopbuttonDown=false;
		};

	};

LPD8RK.reloopButton = function (channel, control, value, status, group) {
	if (LPD8RK.debug){print(LPD8RK.looplen+"len");}
	if (LPD8RK.debug){print(LPD8RK.looptype+"type");}
	
	if (value>0){//button was pressed
		engine.stopTimer(LPD8RK.reloopTimer);
		LPD8RK.loopbuttonDown=true;
		LPD8RK.doreloop=true;
		LPD8RK.reloopTimer = engine.beginTimer(500, "LPD8RK.disablereloop()", true);
		} else {//button was released
		LPD8RK.loopbuttonDown=false;
		if (LPD8RK.doreloop===true) {engine.setValue(group, "reloop_exit", 1);};
		LPD8RK.doreloop=true;
		engine.stopTimer(LPD8RK.reloopTimer);
		};

	};

LPD8RK.disablereloop = function () {
	//timed function - fires half a second after pressing reloop.  Don't do the reloop if you hold down the button (so you can move the loop without exiting)
	LPD8RK.doreloop=false;
	};

LPD8RK.looptypeDial = function (channel, control, value, status, group) {
	//activates variable length type depending on dial position
	//beatlooproll only works in 1.11 or above - script is a placeholder, knob used to select hotcue bank for now
	//if(value>63){LPD8RK.looptype="beatlooproll";}else{LPD8RK.looptype="beatloop";}
	//if (LPD8RK.debug){print(LPD8RK.looptype);}
	};

LPD8RK.resetOldBank = function () {
	//clears stored old hotcue bank
	LPD8RK.oldHotcueBank=0;
	};

LPD8RK.hotcueBankDial = function (channel, control, value, status, group) {
	//sets which hotcue bank to display (separate this out on dedicated controller)
	
	//pause LED resets, so bank indicator lights will be visible
	engine.stopTimer(LPD8RK.ledTimer);

	//select hotcue bank
	if (value>=0 && value <=12){LPD8RK.hotcueBank=1;};
	if (value>12 && value <=46){LPD8RK.hotcueBank=2;};
	if (value>46 && value <=80){LPD8RK.hotcueBank=3;};
	if (value>80 && value <=114){LPD8RK.hotcueBank=4;};
	if (value>114 && value <=128){LPD8RK.hotcueBank=5;};

	//light up indicator light
	if (LPD8RK.oldHotcueBank != LPD8RK.hotcueBank){//check if the bank's changed.  If it has, change the LEDs - LPD8RK.oldHotcueBank != LPD8RK.hotcueBank
		for (var id in LPD8RK.hotcues){
			for (var bank in LPD8RK.hotcues[id][1]){
				var status = LPD8RK.hotcues[id][1][2];
				var ctrl = LPD8RK.hotcues[id][1][3];
				//find bank number indicator light
				if (LPD8RK.hotcues[id][1][1]==LPD8RK.hotcueBank){
					var state = 1;
					}else{
					var state = 0;
					};

				LPD8RK.lightLED(status, ctrl, state);
				};
			};
		};
	//record last hotcue bank
	LPD8RK.oldHotcueBank=LPD8RK.hotcueBank;
	//set timer to clear old bank number after 500 msec, so bank indicator light will light up
	engine.stopTimer(LPD8RK.oldbanktimer);
	LPD8RK.oldbanktimer = engine.beginTimer(500, "LPD8RK.resetOldBank()", true);	

	//set timer to restart LED updates in 500 msec
	engine.stopTimer(LPD8RK.LEDPauseTimer);
	LPD8RK.LEDPauseTimer = engine.beginTimer(LPD8RK.LEDinterval, "LPD8RK.resetLEDTimer()", true);	
	};

LPD8RK.looplenDial = function (channel, control, value, status, group) {
	//activates variable length loop depending on dial position
	LPD8RK.looplen=value;

	if (LPD8RK.loopbuttonDown !== true){return false;}//exit if no loop button down 
	else if (LPD8RK.looplen<=0x12){engine.setValue(group, LPD8RK.looptype+"_0.0625_activate", .0625);return true;} else 
	if (LPD8RK.looplen<=0x25){engine.setValue(group, LPD8RK.looptype+"_0.125_activate", .125);return true;} else 
	if (LPD8RK.looplen<=0x37){engine.setValue(group, LPD8RK.looptype+"_0.25_activate", .25);return true;} else 
	if (LPD8RK.looplen<=0x49){engine.setValue(group, LPD8RK.looptype+"_0.5_activate", .5);return true;} else 
	if (LPD8RK.looplen<=0x5b){engine.setValue(group, LPD8RK.looptype+"_1_activate", 1);return true;} else 
	if (LPD8RK.looplen<=0x6d){engine.setValue(group, LPD8RK.looptype+"_2_activate", 2);return true;} else 
	if (LPD8RK.looplen<=0x70){engine.setValue(group, LPD8RK.looptype+"_4_activate", 4);return true;} else	
	if (LPD8RK.looplen<=0x7f){engine.setValue(group, LPD8RK.looptype+"_8_activate", 8);return true;};	
	};

LPD8RK.loopminus = function (channel, control, value, status, group) {
	//shrinks loop or moves loop back
	if (LPD8RK.loopbuttonDown !== true){engine.setValue(group, "loop_halve", 1);engine.setValue(group, "loop_halve", 0); return false;}//shrink loop if no loop button down 
	else if (engine.getValue(group, "loop_start_position")>=0 && engine.getValue(group, "loop_end_position")>=0 ){
		//move loop
		var interval =	LPD8RK.loopmove*engine.getValue(group, "track_samples")/engine.getValue(group, "duration");
		var start = engine.getValue(group, "loop_start_position");
		var end = engine.getValue(group, "loop_end_position");
		engine.setValue(group, "loop_start_position", start-interval);
		engine.setValue(group, "loop_end_position", end-interval);
		return true;
		};
	};

LPD8RK.loopplus = function (channel, control, value, status, group) {
	//grows loop or moves loop forward
	if (LPD8RK.loopbuttonDown !== true){engine.setValue(group, "loop_double", 1); engine.setValue(group, "loop_double", 0); return false;}//shrink loop if no loop button down 
	else if (engine.getValue(group, "loop_start_position")>=0 && engine.getValue(group, "loop_end_position")>=0 ){
		//move loop
		var interval =	LPD8RK.loopmove*engine.getValue(group, "track_samples")/engine.getValue(group, "duration");
		var start = engine.getValue(group, "loop_start_position");
		var end = engine.getValue(group, "loop_end_position");
		engine.setValue(group, "loop_start_position", start+interval);
		engine.setValue(group, "loop_end_position", end+interval);
		return true;
		};
	};

LPD8RK.beatjump = function (channel, control, value, status, group) {
	//jumps back certain number of beats depending on knob modifier
	var curpos = engine.getValue(group, "playposition")*engine.getValue(group, "track_samples");
	var numbeats = LPD8RK.beatjumpstep;
	var backseconds = numbeats*(1/(engine.getValue(group, "bpm")/60));
	var backsamples = backseconds*engine.getValue(group, "track_samples")/engine.getValue(group, "duration");
	var newpos = curpos-(backsamples+engine.getValue("Master", "latency"));
	
	if (LPD8RK.debug){print("backseconds: "+backseconds);}
	if (LPD8RK.debug){print("backsamples: "+backsamples);}
	if (LPD8RK.debug){print("curpos: "+curpos);}
	if (LPD8RK.debug){print("newpos: "+newpos);}
	if (LPD8RK.debug){print("numbeats: "+numbeats);}
	
	engine.setValue(group, "playposition", newpos/engine.getValue(group, "track_samples"));
	};

LPD8RK.beatjumpDial = function (channel, control, value, status, group) {
	//activates variable length loop depending on dial position
	if(value>=0 && value <=127){
		if (value<=1){LPD8RK.beatjumpstep=.25; return true;} else 
		if (value<=31){LPD8RK.beatjumpstep=.5; return true;} else 	
		if (value<=63){LPD8RK.beatjumpstep=1; return true;} else 	
		if (value<=94){LPD8RK.beatjumpstep=2; return true;} else 	
		if (value<=125){LPD8RK.beatjumpstep=4; return true;} else 	
		if (value<=127){LPD8RK.beatjumpstep=8; return true;};
		};	
	};

LPD8RK.mute = function (group) {
	//toggles mute, then returns to previous volume
	storedvol=LPD8RK.vol[group];
	curvol=engine.getValue(group, "volume");
	engine.softTakeover(group,"volume",false);
	if (curvol==0){//is muted.  unmute.
		engine.setValue(group, "volume", storedvol);
		}else{//is not muted.  mute.
		engine.setValue(group, "volume", 0);
		LPD8RK.vol[group]=curvol;
		};
	engine.softTakeover(group,"volume",true);
	
	if (LPD8RK.debug){print("MUTE");}
	};

LPD8RK.progChng = function (channel, control, value, status, group) {
	if (LPD8RK.debug){print("###PROG CHANGE###");}
	//workaround because prog chng buttons don't seem to like to work unless they're linked to scripts
	if (control==0x07){LPD8RK.toggleplay(group, engine.getValue(group, "play")); return true;} else 
	if (control==0x03){engine.setValue(group, "cue_default", true); engine.setValue(group, "cue_default", false); return true;} else 
	if (control==0x06){engine.setValue(group, "beatsync", true); engine.setValue(group, "beatsync", false); return true;} else 
	if (control==0x02){LPD8RK.togglepfl(group, engine.getValue(group, "pfl")); return true;} else 
	if (control==0x05){LPD8RK.togglereverse(group, engine.getValue(group, "reverse")); return true;} else 
	if (control==0x04){LPD8RK.toggleback(group, engine.getValue(group, "back")); return true;} else 
	if (control==0x00){LPD8RK.togglefwd(group, engine.getValue(group, "fwd")); return true;}
	if (control==0x01){LPD8RK.mute(group); return true;}
	};

LPD8RK.toggleplay = function (group, state) {
	if (state==true){engine.setValue(group, "reverse",0);engine.setValue(group, "play", false);} else {engine.setValue(group, "reverse",0);engine.setValue(group, "play", true);};
	};

LPD8RK.togglepfl = function (group, state) {
	if (state==true){engine.setValue(group, "pfl", false);} else {engine.setValue(group, "pfl", true);};
	};

LPD8RK.togglereverse = function (group, state) {
	if (state==true){engine.setValue(group, "reverse", false);} else {engine.setValue(group, "reverse", true);};	
	};

LPD8RK.toggleback = function (group, state) {
	if (state==true){engine.setValue(group, "back", false);} else {engine.setValue(group, "back", true);};	
	};

LPD8RK.togglefwd = function (group, state) {
	if (state==true){engine.setValue(group, "fwd", false);} else {engine.setValue(group, "fwd", true);};	
	};

LPD8RK.softXfade = function (channel, control, value, status, group) {
	engine.setValue(group, "crossfader", (value/64)-1);
	};

LPD8RK.softVolume = function (channel, control, value, status, group) {
	engine.setValue(group, "volume", (value/127));
	};

LPD8RK.softRate = function (channel, control, value, status, group) {
	engine.setValue(group, "rate", (value/64)-1);
	};


LPD8RK.test = function (channel, control, value, status, group) {
	print("channel: "+channel);
	print("control: "+control.toString(16));
	print("value: "+value);
	print("status: "+status);
	print("group: "+group);
	print("test: ##"+status.toString(16)+control.toString(16)+"##");
	print("loopbuttondown: ##"+LPD8RK.loopbuttonDown+"##");
	print("LPD8RK.looplen: ##"+LPD8RK.looplen+"##");
	print("LPD8RK.looplen.tostring: ##"+LPD8RK.looplen.toString(16)+"##");
	print("LPD8RK.looptype: ##"+LPD8RK.looptype+"##");
	print("test: ##"+2+"##");
	};


