diff --git a/res/controllers/Hercules-DJControl-Inpulse-200-script.js b/res/controllers/Hercules-DJControl-Inpulse-200-script.js index 556ac69b6136..44af50094234 100644 --- a/res/controllers/Hercules-DJControl-Inpulse-200-script.js +++ b/res/controllers/Hercules-DJControl-Inpulse-200-script.js @@ -25,7 +25,8 @@ // //************************************************************************* -var DJCi200 = {}; +var DJCi200 = {}; // eslint-disable-line + /////////////////////////////////////////////////////////////// // USER OPTIONS // /////////////////////////////////////////////////////////////// diff --git a/res/controllers/Hercules-DJControl-Inpulse-500-script.js b/res/controllers/Hercules-DJControl-Inpulse-500-script.js new file mode 100644 index 000000000000..8eb08a49d4a8 --- /dev/null +++ b/res/controllers/Hercules-DJControl-Inpulse-500-script.js @@ -0,0 +1,1528 @@ +// DJControl_Inpulse_500_script.js +// +// *************************************************************************** +// * Mixxx mapping script file for the Hercules DJControl Inpulse 500. +// * Authors: Ev3nt1ne, DJ Phatso, resetreboot +// * contributions by Kerrick Staley, Bentheshrubber, ThatOneRuffian +// +// Version 1.6c: (August 2023) resetreboot +// * Requires Mixxx >= 2.3.4 +// * Volume meters follow correctly the selected channel +// * Use the full 14 bits for knobs for more precision +// * Add effects to the PAD 7 mode +// * Create decks for four channel mode +// * Change the behavior of the FX buttons, use them as Channel selector, using the LEDs +// as indicators of current channel. +// +// +// * When enabling multichannel, ensure: +// - Beat matching guide follows correctly the selected channels +// +// * Move the sampler buttons to the Deck component as well as the new effect buttons +// * Made the filter knob have a function with filter, effect and filter + effect +// * Use the Hotcue component for hotcues +// * Use components and add for the rest of the controls: +// - Play +// - Cue +// - Sync +// - Volume fader +// - EQs +// - PFL +// - Pad Selectors +// - Loop PADs +// - Roll PADs +// - Beat jump PADs +// - Tone key PADs +// - Slicer +// - Loop pot +// - In and Out loop +// - Load button +// - Vinyl +// - Slip +// - Quant +// - Pitch fader +// - Jog wheels (Using the new JogWheelBasic component! +// - Also probably fixed the shift behavior not working properly +// +// * Added option so the browser knob can behave with out of focus window +// +// * Version 1.5c (Summer 2023) +// * Forum: https://mixxx.discourse.group/t/hercules-djcontrol-inpulse-500/19739 +// * Wiki: https://mixxx.org/wiki/doku.php/hercules_djcontrol_inpulse_500 +// +// Version 1.0c: +// * Hot Cue: implementation of the Color API (Work in progress) +// - Assigned color directly to pad (XML) +// * Added DECK LED number - On when playing +// * Moved Beatjump to Pad mode 3 (Slicer) +// * Set different color for upper (Sampler 1-4) and lower (Sampler 5-8) sampler pads +// +// Version 1.0 - Based upon Inpulse 300 v1.2 (official) +// +// TO DO: +// * Browser knob has a ton of colors to do things! +// * Vinyl + SHIFT led should reflect brake status +// * Quant + SHIFT led should reflect key lock status +// * Add beat jump + SHIFT jumps +// +// **************************************************************************** + + +const DJCi500 = {}; + +/////////////////////////////////////////////////////////////// +// USER OPTIONS // +/////////////////////////////////////////////////////////////// + +// If you are spinning your set list and you have your Mixxx window out +// of focus and you want to be able to use the browser knob to traverse +// the current crate or playlist, set to true. Especially useful to spin +// when using Twitch, VRChat or Second Life +DJCi500.browserOffFocusMode = false; + +// Set initial state for vinyl mode button +DJCi500.initialVinylMode = true; + +// Colors +DJCi500.PadColorMapper = new ColorMapper({ + 0xFF0000: 0x60, + 0xFFFF00: 0x7C, + 0x00FF00: 0x1C, + 0x00FFFF: 0x1F, + 0x0000FF: 0x03, + 0xFF00FF: 0x42, + 0xFF88FF: 0x63, + 0xFFFFFF: 0x7F, + 0x000088: 0x02, + 0x008800: 0x10, + 0x008888: 0x12, + 0x228800: 0x30, + 0x880000: 0x40, + 0x882200: 0x4C, + 0x888800: 0x50, + 0x888888: 0x52, + 0x88FF00: 0x5C, + 0xFF8800: 0x74, +}); + +// Constants +DJCi500.EFFECT_ONLY_MODE = 1; +DJCi500.FILTER_AND_EFFECT_MODE = 2; + +// For key shift pads and beat jump pads +const pairColorsOn = [0x1F, 0x1F, 0x03, 0x03, 0x74, 0x74, 0x60, 0x60]; +const pairColorsOff = [0x12, 0x12, 0x02, 0x02, 0x4C, 0x4C, 0x40, 0x40]; + +/////////////////////////////////////////////////////////////// +// SLICER // +/////////////////////////////////////////////////////////////// +DJCi500.selectedSlicerDomain = [8, 8, 8, 8]; // Length of the Slicer domain + +// Slicer storage: +DJCi500.slicerBeatsPassed = [0, 0, 0, 0]; +DJCi500.slicerPreviousBeatsPassed = [0, 0, 0, 0]; +DJCi500.slicerTimer = [false, false, false, false]; +DJCi500.slicerActive = [false, false, false, false]; +DJCi500.slicerAlreadyJumped = [false, false, false, false]; +DJCi500.slicerButton = [-1, -1, -1, -1]; +DJCi500.slicerModes = { + "contSlice": 0, + "loopSlice": 1 +}; +DJCi500.activeSlicerMode = [ + DJCi500.slicerModes.contSlice, + DJCi500.slicerModes.contSlice, + DJCi500.slicerModes.contSlice, + DJCi500.slicerModes.contSlice +]; +DJCi500.slicerLoopBeat8 = [0, 0, 0, 0]; +/////////////////////// + +// Master VU Meter callbacks +DJCi500.vuMeterUpdateMaster = function(value, _group, control) { + // Reserve the red led for peak indicator, this will in turn, make + // the display more similar (I hope) to what Mixxx VU shows + value = script.absoluteLinInverse(value, 0.0, 1.0, 0, 124); + const ctrl = (control === "vu_meter_left") ? 0x40 : 0x41; + midi.sendShortMsg(0xB0, ctrl, value); +}; + +DJCi500.vuMeterPeakLeftMaster = function(value, _group, _control) { + if (value) { + midi.sendShortMsg(0x90, 0x0A, 0x7F); + } else { + midi.sendShortMsg(0x90, 0x0A, 0x00); + } +}; + +DJCi500.vuMeterPeakRightMaster = function(value, _group, _control) { + if (value) { + midi.sendShortMsg(0x90, 0x0F, 0x7F); + } else { + midi.sendShortMsg(0x90, 0x0F, 0x00); + } +}; + +// Deck VU Meter callbacks +DJCi500.vuMeterUpdateDeck = function(value, group) { + // Reserve the red led for peak indicator, this will in turn, make + // the display more similar (I hope) to what Mixxx VU shows + value = script.absoluteLinInverse(value, 0.0, 1.0, 0, 125); + if (DJCi500.deckA.currentDeck === group) { + midi.sendShortMsg(0xB1, 0x40, value); + } else if (DJCi500.deckB.currentDeck === group) { + midi.sendShortMsg(0xB2, 0x40, value); + } +}; + +DJCi500.vuMeterPeakDeck = function(value, group, _control) { + let channel = 0x00; + if (DJCi500.deckA.currentDeck === group) { + channel = 0x91; + } else if (DJCi500.deckB.currentDeck === group) { + channel = 0x92; + } + + if (channel > 0x00) { + if (value) { + midi.sendShortMsg(channel, 0x39, 0x7F); + } else { + midi.sendShortMsg(channel, 0x39, 0x00); + } + } +}; + +DJCi500.numberIndicator = function(value, group, _control) { + if (DJCi500.deckA.currentDeck === group) { + midi.sendShortMsg(0x91, 0x30, value); + } else if (DJCi500.deckB.currentDeck === group) { + midi.sendShortMsg(0x92, 0x30, value); + } +}; + +DJCi500.fxSelIndicator = function(_value, group, _control, _status) { + const deckA = DJCi500.deckA.currentDeck; + const deckB = DJCi500.deckB.currentDeck; + let active = false; + + if (group === "[EffectRack1_EffectUnit1]") { + active = engine.getValue(group, `group_${deckA}_enable`); + if (active) { + midi.sendShortMsg(0x96, 0x63, 0x74); + } else { + midi.sendShortMsg(0x96, 0x63, 0x00); + } + active = engine.getValue(group, `group_${deckB}_enable`); + if (active) { + midi.sendShortMsg(0x97, 0x63, 0x74); + } else { + midi.sendShortMsg(0x97, 0x63, 0x00); + } + } else if (group === "[EffectRack1_EffectUnit2]") { + active = engine.getValue(group, `group_${deckA}_enable`); + if (active) { + midi.sendShortMsg(0x96, 0x67, 0x74); + } else { + midi.sendShortMsg(0x96, 0x67, 0x00); + } + active = engine.getValue(group, `group_${deckB}_enable`); + if (active) { + midi.sendShortMsg(0x97, 0x67, 0x74); + } else { + midi.sendShortMsg(0x97, 0x67, 0x00); + } + } +}; + +DJCi500.fxEnabledIndicator = function(_value, group, _control, _status) { + const deckA = DJCi500.deckA.currentDeck; + const deckB = DJCi500.deckB.currentDeck; + const active = engine.getValue(group, "enabled"); + + if (group === `[QuickEffectRack1_${deckA}]`) { + midi.sendShortMsg(0x96, 0x66, active ? 0x1C : 0x60); + } else if (group === `[QuickEffectRack1_${deckB}]`) { + midi.sendShortMsg(0x97, 0x66, active ? 0x1C : 0x60); + } +}; + +DJCi500.Deck = function(deckNumbers, midiChannel) { + components.Deck.call(this, deckNumbers); + // Allow components to access deck variables + const deckData = this; + + // For loop and looprolls + const fractions = ["0.125", "0.25", "0.5", "1", "2", "4", "8", "16"]; + const shiftFractions = ["0.03125", "0.0625", "32", "64", "128", "256", "512", "512"]; + + // For beatjumps + const jumpValues = ["1", "1", "2", "2", "4", "4", "8", "8"]; + const jumpValuesShift = ["16", "16", "32", "32", "64", "64", "128", "128"]; + + // Brake status for this deck + this.slowPauseSetState = [false, false, false, false]; + + // Vinyl button state + this.vinylButtonState = [DJCi500.initialVinylMode, DJCi500.initialVinylMode, DJCi500.initialVinylMode, DJCi500.initialVinylMode]; + + // Pitch ranges and status + this.pitchRanges = [0.08, 0.10, 0.15, 0.16, 0.24, 0.50, 0.90]; // Select pitch range + this.pitchRangeId = 0; // id of the array, one for each deck + + // Effect section components + this.effectEnabled = false; + + // Make sure the shift button remaps the shift actions + this.shiftButton = new components.Button({ + midi: [0x90 + midiChannel, 0x04], + input: function(_channel, _control, value, _status, _group) { + if (value === 0x7F) { + deckData.shift(); + } else { + deckData.unshift(); + } + + }, + }); + + this.loadButton = new components.Button({ + midi: [0x90 + midiChannel, 0x0D], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + unshift: function() { + this.inKey = "LoadSelectedTrack"; + }, + shift: function() { + this.inKey = "eject"; + }, + }); + + // Transport section + // Play button, for some reason the group is not correct on this one? + this.playButton = new components.PlayButton({ + midi: [0x90 + midiChannel, 0x07], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + unshift: function() { + this.input = function(_channel, _control, value, _status, _group) { + if (value === 0x7F) { + if (engine.getValue(deckData.currentDeck, "play_latched")) { + const deck = script.deckFromGroup(deckData.currentDeck); + if (deckData.slowPauseSetState[deck - 1]) { + engine.brake(deck, + 1, + 54); + } else { + script.toggleControl(deckData.currentDeck, "play"); + } + } else { + script.toggleControl(deckData.currentDeck, "play"); + } + } + }; + }, + shift: function() { + this.input = function(_channel, _control, _value, _status, _group) { + engine.setValue(deckData.currentDeck, "play_stutter", true); + }; + }, + }); + + this.cueButton = new components.CueButton({ + midi: [0x90 + midiChannel, 0x06], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + shift: function() { + this.inKey = "start_play"; + }, + }); + + this.syncButton = new components.SyncButton({ + midi: [0x90 + midiChannel, 0x05], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + shift: function() { + this.inKey = "sync_key"; + }, + }); + + this.pflButton = new components.Button({ + midi: [0x90 + midiChannel, 0x0C], + type: components.Button.prototype.types.toggle, + key: "pfl", + }); + + // Top controls + // Vinyl button + this.vinylButton = new components.Button({ + midi: [0x90 + midiChannel, 0x03], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + unshift: function() { + this.input = function(_channel, _control, value, _status, _group) { + if (value === 0x7F) { + const deck = script.deckFromGroup(deckData.currentDeck); + const newStatus = !deckData.vinylButtonState[deck - 1]; + deckData.jogWheel.vinylMode = newStatus; + deckData.jogWheelShift.vinylMode = newStatus; + deckData.vinylButtonState[deck] = newStatus; + const newMessage = newStatus ? 0x7F : 0x00; + midi.sendShortMsg(this.midi[0], 0x03, newMessage); + } + }; + }, + shift: function() { + this.input = function(channel, control, value, _status, _group) { + if (value === 0x7F) { + const deck = script.deckFromGroup(deckData.currentDeck); + deckData.slowPauseSetState[deck - 1] = !deckData.slowPauseSetState[deck - 1]; + + } + }; + } + }); + + // SLIP mode button + this.slipButton = new components.Button({ + midi: [0x90 + midiChannel, 0x01], + type: components.Button.prototype.types.toggle, + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + key: "slip_enabled", + }); + + // Quant button + this.quantButton = new components.Button({ + midi: [0x90 + midiChannel, 0x02], + type: components.Button.prototype.types.toggle, + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + outKey: "quantize", + unshift: function() { + this.inKey = "quantize"; + }, + shift: function() { + this.inKey = "keylock"; + }, + }); + + // Knobs + this.volume = new components.Pot({ + midi: [0xB0 + midiChannel, 0x00], + inKey: "volume", + }); + + this.eqKnob = []; + for (let k = 1; k <= 3; k++) { + this.eqKnob[k] = new components.Pot({ + midi: [0xB0 + midiChannel, 0x01 + k], + group: `[EqualizerRack1_${this.currentDeck}_Effect1]`, + inKey: `parameter${k}`, + }); + } + + this.gainKnob = new components.Pot({ + midi: [0xB0 + midiChannel, 0x05], + key: "pregain", + }); + + // Pitch-tempo fader + this.pitchFader = new components.Pot({ + midi: [0xB0 + midiChannel, 0x08], + key: "rate", + }); + + // Jog Wheel + // TODO: Handle with less repeat the shift key for this + this.jogWheel = new components.JogWheelBasic({ + midi: [0xB0 + midiChannel, 0x0A], + deck: midiChannel, // Whatever deck this jogwheel controls, in this case we ignore it + wheelResolution: 720, // How many ticks per revolution the jogwheel has + alpha: 5/6, + beta: (5/6)/128, + rpm: 33 + 1/3, + group: `[Channel${midiChannel}]`, + inputWheel: function(_channel, _control, value, _status, _group) { + const deck = script.deckFromGroup(deckData.currentDeck); + value = this.inValueScale(value); + if (engine.isScratching(deck)) { + engine.scratchTick(deck, value); + } else { + engine.setValue(`[Channel${deck}]`, "jog", value); + } + }, + inputTouch: function(_channel, _control, value, _status, _group) { + const deck = script.deckFromGroup(deckData.currentDeck); + if ((value === 0x7F) && deckData.vinylButtonState[deck - 1]) { + engine.scratchEnable(deck, + this.wheelResolution, + this.rpm, + this.alpha, + this.beta); + } else { + engine.scratchDisable(deck); + } + }, + }); + + this.jogWheelShift = new components.JogWheelBasic({ + midi: [0xB3 + midiChannel, 0x0A], + deck: midiChannel, // whatever deck this jogwheel controls, in this case we ignore it + wheelResolution: 720, // how many ticks per revolution the jogwheel has + alpha: 5/6, + beta: (5/6)/128, + rpm: 33 + 1/3, + group: `[Channel${midiChannel}]`, + inputWheel: function(_channel, _control, value, _status, _group) { + const deck = script.deckFromGroup(deckData.currentDeck); + value = this.inValueScale(value) * 4; + if (engine.isScratching(deck)) { + engine.scratchTick(deck, value); + } else { + engine.setValue(`[Channel${deck}]`, "jog", value); + } + }, + inputTouch: function(channel, control, value, status, _group) { + const deck = script.deckFromGroup(deckData.currentDeck); + if (this.isPress(channel, control, value, status) && this.vinylMode) { + engine.scratchEnable(deck, + this.wheelResolution, + this.rpm, + this.alpha, + this.beta); + } else { + engine.scratchDisable(deck); + } + }, + }); + + // Loop controls + this.loopInButton = new components.Button({ + midi: [0x90 + midiChannel, 0x09], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + outKey: "loop_enabled", // TODO: Check with loop_in? + unshift: function() { + this.inKey = "loop_in"; + }, + shift: function() { + this.inKey = "loop_in_goto"; + }, + }); + + this.loopOutButton = new components.Button({ + midi: [0x90 + midiChannel, 0x0A], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + outKey: "loop_enabled", // TODO: Check with loop_in? + unshift: function() { + this.inKey = "loop_out"; + }, + shift: function() { + this.inKey = "loop_out_goto"; + }, + }); + + // Loop rotary encoder functions + // + // Push the rotary encoder + this.loopEncoderPush = new components.Button({ + midi: [0x90 + midiChannel, 0x2C], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + unshift: function() { + this.inKey = "reloop_toggle"; + }, + shift: function() { + this.inKey = "beatloop_4_activate"; + }, + }); + + // Loop encoder + this.loopEncoder = new components.Encoder({ + midi: [0xB0 + midiChannel, 0x0E], + shiftOffset: 3, + shiftControl: false, + shiftChannel: true, + sendShifted: true, + input: function(channel, control, value, _status, _group) { + // FIXME: Toggle for loop halve and double?? + const deckGroup = deckData.currentDeck; + if (value >= 0x40) { + engine.setValue(deckGroup, "loop_halve", true); + } else { + engine.setValue(deckGroup, "loop_double", true); + } + } + }); + + // We only check and attach for slicer mode, but we have all + // pad buttons here if we need something extra! + this.padSelectButtons = []; + for (let i = 1; i <= 8; i++) { + this.padSelectButtons[i] = new components.Button({ + midi: [0x90 + midiChannel, 0x0F + (i - 1)], + input: function(_channel, control, _value, _status, _group) { + const deck = script.deckFromGroup(deckData.currentDeck); + if (control === 0x11) { + DJCi500.slicerActive[deck - 1] = true; + } else { + DJCi500.slicerActive[deck - 1] = false; + } + }, + }); + } + + // Hotcue buttons (PAD Mode 1) + this.hotcueButtons = []; + for (let i = 1; i <= 8; i++) { + this.hotcueButtons[i] = new components.HotcueButton({ + midi: [0x95 + midiChannel, 0x00 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + colorMapper: DJCi500.PadColorMapper, + off: 0x00, + }); + }; + + // Loop buttons (PAD Mode 2) + this.loopButtons = []; + for (let i = 1; i <= 8; i++) { + this.loopButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x10 + (i - 1)], + number: i, + shiftControl: false, + sendShifted: false, + on: 0x5C, + off: 0x30, + outKey: `beatloop_${fractions[i - 1]}_enabled`, + inKey: `beatloop_${fractions[i - 1]}_toggle`, + }); + }; + + // A bit repeated code, but I want the leds to react accordingly + this.loopShiftButtons = []; + for (let i = 1; i <= 8; i++) { + this.loopShiftButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x10 + (i - 1) + 8], + number: i, + shiftControl: false, + sendShifted: false, + on: 0x5C, + off: 0x30, + outKey: `beatloop_${shiftFractions[i - 1]}_enabled`, + inKey: `beatloop_${shiftFractions[i - 1]}_toggle`, + }); + }; + + // Slicer buttons (PAD Mode 3) + this.slicerButtons = []; + for (let i = 1; i <= 8; i++) { + this.slicerButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x20 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + input: function(channel, control, value, status, _group) { + // This is kind of a hack... somehow this is not getting the group correctly! + DJCi500.slicerButtonFunc(channel, control, value, status, deckData.currentDeck); + }, + }); + }; + + // Sampler buttons (PAD Mode 4) + this.samplerButtons = []; + for (let i = 1; i <= 8; i++) { + this.samplerButtons[i] = new components.SamplerButton({ + midi: [0x95 + midiChannel, 0x30 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + loaded: 0x42, + empty: 0x00, + playing: 0x63, + looping: 0x74, + }); + }; + + // Pitch buttons (PAD Mode 5) + this.pitchDownTone = new components.Button({ + midi: [0x95 + midiChannel, 0x40], + on: pairColorsOn[0], + off: pairColorsOff[0], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, "pitch_down", 1); + engine.setValue(deckData.currentDeck, "pitch_down", 1); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }, + }); + + this.pitchDownSemiTone = new components.Button({ + midi: [0x95 + midiChannel, 0x41], + on: pairColorsOn[1], + off: pairColorsOff[1], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, "pitch_down", 1); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }, + }); + + this.pitchUpSemiTone = new components.Button({ + midi: [0x95 + midiChannel, 0x42], + on: pairColorsOn[6], + off: pairColorsOff[6], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, "pitch_up", 1); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }, + }); + + this.pitchUpTone = new components.Button({ + midi: [0x95 + midiChannel, 0x43], + on: pairColorsOn[6], + off: pairColorsOff[6], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, "pitch_up", 1); + engine.setValue(deckData.currentDeck, "pitch_up", 1); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }, + }); + + this.pitchSliderIncrease = new components.Button({ + midi: [0x95 + midiChannel, 0x46], + on: 0x63, + off: 0x42, + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + deckData.pitchRangeId++; + if (deckData.pitchRangeId > 6) { + deckData.pitchRangeId = 6; + } + engine.setValue(deckData.currentDeck, "rateRange", deckData.pitchRanges[deckData.pitchRangeId]); + midi.sendShortMsg(status, control, this.on); //17 -- 3B + } else { + midi.sendShortMsg(status, control, this.off); //3B -- 33 + } + }, + }); + + this.pitchSliderDecrease = new components.Button({ + midi: [0x95 + midiChannel, 0x45], + on: pairColorsOn[3], + off: pairColorsOff[3], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + deckData.pitchRangeId = deckData.pitchRangeId - 1; + if (deckData.pitchRangeId < 0) { + deckData.pitchRangeId = 0; + } + engine.setValue(deckData.currentDeck, "rateRange", deckData.pitchRanges[deckData.pitchRangeId]); + midi.sendShortMsg(status, control, this.on); //17 -- 3B + } else { + midi.sendShortMsg(status, control, this.off); //3B -- 33 + } + }, + }); + + this.pitchSliderReset = new components.Button({ + midi: [0x95 + midiChannel, 0x44], + on: pairColorsOn[6], + off: pairColorsOff[6], + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + deckData.pitchRangeId = 0; + engine.setValue(deckData.currentDeck, "rateRange", deckData.pitchRanges[deckData.pitchRangeId]); + midi.sendShortMsg(status, control, this.on); //17 -- 3B + } else { + midi.sendShortMsg(status, control, this.off); //3B -- 33 + } + }, + }); + + // Beatloop rolls buttons (PAD Mode 6) + this.rollButtons = []; + for (let i = 1; i <= 8; i++) { + this.rollButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x50 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + on: 0x1F, + off: 0x12, + key: `beatlooproll_${fractions[i - 1]}_activate`, + }); + }; + + // Effect buttons (PAD Mode 7) + this.effectButtons = []; + for (let i = 1; i <= 3; i++) { + // First top row effects buttons, just the effect, disable HPF/LPF knob + this.effectButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x60 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + group: `[EffectRack1_EffectUnit${midiChannel}_Effect${i}]`, + outKey: "enabled", + output: function(value, _group, _control) { + if (value) { + this.send(0x7F); + } else { + this.send(0x7C); + } + }, + unshift: function() { + // Normal effect button operation, toggling the effect assigned to it + this.input = function(channel, control, value, _status, _group) { + if (value === 0x7F) { + script.toggleControl(this.group, "enabled"); + } + }; + }, + shift: function() { + // Shift button will change the effect to the next in the list + this.input = function(channel, control, value, _status, _group) { + if (value === 0x7F) { + engine.setValue(this.group, "effect_selector", +1); + } + }; + } + }); + }; + + // Effect chain selectors + this.effectButtons[5] = new components.Button({ + midi: [0x95 + midiChannel, 0x64], + number: 5, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + group: `[QuickEffectRack1_[Channel${midiChannel}]]`, + on: 0x5C, + off: 0x30, + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(this.group, "chain_preset_selector", -1); + midi.sendShortMsg(status, control, this.on); //17 -- 3B + } else { + midi.sendShortMsg(status, control, this.off); //3B -- 33 + } + } + }); + + this.effectButtons[6] = new components.Button({ + midi: [0x95 + midiChannel, 0x65], + number: 6, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + group: `[QuickEffectRack1_[Channel${midiChannel}]]`, + on: 0x5C, + off: 0x30, + input: function(channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(this.group, "chain_preset_selector", 1); + midi.sendShortMsg(status, control, this.on); //17 -- 3B + } else { + midi.sendShortMsg(status, control, this.off); //3B -- 33 + } + } + }); + + // Filter kill switch + this.effectButtons[7] = new components.Button({ + midi: [0x95 + midiChannel, 0x66], + number: 4, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + group: `[QuickEffectRack1_[Channel${midiChannel}]]`, + input: function(_channel, _control, value, _status, _group) { + if (value === 0x7F) { + script.toggleControl(this.group, "enabled"); + } + } + }); + + // Set the current channel FX route with the two extra PADs + this.effectButtons[4] = new components.Button({ + midi: [0x95 + midiChannel, 0x63], + number: 4, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + group: "[EffectRack1_EffectUnit1]", + input: function(channel, _control, value, _status, _group) { + if (value === 0x7F) { + const deckGroup = deckData.currentDeck; + script.toggleControl(this.group, `group_${deckGroup}_enable`); + } + } + }); + + this.effectButtons[8] = new components.Button({ + midi: [0x95 + midiChannel, 0x67], + number: 8, + shiftOffset: 8, + shiftControl: true, + sendShifted: false, + group: "[EffectRack1_EffectUnit2]", + input: function(_channel, _control, value, _status, _group) { + if (value === 0x7F) { + const deckGroup = deckData.currentDeck; + script.toggleControl(this.group, `group_${deckGroup}_enable`); + } + } + }); + + // Filter knob is here since it is affected by effects pads + this.filterKnob = new components.Pot({ + midi: [0xB0 + midiChannel, 0x01], + number: midiChannel, + group: `[QuickEffectRack1_[Channel${midiChannel}]]`, + input: function(channel, control, value, _status, _group) { + if (DJCi500.updateEffectStatus(midiChannel, deckData.currentDeck)) { + // Move the effects knobs + engine.setValue(`[EffectRack1_EffectUnit${this.number}]`, "super1", Math.abs(script.absoluteNonLin(value, 0.0, 0.5, 1.0, 0, 127) - 0.5)*2); + } else { + // Move the filter knob + engine.setValue(`[QuickEffectRack1_${deckData.currentDeck}]`, "super1", script.absoluteNonLin(value, 0.0, 0.5, 1.0, 0, 127)); + } + }, + }); + + // Beat jump (PAD Mode 8) + this.beatJumpButtons = []; + for (let i = 1; i <= 8; i++) { + const movement = (i % 2 === 0) ? "_forward" : "_backward"; + const jmpVal = jumpValues[i - 1]; + const jmpValShft = jumpValuesShift[i - 1]; + this.beatJumpButtons[i] = new components.Button({ + midi: [0x95 + midiChannel, 0x70 + (i - 1)], + number: i, + shiftOffset: 8, + shiftControl: true, + sendShifted: true, + on: pairColorsOn[i - 1], + off: pairColorsOff[i - 1], + jump: `beatjump_${jmpVal}${movement}`, + jumpShift: `beatjump_${jmpValShft}${movement}`, + unshift: function() { + this.input = function(_channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, this.jump, true); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }; + }, + shift: function() { + this.input = function(_channel, control, value, status, _group) { + if (value === 0x7F) { + engine.setValue(deckData.currentDeck, this.jumpShift, true); + midi.sendShortMsg(status, control, this.on); + } else { + midi.sendShortMsg(status, control, this.off); + } + }; + }, + }); + }; + + // As per Mixxx wiki, set the group properties + this.reconnectComponents(function(c) { + if (c.group === undefined) { + c.group = this.currentDeck; + } + }); +}; + +// Give the custom Deck all the methods of the generic deck +DJCi500.Deck.prototype = new components.Deck(); + +// INIT for the controller and decks +DJCi500.init = function() { + DJCi500.AutoHotcueColors = true; + + // Take care of the status of the crossfader status + DJCi500.crossfaderEnabled = true; + DJCi500.xFaderScratch = false; + + // Setup Vinyl buttons LED(one for each deck). + midi.sendShortMsg(0x91, 0x03, DJCi500.initialVinylMode ? 0x7F : 0x00); + midi.sendShortMsg(0x92, 0x03, DJCi500.initialVinylMode ? 0x7F : 0x00); + + //Turn On Browser button LED + midi.sendShortMsg(0x90, 0x05, 0x10); + + // Connect the VUMeters + engine.makeConnection("[Channel1]", "vu_meter", DJCi500.vuMeterUpdateDeck); + engine.getValue("[Channel1]", "vu_meter"); + engine.makeConnection("[Channel2]", "vu_meter", DJCi500.vuMeterUpdateDeck); + engine.getValue("[Channel2]", "vu_meter"); + engine.makeConnection("[Channel3]", "vu_meter", DJCi500.vuMeterUpdateDeck); + engine.getValue("[Channel3]", "vu_meter"); + engine.makeConnection("[Channel4]", "vu_meter", DJCi500.vuMeterUpdateDeck); + engine.getValue("[Channel4]", "vu_meter"); + + // Deck VU meters peak indicators + engine.makeConnection("[Channel1]", "peak_indicator", DJCi500.vuMeterPeakDeck); + engine.makeConnection("[Channel2]", "peak_indicator", DJCi500.vuMeterPeakDeck); + engine.makeConnection("[Channel3]", "peak_indicator", DJCi500.vuMeterPeakDeck); + engine.makeConnection("[Channel4]", "peak_indicator", DJCi500.vuMeterPeakDeck); + + // Connect number leds + engine.makeConnection("[Channel1]", "play_indicator", DJCi500.numberIndicator); + engine.getValue("[Channel1]", "play_indicator"); + engine.makeConnection("[Channel2]", "play_indicator", DJCi500.numberIndicator); + engine.getValue("[Channel2]", "play_indicator"); + engine.makeConnection("[Channel3]", "play_indicator", DJCi500.numberIndicator); + engine.getValue("[Channel3]", "play_indicator"); + engine.makeConnection("[Channel4]", "play_indicator", DJCi500.numberIndicator); + engine.getValue("[Channel4]", "play_indicator"); + + // Connect Master VU meter + engine.makeConnection("[Main]", "vu_meter_left", DJCi500.vuMeterUpdateMaster); + engine.makeConnection("[Main]", "vu_meter_right", DJCi500.vuMeterUpdateMaster); + engine.makeConnection("[Main]", "peak_indicator_left", DJCi500.vuMeterPeakLeftMaster); + engine.makeConnection("[Main]", "peak_indicator_right", DJCi500.vuMeterPeakRightMaster); + + engine.getValue("[Main]", "vu_meter_left"); + engine.getValue("[Main]", "vu_meter_right"); + + // Connect the FX selection leds + engine.makeConnection("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit1]", "group_[Channel3]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit2]", "group_[Channel3]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit1]", "group_[Channel4]_enable", DJCi500.fxSelIndicator); + engine.makeConnection("[EffectRack1_EffectUnit2]", "group_[Channel4]_enable", DJCi500.fxSelIndicator); + + engine.makeConnection("[QuickEffectRack1_[Channel1]]", "enabled", DJCi500.fxEnabledIndicator); + engine.makeConnection("[QuickEffectRack1_[Channel2]]", "enabled", DJCi500.fxEnabledIndicator); + engine.makeConnection("[QuickEffectRack1_[Channel3]]", "enabled", DJCi500.fxEnabledIndicator); + engine.makeConnection("[QuickEffectRack1_[Channel4]]", "enabled", DJCi500.fxEnabledIndicator); + + // Connect the slicer beats + DJCi500.slicerBeat1 = engine.makeConnection("[Channel1]", "beat_active", DJCi500.slicerBeatActive); + DJCi500.slicerBeat2 = engine.makeConnection("[Channel2]", "beat_active", DJCi500.slicerBeatActive); + //var controlsToFunctions = {'beat_active': 'DJCi500.slicerBeatActive'}; + //script.bindConnections('[Channel1]', controlsToFunctions, true); + + // Ask the controller to send all current knob/slider values over MIDI, which will update + // the corresponding GUI controls in MIXXX. + midi.sendShortMsg(0xB0, 0x7F, 0x7F); + + // Turn on lights: + for (let i = 0; i < 2; i++) { + // PAD 5 Key and tempo range controls + midi.sendShortMsg(0x96+i, 0x40, 0x12); + midi.sendShortMsg(0x96+i, 0x41, 0x12); + midi.sendShortMsg(0x96+i, 0x42, 0x40); + midi.sendShortMsg(0x96+i, 0x43, 0x40); + midi.sendShortMsg(0x96+i, 0x44, 0x40); + midi.sendShortMsg(0x96+i, 0x45, 0x02); + midi.sendShortMsg(0x96+i, 0x46, 0x42); + + // PAD 8 Beatjump leds + midi.sendShortMsg(0x96+i, 0x70, pairColorsOff[0]); + midi.sendShortMsg(0x96+i, 0x71, pairColorsOff[1]); + midi.sendShortMsg(0x96+i, 0x72, pairColorsOff[2]); + midi.sendShortMsg(0x96+i, 0x73, pairColorsOff[3]); + midi.sendShortMsg(0x96+i, 0x74, pairColorsOff[4]); + midi.sendShortMsg(0x96+i, 0x75, pairColorsOff[5]); + midi.sendShortMsg(0x96+i, 0x76, pairColorsOff[6]); + midi.sendShortMsg(0x96+i, 0x77, pairColorsOff[7]); + // PAD 8 shift + midi.sendShortMsg(0x96+i, 0x78, pairColorsOff[0]); + midi.sendShortMsg(0x96+i, 0x79, pairColorsOff[1]); + midi.sendShortMsg(0x96+i, 0x7A, pairColorsOff[2]); + midi.sendShortMsg(0x96+i, 0x7B, pairColorsOff[3]); + midi.sendShortMsg(0x96+i, 0x7C, pairColorsOff[4]); + midi.sendShortMsg(0x96+i, 0x7D, pairColorsOff[5]); + midi.sendShortMsg(0x96+i, 0x7E, pairColorsOff[6]); + midi.sendShortMsg(0x96+i, 0x7F, pairColorsOff[7]); + // Light up FX quick effect chain selector buttons + midi.sendShortMsg(0x96+i, 0x64, 0x30); + midi.sendShortMsg(0x96+i, 0x65, 0x30); + } + + DJCi500.tempoTimer = engine.beginTimer(250, DJCi500.tempoLEDs); + + // FX buttons, light them to signal the current deck 1 and 2 as active + midi.sendShortMsg(0x90, 0x14, 0x7F); + midi.sendShortMsg(0x90, 0x15, 0x7F); + + // Create the deck objects + DJCi500.deckA = new DJCi500.Deck([1, 3], 1); + DJCi500.deckB = new DJCi500.Deck([2, 4], 2); + DJCi500.deckA.setCurrentDeck("[Channel1]"); + DJCi500.deckB.setCurrentDeck("[Channel2]"); + + // Update the fx rack selection + DJCi500.fxSelIndicator(0, "[EffectRack1_EffectUnit1]", 0, 0); + DJCi500.fxSelIndicator(0, "[EffectRack1_EffectUnit2]", 0, 0); + + DJCi500.fxEnabledIndicator(0, "[QuickEffectRack1_[Channel1]]", 0, 0); + DJCi500.fxEnabledIndicator(0, "[QuickEffectRack1_[Channel2]]", 0, 0); +}; + +// Crossfader control, set the curve +DJCi500.crossfaderSetCurve = function(channel, control, value, _status, _group) { + switch (value) { + case 0x00: + // Mix + script.crossfaderCurve(0, 0, 127); + DJCi500.xFaderScratch = false; + break; + case 0x7F: + // Scratch + script.crossfaderCurve(127, 0, 127); + DJCi500.xFaderScratch = true; + break; + } +}; + +// Crossfader enable or disable +DJCi500.crossfaderEnable = function(channel, control, value, _status, _group) { + if (value) { + DJCi500.crossfaderEnabled = true; + } else { + DJCi500.crossfaderEnabled = false; + engine.setValue("[Master]", "crossfader", 0); // Set the crossfader in the middle + } +}; + +// Crossfader function +DJCi500.crossfader = function(channel, control, value, status, group) { + if (DJCi500.crossfaderEnabled) { + // Eventine's crossfader scratch mode + if (DJCi500.xFaderScratch) { + let result = 0; + if (value <= 0) { + result = -1; + } else if (value >= 127) { + result = 1; + } else { + result = Math.tan((value-64)*Math.PI/2/63)/32; + } + engine.setValue(group, "crossfader", result); + } else { + engine.setValue(group, "crossfader", (value/64)-1); + } + } +}; + +// Browser button. We move it to a custom JS function to avoid having to focus the Mixxx window for it to respond +DJCi500.moveLibrary = function(channel, control, value, _status, _group) { + if (value > 0x3F) { + if (DJCi500.browserOffFocusMode) { + engine.setValue("[Playlist]", "SelectTrackKnob", -1); + } else { + engine.setValue("[Library]", "MoveUp", 1); + } + } else { + if (DJCi500.browserOffFocusMode) { + engine.setValue("[Playlist]", "SelectTrackKnob", 1); + } else { + engine.setValue("[Library]", "MoveDown", 1); + } + } +}; + +DJCi500.spinbackButton = function(channel, control, value, status, group) { + const deck = script.deckFromGroup(group); + engine.spinback(deck, value > 0, 2.5); // use default starting rate of -10 but decrease speed more quickly +}; + +// Update the Tempo and phase sync leds +DJCi500.tempoLEDs = function() { + // Current active decks + const deckA = DJCi500.deckA.currentDeck; + const deckB = DJCi500.deckB.currentDeck; + + // Tempo: + const tempo1 = engine.getValue(deckA, "bpm"); + const tempo2 = engine.getValue(deckB, "bpm"); + let diff = tempo1 - tempo2; + + // Check double tempo: + let doubleTempo = 0; + if (diff > 0) { + if ((tempo1 / tempo2) > 1.5) { + doubleTempo = 1; + diff = tempo1 / 2 - tempo2; + } + } else { + if ((tempo2 / tempo1) > 1.5) { + doubleTempo = 1; + diff = tempo1 - tempo2 / 2; + } + } + + if (diff < -0.25) { + // Deck1 + midi.sendShortMsg(0x91, 0x1E, 0x0); + midi.sendShortMsg(0x91, 0x1F, 0x7F); + midi.sendShortMsg(0x91, 0x2C, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1F, 0x0); + midi.sendShortMsg(0x92, 0x1E, 0x7F); + midi.sendShortMsg(0x92, 0x2C, 0x0); + + // clear beatalign leds + // Deck1 + midi.sendShortMsg(0x91, 0x1C, 0x0); + midi.sendShortMsg(0x91, 0x1D, 0x0); + midi.sendShortMsg(0x91, 0x2D, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1C, 0x0); + midi.sendShortMsg(0x92, 0x1D, 0x0); + midi.sendShortMsg(0x92, 0x2D, 0x0); + } else if (diff > 0.25) { + // Deck1 + midi.sendShortMsg(0x91, 0x1F, 0x0); + midi.sendShortMsg(0x91, 0x1E, 0x7F); + midi.sendShortMsg(0x91, 0x2C, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1E, 0x0); + midi.sendShortMsg(0x92, 0x1F, 0x7F); + midi.sendShortMsg(0x92, 0x2C, 0x0); + + // clear beatalign leds + // Deck1 + midi.sendShortMsg(0x91, 0x1C, 0x0); + midi.sendShortMsg(0x91, 0x1D, 0x0); + midi.sendShortMsg(0x91, 0x2D, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1C, 0x0); + midi.sendShortMsg(0x92, 0x1D, 0x0); + midi.sendShortMsg(0x92, 0x2D, 0x0); + } else { + // Deck1 + midi.sendShortMsg(0x91, 0x1E, 0x0); + midi.sendShortMsg(0x91, 0x1F, 0x0); + midi.sendShortMsg(0x91, 0x2C, 0x7F); + // Deck2 + midi.sendShortMsg(0x92, 0x1E, 0x0); + midi.sendShortMsg(0x92, 0x1F, 0x0); + midi.sendShortMsg(0x92, 0x2C, 0x7F); + + // Do beat alignment only if the tracks are already on Tempo + // and only if they are playing + if (engine.getValue(deckA, "play_latched") && engine.getValue(deckB, "play_latched")) { + let beat1 = engine.getValue(deckA, "beat_distance"); + let beat2 = engine.getValue(deckB, "beat_distance"); + if (doubleTempo) { + if (tempo1 > tempo2) { + if (beat2 > 0.5) { + beat2 -= 0.5; + } + beat2 *= 2; + } else { //tempo2 >(=) tempo1 + if (beat1 > 0.5) { + beat1 -= 0.5; + } + beat1 *= 2; + } + } + diff = beat1 - beat2; + if (diff < 0) { + diff = 1+diff; + } + if ((diff < 0.02) || (diff > 1-0.02)) { + // Deck1 + midi.sendShortMsg(0x91, 0x1C, 0x0); + midi.sendShortMsg(0x91, 0x1D, 0x0); + midi.sendShortMsg(0x91, 0x2D, 0x7F); + //Deck2 + midi.sendShortMsg(0x92, 0x1C, 0x0); + midi.sendShortMsg(0x92, 0x1D, 0x0); + midi.sendShortMsg(0x92, 0x2D, 0x7F); + } else if (diff < 0.5) { + // Deck1 + midi.sendShortMsg(0x91, 0x1C, 0x0); + midi.sendShortMsg(0x91, 0x1D, 0x7F); + midi.sendShortMsg(0x91, 0x2D, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1D, 0x0); + midi.sendShortMsg(0x92, 0x1C, 0x7F); + midi.sendShortMsg(0x91, 0x2D, 0x0); + } else { + // Deck1 + midi.sendShortMsg(0x91, 0x1D, 0x0); + midi.sendShortMsg(0x91, 0x1C, 0x7F); + midi.sendShortMsg(0x91, 0x2D, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1C, 0x0); + midi.sendShortMsg(0x92, 0x1D, 0x7F); + midi.sendShortMsg(0x92, 0x2D, 0x0); + } + // if playing + } else { + // Deck1 + midi.sendShortMsg(0x91, 0x1C, 0x0); + midi.sendShortMsg(0x91, 0x1D, 0x0); + midi.sendShortMsg(0x91, 0x2D, 0x0); + // Deck2 + midi.sendShortMsg(0x92, 0x1C, 0x0); + midi.sendShortMsg(0x92, 0x1D, 0x0); + midi.sendShortMsg(0x92, 0x2D, 0x0); + } + }// else tempo +}; + +// After a channel change, make sure we read the current status +DJCi500.updateDeckStatus = function(group) { + const playing = engine.getValue(group, "play_indicator"); + const volume = script.absoluteLinInverse(engine.getValue(group, "vu_meter"), 0.0, 1.0, 0, 127); + + // Update the vinyl button + let vinylState = false; + const deckIndex = script.deckFromGroup(group) - 1; + const channel = ((group === "[Channel1]") || (group === "[Channel3]")) ? 1 : 2; + if (channel === 1) { + vinylState = DJCi500.deckA.vinylButtonState[deckIndex]; + } else { + vinylState = DJCi500.deckB.vinylButtonState[deckIndex]; + } + midi.sendShortMsg(0x90 + channel, 0x03, (vinylState) ? 0x7F : 0x00); + midi.sendShortMsg(0xB0 + channel, 0x40, volume); + midi.sendShortMsg(0x90 + channel, 0x30, playing ? 0x7F : 0x00); + + // Update the fx rack selection + DJCi500.fxSelIndicator(0, "[EffectRack1_EffectUnit1]", 0, 0); + DJCi500.fxSelIndicator(0, "[EffectRack1_EffectUnit2]", 0, 0); + + DJCi500.fxEnabledIndicator(0, `[QuickEffectRack1_${group}]`, 0, 0); + + // Slicer + switch (group) { + case "[Channel1]": + DJCi500.slicerBeat1.disconnect(); + DJCi500.slicerBeat1 = engine.makeConnection("[Channel1]", "beat_active", DJCi500.slicerBeatActive); + DJCi500.slicerBeat1.trigger(); + break; + case "[Channel2]": + DJCi500.slicerBeat2.disconnect(); + DJCi500.slicerBeat2 = engine.makeConnection("[Channel2]", "beat_active", DJCi500.slicerBeatActive); + DJCi500.slicerBeat2.trigger(); + break; + case "[Channel3]": + DJCi500.slicerBeat1.disconnect(); + DJCi500.slicerBeat1 = engine.makeConnection("[Channel3]", "beat_active", DJCi500.slicerBeatActive); + DJCi500.slicerBeat1.trigger(); + break; + case "[Channel4]": + DJCi500.slicerBeat2.disconnect(); + DJCi500.slicerBeat2 = engine.makeConnection("[Channel4]", "beat_active", DJCi500.slicerBeatActive); + DJCi500.slicerBeat2.trigger(); + break; + }; +}; + +// This is where we choose the channel using the FX buttons and light them +// up correctly +DJCi500.deckSelector = function(channel, control, value, _status, _group) { + if (value === 0x7F) { + const deckChosen = control - 0x13; // FX1 is 0x14, so this will yield the number + switch (deckChosen) { + case 1: + DJCi500.deckA.setCurrentDeck("[Channel1]"); + DJCi500.updateDeckStatus("[Channel1]"); + midi.sendShortMsg(0x90, 0x14, 0x7F); + midi.sendShortMsg(0x90, 0x16, 0x00); + break; + case 2: + DJCi500.deckB.setCurrentDeck("[Channel2]"); + DJCi500.updateDeckStatus("[Channel2]"); + midi.sendShortMsg(0x90, 0x15, 0x7F); + midi.sendShortMsg(0x90, 0x17, 0x00); + break; + case 3: + DJCi500.deckA.setCurrentDeck("[Channel3]"); + DJCi500.updateDeckStatus("[Channel3]"); + midi.sendShortMsg(0x90, 0x14, 0x00); + midi.sendShortMsg(0x90, 0x16, 0x7F); + break; + case 4: + DJCi500.deckB.setCurrentDeck("[Channel4]"); + DJCi500.updateDeckStatus("[Channel4]"); + midi.sendShortMsg(0x90, 0x15, 0x00); + midi.sendShortMsg(0x90, 0x17, 0x7F); + break; + }; + }; +}; + +DJCi500.updateEffectStatus = function(midiChannel, _channel) { + let status = false; + for (let i = 1; i <= 3; i++) { + status = status || engine.getValue(`[EffectRack1_EffectUnit${midiChannel}_Effect${i}]`, "enabled"); + } + return status; + // return engine.getValue("[EffectRack1_EffectUnit" + midiChannel + "]", "group_[Channel" + channel + "]_enable"); +}; + +/////////////////////////////////////////////////////////////// +// SLICER // +/////////////////////////////////////////////////////////////// +DJCi500.slicerButtonFunc = function(channel, control, value, status, group) { + const index = control - 0x20; + const deck = script.deckFromGroup(group) - 1; + const domain = DJCi500.selectedSlicerDomain[deck]; + const passedTime = engine.getValue(group, "beat_distance"); + const loopEnabled = engine.getValue(group, "loop_enabled"); + + let beatsToJump = 0; + + if (value) { + DJCi500.slicerButton[deck] = index; + // Maybe I need to update this (seems sometimes it does not work.) + // DJCi500.slicerBeatsPassed[deck] = Math.floor((playposition * duration) * (bpm / 60.0)); + beatsToJump = (index * (domain / 8)) - ((DJCi500.slicerBeatsPassed[deck] % domain)); + beatsToJump -= passedTime; + + // activate the one-shot timer for the slip end. + if (!DJCi500.slicerTimer[deck]) { + DJCi500.slicerTimer[deck] = true; + let timerMs = (1-passedTime)*60.0/engine.getValue(group, "bpm")*1000; + + // quality of life fix for not-precise hands or beatgrid + // also good fix for really small timerMs values. + if ((passedTime >= 0.8) && + //this is because while looping doing this thing on beat 8 break the flow. + ((!loopEnabled) || (DJCi500.slicerBeatsPassed[deck] % domain) !== (domain-1))) { + timerMs += 60.0/engine.getValue(group, "bpm")*1000; + } + + engine.beginTimer(timerMs, + // "DJCi500.slicerTimerCallback("+group+")", true); + function() { + // need to do this otherwise loop does not work on beat 8 because of slip. + if ((engine.getValue(group, "loop_enabled") === true)) { + // on the wiki it says it returns an integer, but I tested and instead seems a Real value: + // But it does not work cuz the value does not relate to beat. they are samples. + // var endLoop = engine.getValue(group, "loop_end_position"); + engine.setValue(group, "reloop_toggle", true); //false + engine.setValue(group, "slip_enabled", false); + // Aleatory behavior, probably because the slip does not always have completed before "returning" + // so I need to introduce a timer waiting the slip function to be completely resolved + engine.beginTimer(2, function() { + engine.setValue(group, "reloop_toggle", true); + }, + true); + } else { + engine.setValue(group, "slip_enabled", false); + } + DJCi500.slicerTimer[deck] = false; + DJCi500.slicerButton[deck] = -1; + }, + true); + } + + engine.setValue(group, "slip_enabled", true); + + // Because of Mixxx beatjump implementation, we need to deactivate the loop before jumping + // also there is no "lopp_deactivate" and loop_activate false does not work. + if (loopEnabled) { + engine.setValue(group, "reloop_toggle", true); + } + engine.setValue(group, "beatjump", beatsToJump); + // This sadly does not work. + // engine.setValue(group, "loop_move", -beatsToJump); + if (loopEnabled) { + engine.setValue(group, "reloop_toggle", true); + } + midi.sendShortMsg((0x96+(deck % 2)), 0x20+index, 0x62); + } // if value +}; + +// This below is connected to beat_active +DJCi500.slicerBeatActive = function(value, group, _control) { + // This slicer implementation will work for constant beatgrids only! + const deck = script.deckFromGroup(group) - 1; + const channel = deck % 2; + + const bpm = engine.getValue(group, "file_bpm"), + playposition = engine.getValue(group, "playposition"), + duration = engine.getValue(group, "duration"), + ledBeatState = false, + domain = DJCi500.selectedSlicerDomain[deck]; + + let slicerPosInSection = 0; + + if (engine.getValue(group, "beat_closest") === engine.getValue(group, "beat_next")) { + return; + } + + DJCi500.slicerBeatsPassed[deck] = Math.floor((playposition * duration) * (bpm / 60.0)); + + if (DJCi500.slicerActive[deck]) { + slicerPosInSection = Math.floor((DJCi500.slicerBeatsPassed[deck] % domain) / (domain / 8)); + // PAD Led control: + if (DJCi500.slicerButton[deck] !== slicerPosInSection) { + for (let i = 0; i < 8; i++) { + const active = ((slicerPosInSection === i) ? ledBeatState : !ledBeatState) ? 0x03 : 0x7F; + midi.sendShortMsg((0x96+channel), 0x20+i, active); + } + } else { + midi.sendShortMsg((0x96+channel), 0x20+DJCi500.slicerButton[deck], 0x62); + } + } else { + DJCi500.slicerAlreadyJumped[deck] = false; + DJCi500.slicerPreviousBeatsPassed[deck] = 0; + } +}; + +DJCi500.shutdown = function() { + // Cleanup + midi.sendShortMsg(0x90, 0x05, 0x00); // Turn browser led off + midi.sendShortMsg(0xB0, 0x7F, 0x7E); + +}; diff --git a/res/controllers/Hercules_DJControl_Inpulse_500.midi.xml b/res/controllers/Hercules_DJControl_Inpulse_500.midi.xml new file mode 100644 index 000000000000..cc9317cdcbd5 --- /dev/null +++ b/res/controllers/Hercules_DJControl_Inpulse_500.midi.xml @@ -0,0 +1,3503 @@ + + + + Hercules DJControl Inpulse 500 + DJ Phatso, Event1ne and Reset Reboot + MIDI Preset for Hercules DJControl Inpulse 500 + https://www.mixxx.org/wiki/doku.php/hercules_djcontrol_inpulse_500 + https://mixxx.discourse.group/t/hercules-djcontrol-inpulse-500/19739 + + + + + + + + + + + + + [Library] + MoveFocus + Browser button + 0x90 + 0x00 + + + + + + + + [AutoDJ] + enabled + AutoDJ On/Off + 0x90 + 0x03 + + + + + + [Mixer Profile] + DJCi500.crossfaderEnable + CROSS FADER ENABLE + 0x90 + 0x18 + + + + + + + [Mixer Profile] + DJCi500.crossfaderSetCurve + CROSS FADER SET CURVE + 0xB0 + 0x0B + + + + + + + + + + [Channel1] + DJCi500.deckA.playButton.input + Play button + 0x91 + 0x07 + + + + + + + [Channel1] + DJCi500.deckA.cueButton.input + Cue button + 0x91 + 0x06 + + + + + + + [Channel1] + DJCi500.deckA.syncButton.input + Sync button + 0x91 + 0x05 + + + + + + + [Channel1] + DJCi500.deckA.pflButton.input + PFL button + 0x91 + 0x0C + + + + + + + [Channel1] + DJCi500.deckA.loadButton.input + LOAD A button + 0x91 + 0x0D + + + + + + + [Channel1] + DJCi500.deckA.loadButton.input + LOAD A button + 0x94 + 0x0D + + + + + + + [Channel1] + DJCi500.deckA.shiftButton.input + Shift Deck A button + 0x91 + 0x04 + + + + + + + [Channel1] + DJCi500.deckA.slipButton.input + SLIP button + 0x91 + 0x01 + + + + + + + [Channel1] + DJCi500.deckA.quantButton.input + Quantize button - Deck 1 + 0x91 + 0x02 + + + + + + + [Channel1] + DJCi500.deckA.quantButton.input + Keylock button (shift+quant) - Deck 1 + 0x94 + 0x02 + + + + + + + + [Master] + DJCi500.deckA.vinylButton.input + Vinyl Deck A + 0x91 + 0x03 + + + + + + + + [Channel1] + DJCi500.deckA.vinylButton.input + Shift + Vinyl Deck A + 0x94 + 0x03 + + + + + + + + [Channel1] + DJCi500.deckA.loopInButton.input + Loop In button + 0x91 + 0x09 + + + + + + [Channel1] + DJCi500.deckA.loopOutButton.input + Loop Out button + 0x91 + 0x0A + + + + + + + [Channel1] + DJCi500.deckA.loopInButton.input + S+Loop In button (loop in goto) + 0x94 + 0x09 + + + + + + [Channel1] + DJCi500.deckA.loopOutButton.input + S+Loop Out button (loop out goto) + 0x94 + 0x0A + + + + + + + + [Channel1] + DJCi500.deckA.loopEncoderPush.input + Loop Encoder Push button Deck A Reloop toggle + 0x91 + 0x2C + + + + + + + [Channel1] + DJCi500.deckA.loopEncoderPush.input + Loop Encoder Push button Deck A 4 Beat loop activate + 0x94 + 0x2C + + + + + + + + [Channel1] + DJCi500.deckA.loopEncoder.input + Loop Halve/Double (Loop Knob Deck A) + 0xB1 + 0x0E + + + + + + + + + + [Channel2] + DJCi500.deckB.playButton.input + Play button + 0x92 + 0x07 + + + + + + + [Channel2] + DJCi500.deckB.cueButton.input + Cue button + 0x92 + 0x06 + + + + + + + [Channel2] + DJCi500.deckB.syncButton.input + Sync button + 0x92 + 0x05 + + + + + + + [Channel2] + DJCi500.deckB.pflButton.input + PFL button + 0x92 + 0x0C + + + + + + + [Channel2] + DJCi500.deckB.loadButton.input + LOAD B button + 0x92 + 0x0D + + + + + + + [Channel2] + DJCi500.deckB.loadButton.input + LOAD B button + 0x95 + 0x0D + + + + + + + [Channel1] + DJCi500.deckB.shiftButton.input + Shift Deck A button + 0x92 + 0x04 + + + + + + + [Channel2] + DJCi500.deckB.slipButton.input + SLIP button + 0x92 + 0x01 + + + + + + + [Channel2] + DJCi500.deckB.quantButton.input + Quantize button - Deck 2 + 0x92 + 0x02 + + + + + + + [Channel2] + DJCi500.deckB.quantButton.input + Keylock button (shift+quant) - Deck 2 + 0x95 + 0x02 + + + + + + + + [Master] + DJCi500.deckB.vinylButton.input + Vinyl Deck B + 0x92 + 0x03 + + + + + + + + [Channel2] + DJCi500.deckB.vinylButton.input + Shift + Vinyl Deck B + 0x95 + 0x03 + + + + + + + + [Channel2] + DJCi500.deckB.loopInButton.input + Loop In button + 0x92 + 0x09 + + + + + + [Channel2] + DJCi500.deckB.loopOutButton.input + Loop Out button + 0x92 + 0x0A + + + + + + + [Channel2] + DJCi500.deckB.loopInButton.input + Loop In button (Loop In Goto) + 0x95 + 0x09 + + + + + + [Channel2] + DJCi500.deckB.loopOutButton.input + Loop Out button (loop out goto) + 0x95 + 0x0A + + + + + + + + [Channel2] + DJCi500.deckB.loopEncoderPush.input + Loop Encoder Push button Deck B (reloop toggle) + 0x92 + 0x2C + + + + + + + [Channel2] + DJCi500.deckB.loopEncoderPush.input + Loop Encoder Push button Deck B (beatloop 4 activated) + 0x95 + 0x2C + + + + + + + + + [Channel2] + DJCi500.deckB.loopEncoder.input + Loop Halve/Double (Loop Knob Deck B) + 0xB2 + 0x0E + + + + + + + + + + [Skin] + show_maximized_library + Browser button - Maximize Library view + 0x93 + 0x00 + + + + + + + + + + [Channel1] + DJCi500.deckA.playButton.input + SHIFT + Play: Play Stutter + 0x94 + 0x07 + + + + + + + [Channel1] + DJCi500.deckA.cueButton.input + SHIFT + Cue: REWIND to beginning + 0x94 + 0x06 + + + + + + + [Channel1] + DJCi500.deckA.syncButton.input + SHIFT + Sync: Match key + 0x94 + 0x05 + + + + + + + + + [Channel2] + DJCi500.deckB.playButton.input + SHIFT + Play: Play Stutter + 0x95 + 0x07 + + + + + + + [Channel2] + DJCi500.deckB.cueButton.input + SHIFT + Cue: REWIND to beginning + 0x95 + 0x06 + + + + + + + [Channel2] + DJCi500.deckB.syncButton.input + SHIFT + Sync: Sync key + 0x95 + 0x05 + + + + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[1].input + PAD select + 0x91 + 0x0F + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[2].input + PAD select + 0x91 + 0x10 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[3].input + PAD select + 0x91 + 0x11 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[4].input + PAD select + 0x91 + 0x12 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[5].input + PAD select + 0x91 + 0x13 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[6].input + PAD select + 0x91 + 0x14 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[7].input + PAD select + 0x91 + 0x15 + + + + + + [Channel1] + DJCi500.deckA.padSelectButtons[8].input + PAD select + 0x91 + 0x16 + + + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[1].input + PAD 1 + 0x96 + 0x00 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[2].input + PAD 2 + 0x96 + 0x01 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[3].input + PAD 3 + 0x96 + 0x02 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[4].input + PAD 4 + 0x96 + 0x03 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[5].input + PAD 5 + 0x96 + 0x04 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[6].input + PAD 6 + 0x96 + 0x05 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[7].input + PAD 7 + 0x96 + 0x06 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[8].input + PAD 8 + 0x96 + 0x07 + + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[1].input + PAD 1 + L-Shift + 0x96 + 0x08 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[2].input + PAD 2 + L-Shift + 0x96 + 0x09 + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[3].input + PAD 3 + L-Shift + 0x96 + 0x0A + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[4].input + PAD 4 + L-Shift + 0x96 + 0x0B + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[5].input + PAD 5 + L-Shift + 0x96 + 0x0C + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[6].input + PAD 6 + L-Shift + 0x96 + 0x0D + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[7].input + PAD 7 + L-Shift + 0x96 + 0x0E + + + + + + [Channel1] + DJCi500.deckA.hotcueButtons[8].input + PAD 8 + L-Shift + 0x96 + 0x0F + + + + + + + + [Channel1] + DJCi500.deckA.loopButtons[1].input + Loop 1/8 Beat (Pad 1) + 0x96 + 0x10 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[2].input + Loop 1/4 Beat (Pad 2) + 0x96 + 0x11 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[3].input + Loop 1/2 Beat (Pad 3) + 0x96 + 0x12 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[4].input + Loop 1 Beat (Pad 4) + 0x96 + 0x13 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[5].input + Loop 2 Beat (Pad 5) + 0x96 + 0x14 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[6].input + Loop 4 Beat (Pad 6) + 0x96 + 0x15 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[7].input + Loop 8 Beat (Pad 7) + 0x96 + 0x16 + + + + + + [Channel1] + DJCi500.deckA.loopButtons[8].input + Loop 16 Beat (Pad 8) + 0x96 + 0x17 + + + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[1].input + Loop 3/4 Beat (Pad 1) + 0x96 + 0x18 + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[2].input + Loop 5/4 Beat (Pad 2) + 0x96 + 0x19 + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[3].input + Loop 6/4 Beat (Pad 3) + 0x96 + 0x1A + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[4].input + Loop 7/4 Beat (Pad 4) + 0x96 + 0x1B + + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[5].input + Loop 32 Beat (Pad 5) + 0x96 + 0x1C + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[6].input + Loop 64 Beat (Pad 6) + 0x96 + 0x1D + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[7].input + Loop 128 Beat (Pad 7) + 0x96 + 0x1E + + + + + + [Channel1] + DJCi500.deckA.loopShiftButtons[8].input + Loop 256 Beat (Pad 8) + 0x96 + 0x1F + + + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[1].input + PAD 1 + 0x96 + 0x20 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[2].input + PAD 2 + 0x96 + 0x21 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[3].input + PAD 3 + 0x96 + 0x22 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[4].input + PAD 4 + 0x96 + 0x23 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[5].input + PAD 5 + 0x96 + 0x24 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[6].input + PAD 6 + 0x96 + 0x25 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[7].input + PAD 7 + 0x96 + 0x26 + + + + + + [Channel1] + DJCi500.deckA.slicerButtons[8].input + PAD 8 + 0x96 + 0x27 + + + + + + + + [Sampler1] + DJCi500.deckA.samplerButtons[1].input + PAD 1 + 0x96 + 0x30 + + + + + + [Sampler2] + DJCi500.deckA.samplerButtons[2].input + PAD 2 + 0x96 + 0x31 + + + + + + [Sampler3] + DJCi500.deckA.samplerButtons[3].input + PAD 3 + 0x96 + 0x32 + + + + + + [Sampler4] + DJCi500.deckA.samplerButtons[4].input + PAD 4 + 0x96 + 0x33 + + + + + + [Sampler5] + DJCi500.deckA.samplerButtons[5].input + PAD 5 + 0x96 + 0x34 + + + + + + [Sampler6] + DJCi500.deckA.samplerButtons[6].input + PAD 6 + 0x96 + 0x35 + + + + + + [Sampler7] + DJCi500.deckA.samplerButtons[7].input + PAD 7 + 0x96 + 0x36 + + + + + + [Sampler8] + DJCi500.deckA.samplerButtons[8].input + PAD 8 + 0x96 + 0x37 + + + + + + + + [Sampler1] + DJCi500.deckA.samplerButtons[1].input + PAD 1 + 0x96 + 0x38 + + + + + + [Sampler2] + DJCi500.deckA.samplerButtons[2].input + PAD 2 + 0x96 + 0x39 + + + + + + [Sampler3] + DJCi500.deckA.samplerButtons[3].input + PAD 3 + 0x96 + 0x3A + + + + + + [Sampler4] + DJCi500.deckA.samplerButtons[4].input + PAD 4 + 0x96 + 0x3B + + + + + + [Sampler5] + DJCi500.deckA.samplerButtons[5].input + PAD 5 + 0x96 + 0x3C + + + + + + [Sampler6] + DJCi500.deckA.samplerButtons[6].input + PAD 6 + 0x96 + 0x3D + + + + + + [Sampler7] + DJCi500.deckA.samplerButtons[7].input + PAD 7 + 0x96 + 0x3E + + + + + + [Sampler8] + DJCi500.deckA.samplerButtons[8].input + PAD 8 + 0x96 + 0x3F + + + + + + + + [Channel1] + DJCi500.deckA.pitchDownTone.input + Pitch down - tone + 0x96 + 0x40 + + + + + + [Channel1] + DJCi500.deckA.pitchDownSemiTone.input + Pitch down - semitone + 0x96 + 0x41 + + + + + + [Channel1] + DJCi500.deckA.pitchUpSemiTone.input + Pitch up - semitone + 0x96 + 0x42 + + + + + + [Channel1] + DJCi500.deckA.pitchUpTone.input + Pitch up - tone + 0x96 + 0x43 + + + + + + [Channel1] + DJCi500.deckA.pitchSliderIncrease.input + Pitch slider increase resolution + 0x96 + 0x46 + + + + + + [Channel1] + DJCi500.deckA.pitchSliderDecrease.input + Pitch slider Decrease resolution + 0x96 + 0x45 + + + + + + [Channel1] + DJCi500.deckA.pitchSliderReset.input + Pitch slider Reset resolution + 0x96 + 0x44 + + + + + + + + [Channel1] + DJCi500.deckA.rollButtons[1].input + Loop 1/8 Beat (Pad 1) + 0x96 + 0x50 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[2].input + Loop 1/4 Beat (Pad 2) + 0x96 + 0x51 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[3].input + Loop 1/2 Beat (Pad 3) + 0x96 + 0x52 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[4].input + Loop 1 Beat (Pad 4) + 0x96 + 0x53 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[5].input + Loop 2 Beat (Pad 5) + 0x96 + 0x54 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[6].input + Loop 2 Beat (Pad 6) + 0x96 + 0x55 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[7].input + Loop 8 Beat (Pad 7) + 0x96 + 0x56 + + + + + + [Channel1] + DJCi500.deckA.rollButtons[8].input + Loop 2 Beat (Pad 8) + 0x96 + 0x57 + + + + + + + + [Channel1] + DJCi500.deckA.effectButtons[1].input + PAD 1 + 0x96 + 0x60 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[2].input + PAD 2 + 0x96 + 0x61 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[3].input + PAD 3 + 0x96 + 0x62 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[4].input + PAD 4 + 0x96 + 0x63 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[5].input + PAD 5 + 0x96 + 0x64 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[6].input + PAD 6 + 0x96 + 0x65 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[7].input + PAD 7 + 0x96 + 0x66 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[8].input + PAD 8 + 0x96 + 0x67 + + + + + + + + [Channel1] + DJCi500.deckA.effectButtons[1].input + PAD 1 + 0x96 + 0x68 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[2].input + PAD 2 + 0x96 + 0x69 + + + + + + [Channel1] + DJCi500.deckA.effectButtons[3].input + PAD 3 + 0x96 + 0x6A + + + + + + [Channel1] + DJCi500.deckA.effectButtons[4].input + PAD 4 + 0x96 + 0x6B + + + + + + [Channel1] + DJCi500.deckA.effectButtons[5].input + PAD 5 + 0x96 + 0x6C + + + + + + [Channel1] + DJCi500.deckA.effectButtons[6].input + PAD 6 + 0x96 + 0x6D + + + + + + [Channel1] + DJCi500.deckA.effectButtons[7].input + PAD 7 + 0x96 + 0x6E + + + + + + [Channel1] + DJCi500.deckA.effectButtons[8].input + PAD 8 + 0x96 + 0x6F + + + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[1].input + Beat jump 1 backward + 0x96 + 0x70 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[2].input + Beat jump 1 forward + 0x96 + 0x71 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[3].input + Beat jump 2 backward + 0x96 + 0x72 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[4].input + Beat jump 2 forward + 0x96 + 0x73 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[5].input + Beat jump 4 backward + 0x96 + 0x74 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[6].input + Beat jump 4 forward + 0x96 + 0x75 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[7].input + Beat jump 8 backward + 0x96 + 0x76 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[8].input + Beat jump 8 forward + 0x96 + 0x77 + + + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[1].input + Beat jump 16 backward + 0x96 + 0x78 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[2].input + Beat jump 16 forward + 0x96 + 0x79 + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[3].input + Beat jump 32 backward + 0x96 + 0x7A + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[4].input + Beat jump 32 forward + 0x96 + 0x7B + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[5].input + Beat jump 64 backward + 0x96 + 0x7C + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[6].input + Beat jump 64 forward + 0x96 + 0x7D + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[7].input + Beat jump 128 backward + 0x96 + 0x7E + + + + + + [Channel1] + DJCi500.deckA.beatJumpButtons[8].input + Beat jump 128 forward + 0x96 + 0x7F + + + + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[1].input + PAD select + 0x92 + 0x0F + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[2].input + PAD select + 0x92 + 0x10 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[3].input + PAD select + 0x92 + 0x11 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[4].input + PAD select + 0x92 + 0x12 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[5].input + PAD select + 0x92 + 0x13 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[6].input + PAD select + 0x92 + 0x14 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[7].input + PAD select + 0x92 + 0x15 + + + + + + [Channel2] + DJCi500.deckB.padSelectButtons[8].input + PAD select + 0x92 + 0x16 + + + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[1].input + PAD 1 + 0x97 + 0x00 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[2].input + PAD 2 + 0x97 + 0x01 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[3].input + PAD 3 + 0x97 + 0x02 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[4].input + PAD 4 + 0x97 + 0x03 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[5].input + PAD 5 + 0x97 + 0x04 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[6].input + PAD 6 + 0x97 + 0x05 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[7].input + PAD 7 + 0x97 + 0x06 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[8].input + PAD 8 + 0x97 + 0x07 + + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[1].input + PAD 1 + R-Shift + 0x97 + 0x08 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[2].input + PAD 2 + R-Shift + 0x97 + 0x09 + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[3].input + PAD 3 + R-Shift + 0x97 + 0x0A + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[4].input + PAD 4 + R-Shift + 0x97 + 0x0B + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[5].input + PAD 5 + R-Shift + 0x97 + 0x0C + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[6].input + PAD 6 + R-Shift + 0x97 + 0x0D + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[7].input + PAD 7 + R-Shift + 0x97 + 0x0E + + + + + + [Channel2] + DJCi500.deckB.hotcueButtons[8].input + PAD 8 + R-Shift + 0x97 + 0x0F + + + + + + + [Channel2] + DJCi500.deckB.loopButtons[1].input + Loop 1/8 Beat (Pad 1) + 0x97 + 0x10 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[2].input + Loop 1/4 Beat (Pad 2) + 0x97 + 0x11 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[3].input + Loop 1/2 Beat (Pad 3) + 0x97 + 0x12 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[4].input + Loop 1 Beat (Pad 4) + 0x97 + 0x13 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[5].input + Loop 2 Beat (Pad 5) + 0x97 + 0x14 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[6].input + Loop 4 Beat (Pad 6) + 0x97 + 0x15 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[7].input + Loop 8 Beat (Pad 7) + 0x97 + 0x16 + + + + + + [Channel2] + DJCi500.deckB.loopButtons[8].input + Loop 16 Beat (Pad 8) + 0x97 + 0x17 + + + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[1].input + Loop 3/4 Beat (Pad 1) + 0x97 + 0x18 + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[2].input + Loop 5/4 Beat (Pad 2) + 0x97 + 0x19 + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[3].input + Loop 6/4 Beat (Pad 3) + 0x97 + 0x1A + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[4].input + Loop 7/4 Beat (Pad 4) + 0x97 + 0x1B + + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[5].input + Loop 32 Beat (Pad 5) + 0x97 + 0x1C + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[6].input + Loop 64 Beat (Pad 6) + 0x97 + 0x1D + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[7].input + Loop 128 Beat (Pad 7) + 0x97 + 0x1E + + + + + + [Channel2] + DJCi500.deckB.loopShiftButtons[8].input + Loop 256 Beat (Pad 8) + 0x97 + 0x1F + + + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[1].input + PAD 1 + 0x97 + 0x20 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[2].input + PAD 2 + 0x97 + 0x21 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[3].input + PAD 3 + 0x97 + 0x22 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[4].input + PAD 4 + 0x97 + 0x23 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[5].input + PAD 5 + 0x97 + 0x24 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[6].input + PAD 6 + 0x97 + 0x25 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[7].input + PAD 7 + 0x97 + 0x26 + + + + + + [Channel2] + DJCi500.deckB.slicerButtons[8].input + PAD 8 + 0x97 + 0x27 + + + + + + + + [Sampler1] + DJCi500.deckB.samplerButtons[1].input + PAD 1 + 0x97 + 0x30 + + + + + + [Sampler2] + DJCi500.deckB.samplerButtons[2].input + PAD 2 + 0x97 + 0x31 + + + + + + [Sampler3] + DJCi500.deckB.samplerButtons[3].input + PAD 3 + 0x97 + 0x32 + + + + + + [Sampler4] + DJCi500.deckB.samplerButtons[4].input + PAD 4 + 0x97 + 0x33 + + + + + + [Sampler5] + DJCi500.deckB.samplerButtons[5].input + PAD 5 + 0x97 + 0x34 + + + + + + [Sampler6] + DJCi500.deckB.samplerButtons[6].input + PAD 6 + 0x97 + 0x35 + + + + + + [Sampler7] + DJCi500.deckB.samplerButtons[7].input + PAD 7 + 0x97 + 0x36 + + + + + + [Sampler8] + DJCi500.deckB.samplerButtons[8].input + PAD 8 + 0x97 + 0x37 + + + + + + + + [Sampler1] + DJCi500.deckB.samplerButtons[1].input + PAD 1 + 0x97 + 0x38 + + + + + + [Sampler2] + DJCi500.deckB.samplerButtons[2].input + PAD 2 + 0x97 + 0x39 + + + + + + [Sampler3] + DJCi500.deckB.samplerButtons[3].input + PAD 3 + 0x97 + 0x3A + + + + + + [Sampler4] + DJCi500.deckB.samplerButtons[4].input + PAD 4 + 0x97 + 0x3B + + + + + + [Sampler5] + DJCi500.deckB.samplerButtons[5].input + PAD 5 + 0x97 + 0x3C + + + + + + [Sampler6] + DJCi500.deckB.samplerButtons[6].input + PAD 6 + 0x97 + 0x3D + + + + + + [Sampler7] + DJCi500.deckB.samplerButtons[7].input + PAD 7 + 0x97 + 0x3E + + + + + + [Sampler8] + DJCi500.deckB.samplerButtons[8].input + PAD 8 + 0x97 + 0x3F + + + + + + + + + [Channel2] + DJCi500.deckB.pitchUpSemiTone.input + Pitch up - semitone + 0x97 + 0x42 + + + + + + [Channel2] + DJCi500.deckB.pitchDownSemiTone.input + Pitch down - semitone + 0x97 + 0x41 + + + + + + [Channel2] + DJCi500.deckB.pitchUpTone.input + Pitch up - tone + 0x97 + 0x43 + + + + + + [Channel2] + DJCi500.deckB.pitchDownTone.input + Pitch down - tone + 0x97 + 0x40 + + + + + + [Channel2] + DJCi500.deckB.pitchSliderIncrease.input + Pitch slider increase resolution + 0x97 + 0x46 + + + + + + [Channel2] + DJCi500.deckB.pitchSliderDecrease.input + Pitch slider Decrease resolution + 0x97 + 0x45 + + + + + + [Channel2] + DJCi500.deckB.pitchSliderReset.input + Pitch slider Reset resolution + 0x97 + 0x44 + + + + + + + + [Channel2] + DJCi500.deckB.rollButtons[1].input + Loop 1/8 Beat (Pad 1) + 0x97 + 0x50 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[2].input + Loop 1/4 Beat (Pad 2) + 0x97 + 0x51 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[3].input + Loop 1/2 Beat (Pad 3) + 0x97 + 0x52 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[4].input + Loop 1 Beat (Pad 4) + 0x97 + 0x53 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[5].input + Loop 2 Beat (Pad 5) + 0x97 + 0x54 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[6].input + Loop 2 Beat (Pad 6) + 0x97 + 0x55 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[7].input + Loop 8 Beat (Pad 7) + 0x97 + 0x56 + + + + + + [Channel2] + DJCi500.deckB.rollButtons[8].input + Loop 2 Beat (Pad 8) + 0x97 + 0x57 + + + + + + + + [Channel2] + DJCi500.deckB.effectButtons[1].input + PAD 1 + 0x97 + 0x60 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[2].input + PAD 2 + 0x97 + 0x61 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[3].input + PAD 3 + 0x97 + 0x62 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[4].input + PAD 4 + 0x97 + 0x63 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[5].input + PAD 5 + 0x97 + 0x64 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[6].input + PAD 6 + 0x97 + 0x65 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[7].input + PAD 7 + 0x97 + 0x66 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[8].input + PAD 8 + 0x97 + 0x67 + + + + + + + + [Channel2] + DJCi500.deckB.effectButtons[1].input + PAD 1 + 0x97 + 0x68 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[2].input + PAD 2 + 0x97 + 0x69 + + + + + + [Channel2] + DJCi500.deckB.effectButtons[3].input + PAD 3 + 0x97 + 0x6A + + + + + + [Channel2] + DJCi500.deckB.effectButtons[4].input + PAD 4 + 0x97 + 0x6B + + + + + + [Channel2] + DJCi500.deckB.effectButtons[5].input + PAD 5 + 0x97 + 0x6C + + + + + + [Channel2] + DJCi500.deckB.effectButtons[6].input + PAD 6 + 0x97 + 0x6D + + + + + + [Channel2] + DJCi500.deckB.effectButtons[7].input + PAD 7 + 0x97 + 0x6E + + + + + + [Channel2] + DJCi500.deckB.effectButtons[8].input + PAD 8 + 0x97 + 0x6F + + + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[1].input + Beat jump 1 backward + 0x97 + 0x70 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[2].input + Beat jump 1 forward + 0x97 + 0x71 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[3].input + Beat jump 2 backward + 0x97 + 0x72 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[4].input + Beat jump 2 forward + 0x97 + 0x73 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[5].input + Beat jump 4 backward + 0x97 + 0x74 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[6].input + Beat jump 4 forward + 0x97 + 0x75 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[7].input + Beat jump 8 backward + 0x97 + 0x76 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[8].input + Beat jump 8 forward + 0x97 + 0x77 + + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[1].input + Beat jump 16 backward + 0x97 + 0x78 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[2].input + Beat jump 16 forward + 0x97 + 0x79 + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[3].input + Beat jump 32 backward + 0x97 + 0x7A + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[4].input + Beat jump 32 forward + 0x97 + 0x7B + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[5].input + Beat jump 64 backward + 0x97 + 0x7C + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[6].input + Beat jump 64 forward + 0x97 + 0x7D + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[7].input + Beat jump 128 backward + 0x97 + 0x7E + + + + + + [Channel1] + DJCi500.deckB.beatJumpButtons[8].input + Beat jump 128 forward + 0x97 + 0x7F + + + + + + + + + + + [Master] + DJCi500.crossfader + Crossfader + 0xB0 + 0x00 + + + + + + + [Library] + DJCi500.moveLibrary + Move Vertical (Browser Knob) + 0xB0 + 0x01 + + + + + + [Library] + MoveHorizontal + Move Horizontal (Browser Knob) + 0xB3 + 0x01 + + + + + + + + + + [Channel1] + DJCi500.deckA.volume.inputMSB + Volume Deck A + 0xB1 + 0x00 + + + + + + [Channel1] + DJCi500.deckA.volume.inputLSB + Volume Deck A + 0xB1 + 0x20 + + + + + + + [Channel1] + DJCi500.deckA.volume.inputMSB + Volume Deck A + 0xB4 + 0x00 + + + + + + [Channel1] + DJCi500.deckA.volume.inputLSB + Volume Deck A + 0xB4 + 0x20 + + + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[1].inputMSB + EQ LOW Deck A + 0xB1 + 0x02 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[1].inputLSB + EQ LOW Deck A + 0xB1 + 0x22 + + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[2].inputMSB + EQ MID Deck A + 0xB1 + 0x03 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[2].inputLSB + EQ MID Deck A + 0xB1 + 0x23 + + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[3].inputMSB + EQ HIGH Deck A + 0xB1 + 0x04 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + DJCi500.deckA.eqKnob[3].inputLSB + EQ HIGH Deck A + 0xB1 + 0x24 + + + + + + + [Channel1] + DJCi500.deckA.gainKnob.inputMSB + Gain Deck A + 0xB1 + 0x05 + + + + + + [Channel1] + DJCi500.deckA.gainKnob.inputLSB + Gain Deck A + 0xB1 + 0x25 + + + + + + + [Channel1] + DJCi500.deckA.filterKnob.input + Filter Deck A + 0xB1 + 0x01 + + + + + + + [Channel1] + DJCi500.deckA.pitchFader.inputMSB + 0xB1 + 0x08 + + + + + + [Channel1] + DJCi500.deckA.pitchFader.inputLSB + 0xB1 + 0x28 + + + + + + + [Channel1] + DJCi500.deckA.pitchFader.inputMSB + 0xB4 + 0x08 + + + + + + [Channel1] + DJCi500.deckA.pitchFader.inputLSB + 0xB4 + 0x28 + + + + + + + [Channel1] + DJCi500.deckA.jogWheel.inputTouch + Jog Wheel Touch Deck A + 0x91 + 0x08 + + + + + + [Channel1] + DJCi500.deckA.jogWheel.inputTouch + Jog Wheel Touch Deck A + 0xB1 + 0x0C + + + + + + [Channel1] + DJCi500.deckA.jogWheel.inputWheel + Scratch Deck A (Jog-Wheel) + 0xB1 + 0x0A + + + + + + [Channel1] + DJCi500.deckA.jogWheel.inputWheel + Pitch Bend Deck A (Jog-Wheel) + 0xB1 + 0x09 + + + + + + + [Channel1] + DJCi500.deckA.jogWheel.inputTouch + Jog Wheel Touch Deck A + 0x94 + 0x08 + + + + + + [Channel1] + DJCi500.deckA.jogWheelShift.inputTouch + Jog Wheel Shift Touch Deck A + 0xB4 + 0x0C + + + + + + [Channel1] + DJCi500.deckA.jogWheelShift.inputWheel + Scratch Deck A (Jog-Wheel) + 0xB4 + 0x0A + + + + + + [Channel1] + DJCi500.deckA.jogWheelShift.inputWheel + Pitch Bend Deck A (Jog-Wheel) + 0xB4 + 0x09 + + + + + + + + + [Channel2] + DJCi500.deckB.volume.inputMSB + Volume Deck B + 0xB2 + 0x00 + + + + + + [Channel2] + DJCi500.deckB.volume.inputLSB + Volume Deck B + 0xB5 + 0x20 + + + + + + + [Channel2] + DJCi500.deckB.volume.inputMSB + Volume Deck B + 0xB5 + 0x00 + + + + + + [Channel2] + DJCi500.deckB.volume.inputLSB + Volume Deck B + 0xB2 + 0x20 + + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[1].inputMSB + EQ LOW Deck B + 0xB2 + 0x02 + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[1].inputLSB + EQ LOW Deck B + 0xB2 + 0x22 + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[2].inputMSB + EQ MID Deck B + 0xB2 + 0x03 + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[2].inputLSB + EQ MID Deck B + 0xB2 + 0x23 + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[3].inputMSB + EQ HIGH Deck B + 0xB2 + 0x04 + + + + + + [EqualizerRack1_[Channel2]_Effect1] + DJCi500.deckB.eqKnob[3].inputLSB + EQ HIGH Deck B + 0xB2 + 0x24 + + + + + + + [Channel2] + DJCi500.deckB.gainKnob.inputMSB + Gain Deck A + 0xB2 + 0x05 + + + + + + [Channel2] + DJCi500.deckB.gainKnob.inputLSB + Gain Deck A + 0xB2 + 0x25 + + + + + + + [Channel2] + DJCi500.deckB.filterKnob.input + Filter Deck B + 0xB2 + 0x01 + + + + + + + [Channel2] + DJCi500.deckB.pitchFader.inputMSB + 0xB2 + 0x08 + + + + + + [Channel2] + DJCi500.deckB.pitchFader.inputLSB + 0xB2 + 0x28 + + + + + + + [Channel2] + DJCi500.deckB.pitchFader.inputMSB + 0xB5 + 0x08 + + + + + + [Channel2] + DJCi500.deckB.pitchFader.inputLSB + 0xB5 + 0x28 + + + + + + + [Channel2] + DJCi500.deckB.jogWheel.inputTouch + Jog Wheel Touch Deck B + 0x92 + 0x08 + + + + + + [Channel2] + DJCi500.deckB.jogWheel.inputTouch + Jog Wheel Touch Deck B + 0xB2 + 0x0C + + + + + + [Channel2] + DJCi500.deckB.jogWheel.inputWheel + Scratch Deck B (Jog-Wheel) + 0xB2 + 0x0A + + + + + + [Channel2] + DJCi500.deckB.jogWheel.inputWheel + Pitch Bend Deck B (Jog-Wheel) + 0xB2 + 0x09 + + + + + + + [Channel2] + DJCi500.deckB.jogWheel.inputTouch + Jog Wheel Touch Deck B + 0x95 + 0x08 + + + + + + [Channel2] + DJCi500.deckB.jogWheelShift.inputTouch + Jog Wheel Shift Touch Deck B + 0xB5 + 0x0C + + + + + + [Channel2] + DJCi500.deckB.jogWheelShift.inputWheel + Scratch Deck B (Jog-Wheel) + 0xB5 + 0x0A + + + + + + [Channel2] + DJCi500.deckB.jogWheelShift.inputWheel + Pitch Bend Deck B (Jog-Wheel) + 0xB5 + 0x09 + + + + + + + + + + [Channel] + DJCi500.deckSelector + Activate Deck1 (FX1 button) + 0x90 + 0x14 + + + + + + + [Channel] + DJCi500.deckSelector + Activate Deck2 (FX2 button) + 0x90 + 0x15 + + + + + + + [Channel] + DJCi500.deckSelector + Activate Deck3 (FX3 button) + 0x90 + 0x16 + + + + + + + [Channel] + DJCi500.deckSelector + Activate Deck4 (FX4 button) + 0x90 + 0x17 + + + + + + + + + + + + + [Library] + MoveFocus + Browser LED (Green) + 0.5 + 1 + 0x90 + 0x05 + 0x10 + 0x05 + + + [Skin] + show_maximized_library + Browser LED (BLUE) + 0.5 + 1 + 0x90 + 0x05 + 0x05 + 0x10 + + + + [AutoDJ] + enabled + Auto DJ On + 0.5 + 1 + 0x90 + 0x03 + 0x7f + 0x0 + + + +