Last active
November 3, 2024 12:07
-
-
Save mxmilkiib/daa69382047f21ea0e57535d60e66e66 to your computer and use it in GitHub Desktop.
Launchpad Pro MK3 MIDI mapping
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var LaunchpadProMK3 = {} | |
// console.log("LOG channel " + channel + " control " + control + " value " + value + " status " + status + " group " + group) | |
LaunchpadProMK3.sleep = function(time) { | |
var then = Date.now(); | |
while (true) { | |
var now = Date.now(); | |
if (now - then > time) { | |
break; | |
} | |
} | |
} | |
LaunchpadProMK3.create4LeadupDropHotcues = function (deck, value) { | |
// LaunchpadProMK3.create4LeadupDropHotcues = function (deck, value) { | |
console.log("create4LDH, deck " + deck, "value " + value) | |
// console.log("LOG channel " + channel + " control " + _control + " value " + value + " status " + _status + " group " + group) | |
if (value === 0 || value === undefined) return 0 | |
group = `[Channel${deck}]` | |
for (let X = 1; X <= 64; X++) { | |
let hotcueVariable = "hotcue_" + X + "_status" | |
if (engine.getValue(group, hotcueVariable) === 0) { | |
X += 3 | |
hotcueFocus = "hotcue_"+X+"_set" | |
engine.setValue(group,hotcueFocus, 1) | |
hotcueColourFocus = "hotcue_"+X+"_color" | |
engine.setValue(group,hotcueColourFocus, 0x32be44) // green | |
engine.setValue(group, "beatjump_16_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-1)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-1)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_16_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-2)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-2)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_32_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-3)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-3)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_64_forward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group, "intro_end_activate", 1) | |
return | |
} | |
} | |
} | |
LaunchpadProMK3.selectDeck = function(deck) { | |
LaunchpadProMK3.selectedDeck = deck | |
} | |
LaunchpadProMK3.undoHotcue = function(deck) { | |
} | |
// WIP | |
LaunchpadProMK3.hotcueColourSwitch = function(deck,direction) { | |
engine.setValue(`[Channel${deck}]`,`hotcue_focus_color_${direction}`, 1) | |
} | |
LaunchpadProMK3.initExtras = function() { | |
// deck 3 | |
midi.makeInputHandler(0xB0, 0x65, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(3) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x65, 0x7F, 0x00, 0x7F) | |
// deck 1 | |
midi.makeInputHandler(0xB0, 0x66, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(1) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x66, 0x1D, 0x46, 0x7B) | |
// deck 2 | |
midi.makeInputHandler(0xB0, 0x67, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(2) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x67, 0x7F, 0x58, 0x04) | |
// deck 4 | |
midi.makeInputHandler(0xB0, 0x68, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(4) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x68, 0x44, 0x60, 0x0D) | |
// create multi hotcues | |
midi.makeInputHandler(0xB0, 0x03, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.create4LeadupDropHotcues(LaunchpadProMK3.selectedDeck, value) } | |
}) | |
LaunchpadProMK3.sendRGB(0x03, 0x7F, 0x7F, 0x7F) | |
// undo WIP | |
midi.makeInputHandler(0xB0, 0x01, (channel, control, value, status, group) => { | |
// if (value) { LaunchpadProMK3.undoHotcue(LaunchpadProMK3.selectedDeck, value) } | |
}) | |
LaunchpadProMK3.sendRGB(0x01, 0x7F, 0x7F, 0x7F) | |
// hotcue color switch prev | |
midi.makeInputHandler(0xB0, 0x07, (control, value, status, group) => { | |
let channel = `[Channel${LaunchpadProMK3.selectedDeck}]` | |
// console.log("hotcue colour go prev, deck " + LaunchpadProMK3.selectedDeck + ", channel " + channel + ", hotcue_focus " + engine.getValue(channel, hotcue_focus)) | |
if (value) { LaunchpadProMK3.hotcueColourSwitch(LaunchpadProMK3.selectedDeck, "prev") } | |
}) | |
LaunchpadProMK3.sendRGB(0x07, 0x7F, 0x7F, 0x7F) | |
// hotcue color switch next | |
midi.makeInputHandler(0xB0, 0x08, (control, value, status, group) => { | |
let channel = `[Channel${LaunchpadProMK3.selectedDeck}]` | |
// console.log("hotcue colour go next, deck " + LaunchpadProMK3.selectedDeck + ", channel " + channel + ", hotcue_focus " + engine.getValue(channel, hotcue_focus)) | |
if (value) { LaunchpadProMK3.hotcueColourSwitch(LaunchpadProMK3.selectedDeck, "next") } | |
}) | |
LaunchpadProMK3.sendRGB(0x08, 0x7F, 0x7F, 0x7F) | |
// top right, switch page | |
// midi.makeInputHandler(0xB0, 0x62, (channel, control, value, status) => { | |
// if (value) { LaunchpadProMK3.switchPage(0) } | |
// }) | |
// LaunchpadProMK3.sendRGB(0x62, 0xFF, 0xFF, 0xFF); | |
} | |
// Helper to construct and send SysEx messages | |
LaunchpadProMK3.sendSysEx = function(data) { | |
midi.sendSysexMsg([0xF0, 0x00, 0x20, 0x29, 0x02, 0x0E].concat(data, [0xF7]), data.length + 7); | |
}; | |
// Set Launchpad Pro MK3 to Programmer Mode | |
LaunchpadProMK3.setProgrammerMode = function() { | |
LaunchpadProMK3.sendSysEx([0x0E, 0x01]); | |
}; | |
// Helper function to convert RGB hex value to individual R, G, B values | |
LaunchpadProMK3.hexToRGB = function(hex) { | |
var r = (hex >> 16) & 0xFF; | |
var g = (hex >> 8) & 0xFF; | |
var b = hex & 0xFF; | |
return [r, g, b]; | |
}; | |
// Helper to send RGB values | |
LaunchpadProMK3.sendRGB = function(pad, r, g, b) { | |
LaunchpadProMK3.sendSysEx([0x03, 0x03, pad, r, g, b]); | |
}; | |
LaunchpadProMK3.sendRGB2 = function(pad, hex) { | |
var r = (hex >> 16) & 0xFF; | |
var g = (hex >> 8) & 0xFF; | |
var b = hex & 0xFF; | |
LaunchpadProMK3.sendSysEx([0x03, 0x03, pad, r, g, b]); | |
} | |
// Helper to turn off all pads | |
LaunchpadProMK3.turnOffPad = function(pad) { | |
LaunchpadProMK3.sendRGB(pad, 0, 0, 0); | |
}; | |
// Initialize hotcue buttons for 4 decks | |
LaunchpadProMK3.init = function() { | |
console.log("\n\n\ninit:\n") | |
// Set LPP3 to programmer mode | |
LaunchpadProMK3.setProgrammerMode(); | |
LaunchpadProMK3.padAddressesMain = [ | |
81, 82, 83, 84, 85, 86, 87, 88, | |
71, 72, 73, 74, 75, 76, 77, 78, | |
61, 62, 63, 64, 65, 66, 67, 68, | |
51, 52, 53, 54, 55, 56, 57, 58, | |
41, 42, 43, 44, 45, 46, 47, 48, | |
31, 32, 33, 34, 35, 36, 37, 38, | |
21, 22, 23, 24, 25, 26, 27, 28, | |
11, 12, 13, 14, 15, 16, 17, 18 ] | |
LaunchpadProMK3.sidepadAddresses = [ | |
80, 70, 89, 79, | |
60, 50, 69, 59, | |
40, 30, 49, 39, | |
20, 10, 29, 19 ] | |
LaunchpadProMK3.sidepadNames = [ | |
"intro_start_", | |
"intro_end_", | |
"outro_start_", | |
"outro_end_" | |
] | |
LaunchpadProMK3.deck1 = new LaunchpadProMK3.Deck(1); | |
LaunchpadProMK3.deck2 = new LaunchpadProMK3.Deck(2); | |
LaunchpadProMK3.deck3 = new LaunchpadProMK3.Deck(3); | |
LaunchpadProMK3.deck4 = new LaunchpadProMK3.Deck(4); | |
LaunchpadProMK3.shutdown() | |
LaunchpadProMK3.connectHotcues() | |
LaunchpadProMK3.initExtras() | |
LaunchpadProMK3.updatePadLights() | |
console.log("\n\n\n\n\n\n") | |
LaunchpadProMK3.currentPage = 0; // Page 0 for hotcues | |
// Initialize page 0 (hotcues) | |
// LaunchpadProMK3.switchPage(0); | |
LaunchpadProMK3.selectedDeck = 1 | |
} | |
sendRGBfunc = function (color_obj) { | |
LaunchpadProMK3.sendRGB(this.padAddress, color_obj.red>>1,color_obj.green>>1,color_obj.blue>>1); | |
} | |
LaunchpadProMK3.Deck = function (deckNumber) { | |
components.Deck.call(this, deckNumber); | |
console.log("\n### Deck objects instantiation: deckNumber " + deckNumber + "\n") | |
//// Deck Main Hotcues | |
this.hotcueButtons = []; | |
for (let i = 1; i <= 16; i++) { | |
let padAddressIndex = 16 * (deckNumber - 1) + i - 1 | |
let padAddress = LaunchpadProMK3.padAddressesMain[padAddressIndex] | |
this.i = i | |
console.log("# hotcueButtons: deck " + deckNumber + "/" + this.currentDeck + ", i " + i + ", padAddressIndex " + padAddressIndex + ", padAddress " + padAddress + "\n") | |
this.hotcueButtons[i-1] = new components.HotcueButton({ | |
midi: [0x90, padAddress], | |
number: this.i, // This is the hotcue number | |
padAddress: padAddress, | |
sendRGB: sendRGBfunc, | |
input: midi.makeInputHandler(0x90, padAddress, (channel, control, value, status) => { | |
if (value) { | |
engine.setValue("[Channel" + deckNumber + "]", "hotcue_" + i + "_activate", 1); // Trigger hotcue on input | |
var lastHotcue = i | |
console.log(i) | |
} | |
if (!value) { | |
engine.setValue("[Channel" + deckNumber + "]", "hotcue_" + i + "_activate", 0); // Trigger hotcue on input | |
} | |
}), | |
}) | |
} | |
//// Deck Sidepad Intro/Outro Hotcues | |
console.log("\n ## Deck sidepads instantiation: deckNumber " + deckNumber + "\n") | |
this.sideButtons = [] | |
for (let sidepad = 1; sidepad <= 4; sidepad++) { | |
let sidepadAddressIndex = 4 * (deckNumber - 1) + sidepad - 1 | |
let padAddress = LaunchpadProMK3.sidepadAddresses[sidepadAddressIndex] | |
let sidepadControlName = LaunchpadProMK3.sidepadNames[sidepad-1] | |
let rgb = LaunchpadProMK3.hexToRGB(0x0000FF); | |
console.log("\n# deck " + deckNumber + ", sidepad " + sidepad + ", sidepadAddressIndex " + sidepadAddressIndex + ", padAddress " + padAddress + ", sidepadControlName " + sidepadControlName + "\n") | |
this.sideButtons[sidepad-1] = new components.Button({ | |
midi: [0xB0, padAddress], | |
padAddress: padAddress, // Get ready | |
// sendRGB: LaunchpadProMK3.sendRGB(this.sidepadAddress, 0x00, 0x00, 0xFF), | |
// sendRGB: LaunchpadProMK3.sendRGB(padAddress, rgb[0], rgb[1], rgb[2]), | |
input: midi.makeInputHandler(0xB0, padAddress, (channel, control, value, status) => { | |
if (value) { | |
engine.setValue("[Channel" + deckNumber + "]", `${sidepadControlName}activate`, 1); | |
} | |
if (!value) { | |
engine.setValue("[Channel" + deckNumber + "]", `${sidepadControlName}activate`, 0); | |
} | |
}), | |
}) | |
engine.makeConnection(`[Channel${deckNumber}]`, `${sidepadControlName}enabled`, (value) => { | |
LaunchpadProMK3.onTrackWithInOut(value, deckNumber, padAddress); | |
}); | |
} | |
// Set the group properties of the above Components and connect their output callback functions | |
this.reconnectComponents(function (c) { | |
console.log("\nreconnectComponents: " + c.group + ", this.currentDeck " + this.currentDeck + "\n") | |
if (c.group === undefined) { | |
// 'this' inside a function passed to reconnectComponents refers to the ComponentContainer | |
// so 'this' refers to the custom Deck object being constructed | |
c.group = this.currentDeck; | |
} | |
}); | |
} | |
LaunchpadProMK3.Deck.prototype = new components.Deck(); | |
// Function to turn a sidepad colour to blue or off | |
// LaunchpadProMK3.onTrackWithInOut = function(value, group) { | |
LaunchpadProMK3.onTrackWithInOut = function(value, deckNumber, padAddress) { | |
console.log(" value " + value + ", padAddress " + padAddress) | |
// const padAddress = this.sidepadAddress; // use the stored pad address | |
if (value > 0) { | |
console.log(`Turning sidepad for deck ${deckNumber} blue: ${padAddress}`); | |
LaunchpadProMK3.sendRGB(padAddress, 0x00, 0x00, 0xFF); | |
} else { | |
console.log(`Turning sidepad for deck ${deckNumber} off: ${padAddress}`); | |
LaunchpadProMK3.sendRGB(padAddress, 0x00, 0x00, 0x00); | |
} | |
} | |
// Function to do things on track load/unload | |
LaunchpadProMK3.onTrackLoadedOrUnloaded = function(value, group) { | |
console.log(value === 1 ? `### Track loaded on ${group}\n` : `\n Track unloaded from ${group}\n`) | |
deck = group.match(/(\d+)/)[1] | |
// LaunchpadProMK3.updatePadLights(deck); | |
} | |
// Function to update pad lights for each hotcue | |
LaunchpadProMK3.updatePadLights = function(deck) { | |
console.log("\n ### Helper updatePadLights: " + deck + "\n") | |
if (deck === undefined) { | |
console.log("update all") | |
LaunchpadProMK3.updateDeckLights(1); | |
LaunchpadProMK3.updateDeckLights(2); | |
LaunchpadProMK3.updateDeckLights(3); | |
LaunchpadProMK3.updateDeckLights(4); | |
} else { | |
console.log("update " + deck*1) | |
LaunchpadProMK3.updateDeckLights(1 * deck) | |
} | |
} | |
// Update pad lights for a specific deck | |
LaunchpadProMK3.updateDeckLights = function(deck) { | |
hotcueOffset = deck * 16 - 16 | |
console.log("\nupdateDeckLights: deck: " + deck + " hotcutOffset: " + hotcueOffset + "\n") | |
for (var i = 0; i < 16; i++) { | |
let cueEnabled = engine.getValue(`[Channel${deck}]`, `hotcue_${i + 1}_status`); | |
let cueColor = engine.getValue(`[Channel${deck}]`, `hotcue_${i + 1}_color`); | |
if (cueEnabled) { | |
let rgb = LaunchpadProMK3.hexToRGB(cueColor); | |
LaunchpadProMK3.sendRGB(LaunchpadProMK3.padAddressesMain[i + hotcueOffset], rgb[0], rgb[1], rgb[2]); | |
} else { | |
LaunchpadProMK3.turnOffPad(LaunchpadProMK3.padAddressesMain[i + hotcueOffset]); | |
} | |
} | |
} | |
// Helper to connect hotcues for all channels | |
LaunchpadProMK3.connectHotcues = function() { | |
console.log("### Helper connectHotcues:\n") | |
lpArray = LaunchpadProMK3.padAddressesMain | |
for (let deck = 1; deck <= 4; deck++) { | |
console.log("\x1b[33mconnectHotcues decks:\x1b[0m " + deck + "\n") | |
engine.makeConnection(`[Channel${deck}]`, "track_loaded", LaunchpadProMK3.onTrackLoadedOrUnloaded); | |
// for (let i = 1; i <= 16; i++) { | |
// console.log() | |
// let pad = LaunchpadProMK3.padAddressesMain[deck * 16 - 16 + i - 1] | |
// let hotcueIndex = lpArray.indexOf(pad) + ((deck - 1) * 16 + 1) | |
// console.log("hotcueIndex:" + hotcueIndex) | |
// console.log("hotcueIndex16: " + hotcueIndex.toString(16)) | |
// console.log("pad: " + pad) | |
// engine.makeConnection(`[Channel${deck}]`, `hotcue_${i}_status`, function(value) { | |
// if (value === 0) { | |
// LaunchpadProMK3.turnOffPad(pad); | |
// } | |
// }); | |
// } | |
// for (let sidepad = 1; sidepad <= 4; sidepad++) { | |
// let sidepadAddressIndex = 4 * (deck - 1) + sidepad - 1 | |
// let sidepadAddress = LaunchpadProMK3.sidepadAddresses[sidepadAddressIndex] | |
// let sidepadControlName = LaunchpadProMK3.sidepadNames[sidepad-1] | |
// let rgb = LaunchpadProMK3.hexToRGB(0x0000FF); | |
// console.log(" sidepad " + sidepad + ", sidepadAddressIndex " + sidepadAddressIndex + ", sidepadAddress " + sidepadAddress + ", sidepadControlName " + sidepadControlName ) | |
// LaunchpadProMK3.onTrackWithInOut | |
// if (`${sidepadControlName}enabled`) { LaunchpadProMK3.sendRGB(sidepadAddress, rgb[0], rgb[1], rgb[2])} | |
// midi.makeInputHandler(0xB0, sidepadAddress, (channel, control, value, status) => { | |
// if (value) { | |
// engine.setValue("[Channel" + deck + "]", `${sidepadControlName}activate`, 1); | |
// } | |
// if (!value) { | |
// engine.setValue("[Channel" + deck + "]", `${sidepadControlName}activate`, 0); | |
// } | |
// }) | |
// engine.makeConnection(`[Channel${deck}]`, `${sidepadControlName}enabled`, LaunchpadProMK3.onTrackWithInOut); | |
// } | |
} | |
} | |
// Handle switching back to page 0 (hotcues) and refreshing lights | |
LaunchpadProMK3.switchPage = function(pageNumber) { | |
LaunchpadProMK3.currentPage = pageNumber; | |
LaunchpadProMK3.updatePadLights(); | |
}; | |
// Shutdown function to turn off LEDs when the controller is disconnected | |
LaunchpadProMK3.shutdown = function() { | |
console.log("\nshutdown:\n") | |
for (var i = 0; i < 0x7F; i++) { | |
LaunchpadProMK3.turnOffPad(i); | |
} | |
} | |
```var LaunchpadProMK3 = {} | |
// console.log("LOG channel " + channel + " control " + control + " value " + value + " status " + status + " group " + group) | |
LaunchpadProMK3.sleep = function(time) { | |
var then = Date.now(); | |
while (true) { | |
var now = Date.now(); | |
if (now - then > time) { | |
break; | |
} | |
} | |
} | |
LaunchpadProMK3.create4LeadupDropHotcues = function (deck, value) { | |
// LaunchpadProMK3.create4LeadupDropHotcues = function (deck, value) { | |
console.log("create4LDH, deck " + deck, "value " + value) | |
// console.log("LOG channel " + channel + " control " + _control + " value " + value + " status " + _status + " group " + group) | |
if (value === 0 || value === undefined) return 0 | |
group = `[Channel${deck}]` | |
for (let X = 1; X <= 64; X++) { | |
let hotcueVariable = "hotcue_" + X + "_status" | |
if (engine.getValue(group, hotcueVariable) === 0) { | |
X += 3 | |
hotcueFocus = "hotcue_"+X+"_set" | |
engine.setValue(group,hotcueFocus, 1) | |
hotcueColourFocus = "hotcue_"+X+"_color" | |
engine.setValue(group,hotcueColourFocus, 0x32be44) // green | |
engine.setValue(group, "beatjump_16_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-1)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-1)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_16_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-2)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-2)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_32_backward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group,"hotcue_"+(X-3)+"_set", 1) | |
engine.setValue(group,"hotcue_"+(X-3)+"_color", 0xf8d200) // yellow | |
engine.setValue(group, "beatjump_64_forward", 1) | |
LaunchpadProMK3.sleep(50); | |
engine.setValue(group, "intro_end_activate", 1) | |
return | |
} | |
} | |
} | |
LaunchpadProMK3.selectDeck = function(deck) { | |
LaunchpadProMK3.selectedDeck = deck | |
} | |
LaunchpadProMK3.undoHotcue = function(deck) { | |
} | |
LaunchpadProMK3.hotcueColourSwitch = function(deck,direction) { | |
engine.setValue(`[Channel${deck}]`,`hotcue_focus_color_${direction}`, 1) | |
} | |
LaunchpadProMK3.initExtras = function() { | |
// deck 3 | |
midi.makeInputHandler(0xB0, 0x65, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(3) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x65, 0x7F, 0x00, 0x7F) | |
// deck 1 | |
midi.makeInputHandler(0xB0, 0x66, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(1) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x66, 0x1D, 0x46, 0x7B) | |
// deck 2 | |
midi.makeInputHandler(0xB0, 0x67, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(2) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x67, 0x7F, 0x58, 0x04) | |
// deck 4 | |
midi.makeInputHandler(0xB0, 0x68, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.selectDeck(4) } | |
console.log("selectedDeck = " + LaunchpadProMK3.selectedDeck) | |
}) | |
LaunchpadProMK3.sendRGB(0x68, 0x44, 0x60, 0x0D) | |
// create multi hotcues | |
midi.makeInputHandler(0xB0, 0x03, (channel, control, value, status, group) => { | |
if (value) { LaunchpadProMK3.create4LeadupDropHotcues(LaunchpadProMK3.selectedDeck, value) } | |
}) | |
LaunchpadProMK3.sendRGB(0x03, 0x7F, 0x7F, 0x7F) | |
// undo WIP | |
midi.makeInputHandler(0xB0, 0x01, (channel, control, value, status, group) => { | |
// if (value) { LaunchpadProMK3.undoHotcue(LaunchpadProMK3.selectedDeck, value) } | |
}) | |
LaunchpadProMK3.sendRGB(0x01, 0x7F, 0x7F, 0x7F) | |
// hotcue color switch prev | |
midi.makeInputHandler(0xB0, 0x07, (control, value, status, group) => { | |
let channel = `[Channel${LaunchpadProMK3.selectedDeck}]` | |
// console.log("hotcue colour go prev, deck " + LaunchpadProMK3.selectedDeck + ", channel " + channel + ", hotcue_focus " + engine.getValue(channel, hotcue_focus)) | |
if (value) { LaunchpadProMK3.hotcueColourSwitch(LaunchpadProMK3.selectedDeck, "prev") } | |
}) | |
LaunchpadProMK3.sendRGB(0x07, 0x7F, 0x7F, 0x7F) | |
// hotcue color switch next | |
midi.makeInputHandler(0xB0, 0x08, (control, value, status, group) => { | |
let channel = `[Channel${LaunchpadProMK3.selectedDeck}]` | |
// console.log("hotcue colour go next, deck " + LaunchpadProMK3.selectedDeck + ", channel " + channel + ", hotcue_focus " + engine.getValue(channel, hotcue_focus)) | |
if (value) { LaunchpadProMK3.hotcueColourSwitch(LaunchpadProMK3.selectedDeck, "next") } | |
}) | |
LaunchpadProMK3.sendRGB(0x08, 0x7F, 0x7F, 0x7F) | |
// top right, switch page | |
// midi.makeInputHandler(0xB0, 0x62, (channel, control, value, status) => { | |
// if (value) { LaunchpadProMK3.switchPage(0) } | |
// }) | |
// LaunchpadProMK3.sendRGB(0x62, 0xFF, 0xFF, 0xFF); | |
} | |
// Helper to construct and send SysEx messages | |
LaunchpadProMK3.sendSysEx = function(data) { | |
midi.sendSysexMsg([0xF0, 0x00, 0x20, 0x29, 0x02, 0x0E].concat(data, [0xF7]), data.length + 7); | |
}; | |
// Set Launchpad Pro MK3 to Programmer Mode | |
LaunchpadProMK3.setProgrammerMode = function() { | |
LaunchpadProMK3.sendSysEx([0x0E, 0x01]); | |
}; | |
// Helper function to convert RGB hex value to individual R, G, B values | |
LaunchpadProMK3.hexToRGB = function(hex) { | |
var r = (hex >> 16) & 0xFF; | |
var g = (hex >> 8) & 0xFF; | |
var b = hex & 0xFF; | |
return [r, g, b]; | |
}; | |
// Helper to send RGB values | |
LaunchpadProMK3.sendRGB = function(pad, r, g, b) { | |
LaunchpadProMK3.sendSysEx([0x03, 0x03, pad, r, g, b]); | |
}; | |
LaunchpadProMK3.sendRGB2 = function(pad, hex) { | |
var r = (hex >> 16) & 0xFF; | |
var g = (hex >> 8) & 0xFF; | |
var b = hex & 0xFF; | |
LaunchpadProMK3.sendSysEx([0x03, 0x03, pad, r, g, b]); | |
} | |
// Helper to turn off all pads | |
LaunchpadProMK3.turnOffPad = function(pad) { | |
LaunchpadProMK3.sendRGB(pad, 0, 0, 0); | |
}; | |
// Initialize hotcue buttons for 4 decks | |
LaunchpadProMK3.init = function() { | |
console.log("\n\n\ninit:\n") | |
// Set LPP3 to programmer mode | |
LaunchpadProMK3.setProgrammerMode(); | |
LaunchpadProMK3.padAddressesMain = [ | |
81, 82, 83, 84, 85, 86, 87, 88, | |
71, 72, 73, 74, 75, 76, 77, 78, | |
61, 62, 63, 64, 65, 66, 67, 68, | |
51, 52, 53, 54, 55, 56, 57, 58, | |
41, 42, 43, 44, 45, 46, 47, 48, | |
31, 32, 33, 34, 35, 36, 37, 38, | |
21, 22, 23, 24, 25, 26, 27, 28, | |
11, 12, 13, 14, 15, 16, 17, 18 ] | |
LaunchpadProMK3.sidepadAddresses = [ | |
80, 70, 89, 79, | |
60, 50, 69, 59, | |
40, 30, 49, 39, | |
20, 10, 29, 19 ] | |
LaunchpadProMK3.sidepadNames = [ | |
"intro_start_", | |
"intro_end_", | |
"outro_start_", | |
"outro_end_" | |
] | |
LaunchpadProMK3.deck1 = new LaunchpadProMK3.Deck(1); | |
LaunchpadProMK3.deck2 = new LaunchpadProMK3.Deck(2); | |
LaunchpadProMK3.deck3 = new LaunchpadProMK3.Deck(3); | |
LaunchpadProMK3.deck4 = new LaunchpadProMK3.Deck(4); | |
LaunchpadProMK3.shutdown() | |
LaunchpadProMK3.connectHotcues() | |
LaunchpadProMK3.initExtras() | |
LaunchpadProMK3.updatePadLights() | |
console.log("\n\n\n\n\n\n") | |
LaunchpadProMK3.currentPage = 0; // Page 0 for hotcues | |
// Initialize page 0 (hotcues) | |
// LaunchpadProMK3.switchPage(0); | |
LaunchpadProMK3.selectedDeck = 1 | |
} | |
sendRGBfunc = function (color_obj) { | |
LaunchpadProMK3.sendRGB(this.padAddress, color_obj.red>>1,color_obj.green>>1,color_obj.blue>>1); | |
} | |
LaunchpadProMK3.Deck = function (deckNumber) { | |
components.Deck.call(this, deckNumber); | |
console.log("\n### Deck objects instantiation: deckNumber " + deckNumber + "\n") | |
//// Deck Main Hotcues | |
this.hotcueButtons = []; | |
for (let i = 1; i <= 16; i++) { | |
let padAddressIndex = 16 * (deckNumber - 1) + i - 1 | |
let padAddress = LaunchpadProMK3.padAddressesMain[padAddressIndex] | |
this.i = i | |
console.log("# hotcueButtons: deck " + deckNumber + "/" + this.currentDeck + ", i " + i + ", padAddressIndex " + padAddressIndex + ", padAddress " + padAddress + "\n") | |
this.hotcueButtons[i-1] = new components.HotcueButton({ | |
midi: [0x90, padAddress], | |
number: this.i, // This is the hotcue number | |
padAddress: padAddress, | |
sendRGB: sendRGBfunc, | |
input: midi.makeInputHandler(0x90, padAddress, (channel, control, value, status) => { | |
if (value) { | |
engine.setValue("[Channel" + deckNumber + "]", "hotcue_" + i + "_activate", 1); // Trigger hotcue on input | |
var lastHotcue = i | |
console.log(i) | |
} | |
if (!value) { | |
engine.setValue("[Channel" + deckNumber + "]", "hotcue_" + i + "_activate", 0); // Trigger hotcue on input | |
} | |
}), | |
}) | |
} | |
//// Deck Sidepad Intro/Outro Hotcues | |
console.log("\n ## Deck sidepads instantiation: deckNumber " + deckNumber + "\n") | |
this.sideButtons = [] | |
for (let sidepad = 1; sidepad <= 4; sidepad++) { | |
let sidepadAddressIndex = 4 * (deckNumber - 1) + sidepad - 1 | |
let padAddress = LaunchpadProMK3.sidepadAddresses[sidepadAddressIndex] | |
let sidepadControlName = LaunchpadProMK3.sidepadNames[sidepad-1] | |
let rgb = LaunchpadProMK3.hexToRGB(0x0000FF); | |
console.log("\n# deck " + deckNumber + ", sidepad " + sidepad + ", sidepadAddressIndex " + sidepadAddressIndex + ", padAddress " + padAddress + ", sidepadControlName " + sidepadControlName + "\n") | |
this.sideButtons[sidepad-1] = new components.Button({ | |
midi: [0xB0, padAddress], | |
padAddress: padAddress, // Get ready | |
// sendRGB: LaunchpadProMK3.sendRGB(this.sidepadAddress, 0x00, 0x00, 0xFF), | |
// sendRGB: LaunchpadProMK3.sendRGB(padAddress, rgb[0], rgb[1], rgb[2]), | |
input: midi.makeInputHandler(0xB0, padAddress, (channel, control, value, status) => { | |
if (value) { | |
engine.setValue("[Channel" + deckNumber + "]", `${sidepadControlName}activate`, 1); | |
} | |
if (!value) { | |
engine.setValue("[Channel" + deckNumber + "]", `${sidepadControlName}activate`, 0); | |
} | |
}), | |
}) | |
engine.makeConnection(`[Channel${deckNumber}]`, `${sidepadControlName}enabled`, (value) => { | |
LaunchpadProMK3.onTrackWithInOut(value, deckNumber, padAddress); | |
}); | |
} | |
// Set the group properties of the above Components and connect their output callback functions | |
this.reconnectComponents(function (c) { | |
console.log("\nreconnectComponents: " + c.group + ", this.currentDeck " + this.currentDeck + "\n") | |
if (c.group === undefined) { | |
// 'this' inside a function passed to reconnectComponents refers to the ComponentContainer | |
// so 'this' refers to the custom Deck object being constructed | |
c.group = this.currentDeck; | |
} | |
}); | |
} | |
LaunchpadProMK3.Deck.prototype = new components.Deck(); | |
// Function to turn a sidepad colour to blue or off | |
// LaunchpadProMK3.onTrackWithInOut = function(value, group) { | |
LaunchpadProMK3.onTrackWithInOut = function(value, deckNumber, padAddress) { | |
console.log(" value " + value + ", padAddress " + padAddress) | |
// const padAddress = this.sidepadAddress; // use the stored pad address | |
if (value > 0) { | |
console.log(`Turning sidepad for deck ${deckNumber} blue: ${padAddress}`); | |
LaunchpadProMK3.sendRGB(padAddress, 0x00, 0x00, 0xFF); | |
} else { | |
console.log(`Turning sidepad for deck ${deckNumber} off: ${padAddress}`); | |
LaunchpadProMK3.sendRGB(padAddress, 0x00, 0x00, 0x00); | |
} | |
} | |
// Function to do things on track load/unload | |
LaunchpadProMK3.onTrackLoadedOrUnloaded = function(value, group) { | |
console.log(value === 1 ? `### Track loaded on ${group}\n` : `\n Track unloaded from ${group}\n`) | |
deck = group.match(/(\d+)/)[1] | |
// LaunchpadProMK3.updatePadLights(deck); | |
} | |
// Function to update pad lights for each hotcue | |
LaunchpadProMK3.updatePadLights = function(deck) { | |
console.log("\n ### Helper updatePadLights: " + deck + "\n") | |
if (deck === undefined) { | |
console.log("update all") | |
LaunchpadProMK3.updateDeckLights(1); | |
LaunchpadProMK3.updateDeckLights(2); | |
LaunchpadProMK3.updateDeckLights(3); | |
LaunchpadProMK3.updateDeckLights(4); | |
} else { | |
console.log("update " + deck*1) | |
LaunchpadProMK3.updateDeckLights(1 * deck) | |
} | |
} | |
// Update pad lights for a specific deck | |
LaunchpadProMK3.updateDeckLights = function(deck) { | |
hotcueOffset = deck * 16 - 16 | |
console.log("\nupdateDeckLights: deck: " + deck + " hotcutOffset: " + hotcueOffset + "\n") | |
for (var i = 0; i < 16; i++) { | |
let cueEnabled = engine.getValue(`[Channel${deck}]`, `hotcue_${i + 1}_status`); | |
let cueColor = engine.getValue(`[Channel${deck}]`, `hotcue_${i + 1}_color`); | |
if (cueEnabled) { | |
let rgb = LaunchpadProMK3.hexToRGB(cueColor); | |
LaunchpadProMK3.sendRGB(LaunchpadProMK3.padAddressesMain[i + hotcueOffset], rgb[0], rgb[1], rgb[2]); | |
} else { | |
LaunchpadProMK3.turnOffPad(LaunchpadProMK3.padAddressesMain[i + hotcueOffset]); | |
} | |
} | |
} | |
// Helper to connect hotcues for all channels | |
LaunchpadProMK3.connectHotcues = function() { | |
console.log("### Helper connectHotcues:\n") | |
lpArray = LaunchpadProMK3.padAddressesMain | |
for (let deck = 1; deck <= 4; deck++) { | |
console.log("\x1b[33mconnectHotcues decks:\x1b[0m " + deck + "\n") | |
engine.makeConnection(`[Channel${deck}]`, "track_loaded", LaunchpadProMK3.onTrackLoadedOrUnloaded); | |
// for (let i = 1; i <= 16; i++) { | |
// console.log() | |
// let pad = LaunchpadProMK3.padAddressesMain[deck * 16 - 16 + i - 1] | |
// let hotcueIndex = lpArray.indexOf(pad) + ((deck - 1) * 16 + 1) | |
// console.log("hotcueIndex:" + hotcueIndex) | |
// console.log("hotcueIndex16: " + hotcueIndex.toString(16)) | |
// console.log("pad: " + pad) | |
// engine.makeConnection(`[Channel${deck}]`, `hotcue_${i}_status`, function(value) { | |
// if (value === 0) { | |
// LaunchpadProMK3.turnOffPad(pad); | |
// } | |
// }); | |
// } | |
// for (let sidepad = 1; sidepad <= 4; sidepad++) { | |
// let sidepadAddressIndex = 4 * (deck - 1) + sidepad - 1 | |
// let sidepadAddress = LaunchpadProMK3.sidepadAddresses[sidepadAddressIndex] | |
// let sidepadControlName = LaunchpadProMK3.sidepadNames[sidepad-1] | |
// let rgb = LaunchpadProMK3.hexToRGB(0x0000FF); | |
// console.log(" sidepad " + sidepad + ", sidepadAddressIndex " + sidepadAddressIndex + ", sidepadAddress " + sidepadAddress + ", sidepadControlName " + sidepadControlName ) | |
// LaunchpadProMK3.onTrackWithInOut | |
// if (`${sidepadControlName}enabled`) { LaunchpadProMK3.sendRGB(sidepadAddress, rgb[0], rgb[1], rgb[2])} | |
// midi.makeInputHandler(0xB0, sidepadAddress, (channel, control, value, status) => { | |
// if (value) { | |
// engine.setValue("[Channel" + deck + "]", `${sidepadControlName}activate`, 1); | |
// } | |
// if (!value) { | |
// engine.setValue("[Channel" + deck + "]", `${sidepadControlName}activate`, 0); | |
// } | |
// }) | |
// engine.makeConnection(`[Channel${deck}]`, `${sidepadControlName}enabled`, LaunchpadProMK3.onTrackWithInOut); | |
// } | |
} | |
} | |
// Handle switching back to page 0 (hotcues) and refreshing lights | |
LaunchpadProMK3.switchPage = function(pageNumber) { | |
LaunchpadProMK3.currentPage = pageNumber; | |
LaunchpadProMK3.updatePadLights(); | |
}; | |
// Shutdown function to turn off LEDs when the controller is disconnected | |
LaunchpadProMK3.shutdown = function() { | |
console.log("\nshutdown:\n") | |
for (var i = 0; i < 0x7F; i++) { | |
LaunchpadProMK3.turnOffPad(i); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment