diff --git a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js index 704cabf2a71..7b3a552b95b 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js @@ -670,19 +670,92 @@ TraktorS2MK3.wheelDeltas = function(deckNumber, value) { }; TraktorS2MK3.fxHandler = function(field) { + /* We support 8 effects in total by having 2 effects per fx button. * + * First press of the button will load the preset at the index of the quick effect preset list * + * Second press will load the preset index + 4 * + * Arrange your quick effect preset list from 1 to 8 like this: 1/5, 2/6, 3/7, 4/8 */ if (field.value === 0) { return; } + const availableGroups = ["[Channel1]", "[Channel2]"]; + const fxButtonCount = 4; + let targetGroups = []; const fxNumber = parseInt(field.id[field.id.length - 1]); - const group = "[EffectRack1_EffectUnit" + fxNumber + "]"; + let noShift = false; - // Toggle effect unit - TraktorS2MK3.fxButtonState[fxNumber] = !TraktorS2MK3.fxButtonState[fxNumber]; + // Target decks whose shift button is pressed. + for (const group of availableGroups) { + if (TraktorS2MK3.shiftPressed[group]) { targetGroups.push(group); } + } + + // If no shift button was pressed fall back to target all decks. + if (targetGroups.length === 0) { + targetGroups = availableGroups; + noShift = true; + } + + const fxToApply = {}; + const activeFx = {}; + // Detect which fx should be enabled + for (const group of targetGroups) { + activeFx[group] = engine.getValue(`[QuickEffectRack1_${group}]`, "loaded_chain_preset") - 1; + if (activeFx[group] === fxNumber) { + // Pressing again the fx button + fxToApply[group] = fxNumber + fxButtonCount; + } else if (activeFx[group] === fxNumber + fxButtonCount) { + // Already on secondary fx so resetting back to fxNumber + fxToApply[group] = fxNumber; + } else { + // First press of a different fx button + fxToApply[group] = fxNumber; + } + } + + /* When we target both decks - No shift pressed - we want * + * to reset fx to same value for both */ + if (targetGroups.length === 2 && noShift) { + const [deck1, deck2] = targetGroups; + const activeFxDeck1 = activeFx[deck1]; + const activeFxDeck2 = activeFx[deck2]; + const fxToApplyDeck1 = fxToApply[deck1]; + const fxToApplyDeck2 = fxToApply[deck2]; + + // If any of deck has already fx enabled but different value to apply + if ((activeFxDeck1 === fxNumber || activeFxDeck2 === fxNumber) && fxToApplyDeck1 !== fxToApplyDeck2) { + // find lower value to reset both to the same one + const fxToApplyAll = Math.min(fxToApplyDeck1, fxToApplyDeck2); + fxToApply[deck1] = fxToApplyAll; + fxToApply[deck2] = fxToApplyAll; + } + } - engine.setValue(group, "group_[Channel1]_enable", TraktorS2MK3.fxButtonState[fxNumber]); - engine.setValue(group, "group_[Channel2]_enable", TraktorS2MK3.fxButtonState[fxNumber]); - TraktorS2MK3.outputHandler(TraktorS2MK3.fxButtonState[fxNumber], field.group, "fxButton" + fxNumber); + // Now apply the new fx value + for (const group of targetGroups) { + engine.setValue(`[QuickEffectRack1_${group}]`, "loaded_chain_preset", fxToApply[group] + 1); + } +}; + +TraktorS2MK3.fxOutputHandler = function() { + const fxButtonCount = 4; + const availableGroups = ["[Channel1]", "[Channel2]"]; + + const activeFx = {}; + for (const group of availableGroups) { + activeFx[group] = engine.getValue(`[QuickEffectRack1_${group}]`, "loaded_chain_preset") - 1; + // We want to lit the proper fx button even when we have applied a higher fxNumber + if (activeFx[group] > fxButtonCount) { activeFx[group] = activeFx[group] - fxButtonCount; } + } + + /* There is no way on the controller to indicate which deck the effect applies * + * to, but keeping both lit indicates that different effects are in use. */ + for (let fxButton = 1; fxButton <= fxButtonCount; ++fxButton) { + let active = false; + for (const group of availableGroups) { + active = active || activeFx[group] === fxButton; + } + TraktorS2MK3.outputHandler(active, "[ChannelX]", "fxButton" + fxButton); + } }; TraktorS2MK3.reverseHandler = function(field) { @@ -836,6 +909,11 @@ TraktorS2MK3.registerOutputPackets = function() { this.samplerCallbacks.push(engine.makeConnection("[Sampler" + i + "]", "play", this.samplesOutputHandler)); } + this.fxCallbacks = []; + for (const group of ["[Channel1]", "[Channel2]"]) { + this.fxCallbacks.push(engine.makeConnection(`[QuickEffectRack1_${group}]`, "loaded_chain_preset", this.fxOutputHandler)); + } + TraktorS2MK3.lightDeck(false); }; @@ -1015,6 +1093,8 @@ TraktorS2MK3.lightDeck = function(switchOff) { TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton2", softLight, false); TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton3", softLight, false); TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton4", softLight, false); + // Set FX button LED state according to active quick effects on start-up + if (!switchOff) { TraktorS2MK3.fxOutputHandler(); } TraktorS2MK3.controller.setOutput("[Channel1]", "reverse", softLight, false); TraktorS2MK3.controller.setOutput("[Channel2]", "reverse", softLight, false);