// Korg KAOSS DJ controller mapping for Mixxx // Seb Dooris, Fayaaz Ahmed, Lee Arromba var KAOSSDJ = {}; var ON = 0x7F, OFF = 0x00, UP = 0x01, DOWN = 0x7F; var ledChannel = { 'btnsL': 0x97, 'btnsR': 0x98, 'knobsL': 0xB7, 'knobsR': 0xB8, 'master': 0xB6 }; var led = { 'cue': 0x1E, 'sync': 0x1D, 'play': 0x1B, 'headphones': 0x19, 'fx': 0x18, // warning: led is owned by controller 'stripL': 0x15, 'stripM': 0x16, 'stripR': 0x17, 'loopStripL': 0x0F, 'loopStripM': 0x10, 'loopStripR': 0x11, }; // initialise decks KAOSSDJ.deck = function(deckNumber) { this.deckNumber = deckNumber; this.group = "[Channel" + deckNumber + "]"; this.jogWheelsInScratchMode = true; this.fx = false; }; KAOSSDJ.decks = []; for (var i = 0; i < 4; i++) { // TODO: currently only 2 decks supported. is 4 possible? KAOSSDJ.decks[i] = new KAOSSDJ.deck(i+1); } // ==== lifecycle ==== KAOSSDJ.init = function(id, debugging) { // turn on main led channels var ledChannels = [ ledChannel['knobsL'], ledChannel['knobsR'], ledChannel['master'] ] for (var led = 0x00; led <= 0xFF; led++) { for (var i = 0; i < ledChannels.length; i++) { midi.sendShortMsg(ledChannels[i], led, ON); } } // This message was copied from communication with Serato DJ Intro & Midi Monitor // It should setup mixxx from the controller defaults var ControllerStatusSysex = [0xF0, 0x42, 0x40, 0x00, 0x01, 0x28, 0x00, 0x1F, 0x70, 0x01, 0xF7]; midi.sendSysexMsg(ControllerStatusSysex, ControllerStatusSysex.length); }; KAOSSDJ.shutdown = function(id, debugging) { // turn off all LEDs for (var led = 0x00; led <= 0xFF; led++) { for (key in ledChannel) { midi.sendShortMsg(ledChannel[key], led, OFF); } } }; // ==== helper ==== KAOSSDJ.getDeckIndexFromChannel = function(channel) { return channel - 7 }; KAOSSDJ.getDeckByChannel = function(channel) { var deckIndex = KAOSSDJ.getDeckIndexFromChannel(channel); return KAOSSDJ.decks[deckIndex]; }; KAOSSDJ.updateDeckByChannel = function(channel, key, value) { var deckIndex = KAOSSDJ.getDeckIndexFromChannel(channel); KAOSSDJ.decks[deckIndex][key] = value; }; // ==== mapped functions ==== KAOSSDJ.wheelTouch = function(channel, control, value, status, group) { var alpha = 1.0 / 8; var beta = alpha / 32; var deck = KAOSSDJ.getDeckByChannel(channel); var deckNumber = deck.deckNumber; var deck_playing = engine.getValue('[Channel' + deckNumber + ']', 'play_indicator'); // If in scratch mode or not playing enable vinyl-like control if (deck.jogWheelsInScratchMode || !deck_playing ) { if (value === ON) { // Enable scratching on touch engine.scratchEnable(deckNumber, 128, 33 + 1 / 3, alpha, beta); } else if (value === OFF) { // Disable scratching engine.scratchDisable(deckNumber); } } }; KAOSSDJ.wheelTurn = function(channel, control, value, status, group) { var deck = KAOSSDJ.getDeckByChannel(channel); var deckNumber = deck.deckNumber; var newValue = 0; if (value < 64) { newValue = value; } else { newValue = value - 128; } if (engine.isScratching(deckNumber)) { engine.scratchTick(deckNumber, newValue); } else { engine.setValue('[Channel' + deckNumber + ']', 'jog', newValue); // Pitch bend } }; KAOSSDJ.wheelTurnShift = function(channel, control, value, status, group) { var deck = KAOSSDJ.getDeckByChannel(channel); if (deck.jogWheelsInScratchMode) { // Fast scratch var newValue = 0; if (value < 64) { newValue = value; } else { newValue = value - 128; } newValue = newValue * 4; // multiplier (to speed it up) engine.scratchTick(deck.deckNumber, newValue); } else { // Move beatgrid if(value === UP){ engine.setValue(deck.group, 'beats_translate_later', true); } else if (value === DOWN){ engine.setValue(deck.group, 'beats_translate_earlier', true); } } }; KAOSSDJ.scratchMode = function(channel, control, value, status, group) { if (value === ON) { // Turn scratch mode on jogwheel (LED is red) KAOSSDJ.updateDeckByChannel(channel, 'jogWheelsInScratchMode', true); } else if (value === OFF) { // Turn scratch mode on jogwheel (LED is off) KAOSSDJ.updateDeckByChannel(channel, 'jogWheelsInScratchMode', false); } }; KAOSSDJ.browseKnob = function(channel, control, value, status, group) { var nval = (value > 0x40 ? value - 0x80 : value); engine.setValue(group, "SelectTrackKnob", nval); }; KAOSSDJ.leftFxSwitch = function(channel, control, value, status, group) { var deck = KAOSSDJ.getDeckByChannel(channel); if(value === ON) { KAOSSDJ.updateDeckByChannel(channel, 'fx', true); } else { KAOSSDJ.updateDeckByChannel(channel, 'fx', false); } }; KAOSSDJ.rightFxSwitch = function(channel, control, value, status, group) { if(value === ON) { KAOSSDJ.updateDeckByChannel(channel, 'fx', true); } else { KAOSSDJ.updateDeckByChannel(channel, 'fx', false); } }; KAOSSDJ.controllerFxTouchMoveVertical = function(channel, control, value, status, group) { var decks = KAOSSDJ.decks; for(key in decks) { var deck = decks[key]; if(deck.fx) { engine.setValue('[EffectRack1_EffectUnit'+deck.deckNumber +']', 'mix', value / 127); } } }; KAOSSDJ.controllerFxTouchMoveHorizontal = function(channel, control, value, status, group) { var decks = KAOSSDJ.decks; for(key in decks) { var deck = decks[key]; if(deck.fx) { engine.setValue('[EffectRack1_EffectUnit'+deck.deckNumber +']', 'super1', value / 127); } } }; KAOSSDJ.controllerFxTouchUp = function(channel, control, value, status, group) { var deck = KAOSSDJ.getDeckByChannel(channel); engine.setValue('[EffectRack1_EffectUnit'+deck.deckNumber +']', 'mix', 0); engine.setValue('[EffectRack1_EffectUnit'+deck.deckNumber +']', 'super1', 0); };