diff --git a/.travis.yml b/.travis.yml index 0f1c6a4a42f9..6d651b39928b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,65 @@ language: c++ -matrix: + +# Build flags common to OS X and Linux. +# Parallel builds are important for avoiding OSX build timeouts. +# We turn off verbose output to avoid going over the 4MB output limit. +# TODO(2019-07-21): Add "ffmpeg=1" if FFmpeg 4.x becomes available in Ubuntu +env: + global: + - COMMON_FLAGS="-j4 test=1 mad=1 faad=1 opus=1 modplug=1 wv=1 hss1394=0 virtualize=0 debug_assertions_fatal=1 verbose=0" + +jobs: include: - - os: linux + - name: qsscheck + os: linux + dist: xenial + before_install: + - pip3 install tinycss + script: + - ./scripts/qsscheck.py . + addons: + apt: + packages: + - python3 + - python3-pip + - python3-pyqt5 + - python3-setuptools + - python3-wheel + + - name: Ubuntu/gcc build + os: linux dist: xenial - sudo: required compiler: gcc - - os: osx + # Ubuntu Xenial build prerequisites + env: EXTRA_FLAGS="localecompare=1" + install: + - scons $COMMON_FLAGS $EXTRA_FLAGS + script: + # NOTE(sblaisot): 2018-01-02 removing gdb wrapper on linux due to a bug in + # return code in order to avoid having a successful build when a test fail. + # https://bugs.launchpad.net/mixxx/+bug/1699689 + - ./mixxx-test + + - name: OSX/clang build + os: osx compiler: clang + # Workaround for bug in libopus's opus.h including + # instead of . + # Virtual X (Xvfb) is needed for analyzer waveform tests + env: >- + CFLAGS="-isystem /usr/local/include/opus" + CXXFLAGS="-isystem /usr/local/include/opus" + DISPLAY=:99.0 + before_install: + - export QTDIR="$(find /usr/local/Cellar/qt -d 1 | tail -n 1)" + - echo "QTDIR=$QTDIR" + install: + - scons $COMMON_FLAGS $EXTRA_FLAGS + script: + # lldb doesn't provide an easy way to exit 1 on error: + # https://bugs.llvm.org/show_bug.cgi?id=27326 + - lldb ./mixxx-test --batch -o run -o quit -k 'thread backtrace all' -k "script import os; os._exit(1)" git: depth: 1 @@ -82,44 +134,6 @@ addons: - taglib - wavpack -install: - # Build flags common to OS X and Linux. - # Parallel builds are important for avoiding OSX build timeouts. - # We turn off verbose output to avoid going over the 4MB output limit. - # TODO(2019-07-21): Add "ffmpeg=1" if FFmpeg 4.x becomes available in Ubuntu - - export COMMON_FLAGS="-j4 test=1 mad=1 faad=1 opus=1 modplug=1 wv=1 hss1394=0 virtualize=0 debug_assertions_fatal=1 verbose=0" - - # Ubuntu Xenial build prerequisites - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export EXTRA_FLAGS="localecompare=1"; fi - - # Define QTDIR. - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export QTDIR=$(find /usr/local/Cellar/qt -d 1 | tail -n 1); fi - - # Workaround for bug in libopus's opus.h including - # instead of . - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export CXXFLAGS="-isystem /usr/local/include/opus"; fi - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export CFLAGS="-isystem /usr/local/include/opus"; fi - - # NOTE(rryan): 2016-11-15 we are experiencing Travis timeouts for the OSX - # build. Turning off optimizations to see if that speeds up compile times. - # TODO(rryan): localecompare doesn't work on Travis with qt5 for some reason. - # TODO(2019-07-21): Move "ffmpeg=1" into COMMON_FLAGS if FFmpeg 4.x becomes available in Ubuntu - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then export EXTRA_FLAGS="ffmpeg=1 optimize=none asan=0 localecompare=0"; fi - - - scons $COMMON_FLAGS $EXTRA_FLAGS - -before_script: - # Virtual X (Xvfb) is needed for analyzer waveform tests - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then export DISPLAY=:99.0; fi - -script: - # NOTE(sblaisot): 2018-01-02 removing gdb wrapper on linux due to a bug in - # return code in order to avoid having a successful build when a test fail. - # https://bugs.launchpad.net/mixxx/+bug/1699689 - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then ./mixxx-test; fi - # lldb doesn't provide an easy way to exit 1 on error: - # https://bugs.llvm.org/show_bug.cgi?id=27326 - - if [ "$TRAVIS_OS_NAME" = "osx" ]; then lldb ./mixxx-test --batch -o run -o quit -k 'thread backtrace all' -k "script import os; os._exit(1)"; fi notifications: webhooks: diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d3f9e07f7e2..de1d408b73e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,6 +309,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/errordialoghandler.cpp src/library/analysisfeature.cpp src/library/analysislibrarytablemodel.cpp + src/library/trackloader.cpp src/library/autodj/autodjfeature.cpp src/library/autodj/autodjprocessor.cpp src/library/autodj/dlgautodj.cpp @@ -401,6 +402,7 @@ add_library(mixxx-lib STATIC EXCLUDE_FROM_ALL src/library/starrating.cpp src/library/tableitemdelegate.cpp src/library/trackcollection.cpp + src/library/trackcollectionmanager.cpp src/library/traktor/traktorfeature.cpp src/library/treeitem.cpp src/library/treeitemmodel.cpp diff --git a/build/depends.py b/build/depends.py index cb9aa2dd110b..d1974d3e7086 100644 --- a/build/depends.py +++ b/build/depends.py @@ -1006,6 +1006,7 @@ def sources(self, build): "src/database/schemamanager.cpp", "src/library/trackcollection.cpp", + "src/library/trackcollectionmanager.cpp", "src/library/externaltrackcollection.cpp", "src/library/basesqltablemodel.cpp", "src/library/basetrackcache.cpp", @@ -1112,6 +1113,8 @@ def sources(self, build): "src/library/parserm3u.cpp", "src/library/parsercsv.cpp", + "src/library/trackloader.cpp", + "src/widget/wwaveformviewer.cpp", "src/waveform/sharedglcontext.cpp", diff --git a/cmake/modules/FindChromaprint.cmake b/cmake/modules/FindChromaprint.cmake index a4da8f245968..529392cfd453 100644 --- a/cmake/modules/FindChromaprint.cmake +++ b/cmake/modules/FindChromaprint.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Chromaprint_LIBRARIES`` Libraries needed to link to Chromaprint. ``Chromaprint_DEFINITIONS`` - Compile defitions needed to use Chromaprint. + Compile definitions needed to use Chromaprint. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindEbur128.cmake b/cmake/modules/FindEbur128.cmake index fd76f0a48872..a9362c46edba 100644 --- a/cmake/modules/FindEbur128.cmake +++ b/cmake/modules/FindEbur128.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Ebur128_LIBRARIES`` Libraries needed to link to Ebur128. ``Ebur128_DEFINITIONS`` - Compile defitions needed to use Ebur128. + Compile definitions needed to use Ebur128. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindFLAC.cmake b/cmake/modules/FindFLAC.cmake index 6b17592b0b2a..daa5d2ed9a39 100644 --- a/cmake/modules/FindFLAC.cmake +++ b/cmake/modules/FindFLAC.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``FLAC_LIBRARIES`` Libraries needed to link to FLAC. ``FLAC_DEFINITIONS`` - Compile defitions needed to use FLAC. + Compile definitions needed to use FLAC. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindGPerfTools.cmake b/cmake/modules/FindGPerfTools.cmake index b8f659b093c0..fd7dd8c2fda4 100644 --- a/cmake/modules/FindGPerfTools.cmake +++ b/cmake/modules/FindGPerfTools.cmake @@ -31,7 +31,7 @@ This will define the following variables: ``GPerfTools_LIBRARIES`` Libraries needed to link to GPerfTools. ``GPerfTools_DEFINITIONS`` - Compile defitions needed to use GPerfTools. + Compile definitions needed to use GPerfTools. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindHIDAPI.cmake b/cmake/modules/FindHIDAPI.cmake index fcf37d1d2b60..a7e57e50b33a 100644 --- a/cmake/modules/FindHIDAPI.cmake +++ b/cmake/modules/FindHIDAPI.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``HIDAPI_LIBRARIES`` Libraries needed to link to HIDAPI. ``HIDAPI_DEFINITIONS`` - Compile defitions needed to use HIDAPI. + Compile definitions needed to use HIDAPI. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindID3Tag.cmake b/cmake/modules/FindID3Tag.cmake index aca75e7daabd..8518d14e0e13 100644 --- a/cmake/modules/FindID3Tag.cmake +++ b/cmake/modules/FindID3Tag.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``ID3Tag_LIBRARIES`` Libraries needed to link to ID3Tag. ``ID3Tag_DEFINITIONS`` - Compile defitions needed to use ID3Tag. + Compile definitions needed to use ID3Tag. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindLibUSB.cmake b/cmake/modules/FindLibUSB.cmake index f227327f72e2..56b158fe2250 100644 --- a/cmake/modules/FindLibUSB.cmake +++ b/cmake/modules/FindLibUSB.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``LibUSB_LIBRARIES`` Libraries needed to link to LibUSB. ``LibUSB_DEFINITIONS`` - Compile defitions needed to use LibUSB. + Compile definitions needed to use LibUSB. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindLilv.cmake b/cmake/modules/FindLilv.cmake index 95848c430edf..cb9a4d46d6a0 100644 --- a/cmake/modules/FindLilv.cmake +++ b/cmake/modules/FindLilv.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Lilv_LIBRARIES`` Libraries needed to link to Lilv. ``Lilv_DEFINITIONS`` - Compile defitions needed to use Lilv. + Compile definitions needed to use Lilv. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindMAD.cmake b/cmake/modules/FindMAD.cmake index 0974ace10cea..bb7f8721b3a5 100644 --- a/cmake/modules/FindMAD.cmake +++ b/cmake/modules/FindMAD.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``MAD_LIBRARIES`` Libraries needed to link to MAD. ``MAD_DEFINITIONS`` - Compile defitions needed to use MAD. + Compile definitions needed to use MAD. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindMP4.cmake b/cmake/modules/FindMP4.cmake index b66cb56648a9..7f5f09c54a70 100644 --- a/cmake/modules/FindMP4.cmake +++ b/cmake/modules/FindMP4.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``MP4_LIBRARIES`` Libraries needed to link to MP4. ``MP4_DEFINITIONS`` - Compile defitions needed to use MP4. + Compile definitions needed to use MP4. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindMP4v2.cmake b/cmake/modules/FindMP4v2.cmake index fc39d5e79d23..f47b07d8f222 100644 --- a/cmake/modules/FindMP4v2.cmake +++ b/cmake/modules/FindMP4v2.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``MP4v2_LIBRARIES`` Libraries needed to link to MP4v2. ``MP4v2_DEFINITIONS`` - Compile defitions needed to use MP4v2. + Compile definitions needed to use MP4v2. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindModplug.cmake b/cmake/modules/FindModplug.cmake index b99d8bdfc599..6bcc9b941237 100644 --- a/cmake/modules/FindModplug.cmake +++ b/cmake/modules/FindModplug.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Modplug_LIBRARIES`` Libraries needed to link to Modplug. ``Modplug_DEFINITIONS`` - Compile defitions needed to use Modplug. + Compile definitions needed to use Modplug. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindOpus.cmake b/cmake/modules/FindOpus.cmake index 67d2a8562d1a..3a094d96a9c7 100644 --- a/cmake/modules/FindOpus.cmake +++ b/cmake/modules/FindOpus.cmake @@ -21,7 +21,7 @@ This will define the following variables: ``Opus_LIBRARIES`` Libraries needed to link to Opus. ``Opus_DEFINITIONS`` - Compile defitions needed to use Opus. + Compile definitions needed to use Opus. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindRubberband.cmake b/cmake/modules/FindRubberband.cmake index 7331388949bd..ef1b2fe1c080 100644 --- a/cmake/modules/FindRubberband.cmake +++ b/cmake/modules/FindRubberband.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Rubberband_LIBRARIES`` Libraries needed to link to Rubberband. ``Rubberband_DEFINITIONS`` - Compile defitions needed to use Rubberband. + Compile definitions needed to use Rubberband. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindSQLite3.cmake b/cmake/modules/FindSQLite3.cmake index 9a6eae403daf..25fbccca5113 100644 --- a/cmake/modules/FindSQLite3.cmake +++ b/cmake/modules/FindSQLite3.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``SQLite3_LIBRARIES`` Libraries needed to link to SQLite3. ``SQLite3_DEFINITIONS`` - Compile defitions needed to use SQLite3. + Compile definitions needed to use SQLite3. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindShout.cmake b/cmake/modules/FindShout.cmake index dc302a242984..5226b7d857cf 100644 --- a/cmake/modules/FindShout.cmake +++ b/cmake/modules/FindShout.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Shout_LIBRARIES`` Libraries needed to link to Shout. ``Shout_DEFINITIONS`` - Compile defitions needed to use Shout. + Compile definitions needed to use Shout. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindSndFile.cmake b/cmake/modules/FindSndFile.cmake index 594ece85bc93..53cc3b29e009 100644 --- a/cmake/modules/FindSndFile.cmake +++ b/cmake/modules/FindSndFile.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``SndFile_LIBRARIES`` Libraries needed to link to SndFile. ``SndFile_DEFINITIONS`` - Compile defitions needed to use SndFile. + Compile definitions needed to use SndFile. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindUpower.cmake b/cmake/modules/FindUpower.cmake index 5e45d719b6a6..5a4d717b1856 100644 --- a/cmake/modules/FindUpower.cmake +++ b/cmake/modules/FindUpower.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``Upower_LIBRARIES`` Libraries needed to link to Upower. ``Upower_DEFINITIONS`` - Compile defitions needed to use Upower. + Compile definitions needed to use Upower. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/cmake/modules/FindWavPack.cmake b/cmake/modules/FindWavPack.cmake index 420c97465a22..719cf448689d 100644 --- a/cmake/modules/FindWavPack.cmake +++ b/cmake/modules/FindWavPack.cmake @@ -29,7 +29,7 @@ This will define the following variables: ``WavPack_LIBRARIES`` Libraries needed to link to WavPack. ``WavPack_DEFINITIONS`` - Compile defitions needed to use WavPack. + Compile definitions needed to use WavPack. Cache Variables ^^^^^^^^^^^^^^^ diff --git a/res/controllers/DJ-Tech-Kontrol-One-scripts.js b/res/controllers/DJ-Tech-Kontrol-One-scripts.js index 6da915d96946..99b24007b7dd 100644 --- a/res/controllers/DJ-Tech-Kontrol-One-scripts.js +++ b/res/controllers/DJ-Tech-Kontrol-One-scripts.js @@ -1221,7 +1221,7 @@ KONTROL1.getNoShiftNoModBankCode = function getNoShiftNoModBankCode() {//return return outstr; }; -KONTROL1.getGroup = function getGroup(groupstr) {//return Mixx group +KONTROL1.getGroup = function getGroup(groupstr) {//return Mixxx group if (KONTROL1.debug>2){print("##function: "+KONTROL1.getFunctionName())}; var outstr; diff --git a/res/controllers/Denon-MC3000-scripts.js b/res/controllers/Denon-MC3000-scripts.js index 0e40aac481af..25ccfc74006a 100644 --- a/res/controllers/Denon-MC3000-scripts.js +++ b/res/controllers/Denon-MC3000-scripts.js @@ -5,7 +5,7 @@ * * 2012/05/11 V0.995 : first "good" version approuved and tested by me * - * Special Thanks to the Programmers of Mixx and all the contributors + * Special Thanks to the Programmers of Mixxx and all the contributors * * Inspired primarily from Numark Total Control script file * diff --git a/res/controllers/Gemini-FirstMix-scripts.js b/res/controllers/Gemini-FirstMix-scripts.js index baa57326f966..520a1a1a850f 100644 --- a/res/controllers/Gemini-FirstMix-scripts.js +++ b/res/controllers/Gemini-FirstMix-scripts.js @@ -12,7 +12,7 @@ * This works great except it marks the track as played. I don't see a Mixxx function to toggle the played state for tracks, so there's nothing I can do about that. * To see the sampler, click on the word "Sampler" above the main VU meters in the center of the Mixxx window. * - * EFX/fader knobs: Since the EFX function in Mixx is kinda useless (only a flanger effect that doesn't sound that different), the EFX knobs adjust the gain, + * EFX/fader knobs: Since the EFX function in Mixxx is kinda useless (only a flanger effect that doesn't sound that different), the EFX knobs adjust the gain, * the gain knobs to adjust the high fader and the treble knobs to adjust the mid fader. This way, you get high/mid/low faders. * * EFX buttons & Master volume: The EFX buttons are mapped to send that deck to the headphones (a.k.a PFL function). The buttons light up to indicate PFL state. diff --git a/res/controllers/Numark-DJ2Go-scripts.js b/res/controllers/Numark-DJ2Go-scripts.js index 8dd2bd0a3d00..9ba6bcf1d260 100644 --- a/res/controllers/Numark-DJ2Go-scripts.js +++ b/res/controllers/Numark-DJ2Go-scripts.js @@ -90,7 +90,7 @@ NumarkDJ2Go.deck = function(deckNum) { var yesno = (engine.getValue(this.group, "track_samples") > 0)?true:false; return yesno; }; - //Brake effect introduced in Mixx 1.11 + //Brake effect introduced in Mixxx 1.11 this.brakeOn = function(factor) { engine.brake(this.deckNum, true, factor); this.braked= true; @@ -616,7 +616,7 @@ NumarkDJ2Go.playLights = function(value, group, key) { }; }; -//Mixx's sync feature is not the same as VDJ, where syncing appears to +//Mixxx's sync feature is not the same as VDJ, where syncing appears to //be continuously going on. Therefore less relevance with Mixxx to having a sync button //that illuminates. Have set it so that it flashes twice when pressed. NumarkDJ2Go.syncLights = function(value, group, key) { diff --git a/res/controllers/Pioneer-DDJ-400-script.js b/res/controllers/Pioneer-DDJ-400-script.js new file mode 100644 index 000000000000..a28afeed9cab --- /dev/null +++ b/res/controllers/Pioneer-DDJ-400-script.js @@ -0,0 +1,665 @@ +// Pioneer-DDJ-400-script.js +// **************************************************************************** +// * Mixxx mapping script file for the Pioneer DDJ-400. +// * Author: Warker, nschloe +// * Forum: https://mixxx.org/forums/viewtopic.php?f=7&t=12113 +// * Wiki: https://www.mixxx.org/wiki/doku.php/pioneer_ddj-400 +// +// Working: +// * Mixer Section (Faders, EQ, Filter, Gain, Cue) +// * Browsing and loading + Waveform zoom (shift) +// * Jogwheels, Scratching, Bending +// * cycle Temporange +// * Beat Sync +// * Beat Loop Mode +// * Sampler Mode +// +// Partially: +// * Beatjump mode (no lighting, shift mode) +// * PAD FX (only slots A-H, Q-P) +// * Effect Section (without Beat FX left + Right - no equivalent function found) +// * Output (lights) +// +// Testing: +// * Keyboard Mode (check pitch value) +// * Keyshift Mode (check pitch value) +// * Hot Cue Mode (including loops) +// * Loop Section: Loop in / Out + Adjust, Call, Double, Half +// * Effect Section (Beat FX left + Right - select the Effect Slot (not Effect BPM)) +// +// Not working/implemented: +// * Channel & Crossfader Start +// +var PioneerDDJ400 = {}; + +var LightsPioneerDDJ400 = { + beatFx: { + status: 0x94, + data1: 0x47, + }, + deck1: { + vuMeter: { + status: 0xB0, + data1: 0x02, + }, + playPause: { + status: 0x90, + data1: 0x0B, + }, + shiftPlayPause: { + status: 0x90, + data1: 0x47, + }, + cue: { + status: 0x90, + data1: 0x0C, + }, + shiftCue: { + status: 0x90, + data1: 0x48, + }, + }, + deck2: { + vuMeter: { + status: 0xB0, + data1: 0x02, + }, + playPause: { + status: 0x91, + data1: 0x0B, + }, + shiftPlayPause: { + status: 0x91, + data1: 0x47, + }, + cue: { + status: 0x91, + data1: 0x0C, + }, + shiftCue: { + status: 0x91, + data1: 0x48, + }, + }, +}; + +// Save the Shift State +PioneerDDJ400.shiftState = [0, 0]; + +// JogWheel +PioneerDDJ400.vinylMode = true; +PioneerDDJ400.alpha = 1.0/8; +PioneerDDJ400.beta = PioneerDDJ400.alpha/32; +PioneerDDJ400.highspeedScale = 2; +PioneerDDJ400.bendScale = 0.5; + +PioneerDDJ400.pointJumpSpace = 0.005; // amount in percent of the Song we can jump back to previous Cue or loop point + +PioneerDDJ400.tempoRanges = [ 0.06, 0.10, 0.16, 0.25 ]; // WIDE = 25%? + +// Keyboard Mode Variables and Settings +PioneerDDJ400.keyboardHotCuePoint = [ 0, 0 ]; // selected HotCue point (eg. PAD) in Keyboard mode per Deck 0 = unset +PioneerDDJ400.keyboardModeRefCount = [ 0, 0 ]; // count the currently pressed Pads per Deck +PioneerDDJ400.halftoneToPadMap = [4, 5, 6, 7, 0, 1, 2, 3 ]; + +// Beatjump Pads +PioneerDDJ400.beatjumpPad = [-1, 1, -2, 2, -4, 4, -8, 8 ]; // < 0 = left; else right +PioneerDDJ400.beatjumpMultiplier = [ 1, 1 ]; // Beatjump Beatcount per Deck + +// Hotcue Pads saved Loop points +PioneerDDJ400.hotcueLoopPoints = { + '[Channel1]' : [], + '[Channel2]' : [] +}; + +// Loop Section +PioneerDDJ400.loopin4beat = [ false, false ]; // inn4loop is pressed +PioneerDDJ400.loopout = [ false, false ]; // out loop is pressed +PioneerDDJ400.loopAdjustMultiply = 5; + + +PioneerDDJ400.init = function() { + 'use strict'; + // init controller + // init tempo Range to 10% (default = 6%) + engine.setValue('[Channel1]', 'rateRange', PioneerDDJ400.tempoRanges[1]); + engine.setValue('[Channel2]', 'rateRange', PioneerDDJ400.tempoRanges[1]); + + // enable effect focus on FX3 for Effect Section + engine.setValue('[EffectRack1_EffectUnit1]', 'show_focus', 0); + engine.setValue('[EffectRack1_EffectUnit1]', 'group_[Channel1]_enable', 1); + + engine.setValue('[EffectRack1_EffectUnit2]', 'show_focus', 0); + engine.setValue('[EffectRack1_EffectUnit2]', 'group_[Channel2]_enable', 1); + + engine.setValue('[EffectRack1_EffectUnit3]', 'show_focus', 1); + + // Connect the VU-Meter LEDS + engine.connectControl('[Channel1]','VuMeter','PioneerDDJ400.vuMeterUpdate'); + engine.connectControl('[Channel2]','VuMeter','PioneerDDJ400.vuMeterUpdate'); + + // reset vumeter + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.deck1.vuMeter, false); + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.deck2.vuMeter, false); +}; + +PioneerDDJ400.toggleLight = function(midiIn, active) { + 'use strict'; + midi.sendShortMsg(midiIn.status, midiIn.data1, active ? 0x7F : 0); +}; + +PioneerDDJ400.jogTurn = function(channel, _control, value, _status, group) { + 'use strict'; + var deckNum = channel + 1; + // wheel center at 64; <64 rew >64 fwd + var newVal = value - 64; + + // loop_in / out adjust + var loopEnabled = engine.getValue(group, 'loop_enabled'); + if (loopEnabled > 0) { + if (this.loopin4beat[channel]) { + newVal = newVal * this.loopAdjustMultiply + engine.getValue(group, 'loop_start_position'); + engine.setValue(group, 'loop_start_position', newVal); + return; + } + if (this.loopout[channel]) { + newVal = newVal * this.loopAdjustMultiply + engine.getValue(group, 'loop_end_position'); + engine.setValue(group, 'loop_end_position', newVal); + return; + } + } + + if (engine.isScratching(deckNum)) { + engine.scratchTick(deckNum, newVal); + } else { // fallback + engine.setValue(group, 'jog', newVal * this.bendScale); + } +}; + + +PioneerDDJ400.jogSearch = function(_channel, _control, value, _status, group) { + 'use strict'; + // "highspeed" (scaleup value) pitch bend + var newVal = (value - 64) * this.highspeedScale; + engine.setValue(group, 'jog', newVal); +}; + +PioneerDDJ400.jogTouch = function(channel, _control, value) { + 'use strict'; + var deckNum = channel + 1; + + // skip scratchmode if we adjust the loop points + if (this.loopin4beat[channel] || this.loopout[channel]) { + return; + } + + // on touch jog with vinylmode enabled -> enable scratchmode + if (value !== 0 && this.vinylMode) { + engine.scratchEnable(deckNum, 720, 33+1/3, this.alpha, this.beta); + } else { + // on release jog (value === 0) disable pitch bend mode or scratch mode + engine.scratchDisable(deckNum); + } +}; + +PioneerDDJ400.cycleTempoRange = function(_channel, _control, value, _status, group) { + 'use strict'; + if (value === 0) return; // ignore release + + var currRange = engine.getValue(group, 'rateRange'); + var idx = 0; + + for(var i = 0; i < this.tempoRanges.length; i++) { + if (currRange === this.tempoRanges[i]) { + idx = (i + 1) % this.tempoRanges.length; + break; + } + } + engine.setValue(group, 'rateRange', this.tempoRanges[idx]); +}; + + +function sortAsc(a, b) { + 'use strict'; + return a > b ? 1 : b > a ? -1 : 0; +} + +PioneerDDJ400.initCuePointsAndLoops = function(group) { + 'use strict'; + // create a list of positions in the track which can be selected + var points = []; + + for (var padNum = 1; padNum <= 8; padNum++) { + points.push( engine.getValue(group, 'hotcue_'+padNum+'_position')); + } + points.push( engine.getValue(group, 'cue_point')); + points.push( engine.getValue(group, 'loop_start_position')); + points.push( engine.getValue(group, 'loop_end_position')); + points.sort(sortAsc); // sort asc + return points; +}; + +PioneerDDJ400.cueLoopCallLeft = function(_channel, _control, value, _status, group) { + 'use strict'; + if (value === 0) { + // ignore release + return; + } + + var loop_on = engine.getValue(group, 'loop_enabled'); + if (loop_on) { + // loop halve + engine.setValue(group, 'loop_scale', 0.5); + } else { + var currentPosition = engine.getValue(group, 'playposition') - this.pointJumpSpace; + var trackSamples = engine.getValue(group, 'track_samples'); + var points = this.initCuePointsAndLoops(group); + var newPosition = currentPosition; + + for(var i = 1; i <= points.length; i++) { + if (i === points.length || points[i] >= currentPosition * trackSamples) { + newPosition = points[i-1] / trackSamples; + break; + } + } + //engine.setValue(group, 'loop_in_goto', 1); + engine.setValue(group, 'playposition', newPosition); + } +}; + +PioneerDDJ400.cueLoopCallRight = function(_channel, _control, value, _status, group) { + 'use strict'; + if (value === 0) { + return; // ignore release + } + + var loop_on = engine.getValue(group, 'loop_enabled'); + if (loop_on) { + // loop double + engine.setValue(group, 'loop_scale', 2.0); + } else { + // jump through the cue points + var currentPosition = engine.getValue(group, 'playposition'); + var trackSamples = engine.getValue(group, 'track_samples'); + var points = this.initCuePointsAndLoops(group); + + var newPosition = currentPosition; + + for(var i = 0; i < points.length; i++ ) { + if (points[i] > currentPosition * trackSamples) { + newPosition = points[i] / trackSamples; + break; + } + } + engine.setValue(group, 'playposition', newPosition); + } +}; + +PioneerDDJ400.keyboardMode = function(channel, _control, value, _status, group) { + 'use strict'; + if (value > 0) { + // clear current set hotcue point and refcount for keyboard mode + this.keyboardHotCuePoint[channel] = 0; + this.keyboardModeRefCount[channel] = 0; + // reset pitch + engine.setValue(group, 'pitch', 0.0); + this.keyboardModeEnabledOutput(channel, group); + } +}; + + +PioneerDDJ400.keyboardModeEnabledOutput = function(channel, group) { + 'use strict'; + var status = channel === 0 ? 0x97 : 0x99; + var hotcuePad = 1; + + if (this.keyboardHotCuePoint[channel] === 0) { + for(hotcuePad = 1; hotcuePad <= 8; hotcuePad++) { + var hotcueEnabled = engine.getValue(group, 'hotcue_'+hotcuePad+'_enabled'); + + midi.sendShortMsg(status, 0x40 + hotcuePad-1, hotcueEnabled > 0 ? 0x7F : 0); + // shift lights on if hotcue is set + midi.sendShortMsg(status+1 , 0x40 + hotcuePad-1, hotcueEnabled > 0 ? 0x7F : 0); + } + } else { + // enable all LEDs + for(hotcuePad = 1; hotcuePad <= 8; hotcuePad++) { + midi.sendShortMsg(status , 0x40 + hotcuePad-1, 0x7F); + } + } + // shift keyboard Pad 7 and 8 are always enabled + midi.sendShortMsg(status+1 , 0x46, 0x7F); + midi.sendShortMsg(status+1 , 0x47, 0x7F); +}; + + +PioneerDDJ400.keyboardModePad = function(channel, control, value, _status, group) { + 'use strict'; + channel = (channel & 0xf) < 10 ? 0 : 1; + var padNum = (control & 0xf) + 1; + var hotcuePad = this.keyboardHotCuePoint[channel]; + + // if no hotcue is set for keyboard mode set on first press on a pad + if (hotcuePad === 0 && value !== 0) { + hotcuePad = padNum; + this.keyboardHotCuePoint[channel] = hotcuePad; + // if there is no hotcue at this pad, set current play position + var hotcuePos = engine.getValue(group, 'hotcue_'+hotcuePad+'_position'); + + if (hotcuePos < 0) { + engine.setValue(group, 'hotcue_'+hotcuePad+'_set', 1); + } + + this.keyboardModeRefCount[channel] = 0; // reset count + this.keyboardModeEnabledOutput(channel, group); + return; + } + + // if hotcue point is set perform coresponding halftone operation + if (value > 0) { + // count pressed Pad per deck + this.keyboardModeRefCount[channel] += 1; + var newValue = this.halftoneToPadMap[padNum-1]; + + engine.setValue(group, 'pitch', newValue); + engine.setValue(group, 'hotcue_'+hotcuePad+'_gotoandplay', 1); + } else { + // decrease the number of active Pads, this should minimize unwanted stops + this.keyboardModeRefCount[channel] -= 1; + if (this.keyboardModeRefCount[channel] <= 0) { + engine.setValue(group, 'hotcue_'+hotcuePad+'_gotoandstop', 1); + engine.setValue(group, 'pitch', 0.0); // reset pitch + this.keyboardModeRefCount[channel] = 0; // reset refcount to 0 + } + } +}; + +PioneerDDJ400.keyshiftModePad = function(_channel, control, value, _status, group) { + 'use strict'; + if (value === 0) { + return; // ignore release + } + engine.setValue(group, 'pitch', this.halftoneToPadMap[control & 0xf]); +}; + +PioneerDDJ400.samplerModeShiftPadPressed = function(_channel, _control, value, _status, group) { + 'use strict'; + if (value === 0) { + return; // ignore release + } + + var playing = engine.getValue(group, 'play'); + // when playing stop and return to start/cue point + if (playing > 0) { + engine.setValue(group, 'cue_gotoandstop', 1); + } else { // load selected track + engine.setValue(group, 'LoadSelectedTrack', 1); + } + // TODO: while playing a sample blink playing PAD? +}; + +// nschloe: This section handles the beat jump mode. It's not working yet, so in the XML +// we simply use the intrinsic beatjump_*_{forward,backward} functions for now. +// +// PioneerDDJ400.beatjumpPadPressed = function(_channel, control, value, status, group) { +// 'use strict'; +// if (value === 0) { +// midi.sendShortMsg(status, control, 0); // turn off LED +// return; // ignore release +// } +// +// var newVal = this.beatjumpPad[control & 0xf] * this.beatjumpMultiplier; +// +// engine.setValue(group, 'beatjump', newVal); +// midi.sendShortMsg(status, control, 0x7f); // turn LED back on +// }; +// +// PioneerDDJ400.beatjumpShiftByOne = function(_channel, control, value, status) { +// 'use strict'; +// if (value === 0) { +// midi.sendShortMsg(status, control, 0); // turn off LED +// return; // ignore release +// } +// +// var direction = status <= 0x98 ? -1 : 1; +// +// if ( direction === -1 && this.beatjumpMultiplier <= 1) { +// direction = 0; +// } +// +// this.beatjumpMultiplier += direction; +// midi.sendShortMsg(status, control, 0x7f); // turn LED back on +// }; + +PioneerDDJ400.shiftPressed = function(channel, _control, value) { + 'use strict'; + this.shiftState[channel] = value; +}; + +PioneerDDJ400.waveFormRotate = function(_channel, _control, value) { + 'use strict'; + // select the Waveform to zoom left shift = deck1, right shift = deck2 + var deckNum = this.shiftState[0] > 0 ? 1 : 2; + var oldVal = engine.getValue('[Channel'+deckNum+']', 'waveform_zoom'); + var newVal = oldVal + (value > 0x64 ? 1 : -1); + + engine.setValue('[Channel'+deckNum+']', 'waveform_zoom', newVal); +}; + +PioneerDDJ400.loopin4beatPressed = function(channel, _control, value, _status, group) { + 'use strict'; + var loopEnabled = engine.getValue(group, 'loop_enabled'); + this.loopin4beat[channel] = (value > 0); + + if (loopEnabled === 0 && value > 0) { + engine.setValue(group, 'loop_in', 1); + } +}; + +PioneerDDJ400.loopin4beatPressedLong = function(_channel, _control, value, _status, group) { + 'use strict'; + var loopEnabled = engine.getValue(group, 'loop_enabled'); + if (!loopEnabled && value > 0) { + engine.setValue(group, 'beatloop_4_activate', 1); + } +}; + +PioneerDDJ400.loopoutPressed = function(channel, _control, value, _status, group) { + 'use strict'; + var loopEnabled = engine.getValue(group, 'loop_enabled'); + this.loopout[channel] = (value > 0); + + if (loopEnabled === 0 && value > 0) { + engine.setValue(group, 'loop_out', 1); + } +}; + +// START BEAT FX + +PioneerDDJ400.numFxSlots = 3; + +Object.defineProperty(PioneerDDJ400, 'selectedFxSlot', { + get: function() { + 'use strict'; + return engine.getValue('[EffectRack1_EffectUnit3]', 'focused_effect'); + }, + set: function(value) { + 'use strict'; + if (value <= 0 || value > PioneerDDJ400.numFxSlots) { + return; + } + + engine.setValue('[EffectRack1_EffectUnit3]', 'focused_effect', value); + + var isEffectEnabled = engine.getValue(PioneerDDJ400.selectedFxGroup, 'enabled'); + + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.beatFx, isEffectEnabled); + }, +}); + +Object.defineProperty(PioneerDDJ400, 'selectedFxGroup', { + get: function() { + 'use strict'; + return '[EffectRack1_EffectUnit3_Effect' + PioneerDDJ400.selectedFxSlot + ']'; + }, +}); + +PioneerDDJ400.beatFxLevelDepthRotate = function(_channel, _control, value) { + 'use strict'; + var newVal = value === 0 ? 0 : (value / 0x7F); + var effectOn = engine.getValue(PioneerDDJ400.selectedFxGroup, 'enabled'); + + if (effectOn) { + engine.setValue(PioneerDDJ400.selectedFxGroup, 'meta', newVal); + } else { + engine.setValue('[EffectRack1_EffectUnit3]', 'mix', newVal); + } +}; + +PioneerDDJ400.beatFxSelectPressed = function(_channel, _control, value) { + 'use strict'; + engine.setValue(PioneerDDJ400.selectedFxGroup, 'next_effect', value); +}; + +PioneerDDJ400.beatFxSelectShiftPressed = function(_channel, _control, value) { + 'use strict'; + engine.setValue(PioneerDDJ400.selectedFxGroup, 'prev_effect', value); +}; + +PioneerDDJ400.beatFxLeftPressed = ignoreRelease(function() { + 'use strict'; + PioneerDDJ400.selectedFxSlot -= 1; +}); + +PioneerDDJ400.beatFxRightPressed = ignoreRelease(function() { + 'use strict'; + PioneerDDJ400.selectedFxSlot += 1; +}); + +PioneerDDJ400.beatFxOnOffPressed = ignoreRelease(function() { + 'use strict'; + var isEnabled = !engine.getValue(PioneerDDJ400.selectedFxGroup, 'enabled'); + + engine.setValue(PioneerDDJ400.selectedFxGroup, 'enabled', isEnabled); + + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.beatFx, isEnabled); +}); + +PioneerDDJ400.beatFxOnOffShiftPressed = ignoreRelease(function() { + 'use strict'; + for (var i = 1; i <= PioneerDDJ400.numFxSlots; i += 1) { + engine.setValue('[EffectRack1_EffectUnit3_Effect' + i + ']', 'enabled', 0); + } + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.beatFx, false); +}); + +PioneerDDJ400.beatFxChannel = ignoreRelease(function(_channel, control, _value, _status, group) { + 'use strict'; + var enableChannel1 = control === 0x10 || control === 0x14; + var enableChannel2 = control === 0x11 || control === 0x14; + + engine.setValue(group, 'group_[Channel1]_enable', enableChannel1); + engine.setValue(group, 'group_[Channel2]_enable', enableChannel2); +}); + +PioneerDDJ400.padFxBelowPressed = ignoreRelease(function(channel, control, value, status, group) { + 'use strict'; + var groupAbove = group.replace(/\[EffectRack1_EffectUnit(\d+)_Effect(\d+)]/, function(all, unit, effect) { + var effectAbove = parseInt(effect) - 4; + + return '[EffectRack1_EffectUnit' + unit + '_Effect' + effectAbove + ']'; + }); + + engine.setValue(groupAbove, 'next_effect', value); +}); + +PioneerDDJ400.padFxShiftBelowPressed = ignoreRelease(function(channel, control, value, status, group) { + 'use strict'; + var groupAbove = group.replace(/\[EffectRack1_EffectUnit(\d+)_Effect(\d+)]/, function(all, unit, effect) { + var effectAbove = parseInt(effect) - 4; + + return '[EffectRack1_EffectUnit' + unit + '_Effect' + effectAbove + ']'; + }); + + engine.setValue(groupAbove, 'prev_effect', value); +}); + +// END BEAT FX + +PioneerDDJ400.vuMeterUpdate = function(value, group) { + 'use strict'; + var newVal = value * 150; + + switch(group) { + case '[Channel1]': + midi.sendShortMsg(0xB0, 0x02, newVal); + break; + + case '[Channel2]': + midi.sendShortMsg(0xB1, 0x02, newVal); + break; + } +}; + + +PioneerDDJ400.samplerModePadPressed = ignoreRelease(function(_channel, control, _value, status, group) { + 'use strict'; + var isLoaded = engine.getValue(group, 'track_loaded') === 1; + + if (!isLoaded) { + return; + } + + engine.setValue(group, 'cue_gotoandplay', 1); + + startSampleFlicker(status, control, group); +}); + +// Wrapper to easily ignore the function when the button is released. +function ignoreRelease(fn) { + 'use strict'; + return function(channel, control, value, status, group) { + if (value === 0) { // This means the button is released. + return; + } + return fn(channel, control, value, status, group); + }; +} + +var TimersPioneerDDJ400 = {}; + +function startSampleFlicker(channel, control, group) { + 'use strict'; + var val = 0x7f; + + stopFlicker(channel, control); + TimersPioneerDDJ400[channel][control] = engine.beginTimer(250, function() { + val = 0x7f - val; + + midi.sendShortMsg(channel, control, val); + + var isPlaying = engine.getValue(group, 'play') === 1; + + if (!isPlaying) { + stopFlicker(channel, control); + midi.sendShortMsg(channel, control, 0x7f); + } + }); +} + +function stopFlicker(channel, control) { + 'use strict'; + TimersPioneerDDJ400[channel] = TimersPioneerDDJ400[channel] || {}; + + if (TimersPioneerDDJ400[channel][control] !== undefined) { + engine.stopTimer(TimersPioneerDDJ400[channel][control]); + TimersPioneerDDJ400[channel][control] = undefined; + } +} + +PioneerDDJ400.shutdown = function() { + 'use strict'; + // reset vumeter + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.deck1.vuMeter, false); + PioneerDDJ400.toggleLight(LightsPioneerDDJ400.deck2.vuMeter, false); +}; diff --git a/res/controllers/Pioneer-DDJ-400.midi.xml b/res/controllers/Pioneer-DDJ-400.midi.xml new file mode 100644 index 000000000000..d9ea645a1726 --- /dev/null +++ b/res/controllers/Pioneer-DDJ-400.midi.xml @@ -0,0 +1,4837 @@ + + + + Pioneer DDJ-400 + Warker/nschloe + Midi Mapping for the Pioneer DDJ-400 + https://www.mixxx.org/wiki/doku.php/pioneer_ddj-400 + https://www.mixxx.org/forums/viewtopic.php?f=7&t=12113 + + + + + + + + + + + BROWSE - rotate - Scroll tracklist/tree view + [Library] + MoveVertical + 0xB6 + 0x40 + + + + + + BROWSE +SHIFT - rotate - Zoom in/out of enlarged waveforms + [Master] + PioneerDDJ400.waveFormRotate + 0xB6 + 0x64 + + + + + + BROWSE - press - Move cursor between track list and tree view / open a folder + [Library] + MoveFocusForward + 0x96 + 0x41 + + + + + + BROWSE +SHIFT - press - Move cursor between track list and tree view / close a folder + + [Library] + MoveFocusBackward + 0x96 + 0x42 + + + + + + + LOAD (DECK1) - press - Load a Track into Deck 1 + [Channel1] + LoadSelectedTrack + 0x96 + 0x46 + + + + + + + LOAD +SHIFT (DECK1) - press - Clone Track from playing Deck + [Channel1] + CloneFromDeck + 0x96 + 0x68 + + + + + + + LOAD (DECK2) - press - Load a Track into Deck 2 + [Channel2] + LoadSelectedTrack + 0x96 + 0x47 + + + + + + + LOAD +SHIFT (DECK2) - press - Clone Track from playing Deck + [Channel2] + CloneFromDeck + 0x96 + 0x7A + + + + + + + + + PLAY/PAUSE (DECK1) - press - Play/Pause + [Channel1] + play + 0x90 + 0x0B + + + + + + PLAY/PAUSE +SHIFT (DECK1) - press - Play/Pause + [Channel1] + play + 0x90 + 0x47 + + + + + + PLAY/PAUSE (DECK2) - press - Play/Pause + [Channel2] + play + 0x91 + 0x0B + + + + + + PLAY/PAUSE +SHIFT (DECK2) - press - Play/Pause + [Channel2] + play + 0x91 + 0x47 + + + + + + + CUE (DECK1) - press - Set/Call Cue, Back Cue + [Channel1] + cue_default + 0x90 + 0x0C + + + + + + CUE +SHIFT (DECK1) - press - Jump to track start + [Channel1] + start_play + 0x90 + 0x48 + + + + + + CUE (DECK2) - press - Set/Call Cue, Back Cue + [Channel2] + cue_default + 0x91 + 0x0C + + + + + + CUE +SHIFT (DECK2) - press - Jump to track start + [Channel2] + start_play + 0x91 + 0x48 + + + + + + + JOG DIAL PLATTER Vinyl mode On (DECK1) - rotate - Scratch + [Channel1] + PioneerDDJ400.jogTurn + 0xB0 + 0x22 + + + + + + JOG DIAL PLATTER Vinyl mode Off (DECK1) - rotate - Pitch bend + [Channel1] + PioneerDDJ400.jogTurn + 0xB0 + 0x23 + + + + + + JOG DIAL PLATTER +SHIFT (DECK1) - rotate - Search (Fast Pitch bend) + [Channel1] + PioneerDDJ400.jogSearch + 0xB0 + 0x29 + + + + + + JOG DIAL PLATTER (DECK1) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + bend + + [Channel1] + PioneerDDJ400.jogTouch + 0x90 + 0x36 + + + + + + JOG DIAL PLATTER +SHIFT (DECK1) - touch - enabe (on touch) / disable (on release) highspeed + Pitch bend + + [Channel1] + PioneerDDJ400.jogTouch + 0x90 + 0x67 + + + + + + JOG DIAL SIDE (DECK1) - rotate - Pitch bend + [Channel1] + PioneerDDJ400.jogTurn + 0xB0 + 0x21 + + + + + + + JOG DIAL PLATTER Vinyl mode On (DECK2) - rotate - Scratch + [Channel2] + PioneerDDJ400.jogTurn + 0xB1 + 0x22 + + + + + + JOG DIAL PLATTER Vinyl mode Off (DECK2) - rotate - Pitch bend + [Channel2] + PioneerDDJ400.jogTurn + 0xB1 + 0x23 + + + + + + JOG DIAL PLATTER +SHIFT (DECK2) - rotate - Search (Fast Pitch bend) + [Channel2] + PioneerDDJ400.jogSearch + 0xB1 + 0x29 + + + + + + JOG DIAL PLATTER (DECK2) - touch - enabe (on touch) / disable (on release) Scraching/Pitch + bend + + [Channel2] + PioneerDDJ400.jogTouch + 0x91 + 0x36 + + + + + + JOG DIAL PLATTER +SHIFT (DECK2) - touch - enabe (on touch) / disable (on release) highspeed + Pitch bend + + [Channel2] + PioneerDDJ400.jogTouch + 0x91 + 0x67 + + + + + + JOG DIAL SIDE (DECK2) - rotate - Pitch bend + [Channel2] + PioneerDDJ400.jogTurn + 0xB1 + 0x21 + + + + + + + TEMPO (DECK1) - fader - Tempo control + [Channel1] + rate + 0xB0 + 0x20 + + + + + + + TEMPO (DECK1) - fader - Tempo control + [Channel1] + rate + 0xB0 + 0x00 + + + + + + + TEMPO (DECK2) - fader - Tempo control + [Channel2] + rate + 0xB1 + 0x20 + + + + + + + TEMPO (DECK2) - fader - Tempo control + [Channel2] + rate + 0xB1 + 0x00 + + + + + + + + BEAT SYNC (DECK1) - press - Beat Sync to Master deck + [Channel1] + sync_enabled + 0x90 + 0x58 + + + + + + BEAT SYNC LONG PRESS (DECK1) - press - Set as Master deck + [Channel1] + sync_master + 0x90 + 0x5C + + + + + + BEAT SYNC +SHIFT (DECK1) - press - change Tempo range + [Channel1] + PioneerDDJ400.cycleTempoRange + 0x90 + 0x60 + + + + + + + BEAT SYNC (DECK2) - press - Beat Sync to Master deck + [Channel2] + sync_enabled + 0x91 + 0x58 + + + + + + BEAT SYNC LONG PRESS (DECK2) - press - Set as Master deck + [Channel2] + sync_master + 0x91 + 0x5C + + + + + + BEAT SYNC +SHIFT (DECK2) - press - change Tempo range + [Channel2] + PioneerDDJ400.cycleTempoRange + 0x91 + 0x60 + + + + + + + LOOP IN/4 BEAT (DECK1) - press - (loop off) set Loop point, (loop on) adjust loop in point + with jog wheel + + [Channel1] + PioneerDDJ400.loopin4beatPressed + 0x90 + 0x10 + + + + + + LOOP IN/4 BEAT LONG PRESS (DECK1) - press - Enable Auto 4 Beat loop + [Channel1] + PioneerDDJ400.loopin4beatPressedLong + 0x90 + 0x14 + + + + + + + LOOP IN/4 BEAT (DECK2) - press - (loop off) set Loop point, (loop on) adjust loop in point + with jog wheel + + [Channel2] + PioneerDDJ400.loopin4beatPressed + 0x91 + 0x10 + + + + + + LOOP IN/4 BEAT LONG PRESS (DECK2) - press - Enable Auto 4 Beat loop + [Channel2] + PioneerDDJ400.loopin4beatPressedLong + 0x91 + 0x14 + + + + + + + LOOP OUT (DECK1) - press - (loop off) set Loop out point, (loop on) adjust loop out point + with jog wheel + + [Channel1] + PioneerDDJ400.loopoutPressed + 0x90 + 0x11 + + + + + + LOOP OUT (DECK2) - press - (loop off) set Loop out point, (loop on) adjust loop out point + with jog wheel + + [Channel2] + PioneerDDJ400.loopoutPressed + 0x91 + 0x11 + + + + + + + RELOOP/EXIT (DECK1) - press - (loop off) Reloop, (loop on) Loop exit + [Channel1] + reloop_toggle + 0x90 + 0x4D + + + + + + RELOOP/EXIT +SHIFT (DECK1) - press - Active loop on/off + [Channel1] + reloop_andstop + 0x90 + 0x50 + + + + + + + RELOOP/EXIT (DECK2) - press - (loop off) Reloop, (loop on) Loop exit + [Channel2] + reloop_toggle + 0x91 + 0x4D + + + + + + RELOOP/EXIT +SHIFT (DECK2) - press - Active loop on/off + [Channel2] + reloop_andstop + 0x91 + 0x50 + + + + + + + CUE/LOOP CALL LEFT (DECK1) - press - (loop off) Call stored cue/loop, (loop on) Loop cutter + *2 (half) + + [Channel1] + PioneerDDJ400.cueLoopCallLeft + 0x90 + 0x51 + + + + + + + + CUE/LOOP CALL LEFT (DECK2) - press - (loop off) Call stored cue/loop, (loop on) Loop cutter + *2 (half) + + [Channel2] + PioneerDDJ400.cueLoopCallLeft + 0x91 + 0x51 + + + + + + + + CUE/LOOP CALL RIGHT (DECK1) - press - (loop off) Call stored cue/loop, (loop on) Loop + double + + [Channel1] + PioneerDDJ400.cueLoopCallRight + 0x90 + 0x53 + + + + + + + + CUE/LOOP CALL RIGHT (DECK2) - press - (loop off) Call stored cue/loop, (loop on) Loop + double + + [Channel2] + PioneerDDJ400.cueLoopCallRight + 0x91 + 0x53 + + + + + + + + SHIFT (Deck1) - press - Shift + [Channel1] + PioneerDDJ400.shiftPressed + 0x90 + 0x3F + + + + + + SHIFT (Deck2) - press - Shift + [Channel2] + PioneerDDJ400.shiftPressed + 0x91 + 0x3F + + + + + + + + + + + CROSSFADER - slider + [Master] + crossfader + 0xB6 + 0x1F + + + + + + CROSSFADER - slider + [Master] + crossfader + 0xB6 + 0x3F + + + + + + + CHANNELFADER - slider + [Channel1] + volume + 0xB0 + 0x33 + + + + + + CHANNELFADER - slider + [Channel1] + volume + 0xB0 + 0x13 + + + + + + CHANNELFADER - slider + [Channel2] + volume + 0xB1 + 0x33 + + + + + + CHANNELFADER - slider + [Channel2] + volume + 0xB1 + 0x13 + + + + + + + TRIM - rotate + [Channel1] + pregain + 0xB0 + 0x24 + + + + + + TRIM - rotate + [Channel1] + pregain + 0xB0 + 0x04 + + + + + + TRIM - rotate + [Channel2] + pregain + 0xB1 + 0x24 + + + + + + TRIM - rotate + [Channel2] + pregain + 0xB1 + 0x04 + + + + + + + + EQ HI - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter3 + 0xB0 + 0x27 + + + + + + EQ MID - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter2 + 0xB0 + 0x2B + + + + + + EQ LOW - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter1 + 0xB0 + 0x2F + + + + + + EQ HI - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter3 + 0xB0 + 0x07 + + + + + + EQ MID - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter2 + 0xB0 + 0x0B + + + + + + EQ LOW - rotate + [EqualizerRack1_[Channel1]_Effect1] + parameter1 + 0xB0 + 0x0F + + + + + + + EQ HI - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter3 + 0xB1 + 0x27 + + + + + + EQ MID - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter2 + 0xB1 + 0x2B + + + + + + EQ LOW - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter1 + 0xB1 + 0x2F + + + + + + EQ HI - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter3 + 0xB1 + 0x07 + + + + + + EQ MID - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter2 + 0xB1 + 0x0B + + + + + + EQ LOW - rotate + [EqualizerRack1_[Channel2]_Effect1] + parameter1 + 0xB1 + 0x0F + + + + + + + CUE Channel - press - toggle Headphone Cue + [Channel1] + pfl + 0x90 + 0x54 + + + + + + CUE Channel - press - toggle Headphone Cue + [Channel2] + pfl + 0x91 + 0x54 + + + + + + + CUE Channel +SHIFT - press - Adjust BPM to match tapped BPM + [Channel1] + bpm_tap + 0x90 + 0x58 + + + + + + CUE Channel +SHIFT - press - Adjust BPM to match tapped BPM + [Channel2] + bpm_tap + 0x91 + 0x58 + + + + + + + MASTER LEVEL - rotate - Master gain + [Master] + gain + 0xB6 + 0x28 + + + + + + MASTER LEVEL - rotate - Master gain + [Master] + gain + 0xB6 + 0x08 + + + + + + + HEADPHONES MIXING - rotate - Monitor Balance + [Master] + headMix + 0xB6 + 0x2C + + + + + + HEADPHONES MIXING - rotate - Monitor Balance + [Master] + headMix + 0xB6 + 0x0C + + + + + + + HEADPHONES LEVEL - rotate - Headphone gain + [Master] + headGain + 0xB6 + 0x2D + + + + + + HEADPHONES LEVEL - rotate - Headphone gain + [Master] + headGain + 0xB6 + 0x0D + + + + + + + + + + + FILTER CH1 - rotate - Filter Effect Knob + [QuickEffectRack1_[Channel1]] + super1 + 0xB6 + 0x17 + + + + + + FILTER CH1 - rotate - Filter Effect Knob + [QuickEffectRack1_[Channel1]] + super1 + 0xB6 + 0x37 + + + + + + FILTER CH2 - rotate - Filter Effect Knob + [QuickEffectRack1_[Channel2]] + super1 + 0xB6 + 0x18 + + + + + + FILTER CH2 - rotate - Filter Effect Knob + [QuickEffectRack1_[Channel2]] + super1 + 0xB6 + 0x38 + + + + + + + + + BEAT LEFT - press - select the FX Slot to the left + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxLeftPressed + 0x94 + 0x4A + + + + + + + BEAT RIGHT - press - select the FX Slot to the right + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxRightPressed + 0x94 + 0x4B + + + + + + + + BEAT FX SELECT - press - next FX in the selected Slot + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxSelectPressed + 0x94 + 0x63 + + + + + + BEAT FX SELECT +SHIFT - press - prev FX in the selected Slot + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxSelectShiftPressed + 0x94 + 0x64 + + + + + + + + BEAT FX CH SELECT CH1 - slide - Select FX on DECK 1 + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxChannel + 0x94 + 0x10 + + + + + + BEAT FX CH SELECT CH2 - slide - Select FX on DECK 2 + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxChannel + 0x94 + 0x11 + + + + + + BEAT FX CH SELECT MASTER - slide - Select FX on Master + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxChannel + 0x94 + 0x14 + + + + + + + BEAT FX LEVEL/DEPTH - rotate (MSB) - Adjust FX Level (mix) and BEAT FX Depth (meta) in the + selected slot + + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxLevelDepthRotate + 0xB4 + 0x02 + + + + + + + BEAT FX ON/OFF - press - Toggle FX in the selected Slot + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxOnOffPressed + 0x94 + 0x47 + + + + + + BEAT FX ON/OFF +SHift - press - Disable all enabled Beat FX Slots + [EffectRack1_EffectUnit3] + PioneerDDJ400.beatFxOnOffShiftPressed + 0x94 + 0x43 + + + + + + + + + + + + + PAD 1 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_1_activate + 0x97 + 0x00 + + + + + + PAD 1 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_1_clear + 0x98 + 0x00 + + + + + + PAD 1 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_1_activate + 0x99 + 0x00 + + + + + + PAD 1 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_1_clear + 0x9A + 0x00 + + + + + + PAD 2 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_2_activate + 0x97 + 0x01 + + + + + + PAD 2 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_2_clear + 0x98 + 0x01 + + + + + + PAD 2 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_2_activate + 0x99 + 0x01 + + + + + + PAD 2 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_2_clear + 0x9A + 0x01 + + + + + + PAD 3 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_3_activate + 0x97 + 0x02 + + + + + + PAD 3 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_3_clear + 0x98 + 0x02 + + + + + + PAD 3 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_3_activate + 0x99 + 0x02 + + + + + + PAD 3 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_3_clear + 0x9A + 0x02 + + + + + + PAD 4 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_4_activate + 0x97 + 0x03 + + + + + + PAD 4 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_4_clear + 0x98 + 0x03 + + + + + + PAD 4 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_4_activate + 0x99 + 0x03 + + + + + + PAD 4 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_4_clear + 0x9A + 0x03 + + + + + + PAD 5(DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_5_activate + 0x97 + 0x04 + + + + + + PAD 5 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_5_clear + 0x98 + 0x04 + + + + + + PAD 5 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_5_activate + 0x99 + 0x04 + + + + + + PAD 5 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_5_clear + 0x9A + 0x04 + + + + + + PAD 6 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_6_activate + 0x97 + 0x05 + + + + + + PAD 6 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_6_clear + 0x98 + 0x05 + + + + + + PAD 6 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_6_activate + 0x99 + 0x05 + + + + + + PAD 6 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_6_clear + 0x9A + 0x05 + + + + + + PAD 7 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_7_activate + 0x97 + 0x06 + + + + + + PAD 7 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_7_clear + 0x98 + 0x06 + + + + + + PAD 7 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_7_activate + 0x99 + 0x06 + + + + + + PAD 7 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_7_clear + 0x9A + 0x06 + + + + + + PAD 8 (DECK1) HOT CUE MODE - press - set hotcue + [Channel1] + hotcue_8_activate + 0x97 + 0x07 + + + + + + PAD 8 +SHIFT (DECK1) HOT CUE MODE - press - delete hotcue + [Channel1] + hotcue_8_clear + 0x98 + 0x07 + + + + + + PAD 8 (DECK2) HOT CUE MODE - press - set hotcue + [Channel2] + hotcue_8_activate + 0x99 + 0x07 + + + + + + PAD 8 +SHIFT (DECK2) HOT CUE MODE - press - delete hotcue + [Channel2] + hotcue_8_clear + 0x9A + 0x07 + + + + + + + + + + PAD 1 (DECK1) BEAT LOOP MODE - press - 1/4 Beatloop + [Channel1] + beatloop_0.25_toggle + 0x97 + 0x60 + + + + + + PAD 1 (DECK2) BEAT LOOP MODE - press - 1/4 Beatloop + [Channel2] + beatloop_0.25_toggle + 0x99 + 0x60 + + + + + + PAD 2 (DECK1) BEAT LOOP MODE - press - 1/2 Beatloop + [Channel1] + beatloop_0.5_toggle + 0x97 + 0x61 + + + + + + PAD 2 (DECK2) BEAT LOOP MODE - press - 1/2 Beatloop + [Channel2] + beatloop_0.5_toggle + 0x99 + 0x61 + + + + + + PAD 3 (DECK1) BEAT LOOP MODE - press - 1/1 Beatloop + [Channel1] + beatloop_1_toggle + 0x97 + 0x62 + + + + + + PAD 3 (DECK2) BEAT LOOP MODE - press - 1/1 Beatloop + [Channel2] + beatloop_1_toggle + 0x99 + 0x62 + + + + + + PAD 4 (DECK1) BEAT LOOP MODE - press - 2 Beatloop + [Channel1] + beatloop_2_toggle + 0x97 + 0x63 + + + + + + PAD 4 (DECK2) BEAT LOOP MODE - press - 2 Beatloop + [Channel2] + beatloop_2_toggle + 0x99 + 0x63 + + + + + + PAD 5 (DECK1) BEAT LOOP MODE - press - 4 Beatloop + [Channel1] + beatloop_4_toggle + 0x97 + 0x64 + + + + + + PAD 5 (DECK2) BEAT LOOP MODE - press - 4 Beatloop + [Channel2] + beatloop_4_toggle + 0x99 + 0x64 + + + + + + PAD 6 (DECK1) BEAT LOOP MODE - press - 8 Beatloop + [Channel1] + beatloop_8_toggle + 0x97 + 0x65 + + + + + + PAD 6 (DECK2) BEAT LOOP MODE - press - 8 Beatloop + [Channel2] + beatloop_8_toggle + 0x99 + 0x65 + + + + + + PAD 7 (DECK1) BEAT LOOP MODE - press - 16 Beatloop + [Channel1] + beatloop_16_toggle + 0x97 + 0x66 + + + + + + PAD 7 (DECK2) BEAT LOOP MODE - press - 16 Beatloop + [Channel2] + beatloop_16_toggle + 0x99 + 0x66 + + + + + + PAD 8 (DECK1) BEAT LOOP MODE - press - 32 Beatloop + [Channel1] + beatloop_32_toggle + 0x97 + 0x67 + + + + + + PAD 8 (DECK2) BEAT LOOP MODE - press - 32 Beatloop + [Channel2] + beatloop_32_toggle + 0x99 + 0x67 + + + + + + + + + + + + [Channel1] + beatjump_1_backward + 0x97 + 0x20 + + + + + + [Channel1] + beatjump_1_forward + 0x97 + 0x21 + + + + + + [Channel1] + beatjump_2_backward + 0x97 + 0x22 + + + + + + [Channel1] + beatjump_2_forward + 0x97 + 0x23 + + + + + + [Channel1] + beatjump_4_backward + 0x97 + 0x24 + + + + + + [Channel1] + beatjump_4_forward + 0x97 + 0x25 + + + + + + [Channel1] + beatjump_8_backward + 0x97 + 0x26 + + + + + + [Channel1] + beatjump_8_forward + 0x97 + 0x27 + + + + + + + [Channel2] + beatjump_1_backward + 0x99 + 0x20 + + + + + + [Channel2] + beatjump_1_forward + 0x99 + 0x21 + + + + + + [Channel2] + beatjump_2_backward + 0x99 + 0x22 + + + + + + [Channel2] + beatjump_2_forward + 0x99 + 0x23 + + + + + + [Channel2] + beatjump_4_backward + 0x99 + 0x24 + + + + + + [Channel2] + beatjump_4_forward + 0x99 + 0x25 + + + + + + [Channel2] + beatjump_8_backward + 0x99 + 0x26 + + + + + + [Channel2] + beatjump_8_forward + 0x99 + 0x27 + + + + + + + + + + + + + PAD 1 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler1] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x30 + + + + + + PAD 1 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler1] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x30 + + + + + + PAD 2 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler2] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x31 + + + + + + PAD 2 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler2] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x31 + + + + + + PAD 3 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler3] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x32 + + + + + + PAD 3 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler3] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x32 + + + + + + PAD 4 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler4] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x33 + + + + + + PAD 4 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler4] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x33 + + + + + + PAD 5 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler5] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x34 + + + + + + PAD 5 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler5] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x34 + + + + + + PAD 6 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler6] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x35 + + + + + + PAD 6 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler6] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x35 + + + + + + PAD 7 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler7] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x36 + + + + + + PAD 7 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler7] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x36 + + + + + + PAD 8 (LEFT) SAMPLE MODE - press - Play Sample + [Sampler8] + PioneerDDJ400.samplerModePadPressed + 0x97 + 0x37 + + + + + + PAD 8 (LEFT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler8] + PioneerDDJ400.samplerModeShiftPadPressed + 0x98 + 0x37 + + + + + + + + PAD 1 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler9] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x30 + + + + + + PAD 1 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler9] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x30 + + + + + + PAD 2 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler10] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x31 + + + + + + PAD 2 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler10] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x31 + + + + + + PAD 3 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler11] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x32 + + + + + + PAD 3 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler11] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x32 + + + + + + PAD 4 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler12] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x33 + + + + + + PAD 4 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler12] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x33 + + + + + + PAD 5 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler13] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x34 + + + + + + PAD 5 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler13] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x34 + + + + + + PAD 6 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler14] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x35 + + + + + + PAD 6 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler14] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x35 + + + + + + PAD 7 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler15] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x36 + + + + + + PAD 7 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler15] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x36 + + + + + + PAD 8 (RIGHT) SAMPLE MODE - press - Play Sample + [Sampler16] + PioneerDDJ400.samplerModePadPressed + 0x99 + 0x37 + + + + + + PAD 8 (RIGHT)+SHIFT SAMPLE MODE - press - Stop Sample or Load Selected Track into Sampler + Pad + + [Sampler16] + PioneerDDJ400.samplerModeShiftPadPressed + 0x9A + 0x37 + + + + + + + + + + HOT CUE (DECK1) +Shift - press - activate Keyboard mode + [Channel1] + PioneerDDJ400.keyboardMode + 0x90 + 0x69 + + + + + + HOT CUE (DECK2) +Shift - press - activate Keyboard mode + [Channel2] + PioneerDDJ400.keyboardMode + 0x91 + 0x69 + + + + + + + PAD 1 (DECK1) KEYBOARD MODE - press - +4 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x40 + + + + + + PAD 1 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x40 + + + + + + PAD 1 (DECK2) KEYBOARD MODE - press - +4 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x40 + + + + + + PAD 1 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x40 + + + + + + + PAD 2 (DECK1) KEYBOARD MODE - press - +5 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x41 + + + + + + PAD 2 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x41 + + + + + + PAD 2 (DECK2) KEYBOARD MODE - press - +5 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x41 + + + + + + PAD 2 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x41 + + + + + + + PAD 3 (DECK1) KEYBOARD MODE - press - +6 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x42 + + + + + + PAD 3 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x42 + + + + + + PAD 3 (DECK2) KEYBOARD MODE - press - +6 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x42 + + + + + + PAD 3 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x42 + + + + + + + PAD 4 (DECK1) KEYBOARD MODE - press - +7 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x43 + + + + + + PAD 4 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x43 + + + + + + PAD 4 (DECK2) KEYBOARD MODE - press - +7 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x43 + + + + + + PAD 4 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x43 + + + + + + + PAD 5 (DECK1) KEYBOARD MODE - press - +0 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x44 + + + + + + PAD 5 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x44 + + + + + + PAD 5 (DECK2) KEYBOARD MODE - press - +0 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x44 + + + + + + PAD 5 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x44 + + + + + + + PAD 6 (DECK1) KEYBOARD MODE - press - +1 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x45 + + + + + + PAD 6 (DECK1) +Shift KEYBOARD MODE - press - unset hotcue + [Channel1] + PioneerDDJ400.keyboardMode + 0x98 + 0x45 + + + + + + PAD 6 (DECK2) KEYBOARD MODE - press - +1 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x45 + + + + + + PAD 6 (DECK2) +Shift KEYBOARD MODE - press - unset hotcue + [Channel2] + PioneerDDJ400.keyboardMode + 0x9A + 0x45 + + + + + + + PAD 7 (DECK1) KEYBOARD MODE - press - +2 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x46 + + + + + + PAD 7 (DECK1) +Shift KEYBOARD MODE - press - Halftone up + [Channel1] + pitch_up + 0x98 + 0x46 + + + + + + PAD 7 (DECK2) KEYBOARD MODE - press - +2 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x46 + + + + + + PAD 7 (DECK2) +Shift KEYBOARD MODE - press - Halftone up + [Channel2] + pitch_up + 0x9A + 0x46 + + + + + + + PAD 8 (DECK1) KEYBOARD MODE - press - +3 Halftone + [Channel1] + PioneerDDJ400.keyboardModePad + 0x97 + 0x47 + + + + + + PAD 8 (DECK1) +Shift KEYBOARD MODE - press - Halftone down + [Channel1] + pitch_down + 0x98 + 0x47 + + + + + + PAD 8 (DECK2) KEYBOARD MODE - press - +3 Halftone + [Channel2] + PioneerDDJ400.keyboardModePad + 0x99 + 0x47 + + + + + + PAD 8 (DECK2) +Shift KEYBOARD MODE - press - Halftone down + [Channel2] + pitch_down + 0x9A + 0x47 + + + + + + + + + + PAD 1 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect1] + enabled + 0x97 + 0x10 + + + + + + PAD 1 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect1] + enabled + 0x99 + 0x10 + + + + + + PAD 2 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect2] + enabled + 0x97 + 0x11 + + + + + + PAD 2 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect2] + enabled + 0x99 + 0x11 + + + + + + PAD 3 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect3] + enabled + 0x97 + 0x12 + + + + + + PAD 3 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect3] + enabled + 0x99 + 0x12 + + + + + + PAD 4 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect4] + enabled + 0x97 + 0x13 + + + + + + PAD 4 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect4] + enabled + 0x99 + 0x13 + + + + + + PAD 5 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect5] + PioneerDDJ400.padFxBelowPressed + 0x97 + 0x14 + + + + + + PAD 5 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect5] + PioneerDDJ400.padFxBelowPressed + 0x99 + 0x14 + + + + + + PAD 6 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect6] + PioneerDDJ400.padFxBelowPressed + 0x97 + 0x15 + + + + + + PAD 6 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect6] + PioneerDDJ400.padFxBelowPressed + 0x99 + 0x15 + + + + + + PAD 7 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect7] + PioneerDDJ400.padFxBelowPressed + 0x97 + 0x16 + + + + + + PAD 7 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect7] + PioneerDDJ400.padFxBelowPressed + 0x99 + 0x16 + + + + + + PAD 8 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect8] + PioneerDDJ400.padFxBelowPressed + 0x97 + 0x17 + + + + + + PAD 8 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect8] + PioneerDDJ400.padFxBelowPressed + 0x99 + 0x17 + + + + + + + + + PAD 5 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect5] + PioneerDDJ400.padFxShiftBelowPressed + 0x98 + 0x14 + + + + + + PAD 5 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect5] + PioneerDDJ400.padFxShiftBelowPressed + 0x9A + 0x14 + + + + + + PAD 6 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect6] + PioneerDDJ400.padFxShiftBelowPressed + 0x98 + 0x15 + + + + + + PAD 6 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect6] + PioneerDDJ400.padFxShiftBelowPressed + 0x9A + 0x15 + + + + + + PAD 7 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect7] + PioneerDDJ400.padFxShiftBelowPressed + 0x98 + 0x16 + + + + + + PAD 7 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect7] + PioneerDDJ400.padFxShiftBelowPressed + 0x9A + 0x16 + + + + + + PAD 8 (DECK1) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit1_Effect8] + PioneerDDJ400.padFxShiftBelowPressed + 0x98 + 0x17 + + + + + + PAD 8 (DECK2) PAD FX 1 MODE - press - Effect + [EffectRack1_EffectUnit2_Effect8] + PioneerDDJ400.padFxShiftBelowPressed + 0x9A + 0x17 + + + + + + + + + + PAD 1 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect1] + enabled + 0x97 + 0x50 + + + + + + PAD 1 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect1] + enabled + 0x99 + 0x50 + + + + + + PAD 2 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect2] + enabled + 0x97 + 0x51 + + + + + + PAD 2 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect2] + enabled + 0x99 + 0x51 + + + + + + PAD 3 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect3] + enabled + 0x97 + 0x52 + + + + + + PAD 3 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect3] + enabled + 0x99 + 0x52 + + + + + + PAD 4 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect4] + enabled + 0x97 + 0x53 + + + + + + PAD 4 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect4] + enabled + 0x99 + 0x53 + + + + + + PAD 5 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect5] + enabled + 0x97 + 0x54 + + + + + + PAD 5 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect5] + enabled + 0x99 + 0x54 + + + + + + PAD 6 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect6] + enabled + 0x97 + 0x55 + + + + + + PAD 6 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect6] + enabled + 0x99 + 0x55 + + + + + + PAD 7 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect7] + enabled + 0x97 + 0x56 + + + + + + PAD 7 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect7] + enabled + 0x99 + 0x56 + + + + + + PAD 8 (DECK1) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit1_Effect8] + enabled + 0x97 + 0x57 + + + + + + PAD 8 (DECK2) PAD FX 2 MODE - press - Effect + [EffectRack2_EffectUnit2_Effect8] + enabled + 0x99 + 0x57 + + + + + + + + + + PAD 1 (DECK1) KEYSHIFT MODE - press - permanent halftone +4 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x70 + + + + + + PAD 2 (DECK1) KEYSHIFT MODE - press - permanent halftone +5 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x71 + + + + + + PAD 3 (DECK1) KEYSHIFT MODE - press - permanent halftone +6 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x72 + + + + + + PAD 4 (DECK1) KEYSHIFT MODE - press - permanent halftone +7 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x73 + + + + + + PAD 5 (DECK1) KEYSHIFT MODE - press - permanent halftone 0 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x74 + + + + + + PAD 6 (DECK1) KEYSHIFT MODE - press - permanent halftone +1 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x75 + + + + + + PAD 7 (DECK1) KEYSHIFT MODE - press - permanent halftone +2 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x76 + + + + + + PAD 7 (DECK1) +SHIFT KEYSHIFT MODE - press - permanent halftone up + [Channel1] + pitch_up + 0x98 + 0x76 + + + + + + PAD 8 (DECK1) KEYSHIFT MODE - press - permanent halftone +3 + [Channel1] + PioneerDDJ400.keyshiftModePad + 0x97 + 0x77 + + + + + + PAD 8 (DECK1) +SHIFT KEYSHIFT MODE - press - permanent halftone down + [Channel1] + pitch_down + 0x98 + 0x77 + + + + + + + + PAD 1 (DECK2) KEYSHIFT MODE - press - permanent halftone +4 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x70 + + + + + + PAD 2 (DECK2) KEYSHIFT MODE - press - permanent halftone +5 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x71 + + + + + + PAD 3 (DECK2) KEYSHIFT MODE - press - permanent halftone +6 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x72 + + + + + + PAD 4 (DECK2) KEYSHIFT MODE - press - permanent halftone +7 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x73 + + + + + + PAD 5 (DECK2) KEYSHIFT MODE - press - permanent halftone 0 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x74 + + + + + + PAD 6 (DECK2) KEYSHIFT MODE - press - permanent halftone +1 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x75 + + + + + + PAD 7 (DECK2) KEYSHIFT MODE - press - permanent halftone +2 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x76 + + + + + + PAD 7 (DECK2) +SHIFT KEYSHIFT MODE - press - permanent halftone up + [Channel2] + pitch_up + 0x9A + 0x76 + + + + + + PAD 8 (DECK2) KEYSHIFT MODE - press - permanent halftone +3 + [Channel2] + PioneerDDJ400.keyshiftModePad + 0x99 + 0x77 + + + + + + PAD 8 (DECK2) +SHIFT KEYSHIFT MODE - press - permanent halftone down + [Channel2] + pitch_down + 0x9A + 0x77 + + + + + + + + + + + + + + + + [Channel1] + play_indicator + 0x90 + 0x0B + 0x7F + 0.5 + + + [Channel2] + play_indicator + 0x91 + 0x0B + 0x7F + 0.5 + + + [Channel1] + play_indicator + 0x90 + 0x47 + 0x7F + 0.5 + + + [Channel2] + play_indicator + 0x91 + 0x47 + 0x7F + 0.5 + + + + + [Channel1] + cue_indicator + 0x90 + 0x0C + 0x7F + 0.5 + + + [Channel2] + cue_indicator + 0x91 + 0x0C + 0x7F + 0.5 + + + + + [Channel1] + cue_indicator + 0x90 + 0x47 + 0x7F + 0.5 + + + [Channel2] + cue_indicator + 0x91 + 0x47 + 0x7F + 0.5 + + + + + [Channel1] + sync_enabled + 0x90 + 0x58 + 0x7F + 0.5 + + + [Channel2] + sync_enabled + 0x91 + 0x58 + 0x7F + 0.5 + + + [Channel1] + sync_master + 0x90 + 0x60 + 0x7F + 0.5 + + + [Channel2] + sync_master + 0x91 + 0x60 + 0x7F + 0.5 + + + + + [Channel1] + loop_in + 0x90 + 0x10 + 0x7F + 0.5 + + + [Channel2] + loop_in + 0x91 + 0x10 + 0x7F + 0.5 + + + + + [Channel1] + loop_out + 0x90 + 0x11 + 0x7F + 0.5 + + + [Channel2] + loop_out + 0x91 + 0x11 + 0x7F + 0.5 + + + + + [Channel1] + loop_start_position + 0x90 + 0x4D + 0x7F + 0.5 + + + [Channel1] + loop_enabled + 0x90 + 0x4D + 0x7F + 0.5 + + + [Channel2] + loop_start_position + 0x91 + 0x4D + 0x7F + 0.5 + + + [Channel2] + loop_enabled + 0x91 + 0x4D + 0x7F + 0.5 + + + [Channel1] + loop_enabled + 0x90 + 0x50 + 0x7F + 0.5 + + + [Channel2] + loop_enabled + 0x91 + 0x50 + 0x7F + 0.5 + + + + + [Channel1] + pfl + 0x90 + 0x54 + 0x7F + 0.5 + + + [Channel2] + pfl + 0x91 + 0x54 + 0x7F + 0.5 + + + + + [Channel1] + hotcue_1_enabled + 0x97 + 0x00 + 0x7F + 0.5 + + + [Channel2] + hotcue_1_enabled + 0x99 + 0x00 + 0x7F + 0.5 + + + [Channel1] + hotcue_2_enabled + 0x97 + 0x01 + 0x7F + 0.5 + + + [Channel2] + hotcue_2_enabled + 0x99 + 0x01 + 0x7F + 0.5 + + + [Channel1] + hotcue_3_enabled + 0x97 + 0x02 + 0x7F + 0.5 + + + [Channel2] + hotcue_3_enabled + 0x99 + 0x02 + 0x7F + 0.5 + + + [Channel1] + hotcue_4_enabled + 0x97 + 0x03 + 0x7F + 0.5 + + + [Channel2] + hotcue_4_enabled + 0x99 + 0x03 + 0x7F + 0.5 + + + [Channel1] + hotcue_5_enabled + 0x97 + 0x04 + 0x7F + 0.5 + + + [Channel2] + hotcue_5_enabled + 0x99 + 0x04 + 0x7F + 0.5 + + + [Channel1] + hotcue_6_enabled + 0x97 + 0x05 + 0x7F + 0.5 + + + [Channel2] + hotcue_6_enabled + 0x99 + 0x05 + 0x7F + 0.5 + + + [Channel1] + hotcue_7_enabled + 0x97 + 0x06 + 0x7F + 0.5 + + + [Channel2] + hotcue_7_enabled + 0x99 + 0x06 + 0x7F + 0.5 + + + [Channel1] + hotcue_8_enabled + 0x97 + 0x07 + 0x7F + 0.5 + + + [Channel2] + hotcue_8_enabled + 0x99 + 0x07 + 0x7F + 0.5 + + + + + [Channel1] + hotcue_1_enabled + 0x98 + 0x00 + 0x7F + 0.5 + + + [Channel2] + hotcue_1_enabled + 0x9A + 0x00 + 0x7F + 0.5 + + + [Channel1] + hotcue_2_enabled + 0x98 + 0x01 + 0x7F + 0.5 + + + [Channel2] + hotcue_2_enabled + 0x9A + 0x01 + 0x7F + 0.5 + + + [Channel1] + hotcue_3_enabled + 0x98 + 0x02 + 0x7F + 0.5 + + + [Channel2] + hotcue_3_enabled + 0x9A + 0x02 + 0x7F + 0.5 + + + [Channel1] + hotcue_4_enabled + 0x98 + 0x03 + 0x7F + 0.5 + + + [Channel2] + hotcue_4_enabled + 0x9A + 0x03 + 0x7F + 0.5 + + + [Channel1] + hotcue_5_enabled + 0x98 + 0x04 + 0x7F + 0.5 + + + [Channel2] + hotcue_5_enabled + 0x9A + 0x04 + 0x7F + 0.5 + + + [Channel1] + hotcue_6_enabled + 0x98 + 0x05 + 0x7F + 0.5 + + + [Channel2] + hotcue_6_enabled + 0x9A + 0x05 + 0x7F + 0.5 + + + [Channel1] + hotcue_7_enabled + 0x98 + 0x06 + 0x7F + 0.5 + + + [Channel2] + hotcue_7_enabled + 0x9A + 0x06 + 0x7F + 0.5 + + + [Channel1] + hotcue_8_enabled + 0x98 + 0x07 + 0x7F + 0.5 + + + [Channel2] + hotcue_8_enabled + 0x9A + 0x07 + 0x7F + 0.5 + + + + + [Channel1] + beatloop_0.25_enabled + 0x97 + 0x60 + 0x7F + 0.5 + + + [Channel2] + beatloop_0.25_enabled + 0x99 + 0x60 + 0x7F + 0.5 + + + [Channel1] + beatloop_0.5_enabled + 0x97 + 0x61 + 0x7F + 0.5 + + + [Channel2] + beatloop_0.5_enabled + 0x99 + 0x61 + 0x7F + 0.5 + + + [Channel1] + beatloop_1_enabled + 0x97 + 0x62 + 0x7F + 0.5 + + + [Channel2] + beatloop_1_enabled + 0x99 + 0x62 + 0x7F + 0.5 + + + [Channel1] + beatloop_2_enabled + 0x97 + 0x63 + 0x7F + 0.5 + + + [Channel2] + beatloop_2_enabled + 0x99 + 0x63 + 0x7F + 0.5 + + + [Channel1] + beatloop_4_enabled + 0x97 + 0x64 + 0x7F + 0.5 + + + [Channel2] + beatloop_4_enabled + 0x99 + 0x64 + 0x7F + 0.5 + + + [Channel1] + beatloop_8_enabled + 0x97 + 0x65 + 0x7F + 0.5 + + + [Channel2] + beatloop_8_enabled + 0x99 + 0x65 + 0x7F + 0.5 + + + [Channel1] + beatloop_16_enabled + 0x97 + 0x66 + 0x7F + 0.5 + + + [Channel2] + beatloop_16_enabled + 0x99 + 0x66 + 0x7F + 0.5 + + + [Channel1] + beatloop_32_enabled + 0x97 + 0x67 + 0x7F + 0.5 + + + [Channel2] + beatloop_32_enabled + 0x99 + 0x67 + 0x7F + 0.5 + + + + + [Sampler1] + track_loaded + 0x97 + 0x30 + 0x7F + 0.5 + + + [Sampler2] + track_loaded + 0x97 + 0x31 + 0x7F + 0.5 + + + [Sampler3] + track_loaded + 0x97 + 0x32 + 0x7F + 0.5 + + + [Sampler4] + track_loaded + 0x97 + 0x33 + 0x7F + 0.5 + + + [Sampler5] + track_loaded + 0x97 + 0x34 + 0x7F + 0.5 + + + [Sampler6] + track_loaded + 0x97 + 0x35 + 0x7F + 0.5 + + + [Sampler7] + track_loaded + 0x97 + 0x36 + 0x7F + 0.5 + + + [Sampler8] + track_loaded + 0x97 + 0x37 + 0x7F + 0.5 + + + + [Sampler1] + track_loaded + 0x98 + 0x30 + 0x7F + 0.5 + + + [Sampler2] + track_loaded + 0x98 + 0x31 + 0x7F + 0.5 + + + [Sampler3] + track_loaded + 0x98 + 0x32 + 0x7F + 0.5 + + + [Sampler4] + track_loaded + 0x98 + 0x33 + 0x7F + 0.5 + + + [Sampler5] + track_loaded + 0x98 + 0x34 + 0x7F + 0.5 + + + [Sampler6] + track_loaded + 0x98 + 0x35 + 0x7F + 0.5 + + + [Sampler7] + track_loaded + 0x98 + 0x36 + 0x7F + 0.5 + + + [Sampler8] + track_loaded + 0x98 + 0x37 + 0x7F + 0.5 + + + + + [Channel1] + hotcue_1_enabled + 0x97 + 0x40 + 0x7F + 0.5 + + + [Channel2] + hotcue_1_enabled + 0x99 + 0x40 + 0x7F + 0.5 + + + [Channel1] + hotcue_2_enabled + 0x97 + 0x41 + 0x7F + 0.5 + + + [Channel2] + hotcue_2_enabled + 0x99 + 0x41 + 0x7F + 0.5 + + + [Channel1] + hotcue_3_enabled + 0x97 + 0x42 + 0x7F + 0.5 + + + [Channel2] + hotcue_3_enabled + 0x99 + 0x42 + 0x7F + 0.5 + + + [Channel1] + hotcue_4_enabled + 0x97 + 0x43 + 0x7F + 0.5 + + + [Channel2] + hotcue_4_enabled + 0x99 + 0x43 + 0x7F + 0.5 + + + [Channel1] + hotcue_5_enabled + 0x97 + 0x44 + 0x7F + 0.5 + + + [Channel2] + hotcue_5_enabled + 0x99 + 0x44 + 0x7F + 0.5 + + + [Channel1] + hotcue_6_enabled + 0x97 + 0x45 + 0x7F + 0.5 + + + [Channel2] + hotcue_6_enabled + 0x99 + 0x45 + 0x7F + 0.5 + + + [Channel1] + hotcue_7_enabled + 0x97 + 0x46 + 0x7F + 0.5 + + + [Channel2] + hotcue_7_enabled + 0x99 + 0x46 + 0x7F + 0.5 + + + [Channel1] + hotcue_8_enabled + 0x97 + 0x47 + 0x7F + 0.5 + + + [Channel2] + hotcue_8_enabled + 0x99 + 0x47 + 0x7F + 0.5 + + + + + [Channel1] + hotcue_1_enabled + 0x98 + 0x40 + 0x7F + 0.5 + + + [Channel2] + hotcue_1_enabled + 0x9A + 0x40 + 0x7F + 0.5 + + + [Channel1] + hotcue_2_enabled + 0x98 + 0x41 + 0x7F + 0.5 + + + [Channel2] + hotcue_2_enabled + 0x9A + 0x41 + 0x7F + 0.5 + + + [Channel1] + hotcue_3_enabled + 0x98 + 0x42 + 0x7F + 0.5 + + + [Channel2] + hotcue_3_enabled + 0x9A + 0x42 + 0x7F + 0.5 + + + [Channel1] + hotcue_4_enabled + 0x98 + 0x43 + 0x7F + 0.5 + + + [Channel2] + hotcue_4_enabled + 0x9A + 0x43 + 0x7F + 0.5 + + + [Channel1] + hotcue_5_enabled + 0x98 + 0x44 + 0x7F + 0.5 + + + [Channel2] + hotcue_5_enabled + 0x9A + 0x44 + 0x7F + 0.5 + + + [Channel1] + hotcue_6_enabled + 0x98 + 0x45 + 0x7F + 0.5 + + + [Channel2] + hotcue_6_enabled + 0x9A + 0x45 + 0x7F + 0.5 + + + [Channel1] + play + 0x98 + 0x46 + 0x7F + 0.5 + + + [Channel2] + play + 0x9A + 0x46 + 0x7F + 0.5 + + + [Channel1] + play + 0x98 + 0x47 + 0x7F + 0.5 + + + [Channel2] + play + 0x9A + 0x47 + 0x7F + 0.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Channel1] + play + 0x97 + 0x70 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x71 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x72 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x73 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x74 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x75 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x76 + 0x7F + 0.5 + + + [Channel1] + play + 0x97 + 0x77 + 0x7F + 0.5 + + + [Channel1] + play + 0x98 + 0x76 + 0x7F + 0.5 + + + [Channel1] + play + 0x98 + 0x77 + 0x7F + 0.5 + + + + [Channel2] + play + 0x99 + 0x70 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x71 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x72 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x73 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x74 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x75 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x76 + 0x7F + 0.5 + + + [Channel2] + play + 0x99 + 0x77 + 0x7F + 0.5 + + + [Channel2] + play + 0x9A + 0x76 + 0x7F + 0.5 + + + [Channel2] + play + 0x9A + 0x77 + 0x7F + 0.5 + + + + + + + + diff --git a/res/controllers/Stanton-SCS3d-alternate-scripts.js b/res/controllers/Stanton-SCS3d-alternate-scripts.js index 8c265a0dda63..a4744e4a1bc2 100644 --- a/res/controllers/Stanton-SCS3d-alternate-scripts.js +++ b/res/controllers/Stanton-SCS3d-alternate-scripts.js @@ -11,7 +11,7 @@ //////////////////////////////////////////////////////////////////////// // Issues -// - Each deck rembembers the mode it was in, confusing? Would it be better to +// - Each deck remembers the mode it was in, confusing? Would it be better to // keep the current mode on deck switch? // Useful tinkering commands, channel reset and flat mode diff --git a/res/controllers/Traktor Kontrol S2 MK3.hid.xml b/res/controllers/Traktor Kontrol S2 MK3.hid.xml new file mode 100644 index 000000000000..556a7e217a1e --- /dev/null +++ b/res/controllers/Traktor Kontrol S2 MK3.hid.xml @@ -0,0 +1,20 @@ + + + + Traktor Kontrol S2 MK3 + Michael Schmidt + HID Mapping for Traktor Kontrol S2 MK3 + https://www.mixxx.org/wiki/doku.php/native_instruments_traktor_s2_mk3 + https://www.mixxx.org/forums/viewtopic.php?f=7&t=12999 + + + + + + + + + + + + diff --git a/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js new file mode 100644 index 000000000000..74789054c6ad --- /dev/null +++ b/res/controllers/Traktor-Kontrol-S2-MK3-hid-scripts.js @@ -0,0 +1,952 @@ +/////////////////////////////////////////////////////////////////////////////////// +// JSHint configuration // +/////////////////////////////////////////////////////////////////////////////////// +/* global engine */ +/* global script */ +/* global HIDDebug */ +/* global HIDPacket */ +/* global HIDController */ +/* jshint -W016 */ +/////////////////////////////////////////////////////////////////////////////////// +/* */ +/* Traktor Kontrol S2 MK3 HID controller script v1.00 */ +/* Last modification: December 2019 */ +/* Author: Michael Schmidt */ +/* https://www.mixxx.org/wiki/doku.php/native_instruments_traktor_kontrol_s2_mk3 */ +/* */ +/////////////////////////////////////////////////////////////////////////////////// + +var TraktorS2MK3 = new function () { + this.controller = new HIDController(); + this.shiftPressed = { "[Channel1]": false, "[Channel2]": false }; + this.fxButtonState = { 1: false, 2: false, 3: false, 4: false }; + this.padModeState = { "[Channel1]": 0, "[Channel2]": 0 }; // 0 = Hotcues Mode, 1 = Samples Mode + + // Knob encoder states (hold values between 0x0 and 0xF) + // Rotate to the right is +1 and to the left is means -1 + this.browseKnobEncoderState = { "[Channel1]": 0, "[Channel2]": 0 }; + this.loopKnobEncoderState = { "[Channel1]": 0, "[Channel2]": 0 }; + this.moveKnobEncoderState = { "[Channel1]": 0, "[Channel2]": 0 }; + + // Microphone button + this.microphonePressedTimer = 0; // Timer to distinguish between short and long press + + // Sync buttons + this.syncPressedTimer = { "[Channel1]": 0, "[Channel2]": 0 }; // Timer to distinguish between short and long press + + // Jog wheels + this.lastTickVal = [0, 0]; + this.lastTickTime = [0.0, 0.0]; + + // VuMeter + this.vuLeftConnection = {}; + this.vuRightConnection = {}; + this.clipLeftConnection = {}; + this.clipRightConnection = {}; + this.vuMeterThresholds = { "vu-18": (1 / 6), "vu-12": (2 / 6), "vu-6": (3 / 6), "vu0": (4 / 6), "vu6": (5 / 6) }; + + // Sampler callbacks + this.samplerCallbacks = []; + this.samplerHotcuesRelation = { + "[Channel1]": { + 1: 1, 2: 2, 3: 3, 4: 4, 5: 9, 6: 10, 7: 11, 8: 12 + }, "[Channel2]": { + 1: 5, 2: 6, 3: 7, 4: 8, 5: 13, 6: 14, 7: 15, 8: 16 + } + }; +}; + +TraktorS2MK3.init = function (id) { + TraktorS2MK3.registerInputPackets(); + TraktorS2MK3.registerOutputPackets(); + HIDDebug("TraktorS2MK3: Init done!"); +}; + +TraktorS2MK3.registerInputPackets = function () { + var messageShort = new HIDPacket("shortmessage", 0x01, this.messageCallback); + var messageLong = new HIDPacket("longmessage", 0x02, this.messageCallback); + + this.registerInputButton(messageShort, "[Channel1]", "!play", 0x02, 0x08, this.playHandler); + this.registerInputButton(messageShort, "[Channel2]", "!play", 0x05, 0x20, this.playHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!cue_default", 0x02, 0x04, this.cueHandler); + this.registerInputButton(messageShort, "[Channel2]", "!cue_default", 0x05, 0x10, this.cueHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!shift", 0x01, 0x20, this.shiftHandler); + this.registerInputButton(messageShort, "[Channel2]", "!shift", 0x04, 0x80, this.shiftHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!sync", 0x02, 0x01, this.syncHandler); + this.registerInputButton(messageShort, "[Channel2]", "!sync", 0x05, 0x04, this.syncHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!keylock", 0x02, 0x02, this.keylockHandler); + this.registerInputButton(messageShort, "[Channel2]", "!keylock", 0x05, 0x08, this.keylockHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!hotcues", 0x01, 0x40, this.padModeHandler); + this.registerInputButton(messageShort, "[Channel2]", "!hotcues", 0x05, 0x01, this.padModeHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!samples", 0x01, 0x80, this.padModeHandler); + this.registerInputButton(messageShort, "[Channel2]", "!samples", 0x05, 0x02, this.padModeHandler); + + // Number pad buttons (Hotcues or Samplers depending on current mode) + this.registerInputButton(messageShort, "[Channel1]", "!pad_1", 0x02, 0x10, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_2", 0x02, 0x20, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_3", 0x02, 0x40, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_4", 0x02, 0x80, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_5", 0x03, 0x01, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_6", 0x03, 0x02, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_7", 0x03, 0x04, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel1]", "!pad_8", 0x03, 0x08, this.numberButtonHandler); + + this.registerInputButton(messageShort, "[Channel2]", "!pad_1", 0x05, 0x40, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_2", 0x05, 0x80, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_3", 0x06, 0x01, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_4", 0x06, 0x02, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_5", 0x06, 0x04, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_6", 0x06, 0x08, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_7", 0x06, 0x10, this.numberButtonHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pad_8", 0x06, 0x20, this.numberButtonHandler); + + // Headphone buttons + this.registerInputButton(messageShort, "[Channel1]", "!pfl", 0x04, 0x01, this.headphoneHandler); + this.registerInputButton(messageShort, "[Channel2]", "!pfl", 0x04, 0x02, this.headphoneHandler); + + // Track browsing + this.registerInputButton(messageShort, "[Channel1]", "!SelectTrack", 0x09, 0x0F, this.selectTrackHandler); + this.registerInputButton(messageShort, "[Channel2]", "!SelectTrack", 0x0A, 0xF0, this.selectTrackHandler); + this.registerInputButton(messageShort, "[Channel1]", "!LoadSelectedTrack", 0x07, 0x01, this.loadTrackHandler); + this.registerInputButton(messageShort, "[Channel2]", "!LoadSelectedTrack", 0x07, 0x08, this.loadTrackHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!MaximizeLibrary", 0x01, 0x08, this.maximizeLibraryHandler); + this.registerInputButton(messageShort, "[Channel2]", "!MaximizeLibrary", 0x04, 0x20, this.maximizeLibraryHandler); + this.registerInputButton(messageShort, "[Channel1]", "!AddTrack", 0x01, 0x04, this.addTrackHandler); + this.registerInputButton(messageShort, "[Channel2]", "!AddTrack", 0x04, 0x10, this.addTrackHandler); + + // Loop control + this.registerInputButton(messageShort, "[Channel1]", "!SelectLoop", 0x0A, 0x0F, this.selectLoopHandler); + this.registerInputButton(messageShort, "[Channel2]", "!SelectLoop", 0x0B, 0xF0, this.selectLoopHandler); + this.registerInputButton(messageShort, "[Channel1]", "!ActivateLoop", 0x07, 0x04, this.activateLoopHandler); + this.registerInputButton(messageShort, "[Channel2]", "!ActivateLoop", 0x07, 0x20, this.activateLoopHandler); + + // Beatjump + this.registerInputButton(messageShort, "[Channel1]", "!SelectBeatjump", 0x09, 0xF0, this.selectBeatjumpHandler); + this.registerInputButton(messageShort, "[Channel2]", "!SelectBeatjump", 0x0B, 0x0F, this.selectBeatjumpHandler); + this.registerInputButton(messageShort, "[Channel1]", "!ActivateBeatjump", 0x07, 0x02, this.activateBeatjumpHandler); + this.registerInputButton(messageShort, "[Channel2]", "!ActivateBeatjump", 0x07, 0x10, this.activateBeatjumpHandler); + + // There is only one button on the controller, we use to toggle quantization for all channels + this.registerInputButton(messageShort, "[ChannelX]", "!quantize", 0x06, 0x40, this.quantizeHandler); + + // Microphone + this.registerInputButton(messageShort, "[Microphone]", "!talkover", 0x06, 0x80, this.microphoneHandler); + + // Jog wheels + this.registerInputButton(messageShort, "[Channel1]", "!jog_touch", 0x08, 0x40, this.jogTouchHandler); + this.registerInputButton(messageShort, "[Channel2]", "!jog_touch", 0x08, 0x80, this.jogTouchHandler); + this.registerInputJog(messageShort, "[Channel1]", "!jog", 0x0C, 0xFFFFFFFF, this.jogHandler); + this.registerInputJog(messageShort, "[Channel2]", "!jog", 0x10, 0xFFFFFFFF, this.jogHandler); + + // FX Buttons + this.registerInputButton(messageShort, "[ChannelX]", "!fx1", 0x03, 0x10, this.fxHandler); + this.registerInputButton(messageShort, "[ChannelX]", "!fx2", 0x03, 0x20, this.fxHandler); + this.registerInputButton(messageShort, "[ChannelX]", "!fx3", 0x03, 0x40, this.fxHandler); + this.registerInputButton(messageShort, "[ChannelX]", "!fx4", 0x03, 0x80, this.fxHandler); + + // Rev / FLUX / GRID + this.registerInputButton(messageShort, "[Channel1]", "!reverse", 0x01, 0x01, this.reverseHandler); + this.registerInputButton(messageShort, "[Channel2]", "!reverse", 0x04, 0x04, this.reverseHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!slip_enabled", 0x01, 0x02, this.fluxHandler); + this.registerInputButton(messageShort, "[Channel2]", "!slip_enabled", 0x04, 0x08, this.fluxHandler); + + this.registerInputButton(messageShort, "[Channel1]", "!grid", 0x01, 0x10, this.beatgridHandler); + this.registerInputButton(messageShort, "[Channel2]", "!grid", 0x04, 0x40, this.beatgridHandler); + + this.controller.registerInputPacket(messageShort); + + this.registerInputScaler(messageLong, "[Channel1]", "rate", 0x01, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Channel2]", "rate", 0x09, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[Channel1]", "volume", 0x03, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Channel2]", "volume", 0x07, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[Channel1]", "pregain", 0x0B, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Channel2]", "pregain", 0x1D, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel1]_Effect1]", "parameter3", 0x0D, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel1]_Effect1]", "parameter2", 0x0F, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel1]_Effect1]", "parameter1", 0x11, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel2]_Effect1]", "parameter3", 0x1F, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel2]_Effect1]", "parameter2", 0x21, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[EqualizerRack1_[Channel2]_Effect1]", "parameter1", 0x23, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[QuickEffectRack1_[Channel1]]", "super1", 0x13, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[QuickEffectRack1_[Channel2]]", "super1", 0x25, 0xFFFF, this.parameterHandler); + + this.registerInputScaler(messageLong, "[Master]", "crossfader", 0x05, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Master]", "gain", 0x15, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Sampler]", "pregain", 0x17, 0xFFFF, this.samplerPregainHandler); + this.registerInputScaler(messageLong, "[Master]", "headMix", 0x19, 0xFFFF, this.parameterHandler); + this.registerInputScaler(messageLong, "[Master]", "headGain", 0x1B, 0xFFFF, this.parameterHandler); + + this.controller.registerInputPacket(messageLong); + + // Soft takeover for all 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("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", true); + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter2", true); + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter1", true); + + engine.softTakeover("[EqualizerRack1_[Channel1]_Effect1]", "parameter3", true); + engine.softTakeover("[EqualizerRack1_[Channel2]_Effect1]", "parameter2", true); + engine.softTakeover("[EqualizerRack1_[Channel3]_Effect1]", "parameter1", true); + + engine.softTakeover("[QuickEffectRack1_[Channel1]]", "super1", true); + engine.softTakeover("[QuickEffectRack1_[Channel2]]", "super1", true); + + engine.softTakeover("[Master]", "crossfader", true); + engine.softTakeover("[Master]", "gain", true); + engine.softTakeover("[Master]", "headMix", true); + engine.softTakeover("[Master]", "headGain", true); + + for (var i = 1; i <= 16; ++i) { + engine.softTakeover("[Sampler" + i + "]", "pregain", true); + } + + // Dirty hack to set initial values in the packet parser + var data = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + TraktorS2MK3.incomingData(data); +}; + +TraktorS2MK3.registerInputJog = function (message, group, name, offset, bitmask, callback) { + // Jog wheels have 4 byte input + message.addControl(group, name, offset, "I", bitmask); + message.setCallback(group, name, callback); +}; + +TraktorS2MK3.registerInputScaler = function (message, group, name, offset, bitmask, callback) { + message.addControl(group, name, offset, "H", bitmask); + message.setCallback(group, name, callback); +}; + +TraktorS2MK3.registerInputButton = function (message, group, name, offset, bitmask, callback) { + message.addControl(group, name, offset, "B", bitmask); + message.setCallback(group, name, callback); +}; + +TraktorS2MK3.playHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "start_stop", field.value); + } else if (field.value === 1) { + script.toggleControl(field.group, "play"); + } +}; + +TraktorS2MK3.cueHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "cue_gotoandstop", field.value); + } else { + engine.setValue(field.group, "cue_default", field.value); + } +}; + +TraktorS2MK3.shiftHandler = function (field) { + TraktorS2MK3.shiftPressed[field.group] = field.value; + engine.setValue("[Controls]", "touch_shift", field.value); + TraktorS2MK3.outputHandler(field.value, field.group, "shift"); +}; + +TraktorS2MK3.keylockHandler = function (field) { + if (field.value === 0) { + return; + } + + script.toggleControl(field.group, "keylock"); +}; + +TraktorS2MK3.syncHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "beatsync_phase", field.value); + // Light LED while pressed + TraktorS2MK3.outputHandler(field.value, field.group, "sync_enabled"); + } else { + if (field.value) { + if (engine.getValue(field.group, 'sync_enabled') === 0) { + script.triggerControl(field.group, "beatsync"); + // Start timer to measure how long button is pressed + TraktorS2MK3.syncPressedTimer[field.group] = engine.beginTimer(300, function () { + engine.setValue(field.group, "sync_enabled", 1); + // Reset sync button timer state if active + if (TraktorS2MK3.syncPressedTimer[field.group] !== 0) { + TraktorS2MK3.syncPressedTimer[field.group] = 0; + } + }, true); + + // Light corresponding LED when button is pressed + TraktorS2MK3.outputHandler(1, field.group, "sync_enabled"); + } else { + // Deactivate sync lock + // LED is turned off by the callback handler for sync_enabled + engine.setValue(field.group, "sync_enabled", 0); + } + } else { + if (TraktorS2MK3.syncPressedTimer[field.group] !== 0) { + // Timer still running -> stop it and unlight LED + engine.stopTimer(TraktorS2MK3.syncPressedTimer[field.group]); + TraktorS2MK3.outputHandler(0, field.group, "sync_enabled"); + } + } + } +}; + +TraktorS2MK3.padModeHandler = function (field) { + if (field.value === 0) { + return; + } + + if (TraktorS2MK3.padModeState[field.group] === 0 && field.name === "!samples") { + // If we are in hotcues mode and samples mode is activated + engine.setValue("[Samplers]", "show_samplers", 1); + TraktorS2MK3.padModeState[field.group] = 1; + TraktorS2MK3.outputHandler(0, field.group, "hotcues"); + TraktorS2MK3.outputHandler(1, field.group, "samples"); + + // Light LEDs for all slots with loaded samplers + for (var key in TraktorS2MK3.samplerHotcuesRelation[field.group]) { + if (TraktorS2MK3.samplerHotcuesRelation[field.group].hasOwnProperty(key)) { + var loaded = engine.getValue("[Sampler" + TraktorS2MK3.samplerHotcuesRelation[field.group][key] + "]", "track_loaded"); + TraktorS2MK3.outputHandler(loaded, field.group, "pad_" + key); + } + } + } else if (field.name === "!hotcues") { + // If we are in samples mode and hotcues mode is activated + TraktorS2MK3.padModeState[field.group] = 0; + TraktorS2MK3.outputHandler(1, field.group, "hotcues"); + TraktorS2MK3.outputHandler(0, field.group, "samples"); + + // Light LEDs for all enabled hotcues + for (var i = 1; i <= 8; ++i) { + var active = engine.getValue(field.group, "hotcue_" + i + "_enabled"); + TraktorS2MK3.outputHandler(active, field.group, "pad_" + i); + } + } +}; + +TraktorS2MK3.numberButtonHandler = function (field) { + var padNumber = parseInt(field.id[field.id.length - 1]); + if (TraktorS2MK3.padModeState[field.group] === 0) { + // Hotcues mode + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "hotcue_" + padNumber + "_clear", field.value); + } else { + engine.setValue(field.group, "hotcue_" + padNumber + "_activate", field.value); + } + } else { + // Samples mode + var sampler = TraktorS2MK3.samplerHotcuesRelation[field.group][padNumber]; + if (TraktorS2MK3.shiftPressed[field.group]) { + var playing = engine.getValue("[Sampler" + sampler + "]", "play"); + if (playing) { + engine.setValue("[Sampler" + sampler + "]", "cue_default", field.value); + } else { + engine.setValue("[Sampler" + sampler + "]", "eject", field.value); + } + } else { + var loaded = engine.getValue("[Sampler" + sampler + "]", "track_loaded"); + if (loaded) { + engine.setValue("[Sampler" + sampler + "]", "cue_gotoandplay", field.value); + } else { + engine.setValue("[Sampler" + sampler + "]", "LoadSelectedTrack", field.value); + } + } + } +}; + +TraktorS2MK3.headphoneHandler = function (field) { + if (field.value === 0) { + return; + } + + script.toggleControl(field.group, "pfl"); +}; + +TraktorS2MK3.selectTrackHandler = function (field) { + var delta = 1; + if ((field.value + 1) % 16 === TraktorS2MK3.browseKnobEncoderState[field.group]) { + delta = -1; + } + + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue("[Library]", "MoveHorizontal", delta); + } else { + engine.setValue("[Library]", "MoveVertical", delta); + } + + TraktorS2MK3.browseKnobEncoderState[field.group] = field.value; +}; + +TraktorS2MK3.loadTrackHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "eject", field.value); + } else { + engine.setValue(field.group, "LoadSelectedTrack", field.value); + } +}; + +TraktorS2MK3.addTrackHandler = function (field) { + TraktorS2MK3.outputHandler(field.value, field.group, "addTrack"); + + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue("[Library]", "AutoDjAddTop", field.value); + } else { + engine.setValue("[Library]", "AutoDjAddBottom", field.value); + } +}; + +TraktorS2MK3.maximizeLibraryHandler = function (field) { + if (field.value === 0) { + return; + } + + script.toggleControl("[Master]", "maximize_library"); +}; + +TraktorS2MK3.selectLoopHandler = function (field) { + if ((field.value + 1) % 16 === TraktorS2MK3.loopKnobEncoderState[field.group]) { + script.triggerControl(field.group, "loop_halve"); + } else { + script.triggerControl(field.group, "loop_double"); + } + + TraktorS2MK3.loopKnobEncoderState[field.group] = field.value; +}; + +TraktorS2MK3.activateLoopHandler = function (field) { + if (field.value === 0) { + return; + } + + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "reloop_toggle", field.value); + } else { + engine.setValue(field.group, "beatloop_activate", field.value); + } +}; + +TraktorS2MK3.selectBeatjumpHandler = function (field) { + var delta = 1; + if ((field.value + 1) % 16 === TraktorS2MK3.moveKnobEncoderState[field.group]) { + delta = -1; + } + + if (TraktorS2MK3.shiftPressed[field.group]) { + var beatjump_size = engine.getValue(field.group, "beatjump_size"); + if (delta > 0) { + engine.setValue(field.group, "beatjump_size", beatjump_size * 2); + } else { + engine.setValue(field.group, "beatjump_size", beatjump_size / 2); + } + } else { + if (delta < 0) { + script.triggerControl(field.group, "beatjump_backward"); + } else { + script.triggerControl(field.group, "beatjump_forward"); + } + } + + TraktorS2MK3.moveKnobEncoderState[field.group] = field.value; +}; + +TraktorS2MK3.activateBeatjumpHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "reloop_andstop", field.value); + } else { + engine.setValue(field.group, "beatlooproll_activate", field.value); + } +}; + +TraktorS2MK3.quantizeHandler = function (field) { + if (field.value === 0) { + return; + } + + var res = !(engine.getValue("[Channel1]", "quantize") && engine.getValue("[Channel2]", "quantize")); + engine.setValue("[Channel1]", "quantize", res); + engine.setValue("[Channel2]", "quantize", res); + TraktorS2MK3.outputHandler(res, field.group, "quantize"); +}; + +TraktorS2MK3.microphoneHandler = function (field) { + if (field.value) { + if (TraktorS2MK3.microphonePressedTimer === 0) { + // Start timer to measure how long button is pressed + TraktorS2MK3.microphonePressedTimer = engine.beginTimer(300, function () { + // Reset microphone button timer status if active + if (TraktorS2MK3.microphonePressedTimer !== 0) { + TraktorS2MK3.microphonePressedTimer = 0; + } + }, true); + } + + script.toggleControl("[Microphone]", "talkover"); + } else { + // Button is released, check if timer is still running + if (TraktorS2MK3.microphonePressedTimer !== 0) { + // short klick -> permanent activation + TraktorS2MK3.microphonePressedTimer = 0; + } else { + engine.setValue("[Microphone]", "talkover", 0); + } + } +}; + +TraktorS2MK3.parameterHandler = function (field) { + engine.setParameter(field.group, field.name, field.value / 4095); +}; + +TraktorS2MK3.samplerPregainHandler = function (field) { + // Map sampler gain knob of all sampler together. + // Dirty hack, but the best we can do for now. + for (var i = 1; i <= 16; ++i) { + engine.setParameter("[Sampler" + i + "]", field.name, field.value / 4095); + } +}; + +TraktorS2MK3.jogTouchHandler = function (field) { + var deckNumber = TraktorS2MK3.controller.resolveDeck(field.group); + if (field.value > 0) { + engine.scratchEnable(deckNumber, 1024, 33 + 1 / 3, 0.125, 0.125 / 8, true); + } else { + engine.scratchDisable(deckNumber); + } +}; + +TraktorS2MK3.jogHandler = function (field) { + var deckNumber = TraktorS2MK3.controller.resolveDeck(field.group); + + // Jog wheel control is based on the S4MK2 mapping, might need some more review + if (engine.isScratching(deckNumber)) { + var deltas = TraktorS2MK3.wheelDeltas(field.group, field.value); + var tickDelta = deltas[0]; + var timeDelta = deltas[1]; + + var velocity = (tickDelta / timeDelta) / 3; + engine.setValue(field.group, "jog", velocity); + if (engine.getValue(field.group, "scratch2_enable")) { + engine.scratchTick(deckNumber, tickDelta); + } + } +}; + +TraktorS2MK3.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 timeval = value >>> 16; + var prevTick = 0; + var prevTime = 0; + + if (group[8] === "1" || group[8] === "3") { + prevTick = this.lastTickVal[0]; + prevTime = this.lastTickTime[0]; + this.lastTickVal[0] = tickval; + this.lastTickTime[0] = timeval; + } else { + prevTick = this.lastTickVal[1]; + prevTime = this.lastTickTime[1]; + this.lastTickVal[1] = tickval; + this.lastTickTime[1] = timeval; + } + + if (prevTime > timeval) { + // We looped around. Adjust current time so that subtraction works. + timeval += 0x10000; + } + var timeDelta = timeval - prevTime; + if (timeDelta === 0) { + // Spinning too fast to detect speed! By not dividing we are guessing it took 1ms. + timeDelta = 1; + } + + var tickDelta = 0; + if (prevTick >= 200 && tickval <= 100) { + tickDelta = tickval + 256 - prevTick; + } else if (prevTick <= 100 && tickval >= 200) { + tickDelta = tickval - prevTick - 256; + } else { + tickDelta = tickval - prevTick; + } + + return [tickDelta, timeDelta]; +}; + +TraktorS2MK3.fxHandler = function (field) { + if (field.value === 0) { + return; + } + + var fxNumber = parseInt(field.id[field.id.length - 1]); + var group = "[EffectRack1_EffectUnit" + fxNumber + "]"; + + // Toggle effect unit + TraktorS2MK3.fxButtonState[fxNumber] = !TraktorS2MK3.fxButtonState[fxNumber]; + + engine.setValue(group, "group_[Channel1]_enable", TraktorS2MK3.fxButtonState[fxNumber]); + engine.setValue(group, "group_[Channel2]_enable", TraktorS2MK3.fxButtonState[fxNumber]); + TraktorS2MK3.outputHandler(TraktorS2MK3.fxButtonState[fxNumber], field.group, "fxButton" + fxNumber); +}; + +TraktorS2MK3.reverseHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "reverseroll", field.value); + } else { + engine.setValue(field.group, "reverse", field.value); + } + + TraktorS2MK3.outputHandler(field.value, field.group, "reverse"); +}; + +TraktorS2MK3.fluxHandler = function (field) { + if (field.value === 0) { + return; + } + + script.toggleControl(field.group, "slip_enabled"); +}; + +TraktorS2MK3.beatgridHandler = function (field) { + if (TraktorS2MK3.shiftPressed[field.group]) { + engine.setValue(field.group, "beats_translate_match_alignment", field.value); + } else { + engine.setValue(field.group, "beats_translate_curpos", field.value); + } + + TraktorS2MK3.outputHandler(field.value, field.group, "grid"); +}; + +TraktorS2MK3.registerOutputPackets = function () { + var output = new HIDPacket("output", 0x80); + + output.addOutput("[Channel1]", "play_indicator", 0x0C, "B"); + output.addOutput("[Channel2]", "play_indicator", 0x33, "B"); + + output.addOutput("[Channel1]", "cue_indicator", 0x0B, "B"); + output.addOutput("[Channel2]", "cue_indicator", 0x32, "B"); + + output.addOutput("[Channel1]", "shift", 0x06, "B"); + output.addOutput("[Channel2]", "shift", 0x2D, "B"); + + output.addOutput("[Channel1]", "hotcues", 0x07, "B"); + output.addOutput("[Channel2]", "hotcues", 0x2E, "B"); + + output.addOutput("[Channel1]", "samples", 0x08, "B"); + output.addOutput("[Channel2]", "samples", 0x2F, "B"); + + output.addOutput("[Channel1]", "sync_enabled", 0x09, "B"); + output.addOutput("[Channel2]", "sync_enabled", 0x30, "B"); + + output.addOutput("[Channel1]", "keylock", 0x0A, "B"); + output.addOutput("[Channel2]", "keylock", 0x31, "B"); + + output.addOutput("[Channel1]", "pad_1", 0x0D, "B"); + output.addOutput("[Channel1]", "pad_2", 0x0E, "B"); + output.addOutput("[Channel1]", "pad_3", 0x0F, "B"); + output.addOutput("[Channel1]", "pad_4", 0x10, "B"); + output.addOutput("[Channel1]", "pad_5", 0x11, "B"); + output.addOutput("[Channel1]", "pad_6", 0x12, "B"); + output.addOutput("[Channel1]", "pad_7", 0x13, "B"); + output.addOutput("[Channel1]", "pad_8", 0x14, "B"); + + output.addOutput("[Channel2]", "pad_1", 0x34, "B"); + output.addOutput("[Channel2]", "pad_2", 0x35, "B"); + output.addOutput("[Channel2]", "pad_3", 0x36, "B"); + output.addOutput("[Channel2]", "pad_4", 0x37, "B"); + output.addOutput("[Channel2]", "pad_5", 0x38, "B"); + output.addOutput("[Channel2]", "pad_6", 0x39, "B"); + output.addOutput("[Channel2]", "pad_7", 0x3A, "B"); + output.addOutput("[Channel2]", "pad_8", 0x3B, "B"); + + output.addOutput("[Channel1]", "pfl", 0x1A, "B"); + output.addOutput("[Channel2]", "pfl", 0x1B, "B"); + + output.addOutput("[Channel1]", "vu-18", 0x1C, "B"); + output.addOutput("[Channel1]", "vu-12", 0x1D, "B"); + output.addOutput("[Channel1]", "vu-6", 0x1E, "B"); + output.addOutput("[Channel1]", "vu0", 0x1F, "B"); + output.addOutput("[Channel1]", "vu6", 0x20, "B"); + output.addOutput("[Channel1]", "PeakIndicator", 0x21, "B"); + + output.addOutput("[Channel2]", "vu-18", 0x22, "B"); + output.addOutput("[Channel2]", "vu-12", 0x23, "B"); + output.addOutput("[Channel2]", "vu-6", 0x24, "B"); + output.addOutput("[Channel2]", "vu0", 0x25, "B"); + output.addOutput("[Channel2]", "vu6", 0x26, "B"); + output.addOutput("[Channel2]", "PeakIndicator", 0x27, "B"); + + output.addOutput("[ChannelX]", "fxButton1", 0x16, "B"); + output.addOutput("[ChannelX]", "fxButton2", 0x17, "B"); + output.addOutput("[ChannelX]", "fxButton3", 0x18, "B"); + output.addOutput("[ChannelX]", "fxButton4", 0x19, "B"); + + output.addOutput("[Channel1]", "reverse", 0x01, "B"); + output.addOutput("[Channel2]", "reverse", 0x28, "B"); + + output.addOutput("[Channel1]", "slip_enabled", 0x02, "B"); + output.addOutput("[Channel2]", "slip_enabled", 0x29, "B"); + + output.addOutput("[Channel1]", "addTrack", 0x03, "B"); + output.addOutput("[Channel2]", "addTrack", 0x2A, "B"); + + output.addOutput("[Channel1]", "grid", 0x05, "B"); + output.addOutput("[Channel2]", "grid", 0x2C, "B"); + + output.addOutput("[Channel1]", "MaximizeLibrary", 0x04, "B"); + output.addOutput("[Channel2]", "MaximizeLibrary", 0x2B, "B"); + + output.addOutput("[ChannelX]", "quantize", 0x3C, "B"); + output.addOutput("[Microphone]", "talkover", 0x3D, "B"); + + this.controller.registerOutputPacket(output); + + this.linkOutput("[Channel1]", "play_indicator", this.outputHandler); + this.linkOutput("[Channel2]", "play_indicator", this.outputHandler); + + this.linkOutput("[Channel1]", "cue_indicator", this.outputHandler); + this.linkOutput("[Channel2]", "cue_indicator", this.outputHandler); + + this.linkOutput("[Channel1]", "sync_enabled", this.outputHandler); + this.linkOutput("[Channel2]", "sync_enabled", this.outputHandler); + + this.linkOutput("[Channel1]", "keylock", this.outputHandler); + this.linkOutput("[Channel2]", "keylock", this.outputHandler); + + for (var i = 1; i <= 8; ++i) { + TraktorS2MK3.controller.linkOutput("[Channel1]", "pad_" + i, "[Channel1]", "hotcue_" + i + "_enabled", this.hotcueOutputHandler); + TraktorS2MK3.controller.linkOutput("[Channel2]", "pad_" + i, "[Channel2]", "hotcue_" + i + "_enabled", this.hotcueOutputHandler); + } + + this.linkOutput("[Channel1]", "pfl", this.outputHandler); + this.linkOutput("[Channel2]", "pfl", this.outputHandler); + + this.linkOutput("[Channel1]", "slip_enabled", this.outputHandler); + this.linkOutput("[Channel2]", "slip_enabled", this.outputHandler); + + this.linkOutput("[Microphone]", "talkover", this.outputHandler); + + // VuMeter + this.vuLeftConnection = engine.makeConnection("[Channel1]", "VuMeter", this.vuMeterHandler); + this.vuRightConnection = engine.makeConnection("[Channel2]", "VuMeter", this.vuMeterHandler); + this.clipLeftConnection = engine.makeConnection("[Channel1]", "PeakIndicator", this.peakOutputHandler); + this.clipRightConnection = engine.makeConnection("[Channel2]", "PeakIndicator", this.peakOutputHandler); + + // Sampler callbacks + for (i = 1; i <= 16; ++i) { + this.samplerCallbacks.push(engine.makeConnection("[Sampler" + i + "]", "track_loaded", this.samplesOutputHandler)); + this.samplerCallbacks.push(engine.makeConnection("[Sampler" + i + "]", "play", this.samplesOutputHandler)); + } + + TraktorS2MK3.lightDeck(false); +}; + +/* Helper function to link output in a short form */ +TraktorS2MK3.linkOutput = function (group, name, callback) { + TraktorS2MK3.controller.linkOutput(group, name, group, name, callback); +}; + +TraktorS2MK3.vuMeterHandler = function (value, group, key) { + var vuKeys = Object.keys(TraktorS2MK3.vuMeterThresholds); + for (var i = 0; i < vuKeys.length; ++i) { + // Avoid spamming HID by only sending last LED update + var last = (i === (vuKeys.length - 1)); + if (TraktorS2MK3.vuMeterThresholds[vuKeys[i]] > value) { + TraktorS2MK3.controller.setOutput(group, vuKeys[i], 0x00, last); + } else { + TraktorS2MK3.controller.setOutput(group, vuKeys[i], 0x7E, last); + } + } +}; + +TraktorS2MK3.peakOutputHandler = function (value, group, key) { + var ledValue = 0x00; + if (value) { + ledValue = 0x7E; + } + + TraktorS2MK3.controller.setOutput(group, key, ledValue, true); +}; + +TraktorS2MK3.outputHandler = function (value, group, key) { + // Custom value for multi-colored LEDs + var ledValue = value; + if (value === 0 || value === false) { + // Off value + ledValue = 0x7C; + } else if (value === 1 || value === true) { + // On value + ledValue = 0x7E; + } + + TraktorS2MK3.controller.setOutput(group, key, ledValue, true); +}; + +TraktorS2MK3.hotcueOutputHandler = function (value, group, key) { + // Light button LED only when we are in hotcue mode + if (TraktorS2MK3.padModeState[group] === 0) { + TraktorS2MK3.outputHandler(value, group, key); + } +}; + +TraktorS2MK3.samplesOutputHandler = function (value, group, key) { + // Sampler 1-4, 9-12 -> Channel1 + // Samples 5-8, 13-16 -> Channel2 + var sampler = TraktorS2MK3.resolveSampler(group); + var deck = "[Channel1]"; + var num = sampler; + if (sampler === undefined) { + return; + } else if (sampler > 4 && sampler < 9) { + deck = "[Channel2]"; + num = sampler - 4; + } else if (sampler > 8 && sampler < 13) { + num = sampler - 4; + } else if (sampler > 12 && sampler < 17) { + deck = "[Channel2]"; + num = sampler - 8; + } + + // If we are in samples modes light corresponding LED + if (TraktorS2MK3.padModeState[deck] === 1) { + if (key === "play" && engine.getValue(group, "track_loaded")) { + if (value) { + // Green light on play + TraktorS2MK3.outputHandler(0x9E, deck, "pad_" + num); + } else { + // Reset LED to full white light + TraktorS2MK3.outputHandler(1, deck, "pad_" + num); + } + } else if (key === "track_loaded") { + TraktorS2MK3.outputHandler(value, deck, "pad_" + num); + } + } +}; + +TraktorS2MK3.resolveSampler = function (group) { + if (group === undefined) { + return undefined; + } + + var result = group.match(script.samplerRegEx); + + if (result === null) { + return undefined; + } + + // Return sample number + return result[1]; +}; + +TraktorS2MK3.lightDeck = function (switchOff) { + var softLight = 0x7C; + var fullLight = 0x7E; + if (switchOff) { + softLight = 0x00; + fullLight = 0x00; + } + + var current = (!!engine.getValue("[Channel1]", "play_indicator") ? fullLight : softLight); + TraktorS2MK3.controller.setOutput("[Channel1]", "play_indicator", current, false); + current = (!!engine.getValue("[Channel2]", "play_indicator")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "play_indicator", current, false); + + current = (!!engine.getValue("[Channel1]", "cue_indicator")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "cue_indicator", current, false); + current = (!!engine.getValue("[Channel2]", "cue_indicator")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "cue_indicator", current, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "shift", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "shift", softLight, false); + + current = (!!engine.getValue("[Channel1]", "sync_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "sync_enabled", current, false); + current = (!!engine.getValue("[Channel1]", "sync_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "sync_enabled", current, false); + + // Hotcues mode is default start value + TraktorS2MK3.controller.setOutput("[Channel1]", "hotcues", fullLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "hotcues", fullLight, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "samples", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "samples", softLight, false); + + current = (!!engine.getValue("[Channel1]", "keylock")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "keylock", current, false); + current = (!!engine.getValue("[Channel2]", "keylock")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "keylock", current, false); + + for (var i = 1; i <= 8; ++i) { + current = (!!engine.getValue("[Channel1]", "hotcue_" + i + "_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "pad_" + i, current, false); + current = (!!engine.getValue("[Channel2]", "hotcue_" + i + "_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "pad_" + i, current, false); + } + + current = (!!engine.getValue("[Channel1]", "pfl")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "pfl", current, false); + current = (!!engine.getValue("[Channel2]", "pfl")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "pfl", current, false); + + TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton1", softLight, false); + TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton2", softLight, false); + TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton3", softLight, false); + TraktorS2MK3.controller.setOutput("[ChannelX]", "fxButton4", softLight, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "reverse", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "reverse", softLight, false); + + current = (!!engine.getValue("[Channel1]", "slip_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel1]", "slip_enabled", current, false); + current = (!!engine.getValue("[Channel2]", "slip_enabled")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Channel2]", "slip_enabled", current, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "addTrack", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "addTrack", softLight, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "grid", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "grid", softLight, false); + + TraktorS2MK3.controller.setOutput("[Channel1]", "MaximizeLibrary", softLight, false); + TraktorS2MK3.controller.setOutput("[Channel2]", "MaximizeLibrary", softLight, false); + + TraktorS2MK3.controller.setOutput("[ChannelX]", "quantize", softLight, false); + + // For the last output we should send the packet finally + current = (!!engine.getValue("[Microphone]", "talkover")) ? fullLight : softLight; + TraktorS2MK3.controller.setOutput("[Microphone]", "talkover", current, true); +}; + +TraktorS2MK3.messageCallback = function (packet, data) { + for (var name in data) { + if (data.hasOwnProperty(name)) { + TraktorS2MK3.controller.processButton(data[name]); + } + } +}; + +TraktorS2MK3.shutdown = function () { + // Deactivate all LEDs + TraktorS2MK3.lightDeck(true); + + HIDDebug("TraktorS2MK3: Shutdown done!"); +}; + +TraktorS2MK3.incomingData = function (data, length) { + TraktorS2MK3.controller.parsePacket(data, length); +}; diff --git a/res/skins/LateNight/aux_unit.xml b/res/skins/LateNight/aux_unit.xml index cacc5a53fa1f..fbf09ecbeb15 100644 --- a/res/skins/LateNight/aux_unit.xml +++ b/res/skins/LateNight/aux_unit.xml @@ -1,195 +1,180 @@