From 5fe86df98ee75f37d0871b2810540216c877f390 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Mon, 24 May 2021 16:00:39 +0200 Subject: [PATCH 01/18] NI Traktor S2 Mk1: add controller mapping --- .../Traktor Kontrol S2 Mk1.hid.xml | 18 + .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 1409 +++++++++++++++++ 2 files changed, 1427 insertions(+) create mode 100644 res/controllers/Traktor Kontrol S2 Mk1.hid.xml create mode 100644 res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js diff --git a/res/controllers/Traktor Kontrol S2 Mk1.hid.xml b/res/controllers/Traktor Kontrol S2 Mk1.hid.xml new file mode 100644 index 00000000000..3f4c66c9798 --- /dev/null +++ b/res/controllers/Traktor Kontrol S2 Mk1.hid.xml @@ -0,0 +1,18 @@ + + + + Native Instruments Traktor Kontrol S2 Mk1 + leifhelm + Native Instruments Traktor Kontrol S2 MK1 + + + + + + + + + + + + diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js new file mode 100644 index 00000000000..b48af5000bf --- /dev/null +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -0,0 +1,1409 @@ +/****************************************************************/ +/* Traktor Kontrol S2 MK1 HID controller script */ +/* Copyright (C) 2021, leifhelm */ +/* Based on: */ +/* Traktor Kontrol S2 MK2 HID controller script v1.00 */ +/* Copyright (C) 2020, Be */ +/* Copyright (C) 2017, z411 */ +/* but feel free to tweak this to your heart's content! */ +/****************************************************************/ + +// ==== Jog Wheel Touch Calibration ==== +// Set the threshold for scratching for each jog wheel. +// Bigger values mean more force. The unpressed value is around 3122. +// The fully pressed value is around 3728. +var JogWheelTouchThreshold = { + "[Channel1]": 3328, + "[Channel2]": 3328, +}; + +// ==== Friendly User Configuration ==== +// The Cue button, when Shift is also held, can have two possible functions: +// 1. "REWIND": seeks to the very start of the track. +// 2. "REVERSEROLL": performs a temporary reverse or "censor" effect, where the track +// is momentarily played in reverse until the button is released. +var ShiftCueButtonAction = "REWIND"; + +// Set the brightness of button LEDs which are off and on. This uses a scale from 0 to 0x1F (31). +// If you don't have the optional power adapter and are using the controller with USB bus power, +var ButtonBrightnessOff = 0x00; +var ButtonBrightnessOn = 0x1F; + +// KNOWN ISSUES: +// * The effect button LEDs briefly flicker when pressing the effect focus button. + +// eslint definitions +/* global controller, HIDController, HIDPacket */ +var TraktorS2MK1 = new function() { + this.controller = new HIDController(); + + // When true, packets will not be sent to the controller. + // Used when updating multiple LEDs simultaneously. + this.batchingLEDUpdate = false; + + // Previous values, used for calculating deltas for encoder knobs. + this.previousBrowse = 0; + this.previousPregain = { + "[Channel1]": 0, + "[Channel2]": 0 + }; + this.previousLeftEncoder = { + "[Channel1]": 0, + "[Channel2]": 0 + }; + this.previousRightEncoder = { + "[Channel1]": 0, + "[Channel2]": 0 + }; + this.wheelTouchInertiaTimer = { + "[Channel1]": 0, + "[Channel2]": 0 + }; + + this.topEncoderPressed = { + "[Channel1]": false, + "[Channel2]": false + }; + this.leftEncoderPressed = { + "[Channel1]": false, + "[Channel2]": false + }; + this.shiftPressed = { + "[Channel1]": false, + "[Channel2]": false + }; + + this.padModes = { + "hotcue": 0, + "introOutro": 1, + "sampler": 2 + }; + this.currentPadMode = { + "[Channel1]": this.padModes.hotcue, + "[Channel2]": this.padModes.hotcue + }; + this.padConnections = { + "[Channel1]": [], + "[Channel2]": [] + }; + + this.lastTickValue = [0, 0]; + this.lastTickTime = [0.0, 0.0]; + this.syncEnabledTime = {}; + + this.longPressTimeoutMilliseconds = 275; + + this.effectButtonLongPressTimer = { + "[EffectRack1_EffectUnit1]": [0, 0, 0, 0], + "[EffectRack1_EffectUnit2]": [0, 0, 0, 0] + }; + this.effectButtonIsLongPressed = { + "[EffectRack1_EffectUnit1]": [false, false, false, false], + "[EffectRack1_EffectUnit2]": [false, false, false, false] + }; + this.effectFocusLongPressTimer = { + "[EffectRack1_EffectUnit1]": 0, + "[EffectRack1_EffectUnit2]": 0 + }; + this.effectFocusChooseModeActive = { + "[EffectRack1_EffectUnit1]": false, + "[EffectRack1_EffectUnit2]": false + }; + this.effectFocusButtonPressedWhenParametersHidden = { + "[EffectRack1_EffectUnit1]": false, + "[EffectRack1_EffectUnit2]": false + }; + this.previouslyFocusedEffect = { + "[EffectRack1_EffectUnit1]": null, + "[EffectRack1_EffectUnit2]": null + }; + this.effectButtonLEDconnections = { + "[EffectRack1_EffectUnit1]": [], + "[EffectRack1_EffectUnit2]": [] + }; + this.playIndicatorConnections = { + "[Channel1]": [], + "[Channel2]": [], + }; + this.pflConnections = { + "[Channel1]": [], + "[Channel2]": [], + }; +}; + +TraktorS2MK1.registerInputPackets = function() { + var MessageShort = new HIDPacket("shortmessage", 0x01, this.shortMessageCallback); + var MessageLong = new HIDPacket("longmessage", 0x02, this.longMessageCallback); + + // Values in the short message are all buttons, except the jog wheels. + // An exclamation point indicates a specially-handled function. Everything else is a standard + // Mixxx control object name. + + MessageShort.addControl("[Channel1]", "!top_encoder_press", 0x0E, "B", 0x01, false, this.topEncoderPress); + MessageShort.addControl("[Channel1]", "!shift", 0x0D, "B", 0x80, false, this.shift); + MessageShort.addControl("[Channel1]", "!sync_enabled", 0x0D, "B", 0x40, false, this.syncButton); + MessageShort.addControl("[Channel1]", "!cue_default", 0x0D, "B", 0x20, false, this.cueButton); + MessageShort.addControl("[Channel1]", "!play", 0x0D, "B", 0x10, false, this.playButton); + MessageShort.addControl("[Channel1]", "!pad1", 0x0D, "B", 0x08, false, this.padButton); + MessageShort.addControl("[Channel1]", "!pad2", 0x0D, "B", 0x04, false, this.padButton); + MessageShort.addControl("[Channel1]", "!pad3", 0x0D, "B", 0x02, false, this.padButton); + MessageShort.addControl("[Channel1]", "!pad4", 0x0D, "B", 0x01, false, this.padButton); + MessageShort.addControl("[Channel1]", "!loop_in", 0x09, "B", 0x40, false, this.loopInButton); + MessageShort.addControl("[Channel1]", "!loop_out", 0x09, "B", 0x20, false, this.loopOutButton); + MessageShort.addControl("[Channel1]", "!remix_button", 0x0B, "B", 0x02, false, this.samplerModeButton); + MessageShort.addControl("[Channel1]", "!flux_button", 0x09, "B", 0x10, false, this.introOutroModeButton); + MessageShort.addControl("[Channel1]", "!left_encoder_press", 0x0E, "B", 0x02, false, this.leftEncoderPress); + MessageShort.addControl("[Channel1]", "!right_encoder_press", 0x0E, "B", 0x04, false, this.rightEncoderPress); + MessageShort.addControl("[Channel1]", "!jog_wheel", 0x01, "I", 0xFFFFFFFF, false, this.jogMove); + MessageShort.addControl("[Channel1]", "!load_track", 0x0B, "B", 0x08, false, this.loadTrackButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effect_focus_button", + 0x09, "B", 0x08, false, this.effectFocusButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x09, "B", 0x04, false, this.effectButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x09, "B", 0x02, false, this.effectButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x09, "B", 0x01, false, this.effectButton); + + MessageShort.addControl("[Channel2]", "!top_encoder_press", 0x0E, "B", 0x10, false, this.topEncoderPress); + MessageShort.addControl("[Channel2]", "!shift", 0x0C, "B", 0x80, false, this.shift); + MessageShort.addControl("[Channel2]", "!sync_enabled", 0x0C, "B", 0x40, false, this.syncButton); + MessageShort.addControl("[Channel2]", "!cue_default", 0x0C, "B", 0x20, false, this.cueButton); + MessageShort.addControl("[Channel2]", "!play", 0x0C, "B", 0x10, false, this.playButton); + MessageShort.addControl("[Channel2]", "!pad1", 0x0C, "B", 0x08, false, this.padButton); + MessageShort.addControl("[Channel2]", "!pad2", 0x0C, "B", 0x04, false, this.padButton); + MessageShort.addControl("[Channel2]", "!pad3", 0x0C, "B", 0x02, false, this.padButton); + MessageShort.addControl("[Channel2]", "!pad4", 0x0C, "B", 0x01, false, this.padButton); + MessageShort.addControl("[Channel2]", "!loop_in", 0x0B, "B", 0x40, false, this.loopInButton); + MessageShort.addControl("[Channel2]", "!loop_out", 0x0B, "B", 0x20, false, this.loopOutButton); + MessageShort.addControl("[Channel2]", "!remix_button", 0x0B, "B", 0x01, false, this.samplerModeButton); + MessageShort.addControl("[Channel2]", "!flux_button", 0x0B, "B", 0x10, false, this.introOutroModeButton); + MessageShort.addControl("[Channel2]", "!left_encoder_press", 0x0E, "B", 0x20, false, this.leftEncoderPress); + MessageShort.addControl("[Channel2]", "!right_encoder_press", 0x0E, "B", 0x40, false, this.rightEncoderPress); + MessageShort.addControl("[Channel2]", "!jog_wheel", 0x05, "I", 0xFFFFFFFF, false, this.jogMove); + MessageShort.addControl("[Channel2]", "!load_track", 0x0B, "B", 0x04, false, this.loadTrackButton); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effect_focus_button", + 0x0A, "B", 0x80, false, this.effectFocusButton); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton1", 0xA, "B", 0x40, false, this.effectButton); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton2", 0xA, "B", 0x20, false, this.effectButton); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton3", 0xA, "B", 0x10, false, this.effectButton); + + MessageShort.addControl("[Channel1]", "!pfl", 0x09, "B", 0x80, false, this.pflButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x0A, "B", 0x02); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x0A, "B", 0x01); + + MessageShort.addControl("[Channel2]", "!pfl", 0x0B, "B", 0x80, false, this.pflButton); + MessageShort.addControl("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x0A, "B", 0x08); + MessageShort.addControl("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x0A, "B", 0x04); + + MessageShort.addControl("[Master]", "maximize_library", 0x0E, "B", 0x08, false, this.toggleButton); + + engine.makeConnection("[EffectRack1_EffectUnit1]", "show_parameters", TraktorS2MK1.onShowParametersChange); + engine.makeConnection("[EffectRack1_EffectUnit2]", "show_parameters", TraktorS2MK1.onShowParametersChange); + + this.controller.registerInputPacket(MessageShort); + + // Most items in the long message are controls that go from 0-4096. + // There are also some 4 bit encoders. + MessageLong.addControl("[Channel1]", "rate", 0x0F, "H"); + MessageLong.addControl("[Channel2]", "rate", 0x1F, "H"); + MessageLong.addControl("[Channel1]", "!left_encoder", 0x01, "B", 0xF0, false, this.leftEncoder); + MessageLong.addControl("[Channel1]", "!right_encoder", 0x02, "B", 0x0F, false, this.rightEncoder); + MessageLong.addControl("[Channel2]", "!left_encoder", 0x03, "B", 0xF0, false, this.leftEncoder); + MessageLong.addControl("[Channel2]", "!right_encoder", 0x04, "B", 0x0F, false, this.rightEncoder); + + MessageLong.addControl("[EffectRack1_EffectUnit1]", "mix", 0x0B, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob1", 0x09, "H", 0xFFFF, false, this.effectKnob); + MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob2", 0x07, "H", 0xFFFF, false, this.effectKnob); + MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob3", 0x05, "H", 0xFFFF, false, this.effectKnob); + + MessageLong.addControl("[EffectRack1_EffectUnit2]", "mix", 0x1B, "H"); + MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob1", 0x19, "H", 0xFFFF, false, this.effectKnob); + MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob2", 0x17, "H", 0xFFFF, false, this.effectKnob); + MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob3", 0x15, "H", 0xFFFF, false, this.effectKnob); + + MessageLong.addControl("[Channel1]", "volume", 0x2B, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", 0x11, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", 0x25, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", 0x27, "H"); + MessageLong.addControl("[Channel1]", "pregain", 0x01, "B", 0x0F, false, this.topEncoder); + MessageLong.addControl("[Channel1]", "!jog_touch", 0x0D, "H", 0xFFFF, false, this.jogTouch); + + MessageLong.addControl("[Channel2]", "volume", 0x2D, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter3", 0x21, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", 0x23, "H"); + MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", 0x29, "H"); + MessageLong.addControl("[Channel2]", "pregain", 0x03, "B", 0x0F, false, this.topEncoder); + MessageLong.addControl("[Channel2]", "!jog_touch", 0x1D, "H", 0xFFFF, false, this.jogTouch); + + MessageLong.addControl("[Master]", "crossfader", 0x2F, "H"); + MessageLong.addControl("[Master]", "headMix", 0x31, "H"); + MessageLong.addControl("[Master]", "!samplerGain", 0x13, "H"); + MessageLong.setCallback("[Master]", "!samplerGain", this.samplerGainKnob); + MessageLong.addControl("[Playlist]", "!browse", 0x02, "B", 0xF0, false, this.browseEncoder); + + // Soft takeover for knobs + engine.softTakeover("[Channel1]", "rate", true); + engine.softTakeover("[Channel2]", "rate", true); + + engine.softTakeover("[Channel1]", "volume", true); + engine.softTakeover("[Channel2]", "volume", true); + + engine.softTakeover("[Channel1]", "pregain", true); + engine.softTakeover("[Channel2]", "pregain", true); + + engine.softTakeover("[Master]", "crossfader", true); + engine.softTakeover("[Master]", "headMix", true); + for (var i = 1; i <= 8; i++) { + engine.softTakeover("[Sampler" + i + "]", "pregain", true); + } + + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", true); + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", true); + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", true); + + engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter3", true); + engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", true); + engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", true); + + for (var i = 1; i <= 3; i++) { + engine.softTakeover("[EffectRack1_EffectUnit1_Effect" + i + "]", "meta", true); + engine.softTakeover("[EffectRack1_EffectUnit2_Effect" + i + "]", "meta", true); + for (var j = 1; j <= 3; j++) { + engine.softTakeover("[EffectRack1_EffectUnit1_Effect" + i + "]", "parameter" + j, true); + engine.softTakeover("[EffectRack1_EffectUnit2_Effect" + i + "]", "parameter" + j, true); + } + } + + // Set scalers + TraktorS2MK1.scalerParameter.useSetParameter = true; + this.controller.setScaler("volume", this.scalerVolume); + this.controller.setScaler("headMix", this.scalerSlider); + this.controller.setScaler("parameter1", this.scalerParameter); + this.controller.setScaler("parameter2", this.scalerParameter); + this.controller.setScaler("parameter3", this.scalerParameter); + this.controller.setScaler("super1", this.scalerParameter); + this.controller.setScaler("crossfader", this.scalerSlider); + this.controller.setScaler("rate", this.scalerSlider); + this.controller.setScaler("mix", this.scalerParameter); + + // Register packet + this.controller.registerInputPacket(MessageLong); +}; + +TraktorS2MK1.registerOutputPackets = function() { + var Output = new HIDPacket("output", 0x80); + + Output.addOutput("[Channel1]", "track_loaded", 0x1F, "B"); + Output.addOutput("[Channel2]", "track_loaded", 0x1E, "B"); + + var VuOffsets = { + "[Channel1]": 0x15, + "[Channel2]": 0x11, + }; + for (var ch in VuOffsets) { + for (var i = 0; i <= 0x03; i++) { + Output.addOutput(ch, "!" + "VuMeter" + i, VuOffsets[ch] + i, "B"); + } + } + + Output.addOutput("[Channel1]", "PeakIndicator", 0x01, "B"); + Output.addOutput("[Channel2]", "PeakIndicator", 0x25, "B"); + + Output.addOutput("[Channel1]", "!flux_button", 0x06, "B"); + Output.addOutput("[Channel1]", "loop_in", 0x02, "B"); + Output.addOutput("[Channel1]", "loop_out", 0x05, "B"); + + Output.addOutput("[Channel2]", "!flux_button", 0x26, "B"); + Output.addOutput("[Channel2]", "loop_in", 0x22, "B"); + Output.addOutput("[Channel2]", "loop_out", 0x21, "B"); + + Output.addOutput("[Channel1]", "!pfl", 0x20, "B"); + Output.addOutput("[Master]", "!warninglight", 0x31, "B"); + Output.addOutput("[Channel2]", "!pfl", 0x1D, "B"); + + Output.addOutput("[EffectRack1_EffectUnit1]", "!effect_focus_button", 0x1C, "B"); + Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x1B, "B"); + Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x1A, "B"); + Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x19, "B"); + + Output.addOutput("[EffectRack1_EffectUnit2]", "!effect_focus_button", 0x39, "B"); + Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton1", 0x38, "B"); + Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton2", 0x37, "B"); + Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton3", 0x36, "B"); + + Output.addOutput("[Channel1]", "!remix_button", 0x35, "B"); + Output.addOutput("[Channel2]", "!remix_button", 0x34, "B"); + + Output.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x3D, "B"); + Output.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x3C, "B"); + Output.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x3B, "B"); + Output.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x3A, "B"); + + Output.addOutput("[Channel1]", "!shift", 0x08, "B"); + Output.addOutput("[Channel1]", "sync_enabled", 0x04, "B"); + Output.addOutput("[Channel1]", "cue_indicator", 0x07, "B"); + Output.addOutput("[Channel1]", "!play_indicator", 0x03, "B"); + + Output.addOutput("[Channel1]", "!pad_1_G", 0x0C, "B"); + Output.addOutput("[Channel1]", "!pad_1_B", 0x10, "B"); + + Output.addOutput("[Channel1]", "!pad_2_G", 0x0B, "B"); + Output.addOutput("[Channel1]", "!pad_2_B", 0x0F, "B"); + + Output.addOutput("[Channel1]", "!pad_3_G", 0x0A, "B"); + Output.addOutput("[Channel1]", "!pad_3_B", 0x0E, "B"); + + Output.addOutput("[Channel1]", "!pad_4_G", 0x09, "B"); + Output.addOutput("[Channel1]", "!pad_4_B", 0x0D, "B"); + + Output.addOutput("[Channel2]", "!shift", 0x28, "B"); + Output.addOutput("[Channel2]", "sync_enabled", 0x24, "B"); + Output.addOutput("[Channel2]", "cue_indicator", 0x27, "B"); + Output.addOutput("[Channel2]", "!play_indicator", 0x23, "B"); + + Output.addOutput("[Channel2]", "!pad_1_G", 0x2C, "B"); + Output.addOutput("[Channel2]", "!pad_1_B", 0x30, "B"); + + Output.addOutput("[Channel2]", "!pad_2_G", 0x2B, "B"); + Output.addOutput("[Channel2]", "!pad_2_B", 0x2F, "B"); + + Output.addOutput("[Channel2]", "!pad_3_G", 0x2A, "B"); + Output.addOutput("[Channel2]", "!pad_3_B", 0x2E, "B"); + + Output.addOutput("[Channel2]", "!pad_4_G", 0x29, "B"); + Output.addOutput("[Channel2]", "!pad_4_B", 0x2D, "B"); + + this.controller.registerOutputPacket(Output); + + // Link up control objects to their outputs + TraktorS2MK1.linkDeckOutputs("sync_enabled", TraktorS2MK1.outputCallback); + TraktorS2MK1.linkDeckOutputs("cue_indicator", TraktorS2MK1.outputCallback); + TraktorS2MK1.setPlayIndicatorMode("[Channel1]", true); + TraktorS2MK1.setPlayIndicatorMode("[Channel2]", true); + TraktorS2MK1.setPflMode("[Channel1]", true); + TraktorS2MK1.setPflMode("[Channel2]", true); + + TraktorS2MK1.setPadMode("[Channel1]", TraktorS2MK1.padModes.hotcue); + TraktorS2MK1.setPadMode("[Channel2]", TraktorS2MK1.padModes.hotcue); + + TraktorS2MK1.linkDeckOutputs("loop_in", TraktorS2MK1.outputCallbackLoop); + TraktorS2MK1.linkDeckOutputs("loop_out", TraktorS2MK1.outputCallbackLoop); + TraktorS2MK1.linkDeckOutputs("LoadSelectedTrack", TraktorS2MK1.outputCallback); + TraktorS2MK1.linkDeckOutputs("slip_enabled", TraktorS2MK1.outputCallback); + TraktorS2MK1.linkChannelOutput("[Channel1]", "track_loaded", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[Channel2]", "track_loaded", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[Channel1]", "PeakIndicator", TraktorS2MK1.outputChannelCallbackDark); + TraktorS2MK1.linkChannelOutput("[Channel2]", "PeakIndicator", TraktorS2MK1.outputChannelCallbackDark); + TraktorS2MK1.linkChannelOutput("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", TraktorS2MK1.outputChannelCallback); + + engine.makeConnection("[EffectRack1_EffectUnit1]", "focused_effect", TraktorS2MK1.onFocusedEffectChange).trigger(); + engine.makeConnection("[EffectRack1_EffectUnit2]", "focused_effect", TraktorS2MK1.onFocusedEffectChange).trigger(); + TraktorS2MK1.connectEffectButtonLEDs("[EffectRack1_EffectUnit1]"); + TraktorS2MK1.connectEffectButtonLEDs("[EffectRack1_EffectUnit2]"); + + engine.makeConnection("[Channel1]", "VuMeter", TraktorS2MK1.onVuMeterChanged).trigger(); + engine.makeConnection("[Channel2]", "VuMeter", TraktorS2MK1.onVuMeterChanged).trigger(); + + engine.makeConnection("[Channel1]", "loop_enabled", TraktorS2MK1.onLoopEnabledChanged); + engine.makeConnection("[Channel2]", "loop_enabled", TraktorS2MK1.onLoopEnabledChanged); +}; + +TraktorS2MK1.linkDeckOutputs = function(key, callback) { + TraktorS2MK1.controller.linkOutput("[Channel1]", key, "[Channel1]", key, callback); + TraktorS2MK1.controller.linkOutput("[Channel2]", key, "[Channel2]", key, callback); +}; + +TraktorS2MK1.linkDeckCustomOutputs = function(key, callback){ + engine.makeConnection("[Channel1]", key, callback).trigger(); + engine.makeConnection("[Channel2]", key, callback).trigger(); +}; + +TraktorS2MK1.linkChannelOutput = function(group, key, callback) { + TraktorS2MK1.controller.linkOutput(group, key, group, key, callback); +}; + +TraktorS2MK1.lightGroup = function(packet, outputGroupName, coGroupName) { + var groupObject = packet.groups[outputGroupName]; + for (var fieldName in groupObject) { + var field = groupObject[fieldName]; + if (field.name[0] === "!") { + continue; + } + if (field.mapped_callback) { + var value = engine.getValue(coGroupName, field.name); + field.mapped_callback(value, coGroupName, field.name); + } + // No callback, no light! + } +}; + +TraktorS2MK1.lightDeck = function(group) { + // Freeze the lights while we do this update so we don't spam HID. + this.batchingLEDUpdate = true; + for (var packetName in this.controller.OutputPackets) { + var packet = this.controller.OutputPackets[packetName]; + TraktorS2MK1.lightGroup(packet, group, group); + // These outputs show state managed by this script and do not react to ControlObject changes, + // so manually set them here. + TraktorS2MK1.outputCallback(0, group, "!shift"); + TraktorS2MK1.outputCallback(0, group, "!flux_button"); + TraktorS2MK1.outputCallback(0, group, "!remix_button"); + } + + this.batchingLEDUpdate = false; + // And now send them all. + for (packetName in this.controller.OutputPackets) { + this.controller.OutputPackets[packetName].send(); + } +}; + +TraktorS2MK1.init = function() { + if (!(ShiftCueButtonAction === "REWIND" || ShiftCueButtonAction === "REVERSEROLL")) { + throw new Error("ShiftCueButtonAction must be either \"REWIND\" or \"REVERSEROLL\"\n" + + "ShiftCueButtonAction is: " + ShiftCueButtonAction); + } + if (typeof ButtonBrightnessOff !== "number" || ButtonBrightnessOff < 0 || ButtonBrightnessOff > 0x1f) { + throw new Error("ButtonBrightnessOff must be a number between 0 and 0x1f (31).\n" + + "ButtonBrightnessOff is: " + ButtonBrightnessOff); + } + if (typeof ButtonBrightnessOff !== "number" || ButtonBrightnessOff < 0 || ButtonBrightnessOff > 0x1f) { + throw new Error("ButtonBrightnessOn must be a number between 0 and 0x1f (31).\n" + + "ButtonBrightnessOn is: " + ButtonBrightnessOn); + } + if (ButtonBrightnessOn < ButtonBrightnessOff) { + throw new Error("ButtonBrightnessOn must be greater than ButtonBrightnessOff.\n" + + "ButtonBrightnessOn is: " + ButtonBrightnessOn + "\n" + + "ButtonBrightnessOff is: " + ButtonBrightnessOff); + } + + TraktorS2MK1.registerInputPackets(); + + var debugLEDs = false; + if (debugLEDs) { + var data = [0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f]; + controller.send(data, data.length, 0x80); + } else { + TraktorS2MK1.registerOutputPackets(); + } + + TraktorS2MK1.controller.setOutput("[Master]", "!warninglight", 0x00, true); + TraktorS2MK1.lightDeck("[Channel1]"); + TraktorS2MK1.lightDeck("[Channel2]"); + TraktorS2MK1.lightDeck("[EffectRack1_EffectUnit1]"); + TraktorS2MK1.lightDeck("[EffectRack1_EffectUnit2]"); +}; + +TraktorS2MK1.shutdown = function() { + var data = []; + for (var i = 0; i < 61; i++) { + data[i] = 0; + } + controller.send(data, data.length, 0x80); +}; + +TraktorS2MK1.incomingData = function(data, length) { + TraktorS2MK1.controller.parsePacket(data, length); +}; + +// The short message handles buttons and jog wheels. +TraktorS2MK1.shortMessageCallback = function(packet, data) { + for (var name in data) { + var field = data[name]; + if (field.name === "!jog_wheel") { + TraktorS2MK1.controller.processControl(field); + continue; + } + + TraktorS2MK1.controller.processButton(field); + } +}; + +// There are no buttons handled by the long message, so this is a little simpler. +TraktorS2MK1.longMessageCallback = function(packet, data) { + for (var name in data) { + var field = data[name]; + TraktorS2MK1.controller.processControl(field); + } +}; + +TraktorS2MK1.samplerGainKnob = function(field) { + for (var i = 1; i <= 8; i++) { + engine.setParameter("[Sampler" + i + "]", "pregain", field.value / 4096); + } +}; + +TraktorS2MK1.toggleButton = function(field) { + if (field.value > 0) { + script.toggleControl(field.group, field.name); + } +}; + +TraktorS2MK1.shift = function(field) { + var shiftPressed = field.value > 0; + TraktorS2MK1.shiftPressed[field.group] = shiftPressed; + TraktorS2MK1.controller.setOutput(field.group, "!shift", + shiftPressed ? ButtonBrightnessOn : ButtonBrightnessOff, field.group, "!shift", + !TraktorS2MK1.batchingLEDUpdate); + TraktorS2MK1.setPlayIndicatorMode(field.group, !shiftPressed); + TraktorS2MK1.setPflMode(field.group, !shiftPressed); +}; + +TraktorS2MK1.loadTrackButton = function(field) { + if (TraktorS2MK1.shiftPressed[field.group]) { + engine.setValue(field.group, "eject", field.value); + } else { + engine.setValue(field.group, "LoadSelectedTrack", field.value); + } +}; + +TraktorS2MK1.syncButton = function(field) { + var now = Date.now(); + + // If shifted, just toggle. + // TODO(later version): actually make this enable explicit master. + if (TraktorS2MK1.shiftPressed[field.group]) { + if (field.value === 0) { + return; + } + var synced = engine.getValue(field.group, "sync_enabled"); + engine.setValue(field.group, "sync_enabled", !synced); + } else { + if (field.value === 1) { + TraktorS2MK1.syncEnabledTime[field.group] = now; + engine.setValue(field.group, "sync_enabled", 1); + } else { + if (!engine.getValue(field.group, "sync_enabled")) { + // If disabled, and switching to disable... stay disabled. + engine.setValue(field.group, "sync_enabled", 0); + return; + } + // was enabled, and button has been let go. maybe latch it. + if (now - TraktorS2MK1.syncEnabledTime[field.group] > 300) { + engine.setValue(field.group, "sync_enabled", 1); + return; + } + engine.setValue(field.group, "sync_enabled", 0); + } + } +}; + +TraktorS2MK1.cueButton = function(field) { + if (TraktorS2MK1.shiftPressed[field.group]) { + if (ShiftCueButtonAction === "REWIND") { + if (field.value === 0) { + return; + } + engine.setValue(field.group, "start_stop", 1); + } else if (ShiftCueButtonAction === "REVERSEROLL") { + engine.setValue(field.group, "reverseroll", field.value); + } + } else { + engine.setValue(field.group, "cue_default", field.value); + } +}; + +TraktorS2MK1.playButton = function(field) { + if (field.value === 0) { + return; + } + if (TraktorS2MK1.shiftPressed[field.group]) { + var locked = engine.getValue(field.group, "keylock"); + engine.setValue(field.group, "keylock", !locked); + } else { + var playing = engine.getValue(field.group, "play"); + var deckNumber = TraktorS2MK1.controller.resolveDeck(field.group); + // Failsafe to disable scratching in case the finishJogTouch timer has not executed yet + // after a backspin. + if (engine.isScratching(deckNumber)) { + engine.scratchDisable(deckNumber, false); + } + engine.setValue(field.group, "play", !playing); + } +}; + +TraktorS2MK1.jogTouch = function(field) { + if (TraktorS2MK1.wheelTouchInertiaTimer[field.group] !== 0) { + // The wheel was touched again, reset the timer. + engine.stopTimer(TraktorS2MK1.wheelTouchInertiaTimer[field.group]); + TraktorS2MK1.wheelTouchInertiaTimer[field.group] = 0; + } + if (field.value > JogWheelTouchThreshold[field.group]) { + var deckNumber = TraktorS2MK1.controller.resolveDeck(field.group); + engine.scratchEnable(deckNumber, 1024, 33.3333, 0.125, 0.125/8, true); + } else { + // The wheel touch sensor can be overly sensitive, so don't release scratch mode right away. + // Depending on how fast the platter was moving, lengthen the time we'll wait. + var scratchRate = Math.abs(engine.getValue(field.group, "scratch2")); + // inertiaTime was experimentally determined. It should be enough time to allow the user to + // press play after a backspin without normal playback starting before they can press the + // button, but not so long that there is an awkward delay before stopping scratching after + // a backspin. + var inertiaTime; + if (TraktorS2MK1.shiftPressed[field.group]) { + inertiaTime = Math.pow(1.7, scratchRate / 10) / 1.6; + } else { + inertiaTime = Math.pow(1.7, scratchRate) / 1.6; + } + if (inertiaTime < 100) { + // Just do it now. + TraktorS2MK1.finishJogTouch(field.group); + } else { + TraktorS2MK1.wheelTouchInertiaTimer[field.group] = engine.beginTimer( + inertiaTime, function() { + TraktorS2MK1.finishJogTouch(field.group); + }, true); + } + } +}; + +TraktorS2MK1.finishJogTouch = function(group) { + TraktorS2MK1.wheelTouchInertiaTimer[group] = 0; + var deckNumber = TraktorS2MK1.controller.resolveDeck(group); + var play = engine.getValue(group, "play"); + if (play !== 0) { + // If we are playing, just hand off to the engine. + engine.scratchDisable(deckNumber, true); + } else { + // If things are paused, there will be a non-smooth handoff between scratching and jogging. + // Instead, keep scratch on until the platter is not moving. + var scratchRate = Math.abs(engine.getValue(group, "scratch2")); + if (scratchRate < 0.01) { + // The platter is basically stopped, now we can disable scratch and hand off to jogging. + engine.scratchDisable(deckNumber, true); + } else { + // Check again soon. + TraktorS2MK1.wheelTouchInertiaTimer[group] = engine.beginTimer( + 1, function() { + TraktorS2MK1.finishJogTouch(group); + }, true); + } + } +}; + +TraktorS2MK1.jogMove = function(field) { + var deltas = TraktorS2MK1.wheelDeltas(field.group, field.value); + var tickDelta = deltas[0]; + var timeDelta = deltas[1]; + + if (engine.getValue(field.group, "scratch2_enable")) { + var deckNumber = TraktorS2MK1.controller.resolveDeck(field.group); + if (TraktorS2MK1.shiftPressed[field.group]) { + tickDelta *= 10; + } + engine.scratchTick(deckNumber, tickDelta); + } else { + var velocity = TraktorS2MK1.scalerJog(tickDelta, timeDelta, field.group); + engine.setValue(field.group, "jog", velocity); + } +}; + +TraktorS2MK1.wheelDeltas = function(group, value) { + // When the wheel is touched, four bytes change, but only the first behaves predictably. + // It looks like the wheel is 1024 ticks per revolution. + var tickval = value & 0xFF; + var timeValue = value >>> 16; + var previousTick = 0; + var previousTime = 0; + + if (group[8] === "1" || group[8] === "3") { + previousTick = TraktorS2MK1.lastTickValue[0]; + previousTime = TraktorS2MK1.lastTickTime[0]; + TraktorS2MK1.lastTickValue[0] = tickval; + TraktorS2MK1.lastTickTime[0] = timeValue; + } else { + previousTick = TraktorS2MK1.lastTickValue[1]; + previousTime = TraktorS2MK1.lastTickTime[1]; + TraktorS2MK1.lastTickValue[1] = tickval; + TraktorS2MK1.lastTickTime[1] = timeValue; + } + + if (previousTime > timeValue) { + // We looped around. Adjust current time so that subtraction works. + timeValue += 0x10000; + } + var timeDelta = timeValue - previousTime; + if (timeDelta === 0) { + // Spinning too fast to detect speed! By not dividing we are guessing it took 1ms. + timeDelta = 1; + } + + var tickDelta = 0; + if (previousTick >= 200 && tickval <= 100) { + tickDelta = tickval + 256 - previousTick; + } else if (previousTick <= 100 && tickval >= 200) { + tickDelta = tickval - previousTick - 256; + } else { + tickDelta = tickval - previousTick; + } + //HIDDebug(group + " " + tickval + " " + previousTick + " " + tickDelta); + return [tickDelta, timeDelta]; +}; + +TraktorS2MK1.scalerJog = function(tickDelta, timeDelta, group) { + if (engine.getValue(group, "play")) { + return (tickDelta / timeDelta) / 3; + } else { + return (tickDelta / timeDelta) * 2.0; + } +}; + +var introOutroKeys = [ + "intro_start", + "intro_end", + "outro_start", + "outro_end" +]; + +var introOutroColors = [ + {green: 0x1F, blue: 0}, + {green: 0x1F, blue: 0}, + {green: 0, blue: 0x1F}, + {green: 0, blue: 0x1F} +]; + +var introOutroColorsDim = [ + {green: 0x05, blue: 0}, + {green: 0x05, blue: 0}, + {green: 0, blue: 0x05}, + {green: 0, blue: 0x05} +]; + + +TraktorS2MK1.setPadMode = function(group, padMode) { + TraktorS2MK1.padConnections[group].forEach(function(connection) { + connection.disconnect(); + }); + TraktorS2MK1.padConnections[group] = []; + + if (padMode === TraktorS2MK1.padModes.hotcue) { + for (var i = 1; i <= 4; i++) { + TraktorS2MK1.padConnections[group].push( + engine.makeConnection(group, "hotcue_" + i + "_enabled", TraktorS2MK1.outputHotcueCallback)); + // TraktorS2MK1.padConnections[group].push( + // engine.makeConnection(group, "hotcue_" + i + "_color", TraktorS2MK1.outputHotcueCallback)); + } + } else if (padMode === TraktorS2MK1.padModes.introOutro) { + for (i = 1; i <= 4; i++) { + // This function to create callback functions is needed so the loop index variable + // i does not get captured in a closure within the callback. + var makeIntroOutroCallback = function(padNumber) { + return function(value, group, _control) { + if (value > 0) { + TraktorS2MK1.sendPadColor(group, padNumber, introOutroColors[padNumber-1]); + } else { + TraktorS2MK1.sendPadColor(group, padNumber, introOutroColorsDim[padNumber-1]); + } + }; + }; + TraktorS2MK1.padConnections[group].push(engine.makeConnection( + group, introOutroKeys[i-1] + "_enabled", makeIntroOutroCallback(i))); + } + } else if (padMode === TraktorS2MK1.padModes.sampler) { + for (i = 1; i <= 4; i++) { + var makeSamplerCallback = function(deckGroup, padNumber) { + var samplerNumber = deckGroup === "[Channel1]" ? padNumber : padNumber + 4; + var samplerGroup = "[Sampler" + samplerNumber + "]"; + return function(_value, _group, _control) { + if (engine.getValue(samplerGroup, "track_loaded")) { + if (engine.getValue(samplerGroup, "play") === 1) { + if (engine.getValue(samplerGroup, "repeat") === 1) { + TraktorS2MK1.sendPadColor(deckGroup, padNumber, + {green: 0x1F, blue: 0x1F}); + } else { + TraktorS2MK1.sendPadColor(deckGroup, padNumber, + {green: 0x1F, blue: 0}); + } + } else { + TraktorS2MK1.sendPadColor(deckGroup, padNumber, {green: 0x05, blue: 0x00}); + } + } else { + TraktorS2MK1.sendPadColor(deckGroup, padNumber, {green: 0, blue: 0}); + } + }; + }; + + var sNumber = group === "[Channel1]" ? i : i + 4; + var sGroup = "[Sampler" + sNumber + "]"; + TraktorS2MK1.padConnections[group].push(engine.makeConnection( + sGroup, "track_loaded", makeSamplerCallback(group, i))); + TraktorS2MK1.padConnections[group].push(engine.makeConnection( + sGroup, "play", makeSamplerCallback(group, i))); + TraktorS2MK1.padConnections[group].push(engine.makeConnection( + sGroup, "repeat", makeSamplerCallback(group, i))); + } + } + + TraktorS2MK1.padConnections[group].forEach(function(connection) { + connection.trigger(); + }); + + TraktorS2MK1.currentPadMode[group] = padMode; +}; + +TraktorS2MK1.hotcueButton = function(buttonNumber, group, value) { + if (TraktorS2MK1.shiftPressed[group]) { + engine.setValue(group, "hotcue_" + buttonNumber + "_clear", value); + } else { + engine.setValue(group, "hotcue_" + buttonNumber + "_activate", value); + } +}; + +TraktorS2MK1.introOutroButton = function(buttonNumber, group, value) { + if (TraktorS2MK1.shiftPressed[group]) { + engine.setValue(group, introOutroKeys[buttonNumber-1] + "_clear", value); + } else { + engine.setValue(group, introOutroKeys[buttonNumber-1] + "_activate", value); + } +}; + +TraktorS2MK1.samplerButton = function(buttonNumber, group, value) { + if (value === 0) { + return; + } + var samplerNumber = group === "[Channel1]" ? buttonNumber : buttonNumber + 4; + var samplerGroup = "[Sampler" + samplerNumber + "]"; + if (TraktorS2MK1.shiftPressed[group]) { + if (engine.getValue(samplerGroup, "play") === 1) { + engine.setValue(samplerGroup, "play", 0); + } else { + script.triggerControl(samplerGroup, "eject"); + } + } else { + if (engine.getValue(samplerGroup, "track_loaded") === 0) { + script.triggerControl(samplerGroup, "LoadSelectedTrack"); + } else { + script.triggerControl(samplerGroup, "cue_gotoandplay"); + } + } +}; + +TraktorS2MK1.padButton = function(field) { + var buttonNumber = parseInt(field.name[field.name.length - 1]); + var padMode = TraktorS2MK1.currentPadMode[field.group]; + + if (padMode === TraktorS2MK1.padModes.hotcue) { + TraktorS2MK1.hotcueButton(buttonNumber, field.group, field.value); + } else if (padMode === TraktorS2MK1.padModes.introOutro) { + TraktorS2MK1.introOutroButton(buttonNumber, field.group, field.value); + } else if (padMode === TraktorS2MK1.padModes.sampler) { + TraktorS2MK1.samplerButton(buttonNumber, field.group, field.value); + } +}; + +TraktorS2MK1.samplerModeButton = function(field) { + if (field.value === 0) { + return; + } + var padMode = TraktorS2MK1.currentPadMode[field.group]; + if (padMode !== TraktorS2MK1.padModes.sampler) { + TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.sampler); + TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOn, false); + TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + } else { + TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.hotcue); + TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + } +}; + +TraktorS2MK1.introOutroModeButton = function(field) { + if (field.value === 0) { + return; + } + var padMode = TraktorS2MK1.currentPadMode[field.group]; + if (padMode !== TraktorS2MK1.padModes.introOutro) { + TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.introOutro); + TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOn, false); + TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + } else { + TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.hotcue); + TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + } +}; + +TraktorS2MK1.loopInButton = function(field) { + engine.setValue(field.group, "loop_in", field.value); +}; + +TraktorS2MK1.loopOutButton = function(field) { + engine.setValue(field.group, "loop_out", field.value); +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.connectEffectButtonLEDs = function(effectUnitGroup) { + TraktorS2MK1.effectButtonLEDconnections[effectUnitGroup].forEach(function(connection) { + connection.disconnect(); + }); + + var focusedEffect = engine.getValue(effectUnitGroup, "focused_effect"); + var makeButtonLEDcallback = function(effectNumber) { + return function(value, _group, _control) { + TraktorS2MK1.controller.setOutput(effectUnitGroup, "!effectbutton" + effectNumber, + value === 1 ? ButtonBrightnessOn : ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + }; + }; + + // FIXME: Why do the LEDs flicker? + TraktorS2MK1.batchingLEDUpdate = true; + for (var i = 0; i <= 2; i++) { + var effectGroup; + var key; + if (focusedEffect === 0) { + effectGroup = effectUnitGroup.slice(0, -1) + "_Effect" + (i+1) + "]"; + key = "enabled"; + } else { + effectGroup = effectUnitGroup.slice(0, -1) + "_Effect" + focusedEffect + "]"; + key = "button_parameter" + (i+1); + } + TraktorS2MK1.effectButtonLEDconnections[effectUnitGroup][i] = engine.makeConnection( + effectGroup, key, makeButtonLEDcallback(i+1)); + TraktorS2MK1.effectButtonLEDconnections[effectUnitGroup][i].trigger(); + } + TraktorS2MK1.batchingLEDUpdate = false; + TraktorS2MK1.effectButtonLEDconnections[effectUnitGroup][2].trigger(); +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.onShowParametersChange = function(value, group, _control) { + if (value === 0) { + if (engine.getValue(group, "show_focus") > 0) { + engine.setValue(group, "show_focus", 0); + TraktorS2MK1.previouslyFocusedEffect[group] = engine.getValue(group, "focused_effect"); + engine.setValue(group, "focused_effect", 0); + } + } else { + engine.setValue(group, "show_focus", 1); + if (TraktorS2MK1.previouslyFocusedEffect[group] !== null) { + engine.setValue(group, "focused_effect", TraktorS2MK1.previouslyFocusedEffect[group]); + } + } + TraktorS2MK1.connectEffectButtonLEDs(group); +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.onFocusedEffectChange = function(value, group, _control) { + TraktorS2MK1.controller.setOutput(group, "!effect_focus_button", value > 0 ? ButtonBrightnessOn : ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + if (value === 0) { + for (var i = 1; i <= 2; i++) { + // The previously focused effect is not available here, so iterate over all effects' parameter knobs. + for (var j = 1; j < 3; j++) { + engine.softTakeoverIgnoreNextValue(group.slice(0, -1) + "_Effect" + i + "]", "parameter" + j); + } + } + } else { + for (i = 1; i <= 2; i++) { + engine.softTakeoverIgnoreNextValue(group.slice(0, -1) + "_Effect" + i + "]", "meta"); + } + } +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.effectFocusButton = function(field) { + var showParameters = engine.getValue(field.group, "show_parameters"); + if (field.value > 0) { + var effectUnitNumber = field.group.slice(-2, -1); + if (TraktorS2MK1.shiftPressed["[Channel" + effectUnitNumber + "]"]) { + engine.setValue(field.group, "load_preset", 1); + return; + } + TraktorS2MK1.effectFocusLongPressTimer[field.group] = engine.beginTimer(TraktorS2MK1.longPressTimeoutMilliseconds, function() { + TraktorS2MK1.effectFocusChooseModeActive[field.group] = true; + TraktorS2MK1.effectButtonLEDconnections[field.group].forEach(function(connection) { + connection.disconnect(); + }); + var makeButtonLEDcallback = function(buttonNumber) { + return function(value, group, _control) { + TraktorS2MK1.controller.setOutput(group, "!effectbutton" + buttonNumber, + value === buttonNumber ? ButtonBrightnessOn : ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + }; + }; + TraktorS2MK1.batchingLEDUpdate = true; + for (var i = 0; i <= 2; i++) { + TraktorS2MK1.effectButtonLEDconnections[i] = engine.makeConnection( + field.group, "focused_effect", makeButtonLEDcallback(i+1)); + TraktorS2MK1.effectButtonLEDconnections[i].trigger(); + } + TraktorS2MK1.batchingLEDUpdate = false; + TraktorS2MK1.effectButtonLEDconnections[2].trigger(); + }); + if (!showParameters) { + engine.setValue(field.group, "show_parameters", 1); + TraktorS2MK1.effectFocusButtonPressedWhenParametersHidden[field.group] = true; + } + } else { + if (TraktorS2MK1.effectFocusLongPressTimer[field.group] !== 0) { + engine.stopTimer(TraktorS2MK1.effectFocusLongPressTimer[field.group]); + TraktorS2MK1.effectFocusLongPressTimer[field.group] = 0; + } + + if (TraktorS2MK1.effectFocusChooseModeActive[field.group]) { + TraktorS2MK1.effectFocusChooseModeActive[field.group] = false; + TraktorS2MK1.connectEffectButtonLEDs(field.group); + } else if (showParameters && !TraktorS2MK1.effectFocusButtonPressedWhenParametersHidden[field.group]) { + engine.setValue(this.group, "show_parameters", 0); + } + + TraktorS2MK1.effectFocusButtonPressedWhenParametersHidden[field.group] = false; + } +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.effectKnob = function(field) { + var knobNumber = parseInt(field.id.slice(-1)); + var effectUnitGroup = field.group; + var focusedEffect = engine.getValue(effectUnitGroup, "focused_effect"); + if (focusedEffect > 0) { + engine.setParameter(effectUnitGroup.slice(0, -1) + "_Effect" + focusedEffect + "]", + "parameter" + knobNumber, + field.value / 4096); + } else { + engine.setParameter(effectUnitGroup.slice(0, -1) + "_Effect" + knobNumber + "]", + "meta", + field.value / 4096); + } +}; + +// Refer to https://github.com/mixxxdj/mixxx/wiki/standard-effects-mapping for how to use this. +TraktorS2MK1.effectButton = function(field) { + var buttonNumber = parseInt(field.id.slice(-1)); + var effectUnitGroup = field.group; + var effectUnitNumber = field.group.match(script.effectUnitRegEx)[1]; + var focusedEffect = engine.getValue(effectUnitGroup, "focused_effect"); + + var toggle = function() { + var group; + var key; + if (focusedEffect === 0) { + group = effectUnitGroup.slice(0, -1) + "_Effect" + buttonNumber + "]"; + key = "enabled"; + } else { + group = effectUnitGroup.slice(0, -1) + "_Effect" + focusedEffect + "]"; + key = "button_parameter" + buttonNumber; + } + script.toggleControl(group, key); + }; + + if (field.value > 0) { + if (TraktorS2MK1.shiftPressed["[Channel" + effectUnitNumber + "]"]) { + engine.setValue(effectUnitGroup, "load_preset", buttonNumber+1); + } else { + if (TraktorS2MK1.effectFocusChooseModeActive[effectUnitGroup]) { + if (focusedEffect === buttonNumber) { + engine.setValue(effectUnitGroup, "focused_effect", 0); + } else { + engine.setValue(effectUnitGroup, "focused_effect", buttonNumber); + } + TraktorS2MK1.effectFocusChooseModeActive[effectUnitGroup] = false; + } else { + toggle(); + TraktorS2MK1.effectButtonLongPressTimer[effectUnitGroup][buttonNumber] = + engine.beginTimer(TraktorS2MK1.longPressTimeoutMilliseconds, + function() { + TraktorS2MK1.effectButtonIsLongPressed[effectUnitGroup][buttonNumber] = true; + TraktorS2MK1.effectButtonLongPressTimer[effectUnitGroup][buttonNumber] = 0; + }, + true + ); + } + } + } else { + engine.stopTimer(TraktorS2MK1.effectButtonLongPressTimer[effectUnitGroup][buttonNumber]); + TraktorS2MK1.effectButtonLongPressTimer[effectUnitGroup][buttonNumber] = 0; + if (TraktorS2MK1.effectButtonIsLongPressed[effectUnitGroup][buttonNumber]) { + toggle(); + } + TraktorS2MK1.effectButtonIsLongPressed[effectUnitGroup][buttonNumber] = false; + } +}; + +/// return value 1 === right turn +/// return value -1 === left turn +TraktorS2MK1.encoderDirection = function(newValue, oldValue) { + var direction = 0; + var min = 0; + var max = 15; + if (oldValue === max && newValue === min) { + direction = 1; + } else if (oldValue === min && newValue === max) { + direction = -1; + } else if (newValue > oldValue) { + direction = 1; + } else { + direction = -1; + } + return direction; +}; + +TraktorS2MK1.topEncoder = function(field) { + var delta = 0.03333 * TraktorS2MK1.encoderDirection(field.value, TraktorS2MK1.previousPregain[field.group]); + TraktorS2MK1.previousPregain[field.group] = field.value; + + if (TraktorS2MK1.shiftPressed[field.group]) { + var currentPregain = engine.getParameter(field.group, "pregain"); + engine.setParameter(field.group, "pregain", currentPregain + delta); + } else { + var quickEffectGroup = "[QuickEffectRack1_" + field.group + "]"; + if (TraktorS2MK1.topEncoderPressed[field.group]) { + script.triggerControl(quickEffectGroup, delta > 0 ? "next_chain" : "prev_chain"); + } else { + var currentQuickEffectSuperKnob = engine.getParameter(quickEffectGroup, "super1"); + engine.setParameter(quickEffectGroup, "super1", currentQuickEffectSuperKnob + delta); + } + } +}; + +TraktorS2MK1.topEncoderPress = function(field) { + if (field.value > 0) { + TraktorS2MK1.topEncoderPressed[field.group] = true; + if (TraktorS2MK1.shiftPressed[field.group]) { + script.triggerControl(field.group, "pregain_set_default"); + } else { + script.triggerControl("[QuickEffectRack1_" + field.group + "]", "super1_set_default"); + } + } else { + TraktorS2MK1.topEncoderPressed[field.group] = false; + } +}; + +TraktorS2MK1.leftEncoder = function(field) { + var delta = TraktorS2MK1.encoderDirection(field.value, TraktorS2MK1.previousLeftEncoder[field.group]); + TraktorS2MK1.previousLeftEncoder[field.group] = field.value; + + if (TraktorS2MK1.shiftPressed[field.group]) { + if (delta === 1) { + script.triggerControl(field.group, "pitch_up_small"); + } else { + script.triggerControl(field.group, "pitch_down_small"); + } + } else { + if (TraktorS2MK1.leftEncoderPressed[field.group]) { + var beatjumpSize = engine.getValue(field.group, "beatjump_size"); + if (delta === 1) { + beatjumpSize *= 2; + } else { + beatjumpSize /= 2; + } + engine.setValue(field.group, "beatjump_size", beatjumpSize); + } else { + if (delta === 1) { + script.triggerControl(field.group, "beatjump_forward"); + } else { + script.triggerControl(field.group, "beatjump_backward"); + } + } + } +}; + +TraktorS2MK1.leftEncoderPress = function(field) { + TraktorS2MK1.leftEncoderPressed[field.group] = (field.value > 0); + if (TraktorS2MK1.shiftPressed[field.group] && field.value > 0) { + script.triggerControl(field.group, "pitch_adjust_set_default"); + } +}; + +TraktorS2MK1.rightEncoder = function(field) { + var delta = TraktorS2MK1.encoderDirection(field.value, TraktorS2MK1.previousRightEncoder[field.group]); + TraktorS2MK1.previousRightEncoder[field.group] = field.value; + + if (TraktorS2MK1.shiftPressed[field.group]) { + if (delta === 1) { + script.triggerControl(field.group, "beatjump_1_forward"); + } else { + script.triggerControl(field.group, "beatjump_1_backward"); + } + } else { + if (delta === 1) { + script.triggerControl(field.group, "loop_double"); + } else { + script.triggerControl(field.group, "loop_halve"); + } + } +}; + +TraktorS2MK1.rightEncoderPress = function(field) { + if (field.value === 0) { + return; + } + var loopEnabled = engine.getValue(field.group, "loop_enabled"); + // The actions triggered below change the state of loop_enabled, + // so to simplify the logic, use script.triggerControl to only act + // on press rather than resetting ControlObjects to 0 on release. + if (TraktorS2MK1.shiftPressed[field.group]) { + if (loopEnabled) { + script.triggerControl(field.group, "reloop_andstop"); + } else { + script.triggerControl(field.group, "reloop_toggle"); + } + } else { + if (loopEnabled) { + script.triggerControl(field.group, "reloop_toggle"); + } else { + script.triggerControl(field.group, "beatloop_activate"); + } + } +}; + +TraktorS2MK1.browseEncoder = function(field) { + var delta = TraktorS2MK1.encoderDirection(field.value, TraktorS2MK1.previousBrowse); + TraktorS2MK1.previousBrowse = field.value; + + if (TraktorS2MK1.shiftPressed["[Channel1]"] || TraktorS2MK1.shiftPressed["[Channel2]"]) { + delta *= 5; + } + engine.setValue("[Playlist]", "SelectTrackKnob", delta); +}; + +TraktorS2MK1.scalerParameter = function(group, name, value) { + return script.absoluteLin(value, 0, 1, 16, 4080); +}; + +TraktorS2MK1.scalerVolume = function(group, name, value) { + if (group === "[Master]") { + return script.absoluteNonLin(value, 0, 1, 4, 16, 4080); + } else { + return script.absoluteNonLin(value, 0, 0.25, 1, 16, 4080); + } +}; + +TraktorS2MK1.scalerSlider = function(group, name, value) { + return script.absoluteLin(value, -1, 1, 16, 4080); +}; + +TraktorS2MK1.outputChannelCallback = function(value, group, key) { + var ledValue = 0x05; + if (value) { + ledValue = 0x1F; + } + TraktorS2MK1.controller.setOutput(group, key, ledValue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.outputChannelCallbackDark = function(value, group, key) { + var ledValue = 0x00; + if (value) { + ledValue = 0x1F; + } + TraktorS2MK1.controller.setOutput(group, key, ledValue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.outputCallback = function(value, group, key) { + var ledValue = ButtonBrightnessOff; + if (value) { + ledValue = ButtonBrightnessOn; + } + TraktorS2MK1.controller.setOutput(group, key, ledValue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.outputCallbackLoop = function(value, group, key) { + var ledValue = ButtonBrightnessOff; + if (engine.getValue(group, "loop_enabled")) { + ledValue = 0x1F; + } + TraktorS2MK1.controller.setOutput(group, key, ledValue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.outputCallbackDark = function(value, group, key) { + var ledValue = 0x00; + if (value) { + ledValue = 0x1F; + } + TraktorS2MK1.controller.setOutput(group, key, ledValue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.pflButton = function(field) { + if (field.value > 0) { + if (TraktorS2MK1.shiftPressed[field.group]) { + script.toggleControl(field.group, "quantize"); + } else { + script.toggleControl(field.group, "pfl"); + } + } +}; + +TraktorS2MK1.sendPadColor = function(group, padNumber, color) { + var padKey = "!pad_" + padNumber + "_"; + var ColorBrightnessScaler = ButtonBrightnessOn / 0x1f; + var green = color.green * ColorBrightnessScaler; + var blue = color.blue * ColorBrightnessScaler; + if (color.green === 0 && color.blue === 0) { + green = ButtonBrightnessOff; + blue = ButtonBrightnessOff; + } + TraktorS2MK1.controller.setOutput(group, padKey + "G", green, false); + TraktorS2MK1.controller.setOutput(group, padKey + "B", blue, !TraktorS2MK1.batchingLEDUpdate); +}; + +TraktorS2MK1.outputHotcueCallback = function(value, group, key) { + var hotcueNumber = key.charAt(7); + var color; + if (engine.getValue(group, "hotcue_" + hotcueNumber + "_enabled")) { + color = {green: 0, blue: 0x1F}; + } else { + color = {green: 0, blue: 0}; + } + TraktorS2MK1.sendPadColor(group, hotcueNumber, color); +}; + +TraktorS2MK1.onVuMeterChanged = function(value, group, _key) { + // This handler is called a lot so it should be as fast as possible. + + // Figure out number of fully-illuminated segments. + var scaledValue = value * 4.0; + var fullIllumCount = Math.floor(scaledValue); + + // Figure out how much the partially-illuminated segment is illuminated. + var partialIllum = (scaledValue - fullIllumCount) * 0x1F; + + for (var i = 0; i <= 3; i++) { + var key = "!VuMeter" + i; + if (i < fullIllumCount) { + // Don't update lights until they're all done, so the last term is false. + TraktorS2MK1.controller.setOutput(group, key, 0x1F, false); + } else if (i === fullIllumCount) { + TraktorS2MK1.controller.setOutput(group, key, partialIllum, false); + } else { + TraktorS2MK1.controller.setOutput(group, key, 0x00, false); + } + } + TraktorS2MK1.controller.OutputPackets["output"].send(); +}; + +TraktorS2MK1.onLoopEnabledChanged = function(value, group, _key) { + TraktorS2MK1.outputCallbackLoop(value, group, "loop_in"); + TraktorS2MK1.outputCallbackLoop(value, group, "loop_out"); +}; + +TraktorS2MK1.setPlayIndicatorMode = function(group, value) { + TraktorS2MK1.playIndicatorConnections[group].forEach(function(connection) { + connection.disconnect(); + }); + var connection = engine.makeConnection(group, value ? "play_indicator" : "keylock", + TraktorS2MK1.makeLEDCallback("!play_indicator")); + + TraktorS2MK1.playIndicatorConnections[group] = [connection]; + connection.trigger(); +}; + +TraktorS2MK1.makeLEDCallback = function(control) { + return function(value, group, _control) { + var ledValue = value ? ButtonBrightnessOn : ButtonBrightnessOff; + TraktorS2MK1.controller.setOutput(group, control, ledValue, !TraktorS2MK1.batchingLEDUpdate); + }; +}; + +TraktorS2MK1.setPflMode = function(group, value) { + TraktorS2MK1.pflConnections[group].forEach(function(connection) { + connection.disconnect(); + }); + var pflLEDCallback = function(value, group, _control) { + var ledValue = value ? ButtonBrightnessOn : 0x05; + TraktorS2MK1.controller.setOutput(group, "!pfl", ledValue, !TraktorS2MK1.batchingLEDUpdate); + }; + var connection; + if (value) { + connection = engine.makeConnection(group, "pfl", pflLEDCallback); + } else { + connection = engine.makeConnection(group, "quantize", TraktorS2MK1.makeLEDCallback("!pfl")); + } + TraktorS2MK1.pflConnections[group] = [connection]; + connection.trigger(); +}; From ebc455e7d53d176c16519055542e1b2a1fe81673 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Mon, 24 May 2021 17:45:58 +0200 Subject: [PATCH 02/18] NI Traktor Kontrol S2 Mk1: fix formatting --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index b48af5000bf..31edb61eb3d 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -263,7 +263,7 @@ TraktorS2MK1.registerInputPackets = function() { engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", true); engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", true); - for (var i = 1; i <= 3; i++) { + for (i = 1; i <= 3; i++) { engine.softTakeover("[EffectRack1_EffectUnit1_Effect" + i + "]", "meta", true); engine.softTakeover("[EffectRack1_EffectUnit2_Effect" + i + "]", "meta", true); for (var j = 1; j <= 3; j++) { @@ -414,7 +414,7 @@ TraktorS2MK1.linkDeckOutputs = function(key, callback) { TraktorS2MK1.controller.linkOutput("[Channel2]", key, "[Channel2]", key, callback); }; -TraktorS2MK1.linkDeckCustomOutputs = function(key, callback){ +TraktorS2MK1.linkDeckCustomOutputs = function(key, callback) { engine.makeConnection("[Channel1]", key, callback).trigger(); engine.makeConnection("[Channel2]", key, callback).trigger(); }; @@ -1377,7 +1377,7 @@ TraktorS2MK1.setPlayIndicatorMode = function(group, value) { connection.disconnect(); }); var connection = engine.makeConnection(group, value ? "play_indicator" : "keylock", - TraktorS2MK1.makeLEDCallback("!play_indicator")); + TraktorS2MK1.makeLEDCallback("!play_indicator")); TraktorS2MK1.playIndicatorConnections[group] = [connection]; connection.trigger(); From fdce87cfcce5d0f8eb2cc54b899c9ab6026d0891 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 18 Jul 2021 12:24:07 +0200 Subject: [PATCH 03/18] NI Traktor S2 Mk1: Fix eslint error --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 1 - 1 file changed, 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 31edb61eb3d..f0f0863a9d1 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -33,7 +33,6 @@ var ButtonBrightnessOn = 0x1F; // * The effect button LEDs briefly flicker when pressing the effect focus button. // eslint definitions -/* global controller, HIDController, HIDPacket */ var TraktorS2MK1 = new function() { this.controller = new HIDController(); From f4d5d6d13d0f44499fc6558e0819d05164a2aff6 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 18 Jul 2021 17:35:25 +0200 Subject: [PATCH 04/18] NI Traktor S2 Mk1: Remove flashing light when pressing shift --- .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 61 +++---------------- 1 file changed, 7 insertions(+), 54 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index f0f0863a9d1..c6a863476db 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -120,14 +120,6 @@ var TraktorS2MK1 = new function() { "[EffectRack1_EffectUnit1]": [], "[EffectRack1_EffectUnit2]": [] }; - this.playIndicatorConnections = { - "[Channel1]": [], - "[Channel2]": [], - }; - this.pflConnections = { - "[Channel1]": [], - "[Channel2]": [], - }; }; TraktorS2MK1.registerInputPackets = function() { @@ -314,9 +306,9 @@ TraktorS2MK1.registerOutputPackets = function() { Output.addOutput("[Channel2]", "loop_in", 0x22, "B"); Output.addOutput("[Channel2]", "loop_out", 0x21, "B"); - Output.addOutput("[Channel1]", "!pfl", 0x20, "B"); + Output.addOutput("[Channel1]", "pfl", 0x20, "B"); Output.addOutput("[Master]", "!warninglight", 0x31, "B"); - Output.addOutput("[Channel2]", "!pfl", 0x1D, "B"); + Output.addOutput("[Channel2]", "pfl", 0x1D, "B"); Output.addOutput("[EffectRack1_EffectUnit1]", "!effect_focus_button", 0x1C, "B"); Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x1B, "B"); @@ -339,7 +331,7 @@ TraktorS2MK1.registerOutputPackets = function() { Output.addOutput("[Channel1]", "!shift", 0x08, "B"); Output.addOutput("[Channel1]", "sync_enabled", 0x04, "B"); Output.addOutput("[Channel1]", "cue_indicator", 0x07, "B"); - Output.addOutput("[Channel1]", "!play_indicator", 0x03, "B"); + Output.addOutput("[Channel1]", "play_indicator", 0x03, "B"); Output.addOutput("[Channel1]", "!pad_1_G", 0x0C, "B"); Output.addOutput("[Channel1]", "!pad_1_B", 0x10, "B"); @@ -356,7 +348,7 @@ TraktorS2MK1.registerOutputPackets = function() { Output.addOutput("[Channel2]", "!shift", 0x28, "B"); Output.addOutput("[Channel2]", "sync_enabled", 0x24, "B"); Output.addOutput("[Channel2]", "cue_indicator", 0x27, "B"); - Output.addOutput("[Channel2]", "!play_indicator", 0x23, "B"); + Output.addOutput("[Channel2]", "play_indicator", 0x23, "B"); Output.addOutput("[Channel2]", "!pad_1_G", 0x2C, "B"); Output.addOutput("[Channel2]", "!pad_1_B", 0x30, "B"); @@ -375,10 +367,7 @@ TraktorS2MK1.registerOutputPackets = function() { // Link up control objects to their outputs TraktorS2MK1.linkDeckOutputs("sync_enabled", TraktorS2MK1.outputCallback); TraktorS2MK1.linkDeckOutputs("cue_indicator", TraktorS2MK1.outputCallback); - TraktorS2MK1.setPlayIndicatorMode("[Channel1]", true); - TraktorS2MK1.setPlayIndicatorMode("[Channel2]", true); - TraktorS2MK1.setPflMode("[Channel1]", true); - TraktorS2MK1.setPflMode("[Channel2]", true); + TraktorS2MK1.linkDeckOutputs("play_indicator", TraktorS2MK1.outputCallback); TraktorS2MK1.setPadMode("[Channel1]", TraktorS2MK1.padModes.hotcue); TraktorS2MK1.setPadMode("[Channel2]", TraktorS2MK1.padModes.hotcue); @@ -387,6 +376,8 @@ TraktorS2MK1.registerOutputPackets = function() { TraktorS2MK1.linkDeckOutputs("loop_out", TraktorS2MK1.outputCallbackLoop); TraktorS2MK1.linkDeckOutputs("LoadSelectedTrack", TraktorS2MK1.outputCallback); TraktorS2MK1.linkDeckOutputs("slip_enabled", TraktorS2MK1.outputCallback); + TraktorS2MK1.linkChannelOutput("[Channel1]", "pfl", TraktorS2MK1.outputChannelCallback); + TraktorS2MK1.linkChannelOutput("[Channel2]", "pfl", TraktorS2MK1.outputChannelCallback); TraktorS2MK1.linkChannelOutput("[Channel1]", "track_loaded", TraktorS2MK1.outputChannelCallback); TraktorS2MK1.linkChannelOutput("[Channel2]", "track_loaded", TraktorS2MK1.outputChannelCallback); TraktorS2MK1.linkChannelOutput("[Channel1]", "PeakIndicator", TraktorS2MK1.outputChannelCallbackDark); @@ -544,8 +535,6 @@ TraktorS2MK1.shift = function(field) { TraktorS2MK1.controller.setOutput(field.group, "!shift", shiftPressed ? ButtonBrightnessOn : ButtonBrightnessOff, field.group, "!shift", !TraktorS2MK1.batchingLEDUpdate); - TraktorS2MK1.setPlayIndicatorMode(field.group, !shiftPressed); - TraktorS2MK1.setPflMode(field.group, !shiftPressed); }; TraktorS2MK1.loadTrackButton = function(field) { @@ -1370,39 +1359,3 @@ TraktorS2MK1.onLoopEnabledChanged = function(value, group, _key) { TraktorS2MK1.outputCallbackLoop(value, group, "loop_in"); TraktorS2MK1.outputCallbackLoop(value, group, "loop_out"); }; - -TraktorS2MK1.setPlayIndicatorMode = function(group, value) { - TraktorS2MK1.playIndicatorConnections[group].forEach(function(connection) { - connection.disconnect(); - }); - var connection = engine.makeConnection(group, value ? "play_indicator" : "keylock", - TraktorS2MK1.makeLEDCallback("!play_indicator")); - - TraktorS2MK1.playIndicatorConnections[group] = [connection]; - connection.trigger(); -}; - -TraktorS2MK1.makeLEDCallback = function(control) { - return function(value, group, _control) { - var ledValue = value ? ButtonBrightnessOn : ButtonBrightnessOff; - TraktorS2MK1.controller.setOutput(group, control, ledValue, !TraktorS2MK1.batchingLEDUpdate); - }; -}; - -TraktorS2MK1.setPflMode = function(group, value) { - TraktorS2MK1.pflConnections[group].forEach(function(connection) { - connection.disconnect(); - }); - var pflLEDCallback = function(value, group, _control) { - var ledValue = value ? ButtonBrightnessOn : 0x05; - TraktorS2MK1.controller.setOutput(group, "!pfl", ledValue, !TraktorS2MK1.batchingLEDUpdate); - }; - var connection; - if (value) { - connection = engine.makeConnection(group, "pfl", pflLEDCallback); - } else { - connection = engine.makeConnection(group, "quantize", TraktorS2MK1.makeLEDCallback("!pfl")); - } - TraktorS2MK1.pflConnections[group] = [connection]; - connection.trigger(); -}; From 8cdd25425643c170f4ce2ebff6196c404bbb3eb5 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:06:29 +0100 Subject: [PATCH 05/18] Traktor S2 Mk1: Rename packats --- .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 302 +++++++++--------- 1 file changed, 151 insertions(+), 151 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index c6a863476db..f15b4e77a20 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -123,112 +123,112 @@ var TraktorS2MK1 = new function() { }; TraktorS2MK1.registerInputPackets = function() { - var MessageShort = new HIDPacket("shortmessage", 0x01, this.shortMessageCallback); - var MessageLong = new HIDPacket("longmessage", 0x02, this.longMessageCallback); + var InputReport0x01 = new HIDPacket("InputReport_0x01", 0x01, this.inputReport0x01Callback); + var InputReport0x02 = new HIDPacket("InputReport_0x02", 0x02, this.inputReport0x02Callback); - // Values in the short message are all buttons, except the jog wheels. + // Values in input report 0x01 are all buttons, except the jog wheels. // An exclamation point indicates a specially-handled function. Everything else is a standard // Mixxx control object name. - MessageShort.addControl("[Channel1]", "!top_encoder_press", 0x0E, "B", 0x01, false, this.topEncoderPress); - MessageShort.addControl("[Channel1]", "!shift", 0x0D, "B", 0x80, false, this.shift); - MessageShort.addControl("[Channel1]", "!sync_enabled", 0x0D, "B", 0x40, false, this.syncButton); - MessageShort.addControl("[Channel1]", "!cue_default", 0x0D, "B", 0x20, false, this.cueButton); - MessageShort.addControl("[Channel1]", "!play", 0x0D, "B", 0x10, false, this.playButton); - MessageShort.addControl("[Channel1]", "!pad1", 0x0D, "B", 0x08, false, this.padButton); - MessageShort.addControl("[Channel1]", "!pad2", 0x0D, "B", 0x04, false, this.padButton); - MessageShort.addControl("[Channel1]", "!pad3", 0x0D, "B", 0x02, false, this.padButton); - MessageShort.addControl("[Channel1]", "!pad4", 0x0D, "B", 0x01, false, this.padButton); - MessageShort.addControl("[Channel1]", "!loop_in", 0x09, "B", 0x40, false, this.loopInButton); - MessageShort.addControl("[Channel1]", "!loop_out", 0x09, "B", 0x20, false, this.loopOutButton); - MessageShort.addControl("[Channel1]", "!remix_button", 0x0B, "B", 0x02, false, this.samplerModeButton); - MessageShort.addControl("[Channel1]", "!flux_button", 0x09, "B", 0x10, false, this.introOutroModeButton); - MessageShort.addControl("[Channel1]", "!left_encoder_press", 0x0E, "B", 0x02, false, this.leftEncoderPress); - MessageShort.addControl("[Channel1]", "!right_encoder_press", 0x0E, "B", 0x04, false, this.rightEncoderPress); - MessageShort.addControl("[Channel1]", "!jog_wheel", 0x01, "I", 0xFFFFFFFF, false, this.jogMove); - MessageShort.addControl("[Channel1]", "!load_track", 0x0B, "B", 0x08, false, this.loadTrackButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effect_focus_button", + InputReport0x01.addControl("[Channel1]", "!top_encoder_press", 0x0E, "B", 0x01, false, this.topEncoderPress); + InputReport0x01.addControl("[Channel1]", "!shift", 0x0D, "B", 0x80, false, this.shift); + InputReport0x01.addControl("[Channel1]", "!sync_enabled", 0x0D, "B", 0x40, false, this.syncButton); + InputReport0x01.addControl("[Channel1]", "!cue_default", 0x0D, "B", 0x20, false, this.cueButton); + InputReport0x01.addControl("[Channel1]", "!play", 0x0D, "B", 0x10, false, this.playButton); + InputReport0x01.addControl("[Channel1]", "!pad1", 0x0D, "B", 0x08, false, this.padButton); + InputReport0x01.addControl("[Channel1]", "!pad2", 0x0D, "B", 0x04, false, this.padButton); + InputReport0x01.addControl("[Channel1]", "!pad3", 0x0D, "B", 0x02, false, this.padButton); + InputReport0x01.addControl("[Channel1]", "!pad4", 0x0D, "B", 0x01, false, this.padButton); + InputReport0x01.addControl("[Channel1]", "!loop_in", 0x09, "B", 0x40, false, this.loopInButton); + InputReport0x01.addControl("[Channel1]", "!loop_out", 0x09, "B", 0x20, false, this.loopOutButton); + InputReport0x01.addControl("[Channel1]", "!remix_button", 0x0B, "B", 0x02, false, this.samplerModeButton); + InputReport0x01.addControl("[Channel1]", "!flux_button", 0x09, "B", 0x10, false, this.introOutroModeButton); + InputReport0x01.addControl("[Channel1]", "!left_encoder_press", 0x0E, "B", 0x02, false, this.leftEncoderPress); + InputReport0x01.addControl("[Channel1]", "!right_encoder_press", 0x0E, "B", 0x04, false, this.rightEncoderPress); + InputReport0x01.addControl("[Channel1]", "!jog_wheel", 0x01, "I", 0xFFFFFFFF, false, this.jogMove); + InputReport0x01.addControl("[Channel1]", "!load_track", 0x0B, "B", 0x08, false, this.loadTrackButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effect_focus_button", 0x09, "B", 0x08, false, this.effectFocusButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x09, "B", 0x04, false, this.effectButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x09, "B", 0x02, false, this.effectButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x09, "B", 0x01, false, this.effectButton); - - MessageShort.addControl("[Channel2]", "!top_encoder_press", 0x0E, "B", 0x10, false, this.topEncoderPress); - MessageShort.addControl("[Channel2]", "!shift", 0x0C, "B", 0x80, false, this.shift); - MessageShort.addControl("[Channel2]", "!sync_enabled", 0x0C, "B", 0x40, false, this.syncButton); - MessageShort.addControl("[Channel2]", "!cue_default", 0x0C, "B", 0x20, false, this.cueButton); - MessageShort.addControl("[Channel2]", "!play", 0x0C, "B", 0x10, false, this.playButton); - MessageShort.addControl("[Channel2]", "!pad1", 0x0C, "B", 0x08, false, this.padButton); - MessageShort.addControl("[Channel2]", "!pad2", 0x0C, "B", 0x04, false, this.padButton); - MessageShort.addControl("[Channel2]", "!pad3", 0x0C, "B", 0x02, false, this.padButton); - MessageShort.addControl("[Channel2]", "!pad4", 0x0C, "B", 0x01, false, this.padButton); - MessageShort.addControl("[Channel2]", "!loop_in", 0x0B, "B", 0x40, false, this.loopInButton); - MessageShort.addControl("[Channel2]", "!loop_out", 0x0B, "B", 0x20, false, this.loopOutButton); - MessageShort.addControl("[Channel2]", "!remix_button", 0x0B, "B", 0x01, false, this.samplerModeButton); - MessageShort.addControl("[Channel2]", "!flux_button", 0x0B, "B", 0x10, false, this.introOutroModeButton); - MessageShort.addControl("[Channel2]", "!left_encoder_press", 0x0E, "B", 0x20, false, this.leftEncoderPress); - MessageShort.addControl("[Channel2]", "!right_encoder_press", 0x0E, "B", 0x40, false, this.rightEncoderPress); - MessageShort.addControl("[Channel2]", "!jog_wheel", 0x05, "I", 0xFFFFFFFF, false, this.jogMove); - MessageShort.addControl("[Channel2]", "!load_track", 0x0B, "B", 0x04, false, this.loadTrackButton); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effect_focus_button", + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x09, "B", 0x04, false, this.effectButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x09, "B", 0x02, false, this.effectButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x09, "B", 0x01, false, this.effectButton); + + InputReport0x01.addControl("[Channel2]", "!top_encoder_press", 0x0E, "B", 0x10, false, this.topEncoderPress); + InputReport0x01.addControl("[Channel2]", "!shift", 0x0C, "B", 0x80, false, this.shift); + InputReport0x01.addControl("[Channel2]", "!sync_enabled", 0x0C, "B", 0x40, false, this.syncButton); + InputReport0x01.addControl("[Channel2]", "!cue_default", 0x0C, "B", 0x20, false, this.cueButton); + InputReport0x01.addControl("[Channel2]", "!play", 0x0C, "B", 0x10, false, this.playButton); + InputReport0x01.addControl("[Channel2]", "!pad1", 0x0C, "B", 0x08, false, this.padButton); + InputReport0x01.addControl("[Channel2]", "!pad2", 0x0C, "B", 0x04, false, this.padButton); + InputReport0x01.addControl("[Channel2]", "!pad3", 0x0C, "B", 0x02, false, this.padButton); + InputReport0x01.addControl("[Channel2]", "!pad4", 0x0C, "B", 0x01, false, this.padButton); + InputReport0x01.addControl("[Channel2]", "!loop_in", 0x0B, "B", 0x40, false, this.loopInButton); + InputReport0x01.addControl("[Channel2]", "!loop_out", 0x0B, "B", 0x20, false, this.loopOutButton); + InputReport0x01.addControl("[Channel2]", "!remix_button", 0x0B, "B", 0x01, false, this.samplerModeButton); + InputReport0x01.addControl("[Channel2]", "!flux_button", 0x0B, "B", 0x10, false, this.introOutroModeButton); + InputReport0x01.addControl("[Channel2]", "!left_encoder_press", 0x0E, "B", 0x20, false, this.leftEncoderPress); + InputReport0x01.addControl("[Channel2]", "!right_encoder_press", 0x0E, "B", 0x40, false, this.rightEncoderPress); + InputReport0x01.addControl("[Channel2]", "!jog_wheel", 0x05, "I", 0xFFFFFFFF, false, this.jogMove); + InputReport0x01.addControl("[Channel2]", "!load_track", 0x0B, "B", 0x04, false, this.loadTrackButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "!effect_focus_button", 0x0A, "B", 0x80, false, this.effectFocusButton); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton1", 0xA, "B", 0x40, false, this.effectButton); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton2", 0xA, "B", 0x20, false, this.effectButton); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "!effectbutton3", 0xA, "B", 0x10, false, this.effectButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "!effectbutton1", 0xA, "B", 0x40, false, this.effectButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "!effectbutton2", 0xA, "B", 0x20, false, this.effectButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "!effectbutton3", 0xA, "B", 0x10, false, this.effectButton); - MessageShort.addControl("[Channel1]", "!pfl", 0x09, "B", 0x80, false, this.pflButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x0A, "B", 0x02); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x0A, "B", 0x01); + InputReport0x01.addControl("[Channel1]", "!pfl", 0x09, "B", 0x80, false, this.pflButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x0A, "B", 0x02); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x0A, "B", 0x01); - MessageShort.addControl("[Channel2]", "!pfl", 0x0B, "B", 0x80, false, this.pflButton); - MessageShort.addControl("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x0A, "B", 0x08); - MessageShort.addControl("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x0A, "B", 0x04); + InputReport0x01.addControl("[Channel2]", "!pfl", 0x0B, "B", 0x80, false, this.pflButton); + InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x0A, "B", 0x08); + InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x0A, "B", 0x04); - MessageShort.addControl("[Master]", "maximize_library", 0x0E, "B", 0x08, false, this.toggleButton); + InputReport0x01.addControl("[Master]", "maximize_library", 0x0E, "B", 0x08, false, this.toggleButton); engine.makeConnection("[EffectRack1_EffectUnit1]", "show_parameters", TraktorS2MK1.onShowParametersChange); engine.makeConnection("[EffectRack1_EffectUnit2]", "show_parameters", TraktorS2MK1.onShowParametersChange); - this.controller.registerInputPacket(MessageShort); + this.controller.registerInputPacket(InputReport0x01); - // Most items in the long message are controls that go from 0-4096. + // Most items in the input report 0x02 are controls that go from 0-4096. // There are also some 4 bit encoders. - MessageLong.addControl("[Channel1]", "rate", 0x0F, "H"); - MessageLong.addControl("[Channel2]", "rate", 0x1F, "H"); - MessageLong.addControl("[Channel1]", "!left_encoder", 0x01, "B", 0xF0, false, this.leftEncoder); - MessageLong.addControl("[Channel1]", "!right_encoder", 0x02, "B", 0x0F, false, this.rightEncoder); - MessageLong.addControl("[Channel2]", "!left_encoder", 0x03, "B", 0xF0, false, this.leftEncoder); - MessageLong.addControl("[Channel2]", "!right_encoder", 0x04, "B", 0x0F, false, this.rightEncoder); - - MessageLong.addControl("[EffectRack1_EffectUnit1]", "mix", 0x0B, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob1", 0x09, "H", 0xFFFF, false, this.effectKnob); - MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob2", 0x07, "H", 0xFFFF, false, this.effectKnob); - MessageLong.addControl("[EffectRack1_EffectUnit1]", "!effectknob3", 0x05, "H", 0xFFFF, false, this.effectKnob); - - MessageLong.addControl("[EffectRack1_EffectUnit2]", "mix", 0x1B, "H"); - MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob1", 0x19, "H", 0xFFFF, false, this.effectKnob); - MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob2", 0x17, "H", 0xFFFF, false, this.effectKnob); - MessageLong.addControl("[EffectRack1_EffectUnit2]", "!effectknob3", 0x15, "H", 0xFFFF, false, this.effectKnob); - - MessageLong.addControl("[Channel1]", "volume", 0x2B, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", 0x11, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", 0x25, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", 0x27, "H"); - MessageLong.addControl("[Channel1]", "pregain", 0x01, "B", 0x0F, false, this.topEncoder); - MessageLong.addControl("[Channel1]", "!jog_touch", 0x0D, "H", 0xFFFF, false, this.jogTouch); - - MessageLong.addControl("[Channel2]", "volume", 0x2D, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter3", 0x21, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", 0x23, "H"); - MessageLong.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", 0x29, "H"); - MessageLong.addControl("[Channel2]", "pregain", 0x03, "B", 0x0F, false, this.topEncoder); - MessageLong.addControl("[Channel2]", "!jog_touch", 0x1D, "H", 0xFFFF, false, this.jogTouch); - - MessageLong.addControl("[Master]", "crossfader", 0x2F, "H"); - MessageLong.addControl("[Master]", "headMix", 0x31, "H"); - MessageLong.addControl("[Master]", "!samplerGain", 0x13, "H"); - MessageLong.setCallback("[Master]", "!samplerGain", this.samplerGainKnob); - MessageLong.addControl("[Playlist]", "!browse", 0x02, "B", 0xF0, false, this.browseEncoder); + InputReport0x02.addControl("[Channel1]", "rate", 0x0F, "H"); + InputReport0x02.addControl("[Channel2]", "rate", 0x1F, "H"); + InputReport0x02.addControl("[Channel1]", "!left_encoder", 0x01, "B", 0xF0, false, this.leftEncoder); + InputReport0x02.addControl("[Channel1]", "!right_encoder", 0x02, "B", 0x0F, false, this.rightEncoder); + InputReport0x02.addControl("[Channel2]", "!left_encoder", 0x03, "B", 0xF0, false, this.leftEncoder); + InputReport0x02.addControl("[Channel2]", "!right_encoder", 0x04, "B", 0x0F, false, this.rightEncoder); + + InputReport0x02.addControl("[EffectRack1_EffectUnit1]", "mix", 0x0B, "H"); + InputReport0x02.addControl("[EffectRack1_EffectUnit1]", "!effectknob1", 0x09, "H", 0xFFFF, false, this.effectKnob); + InputReport0x02.addControl("[EffectRack1_EffectUnit1]", "!effectknob2", 0x07, "H", 0xFFFF, false, this.effectKnob); + InputReport0x02.addControl("[EffectRack1_EffectUnit1]", "!effectknob3", 0x05, "H", 0xFFFF, false, this.effectKnob); + + InputReport0x02.addControl("[EffectRack1_EffectUnit2]", "mix", 0x1B, "H"); + InputReport0x02.addControl("[EffectRack1_EffectUnit2]", "!effectknob1", 0x19, "H", 0xFFFF, false, this.effectKnob); + InputReport0x02.addControl("[EffectRack1_EffectUnit2]", "!effectknob2", 0x17, "H", 0xFFFF, false, this.effectKnob); + InputReport0x02.addControl("[EffectRack1_EffectUnit2]", "!effectknob3", 0x15, "H", 0xFFFF, false, this.effectKnob); + + InputReport0x02.addControl("[Channel1]", "volume", 0x2B, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", 0x11, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", 0x25, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", 0x27, "H"); + InputReport0x02.addControl("[Channel1]", "pregain", 0x01, "B", 0x0F, false, this.topEncoder); + InputReport0x02.addControl("[Channel1]", "!jog_touch", 0x0D, "H", 0xFFFF, false, this.jogTouch); + + InputReport0x02.addControl("[Channel2]", "volume", 0x2D, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter3", 0x21, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", 0x23, "H"); + InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", 0x29, "H"); + InputReport0x02.addControl("[Channel2]", "pregain", 0x03, "B", 0x0F, false, this.topEncoder); + InputReport0x02.addControl("[Channel2]", "!jog_touch", 0x1D, "H", 0xFFFF, false, this.jogTouch); + + InputReport0x02.addControl("[Master]", "crossfader", 0x2F, "H"); + InputReport0x02.addControl("[Master]", "headMix", 0x31, "H"); + InputReport0x02.addControl("[Master]", "!samplerGain", 0x13, "H"); + InputReport0x02.setCallback("[Master]", "!samplerGain", this.samplerGainKnob); + InputReport0x02.addControl("[Playlist]", "!browse", 0x02, "B", 0xF0, false, this.browseEncoder); // Soft takeover for knobs engine.softTakeover("[Channel1]", "rate", true); @@ -276,14 +276,14 @@ TraktorS2MK1.registerInputPackets = function() { this.controller.setScaler("mix", this.scalerParameter); // Register packet - this.controller.registerInputPacket(MessageLong); + this.controller.registerInputPacket(InputReport0x02); }; TraktorS2MK1.registerOutputPackets = function() { - var Output = new HIDPacket("output", 0x80); + var OutputReport0x80 = new HIDPacket("OutputReport_0x80", 0x80); - Output.addOutput("[Channel1]", "track_loaded", 0x1F, "B"); - Output.addOutput("[Channel2]", "track_loaded", 0x1E, "B"); + OutputReport0x80.addOutput("[Channel1]", "track_loaded", 0x1F, "B"); + OutputReport0x80.addOutput("[Channel2]", "track_loaded", 0x1E, "B"); var VuOffsets = { "[Channel1]": 0x15, @@ -291,78 +291,78 @@ TraktorS2MK1.registerOutputPackets = function() { }; for (var ch in VuOffsets) { for (var i = 0; i <= 0x03; i++) { - Output.addOutput(ch, "!" + "VuMeter" + i, VuOffsets[ch] + i, "B"); + OutputReport0x80.addOutput(ch, "!" + "VuMeter" + i, VuOffsets[ch] + i, "B"); } } - Output.addOutput("[Channel1]", "PeakIndicator", 0x01, "B"); - Output.addOutput("[Channel2]", "PeakIndicator", 0x25, "B"); + OutputReport0x80.addOutput("[Channel1]", "PeakIndicator", 0x01, "B"); + OutputReport0x80.addOutput("[Channel2]", "PeakIndicator", 0x25, "B"); - Output.addOutput("[Channel1]", "!flux_button", 0x06, "B"); - Output.addOutput("[Channel1]", "loop_in", 0x02, "B"); - Output.addOutput("[Channel1]", "loop_out", 0x05, "B"); + OutputReport0x80.addOutput("[Channel1]", "!flux_button", 0x06, "B"); + OutputReport0x80.addOutput("[Channel1]", "loop_in", 0x02, "B"); + OutputReport0x80.addOutput("[Channel1]", "loop_out", 0x05, "B"); - Output.addOutput("[Channel2]", "!flux_button", 0x26, "B"); - Output.addOutput("[Channel2]", "loop_in", 0x22, "B"); - Output.addOutput("[Channel2]", "loop_out", 0x21, "B"); + OutputReport0x80.addOutput("[Channel2]", "!flux_button", 0x26, "B"); + OutputReport0x80.addOutput("[Channel2]", "loop_in", 0x22, "B"); + OutputReport0x80.addOutput("[Channel2]", "loop_out", 0x21, "B"); - Output.addOutput("[Channel1]", "pfl", 0x20, "B"); - Output.addOutput("[Master]", "!warninglight", 0x31, "B"); - Output.addOutput("[Channel2]", "pfl", 0x1D, "B"); + OutputReport0x80.addOutput("[Channel1]", "pfl", 0x20, "B"); + OutputReport0x80.addOutput("[Master]", "!warninglight", 0x31, "B"); + OutputReport0x80.addOutput("[Channel2]", "pfl", 0x1D, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "!effect_focus_button", 0x1C, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x1B, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x1A, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x19, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "!effect_focus_button", 0x1C, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton1", 0x1B, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x1A, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x19, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "!effect_focus_button", 0x39, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton1", 0x38, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton2", 0x37, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton3", 0x36, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effect_focus_button", 0x39, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton1", 0x38, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton2", 0x37, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton3", 0x36, "B"); - Output.addOutput("[Channel1]", "!remix_button", 0x35, "B"); - Output.addOutput("[Channel2]", "!remix_button", 0x34, "B"); + OutputReport0x80.addOutput("[Channel1]", "!remix_button", 0x35, "B"); + OutputReport0x80.addOutput("[Channel2]", "!remix_button", 0x34, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x3D, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x3C, "B"); - Output.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x3B, "B"); - Output.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x3A, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x3D, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x3C, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x3B, "B"); + OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x3A, "B"); - Output.addOutput("[Channel1]", "!shift", 0x08, "B"); - Output.addOutput("[Channel1]", "sync_enabled", 0x04, "B"); - Output.addOutput("[Channel1]", "cue_indicator", 0x07, "B"); - Output.addOutput("[Channel1]", "play_indicator", 0x03, "B"); + OutputReport0x80.addOutput("[Channel1]", "!shift", 0x08, "B"); + OutputReport0x80.addOutput("[Channel1]", "sync_enabled", 0x04, "B"); + OutputReport0x80.addOutput("[Channel1]", "cue_indicator", 0x07, "B"); + OutputReport0x80.addOutput("[Channel1]", "play_indicator", 0x03, "B"); - Output.addOutput("[Channel1]", "!pad_1_G", 0x0C, "B"); - Output.addOutput("[Channel1]", "!pad_1_B", 0x10, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_1_G", 0x0C, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_1_B", 0x10, "B"); - Output.addOutput("[Channel1]", "!pad_2_G", 0x0B, "B"); - Output.addOutput("[Channel1]", "!pad_2_B", 0x0F, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_2_G", 0x0B, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_2_B", 0x0F, "B"); - Output.addOutput("[Channel1]", "!pad_3_G", 0x0A, "B"); - Output.addOutput("[Channel1]", "!pad_3_B", 0x0E, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_3_G", 0x0A, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_3_B", 0x0E, "B"); - Output.addOutput("[Channel1]", "!pad_4_G", 0x09, "B"); - Output.addOutput("[Channel1]", "!pad_4_B", 0x0D, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_4_G", 0x09, "B"); + OutputReport0x80.addOutput("[Channel1]", "!pad_4_B", 0x0D, "B"); - Output.addOutput("[Channel2]", "!shift", 0x28, "B"); - Output.addOutput("[Channel2]", "sync_enabled", 0x24, "B"); - Output.addOutput("[Channel2]", "cue_indicator", 0x27, "B"); - Output.addOutput("[Channel2]", "play_indicator", 0x23, "B"); + OutputReport0x80.addOutput("[Channel2]", "!shift", 0x28, "B"); + OutputReport0x80.addOutput("[Channel2]", "sync_enabled", 0x24, "B"); + OutputReport0x80.addOutput("[Channel2]", "cue_indicator", 0x27, "B"); + OutputReport0x80.addOutput("[Channel2]", "play_indicator", 0x23, "B"); - Output.addOutput("[Channel2]", "!pad_1_G", 0x2C, "B"); - Output.addOutput("[Channel2]", "!pad_1_B", 0x30, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_1_G", 0x2C, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_1_B", 0x30, "B"); - Output.addOutput("[Channel2]", "!pad_2_G", 0x2B, "B"); - Output.addOutput("[Channel2]", "!pad_2_B", 0x2F, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_2_G", 0x2B, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_2_B", 0x2F, "B"); - Output.addOutput("[Channel2]", "!pad_3_G", 0x2A, "B"); - Output.addOutput("[Channel2]", "!pad_3_B", 0x2E, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_3_G", 0x2A, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_3_B", 0x2E, "B"); - Output.addOutput("[Channel2]", "!pad_4_G", 0x29, "B"); - Output.addOutput("[Channel2]", "!pad_4_B", 0x2D, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_4_G", 0x29, "B"); + OutputReport0x80.addOutput("[Channel2]", "!pad_4_B", 0x2D, "B"); - this.controller.registerOutputPacket(Output); + this.controller.registerOutputPacket(OutputReport0x80); // Link up control objects to their outputs TraktorS2MK1.linkDeckOutputs("sync_enabled", TraktorS2MK1.outputCallback); @@ -496,8 +496,8 @@ TraktorS2MK1.incomingData = function(data, length) { TraktorS2MK1.controller.parsePacket(data, length); }; -// The short message handles buttons and jog wheels. -TraktorS2MK1.shortMessageCallback = function(packet, data) { +// The input report 0x01 handles buttons and jog wheels. +TraktorS2MK1.inputReport0x01Callback = function(packet, data) { for (var name in data) { var field = data[name]; if (field.name === "!jog_wheel") { @@ -509,8 +509,8 @@ TraktorS2MK1.shortMessageCallback = function(packet, data) { } }; -// There are no buttons handled by the long message, so this is a little simpler. -TraktorS2MK1.longMessageCallback = function(packet, data) { +// There are no buttons handled by input report 0x02, so this is a little simpler. +TraktorS2MK1.inputReport0x02Callback = function(packet, data) { for (var name in data) { var field = data[name]; TraktorS2MK1.controller.processControl(field); @@ -1352,7 +1352,7 @@ TraktorS2MK1.onVuMeterChanged = function(value, group, _key) { TraktorS2MK1.controller.setOutput(group, key, 0x00, false); } } - TraktorS2MK1.controller.OutputPackets["output"].send(); + TraktorS2MK1.controller.OutputPackets["OutputReport_0x80"].send(); }; TraktorS2MK1.onLoopEnabledChanged = function(value, group, _key) { From 027bc5e82ac4a6886a23e3c91f0d1d5696d86e84 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:36:39 +0100 Subject: [PATCH 06/18] Traktor S2 Mk1: Fix value conversion --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index f15b4e77a20..fcee4fc1c8b 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -191,7 +191,7 @@ TraktorS2MK1.registerInputPackets = function() { this.controller.registerInputPacket(InputReport0x01); - // Most items in the input report 0x02 are controls that go from 0-4096. + // Most items in the input report 0x02 are controls that go from 0-4095. // There are also some 4 bit encoders. InputReport0x02.addControl("[Channel1]", "rate", 0x0F, "H"); InputReport0x02.addControl("[Channel2]", "rate", 0x1F, "H"); @@ -519,7 +519,7 @@ TraktorS2MK1.inputReport0x02Callback = function(packet, data) { TraktorS2MK1.samplerGainKnob = function(field) { for (var i = 1; i <= 8; i++) { - engine.setParameter("[Sampler" + i + "]", "pregain", field.value / 4096); + engine.setParameter("[Sampler" + i + "]", "pregain", field.value / 4095); } }; @@ -1043,11 +1043,11 @@ TraktorS2MK1.effectKnob = function(field) { if (focusedEffect > 0) { engine.setParameter(effectUnitGroup.slice(0, -1) + "_Effect" + focusedEffect + "]", "parameter" + knobNumber, - field.value / 4096); + field.value / 4095); } else { engine.setParameter(effectUnitGroup.slice(0, -1) + "_Effect" + knobNumber + "]", "meta", - field.value / 4096); + field.value / 4095); } }; From 22b7b563e5648e1a2355e74083da2d485db62d53 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:39:38 +0100 Subject: [PATCH 07/18] Traktor S2 Mk1: Correct names of buttons --- .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index fcee4fc1c8b..1b815a48807 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -141,8 +141,8 @@ TraktorS2MK1.registerInputPackets = function() { InputReport0x01.addControl("[Channel1]", "!pad4", 0x0D, "B", 0x01, false, this.padButton); InputReport0x01.addControl("[Channel1]", "!loop_in", 0x09, "B", 0x40, false, this.loopInButton); InputReport0x01.addControl("[Channel1]", "!loop_out", 0x09, "B", 0x20, false, this.loopOutButton); - InputReport0x01.addControl("[Channel1]", "!remix_button", 0x0B, "B", 0x02, false, this.samplerModeButton); - InputReport0x01.addControl("[Channel1]", "!flux_button", 0x09, "B", 0x10, false, this.introOutroModeButton); + InputReport0x01.addControl("[Channel1]", "!samples_button", 0x0B, "B", 0x02, false, this.samplerModeButton); + InputReport0x01.addControl("[Channel1]", "!reset_button", 0x09, "B", 0x10, false, this.introOutroModeButton); InputReport0x01.addControl("[Channel1]", "!left_encoder_press", 0x0E, "B", 0x02, false, this.leftEncoderPress); InputReport0x01.addControl("[Channel1]", "!right_encoder_press", 0x0E, "B", 0x04, false, this.rightEncoderPress); InputReport0x01.addControl("[Channel1]", "!jog_wheel", 0x01, "I", 0xFFFFFFFF, false, this.jogMove); @@ -164,8 +164,8 @@ TraktorS2MK1.registerInputPackets = function() { InputReport0x01.addControl("[Channel2]", "!pad4", 0x0C, "B", 0x01, false, this.padButton); InputReport0x01.addControl("[Channel2]", "!loop_in", 0x0B, "B", 0x40, false, this.loopInButton); InputReport0x01.addControl("[Channel2]", "!loop_out", 0x0B, "B", 0x20, false, this.loopOutButton); - InputReport0x01.addControl("[Channel2]", "!remix_button", 0x0B, "B", 0x01, false, this.samplerModeButton); - InputReport0x01.addControl("[Channel2]", "!flux_button", 0x0B, "B", 0x10, false, this.introOutroModeButton); + InputReport0x01.addControl("[Channel2]", "!samples_button", 0x0B, "B", 0x01, false, this.samplerModeButton); + InputReport0x01.addControl("[Channel2]", "!reset_button", 0x0B, "B", 0x10, false, this.introOutroModeButton); InputReport0x01.addControl("[Channel2]", "!left_encoder_press", 0x0E, "B", 0x20, false, this.leftEncoderPress); InputReport0x01.addControl("[Channel2]", "!right_encoder_press", 0x0E, "B", 0x40, false, this.rightEncoderPress); InputReport0x01.addControl("[Channel2]", "!jog_wheel", 0x05, "I", 0xFFFFFFFF, false, this.jogMove); @@ -298,11 +298,11 @@ TraktorS2MK1.registerOutputPackets = function() { OutputReport0x80.addOutput("[Channel1]", "PeakIndicator", 0x01, "B"); OutputReport0x80.addOutput("[Channel2]", "PeakIndicator", 0x25, "B"); - OutputReport0x80.addOutput("[Channel1]", "!flux_button", 0x06, "B"); + OutputReport0x80.addOutput("[Channel1]", "!reset_button", 0x06, "B"); OutputReport0x80.addOutput("[Channel1]", "loop_in", 0x02, "B"); OutputReport0x80.addOutput("[Channel1]", "loop_out", 0x05, "B"); - OutputReport0x80.addOutput("[Channel2]", "!flux_button", 0x26, "B"); + OutputReport0x80.addOutput("[Channel2]", "!reset_button", 0x26, "B"); OutputReport0x80.addOutput("[Channel2]", "loop_in", 0x22, "B"); OutputReport0x80.addOutput("[Channel2]", "loop_out", 0x21, "B"); @@ -320,8 +320,8 @@ TraktorS2MK1.registerOutputPackets = function() { OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton2", 0x37, "B"); OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "!effectbutton3", 0x36, "B"); - OutputReport0x80.addOutput("[Channel1]", "!remix_button", 0x35, "B"); - OutputReport0x80.addOutput("[Channel2]", "!remix_button", 0x34, "B"); + OutputReport0x80.addOutput("[Channel1]", "!samples_button", 0x35, "B"); + OutputReport0x80.addOutput("[Channel2]", "!samples_button", 0x34, "B"); OutputReport0x80.addOutput("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", 0x3D, "B"); OutputReport0x80.addOutput("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", 0x3C, "B"); @@ -437,8 +437,8 @@ TraktorS2MK1.lightDeck = function(group) { // These outputs show state managed by this script and do not react to ControlObject changes, // so manually set them here. TraktorS2MK1.outputCallback(0, group, "!shift"); - TraktorS2MK1.outputCallback(0, group, "!flux_button"); - TraktorS2MK1.outputCallback(0, group, "!remix_button"); + TraktorS2MK1.outputCallback(0, group, "!reset_button"); + TraktorS2MK1.outputCallback(0, group, "!samples_button"); } this.batchingLEDUpdate = false; @@ -886,11 +886,11 @@ TraktorS2MK1.samplerModeButton = function(field) { var padMode = TraktorS2MK1.currentPadMode[field.group]; if (padMode !== TraktorS2MK1.padModes.sampler) { TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.sampler); - TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOn, false); - TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + TraktorS2MK1.controller.setOutput(field.group, "!samples_button", ButtonBrightnessOn, false); + TraktorS2MK1.controller.setOutput(field.group, "!reset_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); } else { TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.hotcue); - TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + TraktorS2MK1.controller.setOutput(field.group, "!samples_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); } }; @@ -901,11 +901,11 @@ TraktorS2MK1.introOutroModeButton = function(field) { var padMode = TraktorS2MK1.currentPadMode[field.group]; if (padMode !== TraktorS2MK1.padModes.introOutro) { TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.introOutro); - TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOn, false); - TraktorS2MK1.controller.setOutput(field.group, "!remix_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + TraktorS2MK1.controller.setOutput(field.group, "!reset_button", ButtonBrightnessOn, false); + TraktorS2MK1.controller.setOutput(field.group, "!samples_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); } else { TraktorS2MK1.setPadMode(field.group, TraktorS2MK1.padModes.hotcue); - TraktorS2MK1.controller.setOutput(field.group, "!flux_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); + TraktorS2MK1.controller.setOutput(field.group, "!reset_button", ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); } }; From 2d03f50a6b0aa751ac5b608a50abd8ed2c798ffa Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:43:01 +0100 Subject: [PATCH 08/18] Traktor S2 Mk1: Rename top_encoder to gain_encoder --- .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 1b815a48807..89f6a4e99d0 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -59,7 +59,7 @@ var TraktorS2MK1 = new function() { "[Channel2]": 0 }; - this.topEncoderPressed = { + this.gainEncoderPressed = { "[Channel1]": false, "[Channel2]": false }; @@ -130,7 +130,7 @@ TraktorS2MK1.registerInputPackets = function() { // An exclamation point indicates a specially-handled function. Everything else is a standard // Mixxx control object name. - InputReport0x01.addControl("[Channel1]", "!top_encoder_press", 0x0E, "B", 0x01, false, this.topEncoderPress); + InputReport0x01.addControl("[Channel1]", "!gain_encoder_press", 0x0E, "B", 0x01, false, this.gainEncoderPress); InputReport0x01.addControl("[Channel1]", "!shift", 0x0D, "B", 0x80, false, this.shift); InputReport0x01.addControl("[Channel1]", "!sync_enabled", 0x0D, "B", 0x40, false, this.syncButton); InputReport0x01.addControl("[Channel1]", "!cue_default", 0x0D, "B", 0x20, false, this.cueButton); @@ -153,7 +153,7 @@ TraktorS2MK1.registerInputPackets = function() { InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effectbutton2", 0x09, "B", 0x02, false, this.effectButton); InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "!effectbutton3", 0x09, "B", 0x01, false, this.effectButton); - InputReport0x01.addControl("[Channel2]", "!top_encoder_press", 0x0E, "B", 0x10, false, this.topEncoderPress); + InputReport0x01.addControl("[Channel2]", "!gain_encoder_press", 0x0E, "B", 0x10, false, this.gainEncoderPress); InputReport0x01.addControl("[Channel2]", "!shift", 0x0C, "B", 0x80, false, this.shift); InputReport0x01.addControl("[Channel2]", "!sync_enabled", 0x0C, "B", 0x40, false, this.syncButton); InputReport0x01.addControl("[Channel2]", "!cue_default", 0x0C, "B", 0x20, false, this.cueButton); @@ -214,14 +214,14 @@ TraktorS2MK1.registerInputPackets = function() { InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", 0x11, "H"); InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", 0x25, "H"); InputReport0x02.addControl("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", 0x27, "H"); - InputReport0x02.addControl("[Channel1]", "pregain", 0x01, "B", 0x0F, false, this.topEncoder); + InputReport0x02.addControl("[Channel1]", "pregain", 0x01, "B", 0x0F, false, this.gainEncoder); InputReport0x02.addControl("[Channel1]", "!jog_touch", 0x0D, "H", 0xFFFF, false, this.jogTouch); InputReport0x02.addControl("[Channel2]", "volume", 0x2D, "H"); InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter3", 0x21, "H"); InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", 0x23, "H"); InputReport0x02.addControl("[EqualizerRack1_[Channel2]_Effect1]", "parameter1", 0x29, "H"); - InputReport0x02.addControl("[Channel2]", "pregain", 0x03, "B", 0x0F, false, this.topEncoder); + InputReport0x02.addControl("[Channel2]", "pregain", 0x03, "B", 0x0F, false, this.gainEncoder); InputReport0x02.addControl("[Channel2]", "!jog_touch", 0x1D, "H", 0xFFFF, false, this.jogTouch); InputReport0x02.addControl("[Master]", "crossfader", 0x2F, "H"); @@ -1122,7 +1122,7 @@ TraktorS2MK1.encoderDirection = function(newValue, oldValue) { return direction; }; -TraktorS2MK1.topEncoder = function(field) { +TraktorS2MK1.gainEncoder = function(field) { var delta = 0.03333 * TraktorS2MK1.encoderDirection(field.value, TraktorS2MK1.previousPregain[field.group]); TraktorS2MK1.previousPregain[field.group] = field.value; @@ -1131,7 +1131,7 @@ TraktorS2MK1.topEncoder = function(field) { engine.setParameter(field.group, "pregain", currentPregain + delta); } else { var quickEffectGroup = "[QuickEffectRack1_" + field.group + "]"; - if (TraktorS2MK1.topEncoderPressed[field.group]) { + if (TraktorS2MK1.gainEncoderPressed[field.group]) { script.triggerControl(quickEffectGroup, delta > 0 ? "next_chain" : "prev_chain"); } else { var currentQuickEffectSuperKnob = engine.getParameter(quickEffectGroup, "super1"); @@ -1140,16 +1140,16 @@ TraktorS2MK1.topEncoder = function(field) { } }; -TraktorS2MK1.topEncoderPress = function(field) { +TraktorS2MK1.gainEncoderPress = function(field) { if (field.value > 0) { - TraktorS2MK1.topEncoderPressed[field.group] = true; + TraktorS2MK1.gainEncoderPressed[field.group] = true; if (TraktorS2MK1.shiftPressed[field.group]) { script.triggerControl(field.group, "pregain_set_default"); } else { script.triggerControl("[QuickEffectRack1_" + field.group + "]", "super1_set_default"); } } else { - TraktorS2MK1.topEncoderPressed[field.group] = false; + TraktorS2MK1.gainEncoderPressed[field.group] = false; } }; From 4e7e356cf211819990c41840bea6057406da6c8d Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:57:16 +0100 Subject: [PATCH 09/18] Traktor S2 Mk1: Remove unnecessary comments --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 89f6a4e99d0..c05b1e08875 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -29,9 +29,6 @@ var ShiftCueButtonAction = "REWIND"; var ButtonBrightnessOff = 0x00; var ButtonBrightnessOn = 0x1F; -// KNOWN ISSUES: -// * The effect button LEDs briefly flicker when pressing the effect focus button. - // eslint definitions var TraktorS2MK1 = new function() { this.controller = new HIDController(); @@ -768,8 +765,6 @@ TraktorS2MK1.setPadMode = function(group, padMode) { for (var i = 1; i <= 4; i++) { TraktorS2MK1.padConnections[group].push( engine.makeConnection(group, "hotcue_" + i + "_enabled", TraktorS2MK1.outputHotcueCallback)); - // TraktorS2MK1.padConnections[group].push( - // engine.makeConnection(group, "hotcue_" + i + "_color", TraktorS2MK1.outputHotcueCallback)); } } else if (padMode === TraktorS2MK1.padModes.introOutro) { for (i = 1; i <= 4; i++) { From 120dcc977644bc2eb32c7ff5c6a0f65c2814cabb Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:57:34 +0100 Subject: [PATCH 10/18] Traktor S1 Mk1: fix setOutput call --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index c05b1e08875..dfed61d5115 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -530,7 +530,7 @@ TraktorS2MK1.shift = function(field) { var shiftPressed = field.value > 0; TraktorS2MK1.shiftPressed[field.group] = shiftPressed; TraktorS2MK1.controller.setOutput(field.group, "!shift", - shiftPressed ? ButtonBrightnessOn : ButtonBrightnessOff, field.group, "!shift", + shiftPressed ? ButtonBrightnessOn : ButtonBrightnessOff, !TraktorS2MK1.batchingLEDUpdate); }; From fb2dec7ff621c540ff099574263979f7be14d2d5 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:58:13 +0100 Subject: [PATCH 11/18] Traktor S2 Mk1: Change eject to CloneFromDeck --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index dfed61d5115..b6df490f893 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -536,7 +536,7 @@ TraktorS2MK1.shift = function(field) { TraktorS2MK1.loadTrackButton = function(field) { if (TraktorS2MK1.shiftPressed[field.group]) { - engine.setValue(field.group, "eject", field.value); + engine.setValue(field.group, "CloneFromDeck", field.value); } else { engine.setValue(field.group, "LoadSelectedTrack", field.value); } From 44324491dcff858bfd846ae8b4f893ea76771472 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 11:59:43 +0100 Subject: [PATCH 12/18] Traktor S2 Mk1: Minor fix --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index b6df490f893..30a207c594e 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -1023,7 +1023,7 @@ TraktorS2MK1.effectFocusButton = function(field) { TraktorS2MK1.effectFocusChooseModeActive[field.group] = false; TraktorS2MK1.connectEffectButtonLEDs(field.group); } else if (showParameters && !TraktorS2MK1.effectFocusButtonPressedWhenParametersHidden[field.group]) { - engine.setValue(this.group, "show_parameters", 0); + engine.setValue(field.group, "show_parameters", 0); } TraktorS2MK1.effectFocusButtonPressedWhenParametersHidden[field.group] = false; From 16b6d9d1cdc87be0b7c6059bdc63518a705a7dc4 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 12:02:33 +0100 Subject: [PATCH 13/18] Traktor S2 Mk1: Fix manual entry --- res/controllers/Traktor Kontrol S2 Mk1.hid.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor Kontrol S2 Mk1.hid.xml b/res/controllers/Traktor Kontrol S2 Mk1.hid.xml index 3f4c66c9798..3ef428b8bdf 100644 --- a/res/controllers/Traktor Kontrol S2 Mk1.hid.xml +++ b/res/controllers/Traktor Kontrol S2 Mk1.hid.xml @@ -4,7 +4,7 @@ Native Instruments Traktor Kontrol S2 Mk1 leifhelm Native Instruments Traktor Kontrol S2 MK1 - + native_instruments_traktor_kontrol_s2_mk1 From 3d146a72f8fa5815b3f619e6f030cf8302c6e4e2 Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 12:07:54 +0100 Subject: [PATCH 14/18] Traktor S2 Mk1: Add comments --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 30a207c594e..679dffdf98e 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -181,6 +181,7 @@ TraktorS2MK1.registerInputPackets = function() { InputReport0x01.addControl("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", 0x0A, "B", 0x08); InputReport0x01.addControl("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", 0x0A, "B", 0x04); + // maximize the library on browse encoder press InputReport0x01.addControl("[Master]", "maximize_library", 0x0E, "B", 0x08, false, this.toggleButton); engine.makeConnection("[EffectRack1_EffectUnit1]", "show_parameters", TraktorS2MK1.onShowParametersChange); From fa9e6574c2b09c289d0bb556d434243c17683bee Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 12:38:17 +0100 Subject: [PATCH 15/18] Traktor S2 Mk1: Fix eslint --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 679dffdf98e..40db05a4b1b 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -120,8 +120,8 @@ var TraktorS2MK1 = new function() { }; TraktorS2MK1.registerInputPackets = function() { - var InputReport0x01 = new HIDPacket("InputReport_0x01", 0x01, this.inputReport0x01Callback); - var InputReport0x02 = new HIDPacket("InputReport_0x02", 0x02, this.inputReport0x02Callback); + var InputReport0x01 = new HIDPacket("InputReport0x01", 0x01, this.inputReport0x01Callback); + var InputReport0x02 = new HIDPacket("InputReport0x02", 0x02, this.inputReport0x02Callback); // Values in input report 0x01 are all buttons, except the jog wheels. // An exclamation point indicates a specially-handled function. Everything else is a standard @@ -278,7 +278,7 @@ TraktorS2MK1.registerInputPackets = function() { }; TraktorS2MK1.registerOutputPackets = function() { - var OutputReport0x80 = new HIDPacket("OutputReport_0x80", 0x80); + var OutputReport0x80 = new HIDPacket("OutputReport0x80", 0x80); OutputReport0x80.addOutput("[Channel1]", "track_loaded", 0x1F, "B"); OutputReport0x80.addOutput("[Channel2]", "track_loaded", 0x1E, "B"); @@ -1348,7 +1348,7 @@ TraktorS2MK1.onVuMeterChanged = function(value, group, _key) { TraktorS2MK1.controller.setOutput(group, key, 0x00, false); } } - TraktorS2MK1.controller.OutputPackets["OutputReport_0x80"].send(); + TraktorS2MK1.controller.OutputPackets.OutputReport0x80.send(); }; TraktorS2MK1.onLoopEnabledChanged = function(value, group, _key) { From 4fd4782b3c76bb0b6162e7d4d695d4e8c9208ccf Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Sun, 22 Jan 2023 17:19:18 +0100 Subject: [PATCH 16/18] Traktor S2 Mk1: Fix CloneFromDeck --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 40db05a4b1b..3b4bc9917de 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -537,7 +537,7 @@ TraktorS2MK1.shift = function(field) { TraktorS2MK1.loadTrackButton = function(field) { if (TraktorS2MK1.shiftPressed[field.group]) { - engine.setValue(field.group, "CloneFromDeck", field.value); + engine.setValue(field.group, "CloneFromDeck", 0); } else { engine.setValue(field.group, "LoadSelectedTrack", field.value); } From b71fec5628b3a3a5833e1a33ef20929ee260f08a Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Wed, 25 Jan 2023 19:23:43 +0100 Subject: [PATCH 17/18] Traktor S2 Mk1: Add Feature report description --- .../Traktor-Kontrol-S2-MK1-hid-scripts.js | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 3b4bc9917de..7abd86d391d 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -1355,3 +1355,110 @@ TraktorS2MK1.onLoopEnabledChanged = function(value, group, _key) { TraktorS2MK1.outputCallbackLoop(value, group, "loop_in"); TraktorS2MK1.outputCallbackLoop(value, group, "loop_out"); }; + +// # Feature Report Description +// +// Feature Report `208` (`0xd0`) +// | Byte | Endianness | Description | +// |--------|------------|-----------------------------------------------------------| +// | 0 | - | Always `d0` | +// | 1..12 | - | I don't know/always `01 00 00 00 10 00 f0 0f 10 00 f0 0f` | +// | 13..14 | LE | Channel 1 volume fader bottom | +// | 15..16 | LE | Channel 1 volume fader top | +// | 17..18 | LE | Channel 2 volume fader bottom | +// | 19..20 | LE | Channel 2 volume fader top | +// | 21..22 | LE | Crossfader left | +// | 23..24 | LE | Crossfader right | +// | 25..32 | - | Padding (`ff`) | + +// Feature Report `209` (`0xd1`) +// | Byte | Endianness | Description | +// |--------|------------|----------------------------------| +// | 0 | - | Always `d1` | +// | 1..2 | LE | Channel 1 FX dry/wet knob left | +// | 3..4 | LE | Channel 1 FX dry/wet knob center | +// | 5..6 | LE | Channel 1 FX dry/wet knob right | +// | 7..8 | LE | Channel 1 FX 1 knob left | +// | 9..10 | LE | Channel 1 FX 1 knob center | +// | 11.12 | LE | Channel 1 FX 1 knob right | +// | 13..14 | LE | Channel 1 FX 2 knob left | +// | 15..16 | LE | Channel 1 FX 2 knob center | +// | 17..18 | LE | Channel 1 FX 2 knob right | +// | 19..20 | LE | Channel 1 FX 3 knob left | +// | 21..22 | LE | Channel 1 FX 3 knob center | +// | 23..24 | LE | Channel 2 FX 3 knob right | +// | 25..26 | LE | Channel 1 EQ hi knob left | +// | 27..28 | LE | Channel 1 EQ hi knob center | +// | 29..30 | LE | Channel 1 EQ hi knob right | +// | 31..32 | LE | Channel 1 EQ mid knob left | + +// Feature Report `210` (`0xd2`) +// | Byte | Endianness | Description | +// |--------|------------|------------------------------| +// | 0 | - | Always `d2` | +// | 1..2 | LE | Channel 1 EQ mid knob center | +// | 3..4 | LE | Channel 1 EQ mid knob right | +// | 5..6 | LE | Channel 1 EQ low knob left | +// | 7..8 | LE | Channel 1 EQ low knob center | +// | 9..10 | LE | Channel 1 EQ low knob right | +// | 11..12 | LE | Channel 2 EQ hi knob left | +// | 13..14 | LE | Channel 2 EQ hi knob center | +// | 15..16 | LE | Channel 2 EQ hi knob right | +// | 17..18 | LE | Channel 2 EQ mid knob left | +// | 19..20 | LE | Channel 2 EQ mid knob center | +// | 21..22 | LE | Channel 2 EQ mid knob right | +// | 23..24 | LE | Channel 2 EQ low knob left | +// | 25..26 | LE | Channel 2 EQ low knob center | +// | 27..28 | LE | Channel 2 EQ low knob right | +// | 29..30 | LE | Sample knob left | +// | 31..32 | LE | Sample knob center | + +// Feature Report `211` (`0xd3`) +// | Byte | Endianness | Description | +// |--------|------------|----------------------------------| +// | 0 | - | Always `d3` | +// | 1..2 | LE | Sample knob right | +// | 3..4 | LE | Channel 2 FX dry/wet knob left | +// | 5..6 | LE | Channel 2 FX dry/wet knob center | +// | 7..8 | LE | Channel 2 FX dry/wet knob right | +// | 9..10 | LE | Channel 2 FX 1 knob left | +// | 11..12 | LE | Channel 2 FX 1 knob center | +// | 13..14 | LE | Channel 2 FX 1 knob right | +// | 15..16 | LE | Channel 2 FX 2 knob left | +// | 17..18 | LE | Channel 2 FX 2 knob center | +// | 19..20 | LE | Channel 2 FX 2 knob right | +// | 21..22 | LE | Channel 2 FX 3 knob left | +// | 23..24 | LE | Channel 2 FX 3 knob center | +// | 25..26 | LE | Channel 2 FX 3 knob right | +// | 27..32 | - | Padding (`ff`) | + +// Feature Report `212` (`0xd4`) +// | Byte | Endianness | Description | +// |--------|------------|-----------------------------------------------------------| +// | 0 | - | Always `d4` | +// | 1..2 | BE | Left jogwheel unpressed | +// | 3..4 | BE | Left jogwheel pressed | +// | 5..6 | BE | Right jogwheel unpressed | +// | 7..8 | BE | Right jogwheel pressed | +// | 9 | - | Left jogwhell calibration type (`00` user, `ff` factory) | +// | 10 | - | Right jogwhell calibration type (`00` user, `ff` factory) | +// | 11..32 | - | Padding (`ff`) | + +// Feature Report `215` (`0xd7`) contains the factory calibration data for jogwheels: + +// Restore of both jogwheels to factory settings: +// Read 215: `d7 00 00 00 00 4e c2 26 82 0c 1b 0d b2 0c 9a 0e 16 2a ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff` +// Write 212: `d4 0c 1b 0c e6 0c 9a 0d 58 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff` + +// | Byte | Endianness | Description | +// |--------|------------|------------------------------| +// | 0 | - | Always `d7` | +// | 1..8 | - | I don't know | +// | 9..10 | BE | Left jogwheel unpressed | +// | 11..12 | BE | Left jogwheel fully pressed | +// | 13..14 | BE | Right jogwheel unpressed | +// | 15..16 | BE | Right jogwheel fully pressed | +// | 17 | - | `42` i guess | +// | 18..32 | - | Padding (`ff`) | + +// `212`'s unpressed seems to be the same as unpressed. `212`'s pressed is `(pressed + unpressed) / 2`. From 707ada01c3ccd74bec2b833005bb5f7e8bf80f8a Mon Sep 17 00:00:00 2001 From: Jakob Leifhelm Date: Wed, 25 Jan 2023 20:46:58 +0100 Subject: [PATCH 18/18] Traktor S2 Mk1: Clarify jogwheel touch calibration --- res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js index 7abd86d391d..e209ae1b3e6 100644 --- a/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js +++ b/res/controllers/Traktor-Kontrol-S2-MK1-hid-scripts.js @@ -10,8 +10,11 @@ // ==== Jog Wheel Touch Calibration ==== // Set the threshold for scratching for each jog wheel. -// Bigger values mean more force. The unpressed value is around 3122. -// The fully pressed value is around 3728. +// If it is always scratching increase the value +// If it never scratches decrease the value +// Bigger values mean more force necessary for it to scratch. +// The unpressed value is around 3100. +// The fully pressed value is around 3700. var JogWheelTouchThreshold = { "[Channel1]": 3328, "[Channel2]": 3328,