function KontrolX1() {}; KontrolX1.debugging = true; KontrolX1.jog_delta = 3; KontrolX1.init = function(id) { KontrolX1.id = id; KontrolX1.ledStates = { off: 0x0, on: 0x7f }; KontrolX1.ledOutStatus = 0xb0; KontrolX1.timers = new Object(); KontrolX1.ledmap = new Object(); KontrolX1.knobmap = new Object(); KontrolX1.buttonmap = new Object(); KontrolX1.encodermap = new Object(); KontrolX1.scalers = new Object(); KontrolX1.registerScalers(); KontrolX1.registerControls(); KontrolX1.resetLEDs(); KontrolX1.debug(KontrolX1.id + " initialized"); } KontrolX1.shutdown = function() { for (var led_name in KontrolX1.ledmap) { var led = KontrolX1.ledmap[led_name]; engine.connectControl(led.group, led.control, KontrolX1.setLED, true); } KontrolX1.debug(KontrolX1.id + " shutdown"); } KontrolX1.debug = function(message) { if (!KontrolX1.debugging) return; print("KontrolX1: " + message); } KontrolX1.registerScalers = function() { KontrolX1.scalers = new Object(); KontrolX1.scalers["volume"] = function(value) { return script.absoluteLin(value, 0, 1, 0, 127); } KontrolX1.scalers["eq"] = function(value) { return script.absoluteNonLin(value, 0, 1, 4, 0, 127); } } KontrolX1.registerControls = function() { KontrolX1.addKnob(0x0, "[Channel1]", "filterHigh", "eq"); KontrolX1.addKnob(0x1, "[Channel2]", "filterHigh", "eq"); KontrolX1.addKnob(0x2, "[Channel1]", "filterMid", "eq"); KontrolX1.addKnob(0x3, "[Channel2]", "filterMid", "eq"); KontrolX1.addKnob(0x4, "[Channel1]", "filterLow", "eq"); KontrolX1.addKnob(0x5, "[Channel2]", "filterLow", "eq"); KontrolX1.addKnob(0x6, "[Channel1]", "volume"); KontrolX1.addKnob(0x7, "[Channel2]", "volume"); KontrolX1.addKnob(0x2c, "[Channel1]", "mixer_1_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x2d, "[Channel2]", "mixer_1_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x2e, "[Channel1]", "mixer_2_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x2f, "[Channel2]", "mixer_2_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x30, "[Channel1]", "mixer_3_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x31, "[Channel2]", "mixer_3_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x32, "[Channel1]", "mixer_4_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addKnob(0x33, "[Channel2]", "mixer_4_shift", "eq", KontrolX1.UnmappedShiftedKnob); KontrolX1.addLEDButton(0x8, "[Channel1]", "filterHighKill"); KontrolX1.addLEDButton(0x9, "[Channel2]", "filterHighKill"); KontrolX1.addLEDButton(0xa, "[Channel1]", "filterMidKill"); KontrolX1.addLEDButton(0xb, "[Channel2]", "filterMidKill"); KontrolX1.addLEDButton(0xc, "[Channel1]", "filterLowKill"); KontrolX1.addLEDButton(0xd, "[Channel2]", "filterLowKill"); KontrolX1.addLEDButton(0xe, "[Channel1]", "pfl"); KontrolX1.addLEDButton(0xf, "[Channel2]", "pfl"); KontrolX1.addButton(0x34, "[Channel1]", "mixer_1_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x35, "[Channel2]", "mixer_1_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x36, "[Channel1]", "mixer_2_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x37, "[Channel2]", "mixer_2_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x38, "[Channel1]", "mixer_3_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x39, "[Channel2]", "mixer_3_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x3a, "[Channel1]", "mixer_4_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addButton(0x3b, "[Channel2]", "mixer_4_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addEncoder(0x10, "[Playlist]", "SelectPlaylistKnob", KontrolX1.SelectPlaylistKnob); KontrolX1.addButton(0x12, "[Playlist]", "ToggleSelectedSidebarItem"); KontrolX1.addEncoder(0x11, "[Playlist]", "SelectTrackKnob", KontrolX1.SelectTrackKnob); KontrolX1.addButton(0x13, "[Playlist]", "LoadSelectedIntoFirstStopped", true); KontrolX1.addEncoder(0x1a, "[Channel1]", "jog", KontrolX1.jog_encoder); KontrolX1.addButton(0x18, "[Channel1]", "rate_reset", true, KontrolX1.rate_reset); KontrolX1.addEncoder(0x1b, "[Channel2]", "jog", KontrolX1.jog_encoder); KontrolX1.addButton(0x19, "[Channel2]", "rate_reset", true, KontrolX1.rate_reset); KontrolX1.addEncoder(0x3c, "[Channel1]", "encoder_1_shift", KontrolX1.UnmappedShiftedEncoder); KontrolX1.addButton(0x3e, "[Channel1]", "encoder_1_button_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addEncoder(0x3d, "[Channel2]", "encoder_1_shift", KontrolX1.UnmappedShiftedEncoder); KontrolX1.addButton(0x3f, "[Channel2]", "encoder_1_button_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addEncoder(0x46, "[Channel1]", "encoder_2_shift", KontrolX1.UnmappedShiftedEncoder); KontrolX1.addButton(0x44, "[Channel1]", "encoder_2_button_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addEncoder(0x47, "[Channel2]", "encoder_2_shift", KontrolX1.UnmappedShiftedEncoder); KontrolX1.addButton(0x45, "[Channel2]", "encoder_2_button_shift", KontrolX1.UnmappedShiftedButton); KontrolX1.addLEDButton(0x14, "[Channel1]", "quantize"); KontrolX1.addLEDButton(0x15, "[Channel2]", "quantize"); KontrolX1.addLEDButton(0x16, "[Channel1]", "keylock"); KontrolX1.addLEDButton(0x17, "[Channel2]", "keylock"); KontrolX1.addLEDButton(0x40, "[Channel1]", "beats_translate_curpos", true); KontrolX1.addLEDButton(0x41, "[Channel2]", "beats_translate_curpos", true); KontrolX1.addLEDButton(0x42, "[Channel1]", "slip_enabled", true); KontrolX1.addLEDButton(0x43, "[Channel2]", "slip_enabled", true); KontrolX1.addButton(0x1c, "[Channel1]", "loop_in", true); KontrolX1.addButton(0x1d, "[Channel2]", "loop_in", true); KontrolX1.addButton(0x1e, "[Channel1]", "loop_out", true); KontrolX1.addButton(0x1f, "[Channel2]", "loop_out", true); KontrolX1.addLEDButton(0x20, "[Channel1]", "seek_back", true, KontrolX1.seek); KontrolX1.addLEDButton(0x21, "[Channel2]", "seek_back", true, KontrolX1.seek); KontrolX1.addLEDButton(0x22, "[Channel1]", "seek_fwd", true, KontrolX1.seek); KontrolX1.addLEDButton(0x23, "[Channel2]", "seek_fwd", true, KontrolX1.seek); KontrolX1.addLEDButton(0x24, "[Channel1]", "cue_default",true); KontrolX1.addLEDButton(0x25, "[Channel2]", "cue_default",true); KontrolX1.addLEDButton(0x26, "[Channel1]", "reloop_exit", true); KontrolX1.addLEDButton(0x27, "[Channel2]", "reloop_exit", true); KontrolX1.addLEDButton(0x28, "[Channel1]", "play"); KontrolX1.addLEDButton(0x29, "[Channel2]", "play"); KontrolX1.addLEDButton(0x2a, "[Channel1]", "beatsync", true); KontrolX1.addLEDButton(0x2b, "[Channel2]", "beatsync", true); KontrolX1.addLEDButton(0x48, "[Channel1]", "loop_halve", true); KontrolX1.addLEDButton(0x49, "[Channel2]", "loop_halve", true); KontrolX1.addLEDButton(0x4a, "[Channel1]", "loop_double", true); KontrolX1.addLEDButton(0x4b, "[Channel2]", "loop_double", true); KontrolX1.addLEDButton(0x4c, "[Channel1]", "back", true); KontrolX1.addLEDButton(0x4d, "[Channel2]", "back", true); KontrolX1.addLEDButton(0x4e, "[Channel1]", "fwd", true); KontrolX1.addLEDButton(0x4f, "[Channel2]", "fwd", true); KontrolX1.addLEDButton(0x50, "[Channel1]", "beatlooproll_0.25_activate", true); KontrolX1.addLEDButton(0x51, "[Channel2]", "beatlooproll_0.25_activate", true); KontrolX1.addLEDButton(0x52, "[Channel1]", "beatlooproll_0.5_activate", true); KontrolX1.addLEDButton(0x53, "[Channel2]", "beatlooproll_0.5_activate", true); KontrolX1.addLEDButton(0x54, "[Channel1]", "beatlooproll_1_activate", true); KontrolX1.addLEDButton(0x55, "[Channel2]", "beatlooproll_1_activate", true); KontrolX1.addLEDButton(0x56, "[Channel1]", "beatlooproll_2_activate", true); KontrolX1.addLEDButton(0x57, "[Channel2]", "beatlooproll_2_activate", true); } KontrolX1.addLED = function(index, group, control) { var led = new Object(); led.id = group+"."+control; led.group = group; led.control = control; led.index = index; KontrolX1.ledmap[led.id] = led; // KontrolX1.debug("register LED "+led.id+" group "+led.group+" index "+led.index) engine.connectControl(led.group, led.control, KontrolX1.setLED); } KontrolX1.resetLEDs = function() { var led; for (var led_name in KontrolX1.ledmap) { led = KontrolX1.ledmap[led_name]; shifted = led.index + 0x2c; midi.sendShortMsg(KontrolX1.ledOutStatus, led.index, KontrolX1.ledStates.off); midi.sendShortMsg(KontrolX1.ledOutStatus, shifted, KontrolX1.ledStates.off); } } KontrolX1.setLED = function(value, group, key) { var led_id = group+"."+key; var led = KontrolX1.ledmap[led_id]; if (led==undefined) { KontrolX1.debug("Unknown LED to update: " + led_id); return; } value = (value==1) ? KontrolX1.ledStates.on : KontrolX1.ledStates.off; // KontrolX1.debug("KontrolX1.setLED "+KontrolX1.ledOutStatus+" index "+led.index+" value "+value); midi.sendShortMsg(KontrolX1.ledOutStatus, led.index, value); } KontrolX1.addLEDButton = function(index, group, control, hold, callback) { KontrolX1.addButton(index, group, control, hold, callback); KontrolX1.addLED(index, group, control); } KontrolX1.addButton = function(index, group, control, hold, callback) { KontrolX1.buttonmap[index] = { "id": group+"."+control, "group": group, "control": control, "hold": hold, "callback": callback }; } // Callback from MIDI mapping for all buttons in device KontrolX1.buttons = function(channel, control, value, status, group) { var button = KontrolX1.buttonmap[control]; var shift = (control>=0x2c) ? true : false; if (button==undefined) { KontrolX1.debug("BUTTON not defined in mapping: " + control); return; } if (button.callback!=undefined) { button.callback(channel, button.control, value, status, button.group); return; } if (!button.hold && value==0) return; if (button.control=="play") { if (engine.getValue(button.group, "play")) engine.setValue(button.group, "play", false); else engine.setValue(button.group, "play", true); return; } //if (!button.hold) value = engine.getValue(button.group, button.control) ? false : true; engine.setValue(button.group, button.control, value); } KontrolX1.addKnob = function(index, group, control, scaler, callback) { if (scaler==undefined && control in KontrolX1.scalers) scaler = control; scaler = KontrolX1.scalers[scaler]; if (scaler==undefined) { KontrolX1.debug("Invalid scaling function for " +group+"."+control + ": " + scaler); return; } KontrolX1.knobmap[index] = { "id": group+"."+control, "group": group, "control": control, "scaler": scaler, "callback": callback }; } KontrolX1.knobs = function(channel, control, value, status, group) { var knob = KontrolX1.knobmap[control]; var shift = (control>=0x2c) ? true : false; if (knob==undefined) { KontrolX1.debug("Knob not defined in mapping: " + control); return; } if (knob.scaler==undefined) { KontrolX1.debug("No valid scaling function registered for " + knob.id); return; } if (knob.callback!=undefined) { knob.callback(channel, control, value, status, group); return; } value = knob.scaler(value); engine.setValue(knob.group, knob.control, value); } KontrolX1.addEncoder = function(index, group, control, callback) { KontrolX1.encodermap[index] = { "id": group+"."+control, "group": group, "control": control, "callback": callback }; } // Callback from MIDI mapping for all encoders in device KontrolX1.encoders = function(channel, control, value, status, group) { var encoder = KontrolX1.encodermap[control]; var shift = (control>=0x2c) ? true : false; if (encoder==undefined) { KontrolX1.debug("ENCODER not defined in mapping: " + control); return; } // Encoders in F1 send 127 for -1, 1 for +1 value = (value==127)?value=-1:value=+1; if (encoder.callback!=undefined) { encoder.callback(channel, control, value, status, encoder.group); return; } engine.setValue(encoder.group, encoder.control, value); } // Track selector encoder callback parsed with KontrolX1.encoders to -1/1 KontrolX1.SelectTrackKnob = function(channel, control, value, status, group) { control = (value==-1) ? "SelectPrevTrack" : "SelectNextTrack"; // KontrolX1.debug(engine+' KontrolX1.SelectTrackKnob '+group+" "+control+" "+1); engine.setValue(group, control, 1); } KontrolX1.SelectPlaylistKnob = function(channel, control, value, status, group) { control = (value==-1) ? "SelectPrevPlaylist" : "SelectNextPlaylist"; // KontrolX1.debug(engine+' KontrolX1.SelectPlaylistKnob '+group+" "+control+" "+1); engine.setValue(group, control, 1); } // Seek button callback KontrolX1.seek = function(channel, control, value, status, group) { if (value==0) { engine.setValue(group, 'wheel', 0); return; } value = (engine.getValue(group, "play")==true) ? 0.02 : 0.5; if (control=='seek_back') value = -value; engine.setValue(group, 'wheel', value); } // Reset rate button KontrolX1.rate_reset = function(channel, control, value, status, group) { engine.setValue(group, 'rate', 0); } // Callback for rate encoders KontrolX1.rate_encoder = function(channel, control, value, status, group) { switch (value) { case -1: control = "rate_perm_down_small"; break; case 1: control = "rate_perm_up_small"; break; default: KontrolX1.debug("Unknown value for rate_encoder: " + value); return; } engine.setValue(group, control, value); engine.setValue(group, control, false); } // Callback for jog encoders KontrolX1.jog_encoder = function(channel, control, value, status, group) { value = KontrolX1.jog_delta * value; KontrolX1.debug("jog_encoder group "+group+" value "+value); engine.setValue(group, 'jog', value); } // Callback for loop size encoders KontrolX1.loop_size = function(channel, control, value, status, group) { switch (value) { case -1: control = "loop_halve"; break; case 1: control = "loop_double"; break; default: KontrolX1.debug("Unknown value for rate_encoder: " + value); return; } engine.setValue(group, control, true); engine.setValue(group, control, false); } // Unmapped top left encoder callbacks KontrolX1.ExtraEncoder = function(channel, control, value, status, group) { } KontrolX1.ExtraEncoderButton = function(channel, control, value, status, group) { } // Unmapped shifted knobs, buttons and encoders KontrolX1.UnmappedShiftedKnob = function(channel, control, value, status, group) {} KontrolX1.UnmappedShiftedButton = function(channel, control, value, status, group) {} KontrolX1.UnmappedShiftedEncoder = function(channel, control, value, status, group) {}