Skip to content

Instantly share code, notes, and snippets.

@mxmilkiib
Last active November 3, 2024 12:07
Show Gist options
  • Save mxmilkiib/daa69382047f21ea0e57535d60e66e66 to your computer and use it in GitHub Desktop.
Save mxmilkiib/daa69382047f21ea0e57535d60e66e66 to your computer and use it in GitHub Desktop.
Launchpad Pro MK3 MIDI mapping
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