From 055b328f29c0570c6bf0878a54a49d4a91f2bfa3 Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Sun, 25 Mar 2018 10:15:28 +0100 Subject: [PATCH 1/7] Add beatgrid move and record functions --- .../Traktor-Kontrol-S4-MK2-hid-scripts.js | 87 +++++++++++++++++-- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index 4b07bd025f9e..27f5f194d523 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -102,7 +102,7 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck1", "loop_out", 0x0E, "B", 0x08); MessageShort.addControl("deck1", "loop_in", 0x0E, "B", 0x04); MessageShort.addControl("deck1", "slip_enabled", 0x0E, "B", 0x02); - MessageShort.addControl("deck1", "!reset", 0x0E, "B", 0x01); + MessageShort.addControl("deck1", "eject", 0x0E, "B", 0x01); MessageShort.addControl("deck1", "beatloop_activate", 0x13, "B", 0x02); MessageShort.addControl("deck1", "!loop_activate", 0x13, "B", 0x01); MessageShort.addControl("deck1", "!jog_touch", 0x11, "B", 0x01); @@ -130,7 +130,7 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck2", "loop_out", 0x0B, "B", 0x08); MessageShort.addControl("deck2", "loop_in", 0x0B, "B", 0x04); MessageShort.addControl("deck2", "slip_enabled", 0x0B, "B", 0x02); - MessageShort.addControl("deck2", "!reset", 0x0B, "B", 0x01); + MessageShort.addControl("deck2", "eject", 0x0B, "B", 0x01); MessageShort.addControl("deck2", "beatloop_activate", 0x13, "B", 0x10); MessageShort.addControl("deck2", "!loop_activate", 0x13, "B", 0x08); MessageShort.addControl("deck2", "!jog_touch", 0x11, "B", 0x02); @@ -165,8 +165,11 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("[Playlist]", "LoadSelectedIntoFirstStopped", 0x13, "B", 0x04); MessageShort.addControl("[PreviewDeck1]", "!previewdeck", 0x0F, "B", 0x01); + MessageShort.addControl("[Recording]", "toggle_recording", 0x0F, "B", 0x04); + MessageShort.addControl("[Master]", "!quantize", 0x0A, "B", 0x08); + MessageShort.addControl("[Master]", "!snap", 0x0A, "B", 0x02) MessageShort.setCallback("deck1", "!shift", this.shiftHandler); MessageShort.setCallback("deck2", "!shift", this.shiftHandler); @@ -204,6 +207,8 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.setCallback("deck2", "!remix4", this.remixHandler); MessageShort.setCallback("[PreviewDeck1]", "!previewdeck", this.previewDeckHandler); MessageShort.setCallback("[Master]", "!quantize", this.quantizeHandler); + MessageShort.setCallback("[Master]", "!snap", this.snapHandler); + // TODO: the rest of the "!" controls. this.controller.registerInputPacket(MessageShort); @@ -306,6 +311,8 @@ TraktorS4MK2.registerOutputPackets = function() { } } + + Output1.addOutput("[Channel1]", "PeakIndicator", 0x0F, "B"); Output1.addOutput("[Channel2]", "PeakIndicator", 0x17, "B"); Output1.addOutput("[Channel3]", "PeakIndicator", 0x07, "B"); @@ -314,6 +321,8 @@ TraktorS4MK2.registerOutputPackets = function() { Output1.addOutput("[Master]", "!usblight", 0x2A, "B"); Output1.addOutput("[Master]", "!quantize", 0x31, "B"); Output1.addOutput("[InternalClock]", "sync_master", 0x30, "B"); + Output1.addOutput("[Recording]", "status", 0x34, "B" ); + this.controller.registerOutputPacket(Output1); Output2.addOutput("deck1", "!shift", 0x1D, "B"); @@ -365,6 +374,7 @@ TraktorS4MK2.registerOutputPackets = function() { Output2.addOutput("[PreviewDeck1]", "play_indicator", 0x3D, "B"); + // Note: this logic means remix button actions are not switchable without reloading the script. // Once we have support for controller preferences, this can be changed. if (TraktorS4MK2.RemixSlotButtonAction === "SAMPLES") { @@ -457,6 +467,7 @@ TraktorS4MK2.registerOutputPackets = function() { TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2]", "show_parameters", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[PreviewDeck1]", "play_indicator", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[InternalClock]", "sync_master", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[Recording]", "status", TraktorS4MK2.outputChannelCallback); if (TraktorS4MK2.RemixSlotButtonAction === "SAMPLES") { TraktorS4MK2.linkChannelOutput("[Sampler1]", "play_indicator", TraktorS4MK2.outputChannelCallback); @@ -535,6 +546,8 @@ TraktorS4MK2.lightDeck = function(group) { TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit1]", "[EffectRack1_EffectUnit1]"); TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2]", "[EffectRack1_EffectUnit2]"); + // Loop size indicator + // Selected deck lights if (group === "[Channel1]") { TraktorS4MK2.controller.setOutput("[Channel1]", "!deck_A", 0x7F, false); @@ -578,6 +591,7 @@ TraktorS4MK2.pointlessLightShow = function() { packets[i][j] = k; } } + controller.send(packets[0], packets[0].length, 0); controller.send(packets[1], packets[1].length, 0); controller.send(packets[2], packets[2].length, 0); @@ -607,7 +621,9 @@ TraktorS4MK2.init = function(id) { TraktorS4MK2.controller.setOutput("[Master]", "!quantize", 0x7F * TraktorS4MK2.master_quantize, true); TraktorS4MK2.controller.setOutput("[Master]", "!usblight", 0x7F, true); + TraktorS4MK2.outputChannelCallback(engine.getValue("[InternalClock]", "sync_master"), "[InternalClock]", "sync_master"); + TraktorS4MK2.outputChannelCallback(engine.getValue("[Recording]", "status"), "[Recording]", "status"); TraktorS4MK2.lightDeck("[PreviewDeck1]"); // Light 3 and 4 first so we get the mixer lights on, then do 1 and 2 since those are active // on startup. @@ -1088,6 +1104,14 @@ TraktorS4MK2.quantizeHandler = function(field) { TraktorS4MK2.controller.setOutput("[Master]", "!quantize", 0x7F * TraktorS4MK2.master_quantize, true); } +TraktorS4MK2.snapHandler = function(field) { + if (field.value === 0) { + return; + } + library_maximized = engine.getValue("[Master]", "maximize_library"); + engine.setValue("[Master]", "maximize_library", !library_maximized); +} + TraktorS4MK2.callbackPregain = function(field) { // TODO: common-hid-packet-parser looks like it should do deltas, but I can't get them to work. prev_pregain = TraktorS4MK2.controller.prev_pregain[field.group]; @@ -1103,8 +1127,21 @@ TraktorS4MK2.callbackPregain = function(field) { delta = -0.05; } - var cur_pregain = engine.getValue(group, "pregain"); - engine.setValue(group, "pregain", cur_pregain + delta); + if ( + TraktorS4MK2.controller.shift_pressed['deck1'] || + TraktorS4MK2.controller.shift_pressed['deck2'] + ) { + if(delta > 0){ + engine.setValue(group, 'beats_translate_later', true); + } else if (delta < 0){ + engine.setValue(group, 'beats_translate_earlier', true); + } + } + else { + var cur_pregain = engine.getValue(group, "pregain"); + engine.setValue(group, "pregain", cur_pregain + delta); + } + } TraktorS4MK2.callbackLoopMove = function(field) { @@ -1138,6 +1175,36 @@ TraktorS4MK2.callbackLoopMove = function(field) { } } +TraktorS4MK2.sendLoopSizeMessage = function(group, beats) { + var LoopSizeIndicators = { + "deck2" : [0x2B, 0x3A], + "deck1" : [0x1B, 0x2A], + } + start_signal = LoopSizeIndicators[group] + + var sizesArray = { + 64: [1,2,4,5,6,7,9,10,11,13], + 32: [1,2,3,4,7,9,11,12,14,15], + 16: [2,3,9,10,12,13,14,15], + 8: [9,10,11,12,13,14,15], + 4: [9,10,11,13], + 2: [9,11,12,14,15], + } + var packets = Object(); + + packets.length = 61; + + start_signal = parseInt(LoopSizeIndicators[group][0]) + for (k = 0; k < 0x7F; k+=0x05) { + packets[0] = 0x82; + for (j = 0; j < sizesArray[beats].length; j++) { + var hid_msg = start_signal + sizesArray[beats][j] + packets[hid_msg] = k; + } + controller.send(packets, packets.length, 0); + } +} + TraktorS4MK2.callbackLoopSize = function(field) { var splitted = field.id.split("."); var group = splitted[0] @@ -1171,6 +1238,7 @@ TraktorS4MK2.callbackLoopSize = function(field) { engine.setValue(field.group, "loop_halve", 0); } } + // TraktorS4MK2.sendLoopSizeMessage(group, engine.getValue(field.group, "beatloop_size")); } TraktorS4MK2.callbackBrowse = function(field) { @@ -1187,8 +1255,15 @@ TraktorS4MK2.callbackBrowse = function(field) { } else { delta = -1; } - - engine.setValue("[Playlist]", "SelectTrackKnob", delta); + if ( + TraktorS4MK2.controller.shift_pressed["deck1"] || + TraktorS4MK2.controller.shift_pressed["deck2"] + ) { + engine.setValue("[Playlist]", "SelectPlaylist", delta); + } + else { + engine.setValue("[Playlist]", "SelectTrackKnob", delta); + } } TraktorS4MK2.scalerParameter = function(group, name, value) { From 36f66ee90cf0590ce542864e6e4e598b0344204a Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Sun, 25 Mar 2018 23:28:49 +0100 Subject: [PATCH 2/7] FX buttons now turn FX on and off --- .../Traktor-Kontrol-S4-MK2-hid-scripts.js | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index 27f5f194d523..f0d8504830c2 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -109,10 +109,10 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck1", "!jog_wheel", 0x01, "I"); MessageShort.addControl("deck1", "!deckswitch", 0x0F, "B", 0x20); MessageShort.addControl("deck1", "!load_track", 0x0F, "B", 0x10); - MessageShort.addControl("deck1", "!FX1", 0x12, "B", 0x80); - MessageShort.addControl("deck1", "!FX2", 0x12, "B", 0x40); - MessageShort.addControl("deck1", "!FX3", 0x12, "B", 0x20); - MessageShort.addControl("deck1", "!FX4", 0x12, "B", 0x10); + MessageShort.addControl("deck1", "!FXon", 0x12, "B", 0x80); + MessageShort.addControl("[EffectRack1_EffectUnit1_Effect1]", "!FXButton", 0x12, "B", 0x40); + MessageShort.addControl("[EffectRack1_EffectUnit1_Effect2]", "!FXButton", 0x12, "B", 0x20); + MessageShort.addControl("[EffectRack1_EffectUnit1_Effect3]", "!FXButton", 0x12, "B", 0x10); MessageShort.addControl("[EffectRack1_EffectUnit1]", "show_parameters", 0x11, "B", 0x08); MessageShort.addControl("deck2", "!shift", 0x0C, "B", 0x08); @@ -137,10 +137,10 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck2", "!jog_wheel", 0x05, "I"); MessageShort.addControl("deck2", "!deckswitch", 0x0A, "B", 0x20); MessageShort.addControl("deck2", "!load_track", 0x0A, "B", 0x10); - MessageShort.addControl("deck2", "!FX1", 0x10, "B", 0x08); - MessageShort.addControl("deck2", "!FX2", 0x10, "B", 0x04); - MessageShort.addControl("deck2", "!FX3", 0x10, "B", 0x02); - MessageShort.addControl("deck2", "!FX4", 0x10, "B", 0x01); + MessageShort.addControl("deck2", "!FXon", 0x10, "B", 0x08); + MessageShort.addControl("[EffectRack1_EffectUnit2_Effect1]", "!FXButton", 0x10, "B", 0x04); + MessageShort.addControl("[EffectRack1_EffectUnit2_Effect2]", "!FXButton", 0x10, "B", 0x02); + MessageShort.addControl("[EffectRack1_EffectUnit2_Effect3]", "!FXButton", 0x10, "B", 0x01); MessageShort.addControl("[EffectRack1_EffectUnit2]", "show_parameters", 0x11, "B", 0x04); MessageShort.addControl("[Channel1]", "pfl", 0x0F, "B", 0x40); @@ -209,6 +209,16 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.setCallback("[Master]", "!quantize", this.quantizeHandler); MessageShort.setCallback("[Master]", "!snap", this.snapHandler); + MessageShort.setCallback("[EffectRack1_EffectUnit1_Effect1]", "!FXButton", this.FXButtonHandler); + MessageShort.setCallback("[EffectRack1_EffectUnit1_Effect2]", "!FXButton", this.FXButtonHandler); + MessageShort.setCallback("[EffectRack1_EffectUnit1_Effect3]", "!FXButton", this.FXButtonHandler); + + MessageShort.setCallback("[EffectRack1_EffectUnit2_Effect1]", "!FXButton", this.FXButtonHandler); + MessageShort.setCallback("[EffectRack1_EffectUnit2_Effect2]", "!FXButton", this.FXButtonHandler); + MessageShort.setCallback("[EffectRack1_EffectUnit2_Effect3]", "!FXButton", this.FXButtonHandler); + + + // TODO: the rest of the "!" controls. this.controller.registerInputPacket(MessageShort); @@ -422,9 +432,19 @@ TraktorS4MK2.registerOutputPackets = function() { Output3.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel4]_enable", 0x0B, "B"); Output3.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel4]_enable", 0x0C, "B"); + Output3.addOutput("[EffectRack1_EffectUnit1_Effect1]", "enabled", 0x02, "B"); + Output3.addOutput("[EffectRack1_EffectUnit1_Effect2]", "enabled", 0x03, "B"); + Output3.addOutput("[EffectRack1_EffectUnit1_Effect3]", "enabled", 0x04, "B"); + + Output3.addOutput("[EffectRack1_EffectUnit2_Effect1]", "enabled", 0x0E, "B"); + Output3.addOutput("[EffectRack1_EffectUnit2_Effect2]", "enabled", 0x0F, "B"); + Output3.addOutput("[EffectRack1_EffectUnit2_Effect3]", "enabled", 0x10, "B"); + Output3.addOutput("[EffectRack1_EffectUnit1]", "show_parameters", 0x11, "B"); + Output3.addOutput("[EffectRack1_EffectUnit2]", "show_parameters", 0x12, "B"); + this.controller.registerOutputPacket(Output3); // Link up control objects to their outputs @@ -465,6 +485,13 @@ TraktorS4MK2.registerOutputPackets = function() { TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1]", "show_parameters", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2]", "show_parameters", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect1]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect2]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect3]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2_Effect1]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2_Effect2]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2_Effect3]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[PreviewDeck1]", "play_indicator", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[InternalClock]", "sync_master", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[Recording]", "status", TraktorS4MK2.outputChannelCallback); @@ -545,6 +572,12 @@ TraktorS4MK2.lightDeck = function(group) { var packet = this.controller.OutputPackets["output3"]; TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit1]", "[EffectRack1_EffectUnit1]"); TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2]", "[EffectRack1_EffectUnit2]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit1_Effect1]", "[EffectRack1_EffectUnit1_Effect1]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit1_Effect2]", "[EffectRack1_EffectUnit1_Effect2]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit1_Effect3]", "[EffectRack1_EffectUnit1_Effect3]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2_Effect1]", "[EffectRack1_EffectUnit2_Effect1]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2_Effect2]", "[EffectRack1_EffectUnit2_Effect2]"); + TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2_Effect3]", "[EffectRack1_EffectUnit2_Effect3]"); // Loop size indicator @@ -1112,6 +1145,21 @@ TraktorS4MK2.snapHandler = function(field) { engine.setValue("[Master]", "maximize_library", !library_maximized); } +TraktorS4MK2.FXButtonHandler = function(field){ + if(field.value){ + if ( + TraktorS4MK2.controller.shift_pressed['deck1'] || + TraktorS4MK2.controller.shift_pressed['deck2'] + ) { + engine.setValue(field.group, "effect_selector", 1); + } + else { + engine.setValue(field.group, "enabled", !engine.getValue(field.group, "enabled")); + } + } + TraktorS4MK2.lightDeck(field.group); +} + TraktorS4MK2.callbackPregain = function(field) { // TODO: common-hid-packet-parser looks like it should do deltas, but I can't get them to work. prev_pregain = TraktorS4MK2.controller.prev_pregain[field.group]; From 7947e897f84d7aa3e2aabd30dfb7eaef0638c260 Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Mon, 26 Mar 2018 03:48:33 +0100 Subject: [PATCH 3/7] Update fx meta and add shift jogwheel functions --- .../Traktor-Kontrol-S4-MK2-hid-scripts.js | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index f0d8504830c2..677bdf0eab89 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -240,14 +240,22 @@ TraktorS4MK2.registerInputPackets = function() { MessageLong.setCallback("deck2", "!loopsize", this.callbackLoopSize); MessageLong.addControl("[EffectRack1_EffectUnit1]", "mix", 0x3F, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit1_Effect1]", "meta", 0x41, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit1_Effect2]", "meta", 0x43, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit1_Effect3]", "meta", 0x45, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit1_Effect1]", "!FXMeta", 0x41, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit1_Effect2]", "!FXMeta", 0x43, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit1_Effect3]", "!FXMeta", 0x45, "H"); + + MessageLong.setCallback("[EffectRack1_EffectUnit1_Effect1]", "!FXMeta",this.FXMetaHandler); + MessageLong.setCallback("[EffectRack1_EffectUnit1_Effect2]", "!FXMeta",this.FXMetaHandler); + MessageLong.setCallback("[EffectRack1_EffectUnit1_Effect3]", "!FXMeta",this.FXMetaHandler); MessageLong.addControl("[EffectRack1_EffectUnit2]", "mix", 0x47, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit2_Effect1]", "meta", 0x49, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit2_Effect2]", "meta", 0x4B, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit2_Effect3]", "meta", 0x4D, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit2_Effect1]", "!FXMeta", 0x49, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit2_Effect2]", "!FXMeta", 0x4B, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit2_Effect3]", "!FXMeta", 0x4D, "H"); + + MessageLong.setCallback("[EffectRack1_EffectUnit2_Effect1]", "!FXMeta",this.FXMetaHandler); + MessageLong.setCallback("[EffectRack1_EffectUnit2_Effect2]", "!FXMeta",this.FXMetaHandler); + MessageLong.setCallback("[EffectRack1_EffectUnit2_Effect3]", "!FXMeta",this.FXMetaHandler); MessageLong.addControl("[Channel1]", "volume", 0x37, "H"); MessageLong.addControl("[QuickEffectRack1_[Channel1]]", "super1", 0x1D, "H"); @@ -485,7 +493,7 @@ TraktorS4MK2.registerOutputPackets = function() { TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1]", "show_parameters", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2]", "show_parameters", TraktorS4MK2.outputChannelCallback); - TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect1]", "enabled", TraktorS4MK2.outputChannelCallback); + TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect1]", "enabled", TraktorS4MK2.outputChannelCallback) TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect2]", "enabled", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit1_Effect3]", "enabled", TraktorS4MK2.outputChannelCallback); TraktorS4MK2.linkChannelOutput("[EffectRack1_EffectUnit2_Effect1]", "enabled", TraktorS4MK2.outputChannelCallback); @@ -1073,10 +1081,19 @@ TraktorS4MK2.wheelDeltas = function(group, value) { } TraktorS4MK2.scalerJog = function(tick_delta, time_delta) { + // If it's playing nudge if (engine.getValue(group, "play")) { return (tick_delta / time_delta) / 3; } else { - return (tick_delta / time_delta) * 2.0; + //If shift pressed, fast search through tracks + // otherwise search normal speed + if (TraktorS4MK2.controller.shift_pressed['deck1'] || + TraktorS4MK2.controller.shift_pressed['deck2'] + ){ + return (tick_delta / time_delta) * 20.0; + } else { + return (tick_delta / time_delta) * 2.0; + } } } @@ -1160,6 +1177,15 @@ TraktorS4MK2.FXButtonHandler = function(field){ TraktorS4MK2.lightDeck(field.group); } +TraktorS4MK2.FXMetaHandler = function(field){ + engine.setValue(field.group, "meta", field.value / parseFloat(4096)); +} + + +TraktorS4MK2.outputFXCallback = function(value, group, key) { + TraktorS4MK2.controller.setOutput(group, key, value * 0x7F, !TraktorS4MK2.controller.freeze_lights); +} + TraktorS4MK2.callbackPregain = function(field) { // TODO: common-hid-packet-parser looks like it should do deltas, but I can't get them to work. prev_pregain = TraktorS4MK2.controller.prev_pregain[field.group]; From d6de2393abbab89a7d9faf8b9b64fd26e02bcbe3 Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Tue, 27 Mar 2018 02:13:41 +0100 Subject: [PATCH 4/7] Working beatloop counters --- .../Traktor-Kontrol-S4-MK2-hid-scripts.js | 110 ++++++++++++++---- 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index 677bdf0eab89..a8f277558bf6 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -453,6 +453,11 @@ TraktorS4MK2.registerOutputPackets = function() { Output3.addOutput("[EffectRack1_EffectUnit2]", "show_parameters", 0x12, "B"); + for (i=0; i < 16; i++){ + Output3.addOutput("deck1", "!loopSize"+i, 0x1B+i, "B"); + Output3.addOutput("deck2", "!loopSize"+i, 0x2B+i, "B"); + } + this.controller.registerOutputPacket(Output3); // Link up control objects to their outputs @@ -530,6 +535,12 @@ TraktorS4MK2.registerOutputPackets = function() { engine.connectControl("[Channel2]", "loop_enabled", "TraktorS4MK2.onLoopEnabledChanged"); engine.connectControl("[Channel3]", "loop_enabled", "TraktorS4MK2.onLoopEnabledChanged"); engine.connectControl("[Channel4]", "loop_enabled", "TraktorS4MK2.onLoopEnabledChanged"); + + engine.connectControl("[Channel1]", "beatloop_size", "TraktorS4MK2.onLoopSizeChanged"); + engine.connectControl("[Channel2]", "beatloop_size", "TraktorS4MK2.onLoopSizeChanged"); + engine.connectControl("[Channel3]", "beatloop_size", "TraktorS4MK2.onLoopSizeChanged"); + engine.connectControl("[Channel4]", "beatloop_size", "TraktorS4MK2.onLoopSizeChanged"); + } TraktorS4MK2.linkDeckOutputs = function(key, callback) { @@ -588,6 +599,7 @@ TraktorS4MK2.lightDeck = function(group) { TraktorS4MK2.lightGroup(packet, "[EffectRack1_EffectUnit2_Effect3]", "[EffectRack1_EffectUnit2_Effect3]"); // Loop size indicator + TraktorS4MK2.loopSizeSet(group); // Selected deck lights if (group === "[Channel1]") { @@ -1249,36 +1261,55 @@ TraktorS4MK2.callbackLoopMove = function(field) { } } -TraktorS4MK2.sendLoopSizeMessage = function(group, beats) { - var LoopSizeIndicators = { - "deck2" : [0x2B, 0x3A], - "deck1" : [0x1B, 0x2A], - } - start_signal = LoopSizeIndicators[group] +TraktorS4MK2.sendLoopSizeMessage = function(deck, firstChar, secondChar, firstDot, secondDot) { +// display_num must be a string with two chars + // Do the second number first + TraktorS4MK2.displayCharLoopCounter(deck, 0, firstChar); + TraktorS4MK2.displayCharLoopCounter(deck, 1, secondChar); + TraktorS4MK2.displayCharLoopDot(deck, 1, firstDot); + TraktorS4MK2.displayCharLoopDot(deck, 0, secondDot); - var sizesArray = { - 64: [1,2,4,5,6,7,9,10,11,13], - 32: [1,2,3,4,7,9,11,12,14,15], - 16: [2,3,9,10,12,13,14,15], - 8: [9,10,11,12,13,14,15], - 4: [9,10,11,13], - 2: [9,11,12,14,15], - } - var packets = Object(); - - packets.length = 61; +} - start_signal = parseInt(LoopSizeIndicators[group][0]) - for (k = 0; k < 0x7F; k+=0x05) { - packets[0] = 0x82; - for (j = 0; j < sizesArray[beats].length; j++) { - var hid_msg = start_signal + sizesArray[beats][j] - packets[hid_msg] = k; - } - controller.send(packets, packets.length, 0); +TraktorS4MK2.displayCharLoopCounter = function(deck, charPos, character){ + // charPost is 0 or 1 for first or second character + var numArray = { + '': [], + 0: [2,3,4,5,6,7], + 1: [2,3], + 2: [1,3,4,6,7], + 3: [1,2,3,4,7], + 4: [1,2,3,5], + 5: [4,5,1,2,7], + 6: [4,5,1,2,6,7], + 7: [4,3,2], + 8: [1,2,3,4,5,6,7], + 9: [5,4,1,3,2,7], +// Add a few special characters + 'h': [5,1,6,2], + 'n': [6,1,2], + 'o': [6,1,2,7], + '-': [1], + + } + + for (j = 0; j < 8; j++) { + loop_key = 8*charPos + j; + var key = "!loopSize" + loop_key; + TraktorS4MK2.controller.setOutput( + deck, key, (numArray[character].indexOf(j) > -1)*0x7F, + !TraktorS4MK2.controller.freeze_lights + ); } } +TraktorS4MK2.displayCharLoopDot = function(deck, charPos, on){ + var key = "!loopSize" + 8*charPos; + TraktorS4MK2.controller.setOutput( + deck, key, on*0x7F, + !TraktorS4MK2.controller.freeze_lights + ); +} TraktorS4MK2.callbackLoopSize = function(field) { var splitted = field.id.split("."); var group = splitted[0] @@ -1500,3 +1531,32 @@ TraktorS4MK2.onLoopEnabledChanged = function(value, group, key) { TraktorS4MK2.outputCallbackLoop(value, group, "loop_in"); TraktorS4MK2.outputCallbackLoop(value, group, "loop_out"); } + +TraktorS4MK2.onLoopSizeChanged = function(value, group, key) { + var deck = TraktorS4MK2.resolveDeckIfActive(group); + //deal with single digit values + if (value.toString().length === 1){ + TraktorS4MK2.sendLoopSizeMessage(deck, '', value, false, false); + // values with two digits + } else if (value.toString().length === 2 ) { + TraktorS4MK2.sendLoopSizeMessage(deck, value.toString().split("")[0], value.toString().split("")[1], false, false); + // deal with fraction beats + } else if (1 > value > 0 ) { + if (value === 0.5){ + TraktorS4MK2.sendLoopSizeMessage(deck, '-', 2, false, false); + } else if (value === 0.25){ + TraktorS4MK2.sendLoopSizeMessage(deck, '-', 4, false, false); + } else if (value === 0.125){ + TraktorS4MK2.sendLoopSizeMessage(deck, '-', 8, false, false); + } else { + TraktorS4MK2.sendLoopSizeMessage(deck, '-', 'n', false, false); + } + // deal with larger Loops + } else if (value.toString().length > 2){ + TraktorS4MK2.sendLoopSizeMessage(deck, value.toString().split("")[0], value.toString().split("")[1], true, true); + } +} + +TraktorS4MK2.loopSizeSet = function(group) { + TraktorS4MK2.onLoopSizeChanged(engine.getValue(group, "beatloop_size"), group); +} From d005fe7edc95512f52e4f16e9405c8d352ed8998 Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Tue, 27 Mar 2018 02:17:47 +0100 Subject: [PATCH 5/7] Style changes --- res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index a8f277558bf6..7a7f1ceabf41 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -1181,8 +1181,7 @@ TraktorS4MK2.FXButtonHandler = function(field){ TraktorS4MK2.controller.shift_pressed['deck2'] ) { engine.setValue(field.group, "effect_selector", 1); - } - else { + } else { engine.setValue(field.group, "enabled", !engine.getValue(field.group, "enabled")); } } @@ -1217,13 +1216,12 @@ TraktorS4MK2.callbackPregain = function(field) { TraktorS4MK2.controller.shift_pressed['deck1'] || TraktorS4MK2.controller.shift_pressed['deck2'] ) { - if(delta > 0){ + if (delta > 0){ engine.setValue(group, 'beats_translate_later', true); } else if (delta < 0){ engine.setValue(group, 'beats_translate_earlier', true); } - } - else { + } else { var cur_pregain = engine.getValue(group, "pregain"); engine.setValue(group, "pregain", cur_pregain + delta); } @@ -1343,7 +1341,6 @@ TraktorS4MK2.callbackLoopSize = function(field) { engine.setValue(field.group, "loop_halve", 0); } } - // TraktorS4MK2.sendLoopSizeMessage(group, engine.getValue(field.group, "beatloop_size")); } TraktorS4MK2.callbackBrowse = function(field) { From 37a78c263d27180ef98cea01e3625a2c013e2b25 Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Tue, 27 Mar 2018 02:59:42 +0100 Subject: [PATCH 6/7] Change reset to reset key --- res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index 7a7f1ceabf41..b41015077759 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -102,7 +102,7 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck1", "loop_out", 0x0E, "B", 0x08); MessageShort.addControl("deck1", "loop_in", 0x0E, "B", 0x04); MessageShort.addControl("deck1", "slip_enabled", 0x0E, "B", 0x02); - MessageShort.addControl("deck1", "eject", 0x0E, "B", 0x01); + MessageShort.addControl("deck1", "reset_key", 0x0E, "B", 0x01); MessageShort.addControl("deck1", "beatloop_activate", 0x13, "B", 0x02); MessageShort.addControl("deck1", "!loop_activate", 0x13, "B", 0x01); MessageShort.addControl("deck1", "!jog_touch", 0x11, "B", 0x01); @@ -130,7 +130,7 @@ TraktorS4MK2.registerInputPackets = function() { MessageShort.addControl("deck2", "loop_out", 0x0B, "B", 0x08); MessageShort.addControl("deck2", "loop_in", 0x0B, "B", 0x04); MessageShort.addControl("deck2", "slip_enabled", 0x0B, "B", 0x02); - MessageShort.addControl("deck2", "eject", 0x0B, "B", 0x01); + MessageShort.addControl("deck2", "reset_key", 0x0B, "B", 0x01); MessageShort.addControl("deck2", "beatloop_activate", 0x13, "B", 0x10); MessageShort.addControl("deck2", "!loop_activate", 0x13, "B", 0x08); MessageShort.addControl("deck2", "!jog_touch", 0x11, "B", 0x02); From 57e90d2678d8861b96eb6f5e3200628233c9445d Mon Sep 17 00:00:00 2001 From: Fayaaz Ahmed Date: Tue, 27 Mar 2018 03:00:25 +0100 Subject: [PATCH 7/7] Add comments about the display --- .../Traktor-Kontrol-S4-MK2-hid-scripts.js | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js index b41015077759..75226a8e556f 100644 --- a/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S4-MK2-hid-scripts.js @@ -1270,9 +1270,22 @@ TraktorS4MK2.sendLoopSizeMessage = function(deck, firstChar, secondChar, firstDo } TraktorS4MK2.displayCharLoopCounter = function(deck, charPos, character){ - // charPost is 0 or 1 for first or second character + // charPost is 0 or 1 for first or second character on the display + // the display is placed like this: + // o -- 4 -- + // | | + // 5 3 + // | | + // -- 1 -- + // | | + // 6 2 + // | | + // -- 7 -- + // Where the numbers respresent each segment of the display + // and the dot before it is 0 (but this is dealt with in displayCharLoopDot) + var numArray = { - '': [], + '': [], //empty 0: [2,3,4,5,6,7], 1: [2,3], 2: [1,3,4,6,7], @@ -1288,14 +1301,16 @@ TraktorS4MK2.displayCharLoopCounter = function(deck, charPos, character){ 'n': [6,1,2], 'o': [6,1,2,7], '-': [1], - + 'b': [5,6,7,2,1], + 'c': [1,6,7], + 'u': [6,2,7], } for (j = 0; j < 8; j++) { loop_key = 8*charPos + j; var key = "!loopSize" + loop_key; TraktorS4MK2.controller.setOutput( - deck, key, (numArray[character].indexOf(j) > -1)*0x7F, + deck, key, (numArray[character].indexOf(j) > -1)*0x7F, // if it's in the array turn it on, off otherwise !TraktorS4MK2.controller.freeze_lights ); }