diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ee828fa3300..cb0f400ccc1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,11 +36,8 @@ jobs: artifacts_path: build/*.deb artifacts_slug: ubuntu-jammy qt_qpa_platform: offscreen - - name: Arch Linux (Qt 6.3, gcc) + - name: Ubuntu 22.04 (Qt 6.2, gcc) os: ubuntu-22.04 - # The Dockerfile for this container can be found at: - # https://github.com/Holzhaus/mixxx-ci-docker - container: holzhaus/mixxx-ci:20220612-qt6 cmake_args: >- -DWARNINGS_FATAL=ON -DQT6=ON @@ -54,6 +51,12 @@ jobs: ctest_args: [] compiler_cache: ccache compiler_cache_path: ~/.ccache + cpack_generator: DEB + buildenv_basepath: /home/runner/buildenv + buildenv_script: tools/debian_buildenv_qt6.sh + artifacts_name: Ubuntu 22.04 Qt6 DEB + artifacts_path: build/*.deb + artifacts_slug: ubuntu-jammy qt_qpa_platform: offscreen - name: macOS 11 os: macos-11 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c459495d97e..2df5363e8e5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -118,10 +118,11 @@ repos: hooks: - id: prettier types: [yaml] - - repo: https://github.com/qarmin/qml_formatter.git - rev: 0.2.0 - hooks: - - id: qml_formatter + # disabled until https://github.com/mixxxdj/mixxx/issues/11386 is fixed + #- repo: https://github.com/qarmin/qml_formatter.git + # rev: 0.2.0 + # hooks: + # - id: qml_formatter - repo: local hooks: - id: qsscheck diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f2bd7eb31..535aa258d5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -205,7 +205,7 @@ * Fix an issue when pressing multiple cue buttons at the same time [#3382](https://github.com/mixxxdj/mixxx/pull/3382) * Fix synchronization of main cue point/position [#4137](https://github.com/mixxxdj/mixxx/pull/4137) - [lp1937074](https://github.com/mixxxdj/mixxx/issues/10478) + [#10478](https://github.com/mixxxdj/mixxx/issues/10478) [#4153](https://github.com/mixxxdj/mixxx/pull/4153) * Add halve/double controls for beatjump size [#4269](https://github.com/mixxxdj/mixxx/pull/4269) * Fix possible segfault when ejecting track [#4362](https://github.com/mixxxdj/mixxx/pull/4362) [#10497](https://github.com/mixxxdj/mixxx/issues/10497) @@ -476,7 +476,7 @@ [#4704](https://github.com/mixxxdj/mixxx/pull/4704) [#4748](https://github.com/mixxxdj/mixxx/pull/4748) [#4833](https://github.com/mixxxdj/mixxx/pull/4833) [#10762](https://github.com/mixxxdj/mixxx/issues/10762) - [#4884](https://github.com/mixxxdj/mixxx/pull/4884) [#10802](https://github.com/mixxxdj/mixxx/issues/10802) [lp1983764](https://github.com/mixxxdj/mixxx/issues/10801) + [#4884](https://github.com/mixxxdj/mixxx/pull/4884) [#10802](https://github.com/mixxxdj/mixxx/issues/10802) [#10801](https://github.com/mixxxdj/mixxx/issues/10801) [#4899](https://github.com/mixxxdj/mixxx/pull/4899) [#8817](https://github.com/mixxxdj/mixxx/pull/8817) [#10868](https://github.com/mixxxdj/mixxx/pull/10868) @@ -904,7 +904,7 @@ ### Controller Fixes * Traktor S3: Fix issues with sampler and hotcue buttons [#4676](https://github.com/mixxxdj/mixxx/pull/4676) -* Numark DJ2GO2: Fix sliders and knobs [#4835](https://github.com/mixxxdj/mixxx/pull/4835) [lp:1948596](https://bugs.launchpad.net/mixxx/+bug/1948596) +* Numark DJ2GO2: Fix sliders and knobs [#4835](https://github.com/mixxxdj/mixxx/pull/4835) [#10586](https://github.com/mixxxdj/mixxx/issues/10586) * Numark DJ2Go2: Support HotCue clear with pad [#10841](https://github.com/mixxxdj/mixxx/pull/10841) * Numark DJ2Go2: Fix inverted tempo fader [#10852](https://github.com/mixxxdj/mixxx/pull/10852) [#10586](https://github.com/mixxxdj/mixxx/issues/10586) * Numark N4: Inverted pitch slider, to match the GUI orientation [#11057](https://github.com/mixxxdj/mixxx/pull/11046) @@ -954,7 +954,7 @@ * Playlist: Enable sorting by color [#4352](https://github.com/mixxxdj/mixxx/pull/4352) [#10546](https://github.com/mixxxdj/mixxx/issues/10546) * Fix crash when using Doubling/Halving/etc. BPM from track's Properties window on tracks without BPM [#4587](https://github.com/mixxxdj/mixxx/pull/4587) [#10625](https://github.com/mixxxdj/mixxx/issues/10625) * Fix writing metadata on Windows for files that have never been played [#4586](https://github.com/mixxxdj/mixxx/pull/4586) [#10620](https://github.com/mixxxdj/mixxx/issues/10620) -* Preserve file creation time when writing metadata on Windows [#4586](https://github.com/mixxxdj/mixxx/pull/4586) [lp1955314](https://github.com/mixxxdj/mixxx/issues/10619) +* Preserve file creation time when writing metadata on Windows [#4586](https://github.com/mixxxdj/mixxx/pull/4586) [#10619](https://github.com/mixxxdj/mixxx/issues/10619) * Fix handling of file extension when importing and exporting sampler settings [#4539](https://github.com/mixxxdj/mixxx/pull/4539) * Fix crash when using an empty directory as resource path using the `--resource-path` command line option [#4575](https://github.com/mixxxdj/mixxx/pull/4575) [#10461](https://github.com/mixxxdj/mixxx/issues/10461) * Pioneer DDJ-SB3: Add controller mapping [#3821](https://github.com/mixxxdj/mixxx/pull/3821) @@ -983,14 +983,14 @@ * Denon MC7000: Improve slip mode and jog wheel handling [#4021](https://github.com/mixxxdj/mixxx/pull/4021) [#4324](https://github.com/mixxxdj/mixxx/pull/4324) * Disabled detection of keyboards and mice as HID controllers [#4243](https://github.com/mixxxdj/mixxx/pull/4243) * Disabled detection of all HID controllers with Apple's vendor ID. Apple doesn't build actual controllers. [#4260](https://github.com/mixxxdj/mixxx/pull/4260) [#4273](https://github.com/mixxxdj/mixxx/pull/4273) -* Add support for HiDPI scale factors of 125% and 175% (only with Qt 5.14+) [lp1938102](https://github.com/mixxxdj/mixxx/issues/10485) [#4161](https://github.com/mixxxdj/mixxx/pull/4161) -* Fix unhandled exception when parsing corrupt Rekordbox PDB files [lp1933853](https://github.com/mixxxdj/mixxx/issues/10452) [#4040](https://github.com/mixxxdj/mixxx/pull/4040) +* Add support for HiDPI scale factors of 125% and 175% (only with Qt 5.14+) [#10485](https://github.com/mixxxdj/mixxx/issues/10485) [#4161](https://github.com/mixxxdj/mixxx/pull/4161) +* Fix unhandled exception when parsing corrupt Rekordbox PDB files [#10452](https://github.com/mixxxdj/mixxx/issues/10452) [#4040](https://github.com/mixxxdj/mixxx/pull/4040) * Fix Echo effect adding left channel samples to right channel [#4141](https://github.com/mixxxdj/mixxx/pull/4141) -* Fix bad phase seek when starting from preroll [lp1930143](https://github.com/mixxxdj/mixxx/issues/10423) [#4093](https://github.com/mixxxdj/mixxx/pull/4093) +* Fix bad phase seek when starting from preroll [#10423](https://github.com/mixxxdj/mixxx/issues/10423) [#4093](https://github.com/mixxxdj/mixxx/pull/4093) * Fix bad phase seek when a channel's audible status changes [#4156](https://github.com/mixxxdj/mixxx/pull/4156) * Tango skin: Show crossfader assign buttons by default [#4046](https://github.com/mixxxdj/mixxx/pull/4046) * Fix keyfinder library in arm64 builds [#4047](https://github.com/mixxxdj/mixxx/pull/4047) -* Fix wrong track being recorded in History [lp1933991](https://github.com/mixxxdj/mixxx/issues/10454) [#4041](https://github.com/mixxxdj/mixxx/pull/4041) [#4059](https://github.com/mixxxdj/mixxx/pull/4059) [#4107](https://github.com/mixxxdj/mixxx/pull/4107) [#4296](https://github.com/mixxxdj/mixxx/pull/4296) +* Fix wrong track being recorded in History [#10454](https://github.com/mixxxdj/mixxx/issues/10454) [#4041](https://github.com/mixxxdj/mixxx/pull/4041) [#4059](https://github.com/mixxxdj/mixxx/pull/4059) [#4107](https://github.com/mixxxdj/mixxx/pull/4107) [#4296](https://github.com/mixxxdj/mixxx/pull/4296) * Fix support for relative paths in the skin system which caused missing images in third-party skins [#4151](https://github.com/mixxxdj/mixxx/pull/4151) * Fix relocation of directories with special/reserved characters in path name [#4146](https://github.com/mixxxdj/mixxx/pull/4146) * Update keyboard shortcuts sheet [#4042](https://github.com/mixxxdj/mixxx/pull/4042) @@ -1006,8 +1006,8 @@ * Library sidebar: Also activate items on PageUp/Down events. [#4237](https://github.com/mixxxdj/mixxx/pull/4237) * Fix handling of preview button cell events in developer mode. [#4264](https://github.com/mixxxdj/mixxx/pull/4264) [#10418](https://github.com/mixxxdj/mixxx/issues/10418) * Auto DJ: Fix bug which could make an empty track stop Auto DJ. [#4267](https://github.com/mixxxdj/mixxx/pull/4267) [#10504](https://github.com/mixxxdj/mixxx/issues/10504) -* Fix Auto DJ skipping tracks randomly [#4319](https://github.com/mixxxdj/mixxx/pull/4319) [lp1941989](https://github.com/mixxxdj/mixxx/issues/10505) -* Fix high CPU load due to extremely high internal sync clock values [#4312](https://github.com/mixxxdj/mixxx/pull/4312) [lp1943320](https://github.com/mixxxdj/mixxx/issues/10520) +* Fix Auto DJ skipping tracks randomly [#4319](https://github.com/mixxxdj/mixxx/pull/4319) [#10505](https://github.com/mixxxdj/mixxx/issues/10505) +* Fix high CPU load due to extremely high internal sync clock values [#4312](https://github.com/mixxxdj/mixxx/pull/4312) [#10520](https://github.com/mixxxdj/mixxx/issues/10520) * Fix preference option for re-analyzing beatgrids imported from other software [#4288](https://github.com/mixxxdj/mixxx/pull/4288) * Fix wrong base tag used for deployment and displayed in About dialog [#4070](https://github.com/mixxxdj/mixxx/pull/4070) @@ -1138,7 +1138,7 @@ * Update controller mapping for Allen & Heath Xone K2 to add intro/outro cues [#2236](https://github.com/mixxxdj/mixxx/pull/2236) * Update controller mapping for Hercules P32 for more accurate headmix control [#3537](https://github.com/mixxxdj/mixxx/pull/3537) * Update controller mapping for Native Instruments Traktor Kontrol S4MK2 to add auto-slip mode and pitch fader range [#3331](https://github.com/mixxxdj/mixxx/pull/3331) -* Fix Pioneer DDJ-SB2 controller mapping auto tempo going to infinity bug [#2559](https://github.com/mixxxdj/mixxx/pull/2559) [lp:1846403](https://bugs.launchpad.net/mixxx/+bug/1846403) +* Fix Pioneer DDJ-SB2 controller mapping auto tempo going to infinity bug [#2559](https://github.com/mixxxdj/mixxx/pull/2559) [#9838](https://github.com/mixxxdj/mixxx/issues/9838) * Fix Numark Mixtrack Pro 3 controller mapping inverted FX on/off control [#3758](https://github.com/mixxxdj/mixxx/pull/3758) * Gracefully handle MIDI overflow [#825](https://github.com/mixxxdj/mixxx/pull/825) diff --git a/CMakeLists.txt b/CMakeLists.txt index 82cac2a0c6b..798587fe8b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2767,9 +2767,9 @@ if(BROADCAST) # https://github.com/mixxxdj/mixxx/issues/9681 # https://github.com/mixxxdj/mixxx/issues/10305 if(Shoutidjc_FOUND AND Shoutidjc_VERSION VERSION_LESS 2.4.4) - message(STATUS "Installed libshout-idjc version: ${Shoutidjc_VERSION} is suffering from bug lp1833225") + message(STATUS "Installed libshout-idjc version: ${Shoutidjc_VERSION} is suffering from issue #9681") elseif(Shoutidjc_FOUND AND Shoutidjc_VERSION VERSION_LESS 2.4.6) - message(STATUS "Installed libshout version: ${Shout_VERSION} is suffering from bug lp1913579") + message(STATUS "Installed libshout version: ${Shout_VERSION} is suffering from issue #10305") endif() if(NOT Shoutidjc_FOUND OR Shoutidjc_VERSION VERSION_LESS 2.4.6) # Fall back to internal library in the lib tree diff --git a/lib/fidlib/fidlib.c b/lib/fidlib/fidlib.c index 3f4678eef5e..b6a451c144e 100644 --- a/lib/fidlib/fidlib.c +++ b/lib/fidlib/fidlib.c @@ -255,7 +255,7 @@ extern FidFilter *mkfilter(char *, ...); // // Macro for local inline routines that shouldn't be visible externally -// See Mixxx Bug #1179683 +// See Mixxx Issue #7030 #if defined(T_MINGW) || defined(T_MSVC) #define STATIC_INLINE static __inline #else diff --git a/res/controllers/Electrix-Tweaker-scripts.js b/res/controllers/Electrix-Tweaker-scripts.js index 532a9e59ff4..8f138a26b94 100644 --- a/res/controllers/Electrix-Tweaker-scripts.js +++ b/res/controllers/Electrix-Tweaker-scripts.js @@ -1,17 +1,4 @@ -// ====================================================== USER OPTIONS ========================================================= - -// Set this to false if you do not want the volume of samples to be proportional to how hard you press the big buttons. When this is false, the sampler buttons will play the samplers at whatever volume the sample deck is set to. -ElectrixTweaker.samplerVelocityAsVolume = true -// The higher this is, the less hard you have to strike the sample pads to play samples loudly (when ElectrixTweaker.samplerVelocityAsVolume is true). -ElectrixTweaker.samplerSensitivity = 4 - -// Adjust sensitivity of EQs (range 1-7, only use integers) -ElectrixTweaker.eqSensitivity = 6 - -// Set these to true to enable vinyl mode for that deck on startup. This will also enable vinyl control on startup. -ElectrixTweaker.vinylMode = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} - -/** +/* * Electrix Tweaker controller script 1.1.1 for Mixxx 1.12 * Copyright (C) 2015 Be * @@ -28,194 +15,209 @@ ElectrixTweaker.vinylMode = {'[Channel1]': false, '[Channel2]': false, '[Channel * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * See http://mixxx.org/wiki/doku.php/electrix_tweaker for instructions on how to use this mapping + */ - See http://mixxx.org/wiki/doku.php/electrix_tweaker for instructions on how to use this mapping -**/ +var ElectrixTweaker = function() {}; -// ==================================================== GLOBAL VARIABLES ======================================================= +// ====================================================== USER OPTIONS ========================================================= + +// Set this to false if you do not want the volume of samples to be proportional to how hard you press the big buttons. When this is false, the sampler buttons will play the samplers at whatever volume the sample deck is set to. +ElectrixTweaker.samplerVelocityAsVolume = true; +// The higher this is, the less hard you have to strike the sample pads to play samples loudly (when ElectrixTweaker.samplerVelocityAsVolume is true). +ElectrixTweaker.samplerSensitivity = 4; + +// Adjust sensitivity of EQs (range 1-7, only use integers) +ElectrixTweaker.eqSensitivity = 6; + +// Set these to true to enable vinyl mode for that deck on startup. This will also enable vinyl control on startup. +ElectrixTweaker.vinylMode = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; -function ElectrixTweaker() {} + + +// ==================================================== GLOBAL VARIABLES ======================================================= ElectrixTweaker.colorCodes = { - 'off': 0, - 'green': 1, - 'red': 4, - 'yellow': 8, - 'blue': 16, - 'cyan': 32, - 'magenta': 64, - 'white': 127 -} + "off": 0, + "green": 1, + "red": 4, + "yellow": 8, + "blue": 16, + "cyan": 32, + "magenta": 64, + "white": 127 +}; ElectrixTweaker.deckColor = { - '[Channel1]': ElectrixTweaker.colorCodes['blue'], - '[Channel2]': ElectrixTweaker.colorCodes['blue'], - '[Channel3]': ElectrixTweaker.colorCodes['magenta'], - '[Channel4]': ElectrixTweaker.colorCodes['magenta'] -} + "[Channel1]": ElectrixTweaker.colorCodes.blue, + "[Channel2]": ElectrixTweaker.colorCodes.blue, + "[Channel3]": ElectrixTweaker.colorCodes.magenta, + "[Channel4]": ElectrixTweaker.colorCodes.magenta +}; ElectrixTweaker.hotcueColors = [ - ElectrixTweaker.colorCodes['cyan'], - ElectrixTweaker.colorCodes['green'], - ElectrixTweaker.colorCodes['red'], - ElectrixTweaker.colorCodes['white'] -] + ElectrixTweaker.colorCodes.cyan, + ElectrixTweaker.colorCodes.green, + ElectrixTweaker.colorCodes.red, + ElectrixTweaker.colorCodes.white +]; ElectrixTweaker.encoders = { - '[Channel1]': { - 'High': { - 'cc': 57, - 'ring': 79, - 'button': 45 + "[Channel1]": { + "High": { + "cc": 57, + "ring": 79, + "button": 45 }, - 'Mid': { - 'cc': 58, - 'ring': 80, - 'button': 46 + "Mid": { + "cc": 58, + "ring": 80, + "button": 46 }, - 'Low': { - 'cc': 59, - 'ring': 81, - 'button': 47 + "Low": { + "cc": 59, + "ring": 81, + "button": 47 } }, - '[Channel2]': { - 'High': { - 'cc': 60, - 'ring': 82, - 'button': 48 + "[Channel2]": { + "High": { + "cc": 60, + "ring": 82, + "button": 48 }, - 'Mid': { - 'cc': 61, - 'ring': 83, - 'button': 49 + "Mid": { + "cc": 61, + "ring": 83, + "button": 49 }, - 'Low': { - 'cc': 62, - 'ring': 84, - 'button': 50 + "Low": { + "cc": 62, + "ring": 84, + "button": 50 } } -} -ElectrixTweaker.encoders['[Channel3]'] = ElectrixTweaker.encoders['[Channel1]'] -ElectrixTweaker.encoders['[Channel4]'] = ElectrixTweaker.encoders['[Channel2]'] +}; +ElectrixTweaker.encoders["[Channel3]"] = ElectrixTweaker.encoders["[Channel1]"]; +ElectrixTweaker.encoders["[Channel4]"] = ElectrixTweaker.encoders["[Channel2]"]; // each consecutive value in this array sets the encoder ring LEDs to the show the next LED -ElectrixTweaker.encoderRingSteps = [0, 10, 25, 35, 50, 60, 64, 75, 85, 95, 105, 115, 127] -ElectrixTweaker.encoderRingStepsFill = [0, 1, 20, 30, 40, 50, 60, 64, 75, 85, 95, 105, 120, 127] +ElectrixTweaker.encoderRingSteps = [0, 10, 25, 35, 50, 60, 64, 75, 85, 95, 105, 115, 127]; +ElectrixTweaker.encoderRingStepsFill = [0, 1, 20, 30, 40, 50, 60, 64, 75, 85, 95, 105, 120, 127]; ElectrixTweaker.buttons = { - '[Channel1]': { - 'arrowSide': 42, + "[Channel1]": { + "arrowSide": 42, - 'mode': 33, - 'pfl': 34, - 'play': 35, + "mode": 33, + "pfl": 34, + "play": 35, - 'hotcues': [ - [1, 2, 3, 4], - [9, 10, 11, 12] - ], + "hotcues": [ + [1, 2, 3, 4], + [9, 10, 11, 12] + ], - 'forward': 17, - 'slip': 18, - 'shift': 19, - 'deckToggle': 20, + "forward": 17, + "slip": 18, + "shift": 19, + "deckToggle": 20, - 'back': 25, - 'quantize': 26, - 'key': 27, - 'sync': 28 + "back": 25, + "quantize": 26, + "key": 27, + "sync": 28 }, - '[Channel2]': { - 'mode': 36, - 'pfl': 37, - 'play': 38, + "[Channel2]": { + "mode": 36, + "pfl": 37, + "play": 38, - 'arrowSide': 43, + "arrowSide": 43, - 'hotcues': [ - [5, 6, 7, 8], - [13, 14, 15, 16] - ], + "hotcues": [ + [5, 6, 7, 8], + [13, 14, 15, 16] + ], - 'forward': 21, - 'slip': 22, - 'shift': 23, - 'deckToggle': 24, + "forward": 21, + "slip": 22, + "shift": 23, + "deckToggle": 24, - 'back': 29, - 'quantize': 30, - 'key': 31, - 'sync': 32 + "back": 29, + "quantize": 30, + "key": 31, + "sync": 32 } -} -ElectrixTweaker.buttons['[Channel3]'] = ElectrixTweaker.buttons['[Channel1]'] -ElectrixTweaker.buttons['[Channel4]'] = ElectrixTweaker.buttons['[Channel2]'] - -ElectrixTweaker.shift = false -ElectrixTweaker.topShift = false -ElectrixTweaker.deckShift = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} -ElectrixTweaker.deck = {'[Channel1]': '[Channel1]', '[Channel2]': '[Channel2]'} -ElectrixTweaker.mode = {'[Channel1]': 'eq', '[Channel2]': 'eq', '[Channel3]': 'eq', '[Channel4]': 'eq'} -ElectrixTweaker.loopMoveSize = {'[Channel1]': 1, '[Channel2]': 1, '[Channel3]': 1, '[Channel4]': 1} -ElectrixTweaker.loopSize = {'[Channel1]': 4, '[Channel2]': 4, '[Channel3]': 4, '[Channel4]': 4} -ElectrixTweaker.slipMode = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} -ElectrixTweaker.deckShift = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} -ElectrixTweaker.hotcuePage = {'[Channel1]': 0, '[Channel2]': 0, '[Channel3]': 0, '[Channel4]': 0} -ElectrixTweaker.hotcuesPressed = {'[Channel1]': 0, '[Channel2]': 0, '[Channel3]': 0, '[Channel4]': 0} -ElectrixTweaker.playPressedWhileCueJuggling = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} -ElectrixTweaker.slipModeUnsetWhileLooping = {'[Channel1]': false, '[Channel2]': false, '[Channel3]': false, '[Channel4]': false} -ElectrixTweaker.midEncoderLEDTimer = {'[Channel1]': 0, '[Channel2]': 0, '[Channel3]': 0, '[Channel4]': 0} -ElectrixTweaker.midEncoderLEDTimer = {'[Channel1]': 0, '[Channel2]': 0, '[Channel3]': 0, '[Channel4]': 0} - -ElectrixTweaker.sysexPrefix = [ 240, 0, 1, 106, 1 ] +}; +ElectrixTweaker.buttons["[Channel3]"] = ElectrixTweaker.buttons["[Channel1]"]; +ElectrixTweaker.buttons["[Channel4]"] = ElectrixTweaker.buttons["[Channel2]"]; + +ElectrixTweaker.shift = false; +ElectrixTweaker.topShift = false; +ElectrixTweaker.deckShift = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; +ElectrixTweaker.deck = {"[Channel1]": "[Channel1]", "[Channel2]": "[Channel2]"}; +ElectrixTweaker.mode = {"[Channel1]": "eq", "[Channel2]": "eq", "[Channel3]": "eq", "[Channel4]": "eq"}; +ElectrixTweaker.loopMoveSize = {"[Channel1]": 1, "[Channel2]": 1, "[Channel3]": 1, "[Channel4]": 1}; +ElectrixTweaker.loopSize = {"[Channel1]": 4, "[Channel2]": 4, "[Channel3]": 4, "[Channel4]": 4}; +ElectrixTweaker.slipMode = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; +ElectrixTweaker.deckShift = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; +ElectrixTweaker.hotcuePage = {"[Channel1]": 0, "[Channel2]": 0, "[Channel3]": 0, "[Channel4]": 0}; +ElectrixTweaker.hotcuesPressed = {"[Channel1]": 0, "[Channel2]": 0, "[Channel3]": 0, "[Channel4]": 0}; +ElectrixTweaker.playPressedWhileCueJuggling = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; +ElectrixTweaker.slipModeUnsetWhileLooping = {"[Channel1]": false, "[Channel2]": false, "[Channel3]": false, "[Channel4]": false}; +ElectrixTweaker.midEncoderLEDTimer = {"[Channel1]": 0, "[Channel2]": 0, "[Channel3]": 0, "[Channel4]": 0}; +ElectrixTweaker.midEncoderLEDTimer = {"[Channel1]": 0, "[Channel2]": 0, "[Channel3]": 0, "[Channel4]": 0}; + +ElectrixTweaker.sysexPrefix = [240, 0, 1, 106, 1]; ElectrixTweaker.defaultSettings = [ -[ 240, 0, 1, 106, 1, 1, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 247 ], -[ 240, 0, 1, 106, 1, 2, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 247 ], -[ 240, 0, 1, 106, 1, 3, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 247 ], -[ 240, 0, 1, 106, 1, 4, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 247 ], -[ 240, 0, 1, 106, 1, 5, 126, 5, 1, 247 ], -[ 240, 0, 1, 106, 1, 6, 127, 127, 15, 0, 7, 0, 9, 5, 247 ], -[ 240, 0, 1, 106, 1, 7, 42, 42, 247 ], -[ 240, 0, 1, 106, 1, 8, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 247 ], -[ 240, 0, 1, 106, 1, 9, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 247 ], -[ 240, 0, 1, 106, 1, 13, 15, 247 ], -[ 240, 0, 1, 106, 1, 14, 0, 247 ], -[ 240, 0, 1, 106, 1, 15, 0, 247 ] -] -ElectrixTweaker.requestConfiguration = ElectrixTweaker.sysexPrefix.concat([ 126 , 247 ]) - -ElectrixTweaker.samplerRegEx = /\[Sampler(\d+)\]/ -ElectrixTweaker.channelRegEx = /\[Channel(\d+)\]/ + [240, 0, 1, 106, 1, 1, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 0, 39, 0, 40, 0, 41, 0, 42, 0, 43, 0, 44, 0, 45, 0, 46, 0, 47, 0, 48, 0, 49, 0, 50, 247], + [240, 0, 1, 106, 1, 2, 0, 51, 0, 52, 0, 53, 0, 54, 0, 55, 247], + [240, 0, 1, 106, 1, 3, 0, 56, 0, 57, 0, 58, 0, 59, 0, 60, 0, 61, 0, 62, 247], + [240, 0, 1, 106, 1, 4, 0, 63, 0, 64, 0, 65, 0, 66, 0, 67, 0, 68, 0, 69, 0, 70, 0, 71, 0, 72, 0, 73, 0, 74, 0, 75, 0, 76, 0, 77, 0, 78, 247], + [240, 0, 1, 106, 1, 5, 126, 5, 1, 247], + [240, 0, 1, 106, 1, 6, 127, 127, 15, 0, 7, 0, 9, 5, 247], + [240, 0, 1, 106, 1, 7, 42, 42, 247], + [240, 0, 1, 106, 1, 8, 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 0, 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0, 32, 0, 33, 0, 34, 0, 35, 0, 36, 0, 37, 0, 38, 247], + [240, 0, 1, 106, 1, 9, 0, 79, 0, 80, 0, 81, 0, 82, 0, 83, 0, 84, 247], + [240, 0, 1, 106, 1, 13, 15, 247], + [240, 0, 1, 106, 1, 14, 0, 247], + [240, 0, 1, 106, 1, 15, 0, 247] +]; +ElectrixTweaker.requestConfiguration = ElectrixTweaker.sysexPrefix.concat([126, 247]); + +ElectrixTweaker.samplerRegEx = /\[Sampler(\d+)\]/; +ElectrixTweaker.channelRegEx = /\[Channel(\d+)\]/; // ================================================= INITIALIZATION & SHUTDOWN ============================================ -ElectrixTweaker.init = function () { - if (engine.getValue('[Master]', 'num_samplers') < 8) { - engine.setValue('[Master]', 'num_samplers', 8) +ElectrixTweaker.init = function() { + if (engine.getValue("[Master]", "num_samplers") < 8) { + engine.setValue("[Master]", "num_samplers", 8); } - for (var group in ElectrixTweaker.encoders) { // loop over each [Channel] -// engine.softTakeover('[QuickEffectRack1_'+group+']', 'super1', true) -// engine.softTakeover(group, 'volume', true) - // uncomment the line below when Bug #1472868 is fixed -// ElectrixTweaker.vinylMode[group] = engine.getValue(group, 'vinylcontrol_enabled') - engine.setValue(group, 'vinylcontrol_enabled', ElectrixTweaker.vinylMode[group]) + for (const group in ElectrixTweaker.encoders) { // loop over each [Channel] + // engine.softTakeover('[QuickEffectRack1_'+group+']', 'super1', true) + // engine.softTakeover(group, 'volume', true) + // uncomment the line below when issue #8142 is fixed + // ElectrixTweaker.vinylMode[group] = engine.getValue(group, 'vinylcontrol_enabled') + engine.setValue(group, "vinylcontrol_enabled", ElectrixTweaker.vinylMode[group]); } - ElectrixTweaker.initDeck('[Channel1]') - ElectrixTweaker.initDeck('[Channel2]') - for (i=1; i<=8; i++) { - engine.connectControl('[Sampler'+i+']', 'track_samples', 'ElectrixTweaker.oneShotLED') - engine.trigger('[Sampler'+i+']', 'track_samples') + ElectrixTweaker.initDeck("[Channel1]"); + ElectrixTweaker.initDeck("[Channel2]"); + for (let i=1; i<=8; i++) { + engine.connectControl("[Sampler"+i+"]", "track_samples", "ElectrixTweaker.oneShotLED"); + engine.trigger("[Sampler"+i+"]", "track_samples"); } - midi.sendShortMsg(0x90, 39, 127) // light up arrow - midi.sendShortMsg(0x90, 40, 127) // light top shift button - midi.sendShortMsg(0x90, 41, 127) // light down arrow + midi.sendShortMsg(0x90, 39, 127); // light up arrow + midi.sendShortMsg(0x90, 40, 127); // light top shift button + midi.sendShortMsg(0x90, 41, 127); // light down arrow // midi.sendSysexMsg(ElectrixTweaker.requestConfiguration, ElectrixTweaker.requestConfiguration.length) // for (var msg in ElectrixTweaker.defaultSettings) { // midi.sendSysexMsg(ElectrixTweaker.defaultSettings[msg], ElectrixTweaker.defaultSettings[msg].length) // } -} +}; // ElectrixTweaker.inboundSysex = function (data, length) { // print('========================== incoming sysex message ======================================') // print(length) @@ -226,949 +228,949 @@ ElectrixTweaker.init = function () { // } ElectrixTweaker.shutdown = function() { - for (var group in ElectrixTweaker.encoders) { - for (var encoder in ElectrixTweaker.encoders[group]) { + for (const group in ElectrixTweaker.encoders) { + for (const encoder in ElectrixTweaker.encoders[group]) { // set encoder to absolute EQ mode with speed 5 - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['cc'], 118) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].cc, 118); // enable local control of LED ring - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['ring'], 70) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].ring, 70); // set rings to center - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group][encoder]['cc'], 64) + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group][encoder].cc, 64); // turn off blue button lights - midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group][encoder]['button'], 0) + midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group][encoder].button, 0); } } // turn off all button LEDs - for (i = 0; i <= 70; i++) { - midi.sendShortMsg(0x90, i, ElectrixTweaker.colorCodes['off']) + for (let i = 0; i <= 70; i++) { + midi.sendShortMsg(0x90, i, ElectrixTweaker.colorCodes.off); } -} +}; // ==================================================== MODE SWITCHING FUNCTIONS ================================================ -ElectrixTweaker.initDeck = function (group) { - var disconnectDeck = parseInt(ElectrixTweaker.channelRegEx.exec(group)[1]) +ElectrixTweaker.initDeck = function(group) { + let disconnectDeck = parseInt(ElectrixTweaker.channelRegEx.exec(group)[1]); if (disconnectDeck <= 2) { - disconnectDeck += 2 + disconnectDeck += 2; } else { - disconnectDeck -= 2 + disconnectDeck -= 2; } - disconnectDeck = '[Channel' + disconnectDeck + ']' - ElectrixTweaker.connectDeckControls(disconnectDeck, true) + disconnectDeck = "[Channel" + disconnectDeck + "]"; + ElectrixTweaker.connectDeckControls(disconnectDeck, true); // workaround for https://github.com/mixxxdj/mixxx/issues/8104 - for (i=1; i <= 32; i++) { - engine.setValue(disconnectDeck, 'hotcue_'+i+'_activate', 0) + for (let i=1; i <= 32; i++) { + engine.setValue(disconnectDeck, "hotcue_"+i+"_activate", 0); } - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['shift'], ElectrixTweaker.colorCodes['yellow']) - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['deckToggle'], ElectrixTweaker.deckColor[group]) + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].shift, ElectrixTweaker.colorCodes.yellow); + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].deckToggle, ElectrixTweaker.deckColor[group]); midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['slip'], - ElectrixTweaker.slipMode[group] ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) - - ElectrixTweaker.mode[group] = ElectrixTweaker.mode[disconnectDeck] - - ElectrixTweaker.connectDeckControls(group) -} - -ElectrixTweaker.connectDeckControls = function (group, remove) { - remove = (typeof remove !== 'undefined') ? remove : false // default value for remove is false - - var controlsToFunctions = { - 'pfl': 'ElectrixTweaker.pflButtonLED', -// 'track_samples': 'ElectrixTweaker.arrowSideLED', // the line below would overwrite this attribute - 'track_samples': 'ElectrixTweaker.playButtonLED', - 'play': 'ElectrixTweaker.playButtonLED', - 'playposition': 'ElectrixTweaker.playButtonLED', - 'cue_indicator': 'ElectrixTweaker.playButtonLED', - 'sync_enabled': 'ElectrixTweaker.syncLED', - 'keylock': 'ElectrixTweaker.keylockLED', - 'quantize': 'ElectrixTweaker.quantizeLED' - } - engine.connectControl(group, 'track_samples', 'ElectrixTweaker.arrowSideLED', remove) - for (var control in controlsToFunctions) { - engine.connectControl(group, control, controlsToFunctions[control], remove) + ElectrixTweaker.buttons[group].slip, + ElectrixTweaker.slipMode[group] ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); + + ElectrixTweaker.mode[group] = ElectrixTweaker.mode[disconnectDeck]; + + ElectrixTweaker.connectDeckControls(group); +}; + +ElectrixTweaker.connectDeckControls = function(group, remove) { + remove = (typeof remove !== "undefined") ? remove : false; // default value for remove is false + + const controlsToFunctions = { + "pfl": "ElectrixTweaker.pflButtonLED", + // 'track_samples': 'ElectrixTweaker.arrowSideLED', // the line below would overwrite this attribute + "track_samples": "ElectrixTweaker.playButtonLED", + "play": "ElectrixTweaker.playButtonLED", + "playposition": "ElectrixTweaker.playButtonLED", + "cue_indicator": "ElectrixTweaker.playButtonLED", + "sync_enabled": "ElectrixTweaker.syncLED", + "keylock": "ElectrixTweaker.keylockLED", + "quantize": "ElectrixTweaker.quantizeLED" + }; + engine.connectControl(group, "track_samples", "ElectrixTweaker.arrowSideLED", remove); + for (const control in controlsToFunctions) { + engine.connectControl(group, control, controlsToFunctions[control], remove); if (! remove) { - engine.trigger(group, control) + engine.trigger(group, control); } } - ElectrixTweaker.connectHotcuePage(group, remove) - ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], remove) + ElectrixTweaker.connectHotcuePage(group, remove); + ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], remove); if (ElectrixTweaker.vinylMode[group]) { - ElectrixTweaker.connectVinylLEDs(group, remove) + ElectrixTweaker.connectVinylLEDs(group, remove); } -} +}; -ElectrixTweaker.connectEncoderMode = function (group, mode, remove) { - remove = (typeof remove !== 'undefined') ? remove : false // default value for remove is false +ElectrixTweaker.connectEncoderMode = function(group, mode, remove) { + remove = (typeof remove !== "undefined") ? remove : false; // default value for remove is false switch (mode) { - case 'eq': - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['mode'], ElectrixTweaker.colorCodes['white']) - for (var encoder in ElectrixTweaker.encoders[group]) { - engine.connectControl(group, 'filter' + encoder, 'ElectrixTweaker.eqEncoderLEDs', remove) - engine.connectControl(group, 'filter' + encoder + 'Kill', 'ElectrixTweaker.eqEncoderKillButtonLED', remove) - if (! remove) { - // set encoder to absolute EQ mode with speed 5 - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['cc'], 70 + 8*ElectrixTweaker.eqSensitivity) - // enable local control of LED ring - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['ring'], 70) - - engine.trigger(group, 'filter' + encoder) - engine.trigger(group, 'filter' + encoder + 'Kill') - } - } - break - case 'loop': - engine.connectControl(group, 'loop_enabled', 'ElectrixTweaker.loopButtonToggleLED', remove) + case "eq": + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].mode, ElectrixTweaker.colorCodes.white); + for (const encoder in ElectrixTweaker.encoders[group]) { + engine.connectControl(group, "filter" + encoder, "ElectrixTweaker.eqEncoderLEDs", remove); + engine.connectControl(group, "filter" + encoder + "Kill", "ElectrixTweaker.eqEncoderKillButtonLED", remove); if (! remove) { - engine.trigger(group, 'loop_enabled') - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['mode'], ElectrixTweaker.colorCodes['magenta']) - for (var encoder in ElectrixTweaker.encoders[group]) { - // set encoder to relative mode - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['cc'], 64) - // set LED ring to EQ mode with local control disabled - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['ring'], 98) - } + // set encoder to absolute EQ mode with speed 5 + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].cc, 70 + 8*ElectrixTweaker.eqSensitivity); + // enable local control of LED ring + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].ring, 70); - midi.sendShortMsg( - 0xB0, - ElectrixTweaker.encoders[group]['High']['ring'], - ElectrixTweaker.encoderRingSteps[ - 6 + Math.log(ElectrixTweaker.loopMoveSize[group]) / Math.log(2) - ] - ) + engine.trigger(group, "filter" + encoder); + engine.trigger(group, "filter" + encoder + "Kill"); + } + } + break; + case "loop": + engine.connectControl(group, "loop_enabled", "ElectrixTweaker.loopButtonToggleLED", remove); + if (! remove) { + engine.trigger(group, "loop_enabled"); + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].mode, ElectrixTweaker.colorCodes.magenta); + for (const encoder in ElectrixTweaker.encoders[group]) { + // set encoder to relative mode + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].cc, 64); + // set LED ring to EQ mode with local control disabled + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].ring, 98); + } - midi.sendShortMsg( - 0xB0, - ElectrixTweaker.encoders[group]['Mid']['ring'], - 64 - ) + midi.sendShortMsg( + 0xB0, + ElectrixTweaker.encoders[group].High.ring, + ElectrixTweaker.encoderRingSteps[ + 6 + Math.log(ElectrixTweaker.loopMoveSize[group]) / Math.log(2) + ] + ); - midi.sendShortMsg( - 0xB0, - ElectrixTweaker.encoders[group]['Low']['ring'], - ElectrixTweaker.encoderRingSteps[ - 6 + Math.log(ElectrixTweaker.loopSize[group]) / Math.log(2) - ] - ) - } - break + midi.sendShortMsg( + 0xB0, + ElectrixTweaker.encoders[group].Mid.ring, + 64 + ); + + midi.sendShortMsg( + 0xB0, + ElectrixTweaker.encoders[group].Low.ring, + ElectrixTweaker.encoderRingSteps[ + 6 + Math.log(ElectrixTweaker.loopSize[group]) / Math.log(2) + ] + ); + } + break; } -} +}; -ElectrixTweaker.connectHotcuePage = function (group, remove) { - remove = (typeof remove !== 'undefined') ? remove : false // default value for remove is false +ElectrixTweaker.connectHotcuePage = function(group, remove) { + remove = (typeof remove !== "undefined") ? remove : false; // default value for remove is false - var min = 1 + (ElectrixTweaker.hotcuePage[group] * 8) - var max = min + 7 - for (i=min; i<=max; i++) { - engine.connectControl(group, 'hotcue_'+i+'_enabled', 'ElectrixTweaker.hotcueLED', remove) + const min = 1 + (ElectrixTweaker.hotcuePage[group] * 8); + const max = min + 7; + for (let i=min; i<=max; i++) { + engine.connectControl(group, "hotcue_"+i+"_enabled", "ElectrixTweaker.hotcueLED", remove); if (! remove) { - engine.trigger(group, 'hotcue_'+i+'_enabled') + engine.trigger(group, "hotcue_"+i+"_enabled"); } } -} - -ElectrixTweaker.connectVinylLEDs = function (group, remove) { - var controlsToFunctions = { - 'passthrough': 'ElectrixTweaker.vinylStatusLED', - 'vinylcontrol_status': 'ElectrixTweaker.vinylStatusLED', - 'vinylcontrol_mode': 'ElectrixTweaker.vinylModeLED', - 'vinylcontrol_cueing': 'ElectrixTweaker.vinylModeLED' - } - for (var control in controlsToFunctions) { - engine.connectControl(group, control, controlsToFunctions[control], remove) +}; + +ElectrixTweaker.connectVinylLEDs = function(group, remove) { + const controlsToFunctions = { + "passthrough": "ElectrixTweaker.vinylStatusLED", + "vinylcontrol_status": "ElectrixTweaker.vinylStatusLED", + "vinylcontrol_mode": "ElectrixTweaker.vinylModeLED", + "vinylcontrol_cueing": "ElectrixTweaker.vinylModeLED" + }; + for (const control in controlsToFunctions) { + engine.connectControl(group, control, controlsToFunctions[control], remove); } if (remove) { midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['back'], - (engine.getValue(group, 'quantize')) ? ElectrixTweaker.colorCodes['white'] : ElectrixTweaker.colorCodes['green'] - ) + ElectrixTweaker.buttons[group].back, + (engine.getValue(group, "quantize")) ? ElectrixTweaker.colorCodes.white : ElectrixTweaker.colorCodes.green + ); midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['forward'], - (engine.getValue(group, 'quantize')) ? ElectrixTweaker.colorCodes['white'] : ElectrixTweaker.colorCodes['green'] - ) + ElectrixTweaker.buttons[group].forward, + (engine.getValue(group, "quantize")) ? ElectrixTweaker.colorCodes.white : ElectrixTweaker.colorCodes.green + ); midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['slip'], - (ElectrixTweaker.slipMode[group]) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) + ElectrixTweaker.buttons[group].slip, + (ElectrixTweaker.slipMode[group]) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); } else { - for (var control in controlsToFunctions) { - engine.trigger(group, control) + for (const control in controlsToFunctions) { + engine.trigger(group, control); } } -} +}; -ElectrixTweaker.topShiftButton = function (channel, control, value, status, group) { +ElectrixTweaker.topShiftButton = function(channel, control, value, status, group) { // ElectrixTweaker.shift = ! ElectrixTweaker.shift - ElectrixTweaker.topShift = ! ElectrixTweaker.topShift + ElectrixTweaker.topShift = ! ElectrixTweaker.topShift; - ElectrixTweaker.connectEncoderMode(ElectrixTweaker.deck['[Channel1]'], ElectrixTweaker.mode[group], value/127) - ElectrixTweaker.connectEncoderMode(ElectrixTweaker.deck['[Channel2]'], ElectrixTweaker.mode[group], value/127) + ElectrixTweaker.connectEncoderMode(ElectrixTweaker.deck["[Channel1]"], ElectrixTweaker.mode[group], value/127); + ElectrixTweaker.connectEncoderMode(ElectrixTweaker.deck["[Channel2]"], ElectrixTweaker.mode[group], value/127); if (value) { for (group in ElectrixTweaker.deck) { - for (var encoder in ElectrixTweaker.encoders[group]) { + for (const encoder in ElectrixTweaker.encoders[group]) { // set encoder to absolute EQ mode with speed 5 - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['cc'], 70 + 8*ElectrixTweaker.eqSensitivity) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].cc, 70 + 8*ElectrixTweaker.eqSensitivity); // enable local control of LED ring - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder]['ring'], 70) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group][encoder].ring, 70); } - engine.connectControl(ElectrixTweaker.deck[group], 'pregain', 'ElectrixTweaker.gainLEDs') - engine.trigger(ElectrixTweaker.deck[group], 'pregain') + engine.connectControl(ElectrixTweaker.deck[group], "pregain", "ElectrixTweaker.gainLEDs"); + engine.trigger(ElectrixTweaker.deck[group], "pregain"); } } else { for (group in ElectrixTweaker.deck) { - engine.connectControl(ElectrixTweaker.deck[group], 'pregain', 'ElectrixTweaker.gainLEDs', true) + engine.connectControl(ElectrixTweaker.deck[group], "pregain", "ElectrixTweaker.gainLEDs", true); } } - var controlsToFunctions = { - 'volume': 'ElectrixTweaker.masterGainLEDs', - 'balance': 'ElectrixTweaker.masterBalanceLEDs', - 'headVolume': 'ElectrixTweaker.headGainLEDs', - 'headMix': 'ElectrixTweaker.headMixLEDs', - 'headSplit': 'ElectrixTweaker.headSplitLED' - } - for (var control in controlsToFunctions) { - engine.connectControl('[Master]', control, controlsToFunctions[control], ! value/127) + const controlsToFunctions = { + "volume": "ElectrixTweaker.masterGainLEDs", + "balance": "ElectrixTweaker.masterBalanceLEDs", + "headVolume": "ElectrixTweaker.headGainLEDs", + "headMix": "ElectrixTweaker.headMixLEDs", + "headSplit": "ElectrixTweaker.headSplitLED" + }; + for (const control in controlsToFunctions) { + engine.connectControl("[Master]", control, controlsToFunctions[control], ! value/127); if (value) { - engine.trigger('[Master]', control) + engine.trigger("[Master]", control); } } -} +}; -ElectrixTweaker.deckShiftButton = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] - ElectrixTweaker.deckShift[group] = ! ElectrixTweaker.deckShift[group] +ElectrixTweaker.deckShiftButton = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; + ElectrixTweaker.deckShift[group] = ! ElectrixTweaker.deckShift[group]; if (value) { // set low encoder to relative mode - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['Low']['cc'], 64) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].Low.cc, 64); // set low LED ring to walk mode with local control disabled - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['Low']['ring'], 96) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].Low.ring, 96); midi.sendShortMsg( 0xB0, - ElectrixTweaker.encoders[group]['Low']['ring'], + ElectrixTweaker.encoders[group].Low.ring, ElectrixTweaker.encoderRingStepsFill[ElectrixTweaker.hotcuePage[group]+1] - ) + ); // set mid encoder to relative mode - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['Mid']['cc'], 64) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].Mid.cc, 64); // set mid encoder LED ring to EQ mode with local control disabled // There seems to be a bug in the Tweaker firmware when local control is enabled one LED ring but not another. If local control is enabled here, the other rings behave confusingly. - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['Mid']['ring'], 98) - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Mid']['ring'], 64) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].Mid.ring, 98); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Mid.ring, 64); // set high encoder to absolute EQ mode with sensitivity level 1 // 1 step = 1 MIDI value for fine pitch control - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['High']['cc'], 78) + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].High.cc, 78); // set high LED ring to EQ mode with local control disabled - midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group]['High']['ring'], 78) - engine.connectControl(group, 'rate', 'ElectrixTweaker.rateEncoderLEDs') - engine.trigger(group, 'rate') + midi.sendShortMsg(0xBF, ElectrixTweaker.encoders[group].High.ring, 78); + engine.connectControl(group, "rate", "ElectrixTweaker.rateEncoderLEDs"); + engine.trigger(group, "rate"); if (ElectrixTweaker.topShift && ElectrixTweaker.deckShift[group]) { - ElectrixTweaker.connectVinylLEDs(group, ElectrixTweaker.vinylMode[group]) - ElectrixTweaker.vinylMode[group] = ! ElectrixTweaker.vinylMode[group] + ElectrixTweaker.connectVinylLEDs(group, ElectrixTweaker.vinylMode[group]); + ElectrixTweaker.vinylMode[group] = ! ElectrixTweaker.vinylMode[group]; } } else { - engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]) - engine.connectControl(group, 'rate', 'ElectrixTweaker.rateEncoderLEDs', true) + engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]); + engine.connectControl(group, "rate", "ElectrixTweaker.rateEncoderLEDs", true); } - ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], value/127) -} + ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], value/127); +}; -ElectrixTweaker.rateEncoderLEDs = function (value, group, control) { +ElectrixTweaker.rateEncoderLEDs = function(value, group, _control) { midi.sendShortMsg( - 0xB0, - ElectrixTweaker.encoders[group]['High']['cc'], - script.absoluteLinInverse(value, -1, 1) - ) -} + 0xB0, + ElectrixTweaker.encoders[group].High.cc, + script.absoluteLinInverse(value, -1, 1) + ); +}; // ================================================== ARROWS + BIG ENCODER ==================================================== -ElectrixTweaker.bigEncoder = function (channel, control, value, status, group) { +ElectrixTweaker.bigEncoder = function(channel, control, value, _status, _group) { if (ElectrixTweaker.topShift) { - for (i=0 ; i<35; i++) { - engine.setValue('[Playlist]', (value == 1) ? 'SelectNextTrack' : 'SelectPrevTrack', 1) + for (let i=0; i<35; i++) { + engine.setValue("[Playlist]", (value === 1) ? "SelectNextTrack" : "SelectPrevTrack", 1); } } else { - engine.setValue('[Playlist]', (value == 1) ? 'SelectNextTrack' : 'SelectPrevTrack', 1) + engine.setValue("[Playlist]", (value === 1) ? "SelectNextTrack" : "SelectPrevTrack", 1); } -} -ElectrixTweaker.bigEncoderButton = function (channel, control, value, status, group) { +}; +ElectrixTweaker.bigEncoderButton = function(channel, control, value, _status, _group) { if (value) { if (ElectrixTweaker.topShift) { - engine.setValue('[Playlist]', 'LoadSelectedIntoFirstStopped', 1) + engine.setValue("[Playlist]", "LoadSelectedIntoFirstStopped", 1); } else { - engine.setValue('[Master]', 'maximize_library', ! engine.getValue('[Master]', 'maximize_library')) + engine.setValue("[Master]", "maximize_library", ! engine.getValue("[Master]", "maximize_library")); } } -} -ElectrixTweaker.arrowSide = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.arrowSide = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.topShift) { - engine.setValue(group, 'eject', 1) - engine.beginTimer(250, 'engine.setValue("'+group+'", "eject", 0)', true) + engine.setValue(group, "eject", 1); + engine.beginTimer(250, "engine.setValue(\""+group+"\", \"eject\", 0)", true); } else { - engine.setValue(group, 'LoadSelectedTrack', 1) + engine.setValue(group, "LoadSelectedTrack", 1); } } -} -ElectrixTweaker.arrowSideLED = function (value, group, control) { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['arrowSide'], (value) ? 127 : 0) -} -ElectrixTweaker.arrowUp = function (channel, control, value, status, group) { +}; +ElectrixTweaker.arrowSideLED = function(value, group, _control) { + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].arrowSide, (value) ? 127 : 0); +}; +ElectrixTweaker.arrowUp = function(channel, control, value, _status, _group) { if (value) { if (ElectrixTweaker.topShift) { - engine.setValue('[Playlist]', 'ToggleSelectedSidebarItem', 1) + engine.setValue("[Playlist]", "ToggleSelectedSidebarItem", 1); } else { - engine.setValue('[Playlist]', 'SelectPrevPlaylist', 1) + engine.setValue("[Playlist]", "SelectPrevPlaylist", 1); } } -} -ElectrixTweaker.arrowDown = function (channel, control, value, status, group) { +}; +ElectrixTweaker.arrowDown = function(channel, control, value, _status, _group) { if (value) { if (ElectrixTweaker.topShift) { - engine.setValue('[Playlist]', 'ToggleSelectedSidebarItem', 1) + engine.setValue("[Playlist]", "ToggleSelectedSidebarItem", 1); } else { - engine.setValue('[Playlist]', 'SelectNextPlaylist', 1) + engine.setValue("[Playlist]", "SelectNextPlaylist", 1); } } -} +}; // ===================================================== SAMPLERS =========================================================== -ElectrixTweaker.oneShot = function (channel, control, value, status, group) { +ElectrixTweaker.oneShot = function(channel, control, value, status, group) { if (value) { - if (engine.getValue(group, 'track_samples')) { + if (engine.getValue(group, "track_samples")) { if (ElectrixTweaker.topShift) { - engine.setValue(group, 'key', 0) - engine.setValue(group, 'sync_enabled', 0) - engine.setValue(group, 'repeat', 0) - engine.setValue(group, 'play', 0) - engine.setValue(group, 'eject', 1) - engine.beginTimer(250, 'engine.setValue("'+group+'", "eject", 0)', true) + engine.setValue(group, "key", 0); + engine.setValue(group, "sync_enabled", 0); + engine.setValue(group, "repeat", 0); + engine.setValue(group, "play", 0); + engine.setValue(group, "eject", 1); + engine.beginTimer(250, "engine.setValue(\""+group+"\", \"eject\", 0)", true); } else { if (ElectrixTweaker.samplerVelocityAsVolume) { - engine.setValue(group, 'volume', script.absoluteNonLin(value * ElectrixTweaker.samplerSensitivity, 0, .25, 1)) + engine.setValue(group, "volume", script.absoluteNonLin(value * ElectrixTweaker.samplerSensitivity, 0, .25, 1)); } - engine.setValue(group, 'playposition', 0) - engine.setValue(group, 'play', 1) + engine.setValue(group, "playposition", 0); + engine.setValue(group, "play", 1); } } else { if (ElectrixTweaker.samplerVelocityAsVolume) { - engine.setValue(group, 'volume', script.absoluteNonLin(value, 0, .25, 1)) + engine.setValue(group, "volume", script.absoluteNonLin(value, 0, .25, 1)); } - engine.setValue(group, 'LoadSelectedTrackAndPlay', 1) + engine.setValue(group, "LoadSelectedTrackAndPlay", 1); } } else { - engine.setValue(group, 'play', 0) + engine.setValue(group, "play", 0); } -} -ElectrixTweaker.oneShotLED = function (value, group, control) { - midi.sendShortMsg(0x90, 62 + parseInt(ElectrixTweaker.samplerRegEx.exec(group)[1]), (value) ? 127 : 0) -} +}; +ElectrixTweaker.oneShotLED = function(value, group, _control) { + midi.sendShortMsg(0x90, 62 + parseInt(ElectrixTweaker.samplerRegEx.exec(group)[1]), (value) ? 127 : 0); +}; // ================================================= CHANNEL STRIPS =========================================================== -ElectrixTweaker.leftKnob = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.leftKnob = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; // soft takeover - if (Math.abs(script.absoluteLin(value, 0, 1) - engine.getValue('[QuickEffectRack1_'+group+']', 'super1')) < .1) { - engine.setValue('[QuickEffectRack1_'+group+']', 'super1', script.absoluteLin(value, 0, 1)) + if (Math.abs(script.absoluteLin(value, 0, 1) - engine.getValue("[QuickEffectRack1_"+group+"]", "super1")) < .1) { + engine.setValue("[QuickEffectRack1_"+group+"]", "super1", script.absoluteLin(value, 0, 1)); } -} -ElectrixTweaker.rightKnob = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.rightKnob = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; // soft takeover - if (Math.abs(script.absoluteLin(value, 0, 1) - engine.getValue('[QuickEffectRack1_'+group+']', 'super1')) < .1) { - engine.setValue('[QuickEffectRack1_'+group+']', 'super1', script.absoluteLin(value, 0, 1)) + if (Math.abs(script.absoluteLin(value, 0, 1) - engine.getValue("[QuickEffectRack1_"+group+"]", "super1")) < .1) { + engine.setValue("[QuickEffectRack1_"+group+"]", "super1", script.absoluteLin(value, 0, 1)); } -} +}; -ElectrixTweaker.eqEncoderLEDs = function (value, group, control) { - var encoder = control.replace('filter', '') - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group][encoder]['cc'], script.absoluteNonLinInverse(value, 0, 1, 4)) -} +ElectrixTweaker.eqEncoderLEDs = function(value, group, control) { + const encoder = control.replace("filter", ""); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group][encoder].cc, script.absoluteNonLinInverse(value, 0, 1, 4)); +}; -ElectrixTweaker.eqEncoderKillButtonLED = function (value, group, control) { - var encoder = control.replace('filter', '') - encoder = encoder.replace('Kill', '') - midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group][encoder]['button'], value * 127) -} +ElectrixTweaker.eqEncoderKillButtonLED = function(value, group, control) { + let encoder = control.replace("filter", ""); + encoder = encoder.replace("Kill", ""); + midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group][encoder].button, value * 127); +}; -ElectrixTweaker.masterGainLEDs = function (value, group, control) { - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders['[Channel2]']['High']['cc'], script.absoluteNonLinInverse(value, 0, 1, 4)) -} +ElectrixTweaker.masterGainLEDs = function(value, _group, _control) { + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["[Channel2]"].High.cc, script.absoluteNonLinInverse(value, 0, 1, 4)); +}; -ElectrixTweaker.masterBalanceLEDs = function (value, group, control) { - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders['[Channel2]']['Mid']['cc'], script.absoluteLinInverse(value, -1, 1)) -} +ElectrixTweaker.masterBalanceLEDs = function(value, _group, _control) { + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["[Channel2]"].Mid.cc, script.absoluteLinInverse(value, -1, 1)); +}; -ElectrixTweaker.headGainLEDs = function (value, group, control) { - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders['[Channel1]']['High']['cc'], script.absoluteNonLinInverse(value, 0, 1, 4)) -} +ElectrixTweaker.headGainLEDs = function(value, _group, _control) { + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["[Channel1]"].High.cc, script.absoluteNonLinInverse(value, 0, 1, 4)); +}; -ElectrixTweaker.headMixLEDs = function (value, group, control) { - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders['[Channel1]']['Mid']['cc'], script.absoluteLinInverse(value, -1, 1)) -} +ElectrixTweaker.headMixLEDs = function(value, _group, _control) { + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["[Channel1]"].Mid.cc, script.absoluteLinInverse(value, -1, 1)); +}; -ElectrixTweaker.headSplitLED = function (value, group, control) { - midi.sendShortMsg(0x90, ElectrixTweaker.encoders['[Channel1]']['Mid']['button'], value * 127) -} +ElectrixTweaker.headSplitLED = function(value, _group, _control) { + midi.sendShortMsg(0x90, ElectrixTweaker.encoders["[Channel1]"].Mid.button, value * 127); +}; -ElectrixTweaker.gainLEDs = function (value, group, control) { - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Low']['cc'], script.absoluteNonLinInverse(value, 0, 1, 4)) -} +ElectrixTweaker.gainLEDs = function(value, group, _control) { + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Low.cc, script.absoluteNonLinInverse(value, 0, 1, 4)); +}; -ElectrixTweaker.highEncoder = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.highEncoder = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.topShift) { - if (control == ElectrixTweaker.encoders['[Channel1]']['High']['cc']) { - engine.setValue('[Master]', 'headVolume', script.absoluteNonLin(value, 0, 1, 5)) + if (control === ElectrixTweaker.encoders["[Channel1]"].High.cc) { + engine.setValue("[Master]", "headVolume", script.absoluteNonLin(value, 0, 1, 5)); } else { - engine.setValue('[Master]', 'volume', script.absoluteNonLin(value, 0, 1, 5)) + engine.setValue("[Master]", "volume", script.absoluteNonLin(value, 0, 1, 5)); } } else if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'rate', script.absoluteLin(value, -1, 1, 0, 126)) + engine.setValue(group, "rate", script.absoluteLin(value, -1, 1, 0, 126)); } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - engine.setValue(group, 'filterHigh', script.absoluteNonLin(value, 0, 1, 4) ) - break - case 'loop': - if ((value == 127) && (ElectrixTweaker.loopMoveSize[group] >= Math.pow(2, -5))) { - ElectrixTweaker.loopMoveSize[group] = ElectrixTweaker.loopMoveSize[group] / 2 - } else if ((value == 1) && (ElectrixTweaker.loopMoveSize[group] <= Math.pow(2, 5))) { - ElectrixTweaker.loopMoveSize[group] = ElectrixTweaker.loopMoveSize[group] * 2 - } - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['High']['ring'], ElectrixTweaker.encoderRingSteps[ 6 + Math.log(ElectrixTweaker.loopMoveSize[group]) / Math.log(2) ] ) - break + case "eq": + engine.setValue(group, "filterHigh", script.absoluteNonLin(value, 0, 1, 4)); + break; + case "loop": + if ((value === 127) && (ElectrixTweaker.loopMoveSize[group] >= Math.pow(2, -5))) { + ElectrixTweaker.loopMoveSize[group] = ElectrixTweaker.loopMoveSize[group] / 2; + } else if ((value === 1) && (ElectrixTweaker.loopMoveSize[group] <= Math.pow(2, 5))) { + ElectrixTweaker.loopMoveSize[group] = ElectrixTweaker.loopMoveSize[group] * 2; + } + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].High.ring, ElectrixTweaker.encoderRingSteps[6 + Math.log(ElectrixTweaker.loopMoveSize[group]) / Math.log(2)]); + break; } } -} -ElectrixTweaker.highEncoderPress = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.highEncoderPress = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.topShift) { - if (control == ElectrixTweaker.encoders['[Channel1]']['High']['button']) { - engine.setValue('[Master]', 'headVolume', 1) + if (control === ElectrixTweaker.encoders["[Channel1]"].High.button) { + engine.setValue("[Master]", "headVolume", 1); } else { - engine.setValue('[Master]', 'volume', 1) + engine.setValue("[Master]", "volume", 1); } } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'filterHigh', 1) - } else { - engine.setValue(group, 'filterHighKill', ! engine.getValue(group, 'filterHighKill')) - } - break - case 'loop': - // What to do with this? - break + case "eq": + if (ElectrixTweaker.deckShift[group]) { + engine.setValue(group, "filterHigh", 1); + } else { + engine.setValue(group, "filterHighKill", ! engine.getValue(group, "filterHighKill")); + } + break; + case "loop": + // What to do with this? + break; } } } -} -ElectrixTweaker.midEncoder = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.midEncoder = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.topShift) { - if (control == ElectrixTweaker.encoders['[Channel1]']['Mid']['cc']) { - engine.setValue('[Master]', 'headMix', script.absoluteLin(value, -1, 1)) + if (control === ElectrixTweaker.encoders["[Channel1]"].Mid.cc) { + engine.setValue("[Master]", "headMix", script.absoluteLin(value, -1, 1)); } else { - engine.setValue('[Master]', 'balance', script.absoluteLin(value, -1, 1)) + engine.setValue("[Master]", "balance", script.absoluteLin(value, -1, 1)); } } else if (ElectrixTweaker.deckShift[group]) { - engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]) - if (value == 127) { - engine.setValue(group, 'beatjump_32_backward', 1) - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Mid']['ring'], 0) + engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]); + if (value === 127) { + engine.setValue(group, "beatjump_32_backward", 1); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Mid.ring, 0); } else { - engine.setValue(group, 'beatjump_32_forward', 1) - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Mid']['ring'], 127) + engine.setValue(group, "beatjump_32_forward", 1); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Mid.ring, 127); } - ElectrixTweaker.midEncoderLEDTimer[group] = engine.beginTimer(1000, 'midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["'+group+'"]["Mid"]["ring"], 64)', true) + ElectrixTweaker.midEncoderLEDTimer[group] = engine.beginTimer(1000, "midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[\""+group+"\"][\"Mid\"][\"ring\"], 64)", true); } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - engine.setValue(group, 'filterMid', script.absoluteNonLin(value, 0, 1, 4)) - break - case 'loop': - engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]) - if (value == 127) { - engine.setValue(group, 'loop_move_' + ElectrixTweaker.loopMoveSize[group] + '_backward', 1) - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Mid']['ring'], 0) + case "eq": + engine.setValue(group, "filterMid", script.absoluteNonLin(value, 0, 1, 4)); + break; + case "loop": + engine.stopTimer(ElectrixTweaker.midEncoderLEDTimer[group]); + if (value === 127) { + engine.setValue(group, "loop_move_" + ElectrixTweaker.loopMoveSize[group] + "_backward", 1); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Mid.ring, 0); - } else { - engine.setValue(group, 'loop_move_' + ElectrixTweaker.loopMoveSize[group] + '_forward', 1) - midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group]['Mid']['ring'], 127) - } - ElectrixTweaker.midEncoderLEDTimer[group] = engine.beginTimer(1000, 'midi.sendShortMsg(0xB0, ElectrixTweaker.encoders["'+group+'"]["Mid"]["ring"], 64)', true) - break + } else { + engine.setValue(group, "loop_move_" + ElectrixTweaker.loopMoveSize[group] + "_forward", 1); + midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[group].Mid.ring, 127); + } + ElectrixTweaker.midEncoderLEDTimer[group] = engine.beginTimer(1000, "midi.sendShortMsg(0xB0, ElectrixTweaker.encoders[\""+group+"\"][\"Mid\"][\"ring\"], 64)", true); + break; } } -} -ElectrixTweaker.midEncoderPress = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.midEncoderPress = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.topShift) { - if (control == ElectrixTweaker.encoders['[Channel1]']['Mid']['button']) { - engine.setValue('[Master]', 'headSplit', ! engine.getValue('[Master]', 'headSplit')) + if (control === ElectrixTweaker.encoders["[Channel1]"].Mid.button) { + engine.setValue("[Master]", "headSplit", ! engine.getValue("[Master]", "headSplit")); } else { - engine.setValue('[Master]', 'balance', 0) + engine.setValue("[Master]", "balance", 0); } } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'filterMid', 1) - } else { - engine.setValue(group, 'filterMidKill', ! engine.getValue(group, 'filterMidKill')) - } - break - case 'loop': + case "eq": + if (ElectrixTweaker.deckShift[group]) { + engine.setValue(group, "filterMid", 1); + } else { + engine.setValue(group, "filterMidKill", ! engine.getValue(group, "filterMidKill")); + } + break; + case "loop": // What to do with this? } } } -} -ElectrixTweaker.lowEncoder = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.lowEncoder = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.topShift) { - engine.setValue(group, 'pregain', script.absoluteNonLin(value, 0, 1, 4)) + engine.setValue(group, "pregain", script.absoluteNonLin(value, 0, 1, 4)); } else if (ElectrixTweaker.deckShift[group]) { - if (value == 1 && ElectrixTweaker.hotcuePage[group] < 3) { - ElectrixTweaker.connectHotcuePage(group, true) - ElectrixTweaker.hotcuePage[group]++ - ElectrixTweaker.connectHotcuePage(group) - } else if (value == 127 && ElectrixTweaker.hotcuePage[group] > 0) { - ElectrixTweaker.connectHotcuePage(group, true) - ElectrixTweaker.hotcuePage[group]-- - ElectrixTweaker.connectHotcuePage(group) + if (value === 1 && ElectrixTweaker.hotcuePage[group] < 3) { + ElectrixTweaker.connectHotcuePage(group, true); + ElectrixTweaker.hotcuePage[group]++; + ElectrixTweaker.connectHotcuePage(group); + } else if (value === 127 && ElectrixTweaker.hotcuePage[group] > 0) { + ElectrixTweaker.connectHotcuePage(group, true); + ElectrixTweaker.hotcuePage[group]--; + ElectrixTweaker.connectHotcuePage(group); } midi.sendShortMsg( 0xB0, - ElectrixTweaker.encoders[group]['Low']['ring'], + ElectrixTweaker.encoders[group].Low.ring, ElectrixTweaker.encoderRingStepsFill[ElectrixTweaker.hotcuePage[group]+1] - ) + ); } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - engine.setValue(group, 'filterLow', script.absoluteNonLin(value, 0, 1, 4)) - break - case 'loop': - if ((value == 127) && (ElectrixTweaker.loopSize[group] >= Math.pow(2, -5))) { - ElectrixTweaker.loopSize[group] = ElectrixTweaker.loopSize[group] / 2 - engine.setValue(group, 'loop_halve', 1) - engine.setValue(group, 'loop_halve', 0) - } else if ((value == 1) && (ElectrixTweaker.loopSize[group] <= Math.pow(2, 5))) { - ElectrixTweaker.loopSize[group] = ElectrixTweaker.loopSize[group] * 2 - engine.setValue(group, 'loop_double', 1) - engine.setValue(group, 'loop_double', 0) - } - midi.sendShortMsg( - 0xB0, - ElectrixTweaker.encoders[group]['Low']['ring'], - ElectrixTweaker.encoderRingSteps[ - 6 + Math.log(ElectrixTweaker.loopSize[group]) / Math.log(2) - ] - ) - break + case "eq": + engine.setValue(group, "filterLow", script.absoluteNonLin(value, 0, 1, 4)); + break; + case "loop": + if ((value === 127) && (ElectrixTweaker.loopSize[group] >= Math.pow(2, -5))) { + ElectrixTweaker.loopSize[group] = ElectrixTweaker.loopSize[group] / 2; + engine.setValue(group, "loop_halve", 1); + engine.setValue(group, "loop_halve", 0); + } else if ((value === 1) && (ElectrixTweaker.loopSize[group] <= Math.pow(2, 5))) { + ElectrixTweaker.loopSize[group] = ElectrixTweaker.loopSize[group] * 2; + engine.setValue(group, "loop_double", 1); + engine.setValue(group, "loop_double", 0); + } + midi.sendShortMsg( + 0xB0, + ElectrixTweaker.encoders[group].Low.ring, + ElectrixTweaker.encoderRingSteps[ + 6 + Math.log(ElectrixTweaker.loopSize[group]) / Math.log(2) + ] + ); + break; } } -} -ElectrixTweaker.lowEncoderPress = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.lowEncoderPress = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.topShift) { - engine.setValue(group, 'pregain', 1) + engine.setValue(group, "pregain", 1); } else { switch (ElectrixTweaker.mode[group]) { - case 'eq': - if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'filterLow', 1) - } else { - engine.setValue(group, 'filterLowKill', ! engine.getValue(group, 'filterLowKill')) - } - break - case 'loop': - if (ElectrixTweaker.slipMode[group]) { - engine.setValue(group, 'slip_enabled', ! engine.getValue(group, 'slip_enabled')) - } - if (engine.getValue(group, 'loop_enabled')) { - engine.setValue(group, 'reloop_exit', 1) - } else { - engine.setValue(group, 'beatloop_' + ElectrixTweaker.loopSize[group] + '_activate', 1) - } - break + case "eq": + if (ElectrixTweaker.deckShift[group]) { + engine.setValue(group, "filterLow", 1); + } else { + engine.setValue(group, "filterLowKill", ! engine.getValue(group, "filterLowKill")); + } + break; + case "loop": + if (ElectrixTweaker.slipMode[group]) { + engine.setValue(group, "slip_enabled", ! engine.getValue(group, "slip_enabled")); + } + if (engine.getValue(group, "loop_enabled")) { + engine.setValue(group, "reloop_exit", 1); + } else { + engine.setValue(group, "beatloop_" + ElectrixTweaker.loopSize[group] + "_activate", 1); + } + break; } } - } else if (ElectrixTweaker.mode[group] == 'loop' && (ElectrixTweaker.slipMode[group] || ElectrixTweaker.slipModeUnsetWhileLooping[group])) { - engine.setValue(group, 'slip_enabled', ! engine.getValue(group, 'slip_enabled')) - if (engine.getValue(group, 'loop_enabled')) { - engine.setValue(group, 'reloop_exit', 1) + } else if (ElectrixTweaker.mode[group] === "loop" && (ElectrixTweaker.slipMode[group] || ElectrixTweaker.slipModeUnsetWhileLooping[group])) { + engine.setValue(group, "slip_enabled", ! engine.getValue(group, "slip_enabled")); + if (engine.getValue(group, "loop_enabled")) { + engine.setValue(group, "reloop_exit", 1); } - ElectrixTweaker.slipModeUnsetWhileLooping[group] = false + ElectrixTweaker.slipModeUnsetWhileLooping[group] = false; } -} -ElectrixTweaker.loopButtonToggleLED = function (value, group, control) { - midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group]['Low']['button'], value * 127) -} +}; +ElectrixTweaker.loopButtonToggleLED = function(value, group, _control) { + midi.sendShortMsg(0x90, ElectrixTweaker.encoders[group].Low.button, value * 127); +}; -ElectrixTweaker.modeButton = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.modeButton = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { - ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], true) + ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group], true); switch (ElectrixTweaker.mode[group]) { - case 'eq': - ElectrixTweaker.mode[group] = 'loop' - break - case 'loop': - ElectrixTweaker.mode[group] = 'eq' - break + case "eq": + ElectrixTweaker.mode[group] = "loop"; + break; + case "loop": + ElectrixTweaker.mode[group] = "eq"; + break; } - ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group]) + ElectrixTweaker.connectEncoderMode(group, ElectrixTweaker.mode[group]); } -} +}; -ElectrixTweaker.fader = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.fader = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; // soft takeover. This is necessary for toggling between decks 1/3 or 2/4 // because the fader can't be moved to the new deck's value by this script - if (Math.abs(value - script.absoluteNonLinInverse(engine.getValue(group, 'volume'), 0, .25, 1)) < 30) { - engine.setValue(group, 'volume', script.absoluteNonLin(value, 0, .25, 1)) + if (Math.abs(value - script.absoluteNonLinInverse(engine.getValue(group, "volume"), 0, .25, 1)) < 30) { + engine.setValue(group, "volume", script.absoluteNonLin(value, 0, .25, 1)); } -} +}; -ElectrixTweaker.pflButton = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.pflButton = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'reloop_exit', 1) + engine.setValue(group, "reloop_exit", 1); } else { - engine.setValue(group, 'pfl', ! engine.getValue(group, 'pfl')) + engine.setValue(group, "pfl", ! engine.getValue(group, "pfl")); } } -} -ElectrixTweaker.pflButtonLED = function (value, group, control) { +}; +ElectrixTweaker.pflButtonLED = function(value, group, control) { midi.sendShortMsg( 0x90, ElectrixTweaker.buttons[group][control], - (value) ? ElectrixTweaker.colorCodes['green'] : ElectrixTweaker.colorCodes['off'] - ) -} + (value) ? ElectrixTweaker.colorCodes.green : ElectrixTweaker.colorCodes.off + ); +}; -ElectrixTweaker.playButton = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.playButton = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'cue_default', value) + engine.setValue(group, "cue_default", value); } else if (ElectrixTweaker.topShift) { - engine.setValue(group, 'cue_gotoandstop', 1) + engine.setValue(group, "cue_gotoandstop", 1); } else if (value) { if (ElectrixTweaker.hotcuesPressed[group]) { - ElectrixTweaker.playPressedWhileCueJuggling[group] = true + ElectrixTweaker.playPressedWhileCueJuggling[group] = true; } - engine.setValue(group, 'play', ! engine.getValue(group, 'play')) + engine.setValue(group, "play", ! engine.getValue(group, "play")); } -} -ElectrixTweaker.playButtonLED = function (value, group, control) { - if (control == 'cue_indicator' && value == 1) { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['play'], ElectrixTweaker.colorCodes['yellow']) +}; +ElectrixTweaker.playButtonLED = function(value, group, control) { + if (control === "cue_indicator" && value === 1) { + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].play, ElectrixTweaker.colorCodes.yellow); } else { - if (engine.getValue(group, 'play')) { + if (engine.getValue(group, "play")) { if ( - (control != 'playposition') // do not spam MIDI signals with each update in playposition while playing + (control !== "playposition") // do not spam MIDI signals with each update in playposition while playing && ( (! ElectrixTweaker.hotcuesPressed[group]) || ElectrixTweaker.playPressedWhileCueJuggling[group] ) ) { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['play'], ElectrixTweaker.colorCodes['green']) + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].play, ElectrixTweaker.colorCodes.green); } - } else if (engine.getValue(group, 'track_samples')) { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['play'], ElectrixTweaker.colorCodes['red']) + } else if (engine.getValue(group, "track_samples")) { + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].play, ElectrixTweaker.colorCodes.red); } else { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['play'], ElectrixTweaker.colorCodes['off']) + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].play, ElectrixTweaker.colorCodes.off); } } -} +}; //===================================================================== BUTTON GRID ========================================================= -ElectrixTweaker.hotcue = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] - var row = (control < ElectrixTweaker.buttons[group]['hotcues'][1][0]) ? 0 : 1 - var cueButton = 4 + row*4 - (ElectrixTweaker.buttons[group]['hotcues'][row][3] - control) - var cue = cueButton + (8 * ElectrixTweaker.hotcuePage[group]) +ElectrixTweaker.hotcue = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; + const row = (control < ElectrixTweaker.buttons[group].hotcues[1][0]) ? 0 : 1; + const cueButton = 4 + row*4 - (ElectrixTweaker.buttons[group].hotcues[row][3] - control); + const cue = cueButton + (8 * ElectrixTweaker.hotcuePage[group]); if (value) { - if (engine.getValue(group, 'hotcue_'+cue+'_enabled')) { + if (engine.getValue(group, "hotcue_"+cue+"_enabled")) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'hotcue_'+cue+'_set', 1) + engine.setValue(group, "hotcue_"+cue+"_set", 1); } else if (ElectrixTweaker.topShift) { - engine.setValue(group, 'hotcue_'+cue+'_clear', 1) + engine.setValue(group, "hotcue_"+cue+"_clear", 1); } else { if (ElectrixTweaker.slipMode[group]) { - if (engine.getValue(group, 'play') && (! ElectrixTweaker.hotcuesPressed[group])) { - engine.setValue(group, 'slip_enabled', 1) + if (engine.getValue(group, "play") && (! ElectrixTweaker.hotcuesPressed[group])) { + engine.setValue(group, "slip_enabled", 1); } - engine.setValue(group, 'hotcue_'+cue+'_activate', 1) - ElectrixTweaker.hotcuesPressed[group]++ + engine.setValue(group, "hotcue_"+cue+"_activate", 1); + ElectrixTweaker.hotcuesPressed[group]++; } else { - engine.setValue(group, 'hotcue_'+cue+'_goto', 1) + engine.setValue(group, "hotcue_"+cue+"_goto", 1); } } } else { - engine.setValue(group, 'hotcue_'+cue+'_set', 1) + engine.setValue(group, "hotcue_"+cue+"_set", 1); } } else { if (ElectrixTweaker.hotcuesPressed[group]) { // do not go below 0 - ElectrixTweaker.hotcuesPressed[group]-- + ElectrixTweaker.hotcuesPressed[group]--; } - engine.setValue(group, 'hotcue_'+cue+'_activate', 0) + engine.setValue(group, "hotcue_"+cue+"_activate", 0); if (! ElectrixTweaker.hotcuesPressed[group]) { - ElectrixTweaker.playPressedWhileCueJuggling[group] = false - engine.setValue(group, 'slip_enabled', 0) + ElectrixTweaker.playPressedWhileCueJuggling[group] = false; + engine.setValue(group, "slip_enabled", 0); } } -} -ElectrixTweaker.hotcueLED = function (value, group, control) { - var cue = parseInt(control.split('_')[1]) - (8 * ElectrixTweaker.hotcuePage[group]) - var row = (cue <= 4) ? 0 : 1 +}; +ElectrixTweaker.hotcueLED = function(value, group, control) { + const cue = parseInt(control.split("_")[1]) - (8 * ElectrixTweaker.hotcuePage[group]); + const row = (cue <= 4) ? 0 : 1; midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['hotcues'][row][cue - 1 - 4*row], + ElectrixTweaker.buttons[group].hotcues[row][cue - 1 - 4*row], value * ElectrixTweaker.hotcueColors[ElectrixTweaker.hotcuePage[group]] - ) -} + ); +}; -ElectrixTweaker.slipButton = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.slipButton = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'loop_in', 1) + engine.setValue(group, "loop_in", 1); } else { if (ElectrixTweaker.slipMode[group]) { - if (ElectrixTweaker.hotcuesPressed[group] && ! engine.getValue(group, 'slip_enabled')) { - engine.setValue(group, 'play', 0) + if (ElectrixTweaker.hotcuesPressed[group] && ! engine.getValue(group, "slip_enabled")) { + engine.setValue(group, "play", 0); } - if (engine.getValue(group, 'loop_enabled')) { - ElectrixTweaker.slipModeUnsetWhileLooping[group] = true + if (engine.getValue(group, "loop_enabled")) { + ElectrixTweaker.slipModeUnsetWhileLooping[group] = true; } //engine.setValue(group, 'slip_cancel', 1) - ElectrixTweaker.hotcuesPressed[group] = 0 + ElectrixTweaker.hotcuesPressed[group] = 0; } - ElectrixTweaker.slipMode[group] = ! ElectrixTweaker.slipMode[group] + ElectrixTweaker.slipMode[group] = ! ElectrixTweaker.slipMode[group]; midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['slip'], - ElectrixTweaker.slipMode[group] ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) + ElectrixTweaker.buttons[group].slip, + ElectrixTweaker.slipMode[group] ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); } } -} +}; -ElectrixTweaker.deckToggle = function (channel, control, value, status, group) { +ElectrixTweaker.deckToggle = function(channel, control, value, status, group) { if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(ElectrixTweaker.deck[group], 'loop_out', 1) + engine.setValue(ElectrixTweaker.deck[group], "loop_out", 1); } else { - var deckNumber = parseInt( - ElectrixTweaker.channelRegEx.exec( - ElectrixTweaker.deck[group] - )[1] - ) + let deckNumber = parseInt( + ElectrixTweaker.channelRegEx.exec( + ElectrixTweaker.deck[group] + )[1] + ); if (deckNumber <= 2) { - deckNumber += 2 + deckNumber += 2; } else { - deckNumber -= 2 + deckNumber -= 2; } - ElectrixTweaker.deck[group] = '[Channel' + deckNumber + ']' - ElectrixTweaker.initDeck(ElectrixTweaker.deck[group]) + ElectrixTweaker.deck[group] = "[Channel" + deckNumber + "]"; + ElectrixTweaker.initDeck(ElectrixTweaker.deck[group]); } } -} +}; -ElectrixTweaker.sync = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.sync = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'rate', 0) + engine.setValue(group, "rate", 0); } else { - engine.setValue(group, 'sync_enabled', ! engine.getValue(group, 'sync_enabled')) + engine.setValue(group, "sync_enabled", ! engine.getValue(group, "sync_enabled")); } } -} -ElectrixTweaker.syncLED = function (value, group, control) { +}; +ElectrixTweaker.syncLED = function(value, group, _control) { midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['sync'], - (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) -} + ElectrixTweaker.buttons[group].sync, + (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); +}; -ElectrixTweaker.key = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.key = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.deckShift[group]) { - if (engine.getValue(group, 'file_key') != engine.getValue(group, 'key')) { - engine.setValue(group, 'reset_key', 1) + if (engine.getValue(group, "file_key") !== engine.getValue(group, "key")) { + engine.setValue(group, "reset_key", 1); } else { - engine.setValue(group, 'sync_key', 1) + engine.setValue(group, "sync_key", 1); } } else { - engine.setValue(group, 'keylock', ! engine.getValue(group, 'keylock')) + engine.setValue(group, "keylock", ! engine.getValue(group, "keylock")); } } -} -ElectrixTweaker.keylockLED = function (value, group, control) { +}; +ElectrixTweaker.keylockLED = function(value, group, _control) { midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['key'], - (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) -} + ElectrixTweaker.buttons[group].key, + (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); +}; -ElectrixTweaker.quantize = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.quantize = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'beats_translate_curpos', 1) + engine.setValue(group, "beats_translate_curpos", 1); } else { - engine.setValue(group, 'quantize', ! engine.getValue(group, 'quantize')) + engine.setValue(group, "quantize", ! engine.getValue(group, "quantize")); } } -} -ElectrixTweaker.quantizeLED = function (value, group, control) { +}; +ElectrixTweaker.quantizeLED = function(value, group, _control) { midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['quantize'], - (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes['off'] - ) + ElectrixTweaker.buttons[group].quantize, + (value) ? ElectrixTweaker.deckColor[group] : ElectrixTweaker.colorCodes.off + ); if (! ElectrixTweaker.vinylMode[group]) { midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['back'], - (value) ? ElectrixTweaker.colorCodes['white'] : ElectrixTweaker.colorCodes['green'] - ) + ElectrixTweaker.buttons[group].back, + (value) ? ElectrixTweaker.colorCodes.white : ElectrixTweaker.colorCodes.green + ); midi.sendShortMsg( 0x90, - ElectrixTweaker.buttons[group]['forward'], - (value) ? ElectrixTweaker.colorCodes['white'] : ElectrixTweaker.colorCodes['green'] - ) + ElectrixTweaker.buttons[group].forward, + (value) ? ElectrixTweaker.colorCodes.white : ElectrixTweaker.colorCodes.green + ); } -} +}; -ElectrixTweaker.vinylModeLED = function (value, group, control) { - var color - switch (engine.getValue(group, 'vinylcontrol_mode')) { - // absolute mode - case 0: color = 'off'; break +ElectrixTweaker.vinylModeLED = function(value, group, _control) { + let color; + switch (engine.getValue(group, "vinylcontrol_mode")) { + // absolute mode + case 0: color = "off"; break; // relative mode - case 1: - switch (engine.getValue(group, 'vinylcontrol_cueing')) { - case 0: color = 'white'; break - case 1: color = 'yellow'; break - case 2: color = 'green'; break - } - break + case 1: + switch (engine.getValue(group, "vinylcontrol_cueing")) { + case 0: color = "white"; break; + case 1: color = "yellow"; break; + case 2: color = "green"; break; + } + break; // constant mode - case 2: color = 'red'; break + case 2: color = "red"; break; } - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['forward'], ElectrixTweaker.colorCodes[color]) -} -ElectrixTweaker.vinylStatusLED = function (value, group, control) { - if (engine.getValue(group, 'passthrough')) { - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['back'], ElectrixTweaker.colorCodes['white']) + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].forward, ElectrixTweaker.colorCodes[color]); +}; +ElectrixTweaker.vinylStatusLED = function(value, group, _control) { + if (engine.getValue(group, "passthrough")) { + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].back, ElectrixTweaker.colorCodes.white); } else { - var color - switch (engine.getValue(group, 'vinylcontrol_status')) { - case 0: color = 'off'; break - case 1: color = 'green'; break - case 2: color = 'yellow'; break - case 3: color = 'red'; break + let color; + switch (engine.getValue(group, "vinylcontrol_status")) { + case 0: color = "off"; break; + case 1: color = "green"; break; + case 2: color = "yellow"; break; + case 3: color = "red"; break; } - midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group]['back'], ElectrixTweaker.colorCodes[color]) + midi.sendShortMsg(0x90, ElectrixTweaker.buttons[group].back, ElectrixTweaker.colorCodes[color]); } -} +}; -ElectrixTweaker.forward = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +ElectrixTweaker.forward = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.vinylMode[group]) { if (value) { - switch (engine.getValue(group, 'vinylcontrol_mode')) { - // absolute mode - case 0: engine.setValue(group, 'vinylcontrol_mode', 1); break + switch (engine.getValue(group, "vinylcontrol_mode")) { + // absolute mode + case 0: engine.setValue(group, "vinylcontrol_mode", 1); break; // relative mode - case 1: - if (engine.getValue(group, 'play') && ! ElectrixTweaker.shift) { - switch (engine.getValue(group, 'vinylcontrol_cueing')) { - case 0: engine.setValue(group, 'vinylcontrol_cueing', 1); break - case 1: engine.setValue(group, 'vinylcontrol_cueing', 2); break - case 2: engine.setValue(group, 'vinylcontrol_cueing', 0); break - } - } else { - engine.setValue(group, 'vinylcontrol_mode', 2) + case 1: + if (engine.getValue(group, "play") && ! ElectrixTweaker.shift) { + switch (engine.getValue(group, "vinylcontrol_cueing")) { + case 0: engine.setValue(group, "vinylcontrol_cueing", 1); break; + case 1: engine.setValue(group, "vinylcontrol_cueing", 2); break; + case 2: engine.setValue(group, "vinylcontrol_cueing", 0); break; } - break + } else { + engine.setValue(group, "vinylcontrol_mode", 2); + } + break; // constant mode - case 2: engine.setValue(group, 'vinylcontrol_mode', 0); break + case 2: engine.setValue(group, "vinylcontrol_mode", 0); break; } } } else { - if (engine.getValue(group, 'quantize')) { + if (engine.getValue(group, "quantize")) { if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'beatjump_1_forward', 1) + engine.setValue(group, "beatjump_1_forward", 1); } else { - engine.setValue(group, 'beatjump_4_forward', 1) + engine.setValue(group, "beatjump_4_forward", 1); } } } else { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'rate_temp_up', value / 127) + engine.setValue(group, "rate_temp_up", value / 127); } else { - engine.setValue(group, 'fwd', value) + engine.setValue(group, "fwd", value); } } } -} -ElectrixTweaker.back = function (channel, control, value, status, group) { - group = ElectrixTweaker.deck[group] +}; +ElectrixTweaker.back = function(channel, control, value, status, group) { + group = ElectrixTweaker.deck[group]; if (ElectrixTweaker.vinylMode[group]) { if (value) { - if (ElectrixTweaker.deckShift[group] || engine.getValue(group, 'passthrough')) { - engine.setValue(group, 'passthrough', ! engine.getValue(group, 'passthrough')) + if (ElectrixTweaker.deckShift[group] || engine.getValue(group, "passthrough")) { + engine.setValue(group, "passthrough", ! engine.getValue(group, "passthrough")); } else { - engine.setValue(group, 'vinylcontrol_enabled', ! engine.getValue(group, 'vinylcontrol_enabled')) + engine.setValue(group, "vinylcontrol_enabled", ! engine.getValue(group, "vinylcontrol_enabled")); } } } else { - if (engine.getValue(group, 'quantize')) { + if (engine.getValue(group, "quantize")) { if (value) { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'beatjump_1_backward', 1) + engine.setValue(group, "beatjump_1_backward", 1); } else { - engine.setValue(group, 'beatjump_4_backward', 1) + engine.setValue(group, "beatjump_4_backward", 1); } } } else { if (ElectrixTweaker.deckShift[group]) { - engine.setValue(group, 'rate_temp_down', value / 127) + engine.setValue(group, "rate_temp_down", value / 127); } else { - engine.setValue(group, 'back', value) + engine.setValue(group, "back", value); } } } -} +}; diff --git a/res/controllers/Reloop-Beatmix-2-4-scripts.js b/res/controllers/Reloop-Beatmix-2-4-scripts.js index 655dc003b6a..96ab2e68f0e 100644 --- a/res/controllers/Reloop-Beatmix-2-4-scripts.js +++ b/res/controllers/Reloop-Beatmix-2-4-scripts.js @@ -8,8 +8,8 @@ * You can adjust these values to suit your needs by setting the two variables below. * Set them to -1 if you want to completely disable flashing at the end of track. **************************/ - var JogFlashWarningTime = 30; // number of seconds to slowly blink at the end of track - var JogFlashCriticalTime = 15; // number of seconds to quickly blink at the end of track +const JogFlashWarningTime = 30; // number of seconds to slowly blink at the end of track +const JogFlashCriticalTime = 15; // number of seconds to quickly blink at the end of track /************************ GPL v2 licence ***************************** @@ -58,76 +58,73 @@ //////////////////////////////////////////////////////////////////////// // JSHint configuration // //////////////////////////////////////////////////////////////////////// -/* global engine */ -/* global script */ /* global print */ -/* global midi */ //////////////////////////////////////////////////////////////////////// // Global variables and declarations. // ======================================================== var ReloopBeatmix24 = {}; -var RateRangeArray = [0.08, 0.10, 0.12, 0.16]; +const RateRangeArray = [0.08, 0.10, 0.12, 0.16]; // Timers & long press state -var jogWheelTimers = []; -var loadButtonTimers = []; -var loadButtonLongPressed = []; -var FxModeTimers = []; -var FxModeLongPressed = []; +const jogWheelTimers = []; +const loadButtonTimers = []; +const loadButtonLongPressed = []; +const FxModeTimers = []; +const FxModeLongPressed = []; // A variable to store previous value of some connectControls -var previousValue = []; +const previousValue = []; // Trax mode // 1 for playlist mode // 2 for track mode // 3 for preview mode -var traxMode = 2; +let traxMode = 2; // Effects mode // 1 for single effect mode (1 effect controlled in each EffectUnit) // 2 for multi-effect mode (3 effects controlled in each EffectUnit) // SHIFT + long press on pitchbend +/- to change mode -var FxMode = 1; // Single effect mode by default +let FxMode = 1; // Single effect mode by default // Jog Led variables // set JogFlashWarningTime and JogFlashCriticalTime to -1 to disable jog wheel flash -var JogRPM = 33.0 + 1/3, // Jog Wheel simulates a 33.3RPM turntable - RoundTripTime = 60.0 / JogRPM, // Time in seconds for a complete turn - JogLedNumber = 16, // number of leds (sections) on the jog wheel - JogBaseLed = 0x3f, // Midino of last led (we count backward to turn in the right side) - JogFlashWarningInterval = 400, // number of ms to wait when flashing slowly - JogFlashCriticalInterval = 200; // number of ms to wait when flashing quickly +const JogRPM = 33.0 + 1/3; // Jog Wheel simulates a 33.3RPM turntable +const RoundTripTime = 60.0 / JogRPM; // Time in seconds for a complete turn +const JogLedNumber = 16; // number of leds (sections) on the jog wheel +const JogBaseLed = 0x3f; // Midino of last led (we count backward to turn in the right side) +const JogFlashWarningInterval = 400; // number of ms to wait when flashing slowly +const JogFlashCriticalInterval = 200; // number of ms to wait when flashing quickly -var JogLedLit = []; -var channelPlaying = []; // Keeping track of channel playing -var JogBlinking = []; +const JogLedLit = []; +const channelPlaying = []; // Keeping track of channel playing +const JogBlinking = []; // Buttons and Led Variables -var ON = 0x7F, - OFF = 0x00, - RED = 0x7F, - BLUE = 0x55, - VIOLET = 0x2A, - SHIFT = 0x40, - DOWN = 0x7F, - UP = 0x00; +const ON = 0x7F; +const OFF = 0x00; +const RED = 0x7F; +//const BLUE = 0x55; +const VIOLET = 0x2A; +const SHIFT = 0x40; +const DOWN = 0x7F; +const UP = 0x00; // The SysEx message to send to the controller to force the midi controller // to send the status of every item on the control surface. -var ControllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7]; +const ControllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7]; // Some useful regex -var channelRegEx = /\[Channel(\d+)\]/; -var samplerRegEx = /\[Sampler(\d+)\]/; +const channelRegEx = /\[Channel(\d+)\]/; +const samplerRegEx = /\[Sampler(\d+)\]/; // Initialise and shutdown stuff. // ======================================================== ReloopBeatmix24.TurnLEDsOff = function() { // Turn all LEDS off - var i, j; + let i, j; for (i = 0x91; i <= 0x94; i++) { // 4 decks // Pads @@ -156,10 +153,10 @@ ReloopBeatmix24.TurnLEDsOff = function() { }; ReloopBeatmix24.connectControls = function() { - var group; + let group; // Channels controls - for (var i = 1; i <= 4; i++) { + for (let i = 1; i <= 4; i++) { group = "[Channel" + i + "]"; engine.connectControl(group, "track_samples", "ReloopBeatmix24.deckLoaded"); @@ -174,12 +171,12 @@ ReloopBeatmix24.connectControls = function() { "group_" + group + "_enable", 0); engine.setValue("[EffectRack1_EffectUnit2]", "group_" + group + "_enable", 0); - channelPlaying[group] = engine.getValue(group, "play") ? true : false; + channelPlaying[group] = !!engine.getValue(group, "play"); JogBlinking[group] = false; } // Samplers controls - for (i = 1; i <= 8; i++) { + for (let i = 1; i <= 8; i++) { group = "[Sampler" + i + "]"; engine.connectControl(group, "track_samples", "ReloopBeatmix24.deckLoaded"); @@ -192,12 +189,12 @@ ReloopBeatmix24.connectControls = function() { engine.setValue("[EffectRack1_EffectUnit2]", "group_[Master]_enable", 0); }; -ReloopBeatmix24.init = function(id, debug) { +ReloopBeatmix24.init = function(id, _debug) { ReloopBeatmix24.id = id; ReloopBeatmix24.TurnLEDsOff(); // Turn off all LEDs ReloopBeatmix24.connectControls(false); - for (var i = 1; i <= 4; i++) { + for (let i = 1; i <= 4; i++) { engine.trigger("[Channel" + i + "]", "loop_end_position"); } @@ -217,8 +214,8 @@ ReloopBeatmix24.shutdown = function() { // Button functions. // ======================================================== ReloopBeatmix24.GetNextRange = function(previous) { - var len = RateRangeArray.length; - var pos = RateRangeArray.indexOf(previous); + const len = RateRangeArray.length; + const pos = RateRangeArray.indexOf(previous); // If 'previous' is not found in the array, pos == -1 and (pos+1) == 0, // so this function will return the first element return RateRangeArray[(pos + 1) % len]; @@ -226,7 +223,7 @@ ReloopBeatmix24.GetNextRange = function(previous) { ReloopBeatmix24.Range = function(channel, control, value, status, group) { if (value === DOWN) { - var oldvalue = engine.getValue(group, "rateRange"); + const oldvalue = engine.getValue(group, "rateRange"); engine.setValue(group, "rateRange", ReloopBeatmix24.GetNextRange( oldvalue)); engine.softTakeoverIgnoreNextValue(group, "rate"); @@ -255,70 +252,69 @@ ReloopBeatmix24.PitchSlider = function(channel, control, value, status, group) { // ======================================================== ReloopBeatmix24.traxSelect = function(value, step) { switch (traxMode) { - case 1: // Playlist mode - var i, j; - for (i = 0; i < Math.abs(value); i++) { - for (j = 0; j < step; j++) { - if (value < 0) { - engine.setValue("[Playlist]", "SelectPrevPlaylist", - true); - } else { - engine.setValue("[Playlist]", "SelectNextPlaylist", - true); - } + case 1: // Playlist mode + for (let i = 0; i < Math.abs(value); i++) { + for (let j = 0; j < step; j++) { + if (value < 0) { + engine.setValue("[Playlist]", "SelectPrevPlaylist", + true); + } else { + engine.setValue("[Playlist]", "SelectNextPlaylist", + true); } } - break; - case 2: // Track mode - engine.setValue("[Playlist]", "SelectTrackKnob", value * step); - break; - case 3: // Preview mode - engine.setValue("[PreviewDeck1]", "playposition", Math.max(0, - Math.min(1, engine.getValue("[PreviewDeck1]", - "playposition") + 0.02 * value * step))); - break; + } + break; + case 2: // Track mode + engine.setValue("[Playlist]", "SelectTrackKnob", value * step); + break; + case 3: // Preview mode + engine.setValue("[PreviewDeck1]", "playposition", Math.max(0, + Math.min(1, engine.getValue("[PreviewDeck1]", + "playposition") + 0.02 * value * step))); + break; } }; -ReloopBeatmix24.TraxTurn = function(channel, control, value, status, group) { +ReloopBeatmix24.TraxTurn = function(channel, control, value, _status, _group) { ReloopBeatmix24.traxSelect(value - 0x40, 1); }; -ReloopBeatmix24.ShiftTraxTurn = function(channel, control, value, status, group) { +ReloopBeatmix24.ShiftTraxTurn = function(channel, control, value, _status, _group) { ReloopBeatmix24.traxSelect(value - 0x40, 10); }; -ReloopBeatmix24.TraxPush = function(channel, control, value, status, group) { +ReloopBeatmix24.TraxPush = function(channel, control, value, _status, _group) { switch (traxMode) { + case 1: // Playlist mode + engine.setValue("[Playlist]", "ToggleSelectedSidebarItem", + value); + break; + case 2: // Track mode + engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", + value); + traxMode = 3; + break; + case 3: // Preview mode + if (value === DOWN) { + script.toggleControl("[PreviewDeck1]", "play"); + } + break; + } +}; + +ReloopBeatmix24.BackButton = function(channel, control, value, _status, _group) { + if (value === DOWN) { + switch (traxMode) { case 1: // Playlist mode - engine.setValue("[Playlist]", "ToggleSelectedSidebarItem", - value); + traxMode = 2; // Switch to track mode break; case 2: // Track mode - engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", - value); - traxMode = 3; + traxMode = 1; // Switch to playlist mode break; case 3: // Preview mode - if (value == DOWN) { - script.toggleControl("[PreviewDeck1]", "play"); - } + traxMode = 2; // Switch to track mode break; - } -}; - -ReloopBeatmix24.BackButton = function(channel, control, value, status, group) { - if (value === DOWN) { - switch (traxMode) { - case 1: // Playlist mode - traxMode = 2; // Switch to track mode - break; - case 2: // Track mode - traxMode = 1; // Switch to playlist mode - break; - case 3: // Preview mode - traxMode = 2; // Switch to track mode - break; } } }; @@ -379,8 +375,8 @@ ReloopBeatmix24.ShiftSamplerPad = function(channel, control, value, status, } }; -ReloopBeatmix24.SamplerVol = function(channel, control, value, status, group) { - for (var i = 1; i <= engine.getValue("[Master]", "num_samplers"); i++) { +ReloopBeatmix24.SamplerVol = function(channel, control, value, _status, _group) { + for (let i = 1; i <= engine.getValue("[Master]", "num_samplers"); i++) { engine.setValue("[Sampler" + i + "]", "volume", value / 127.0); } }; @@ -389,10 +385,10 @@ ReloopBeatmix24.SamplerVol = function(channel, control, value, status, group) { // ======================================================== ReloopBeatmix24.WheelTouch = function(channel, control, value, status, group) { - var deck = parseInt(group.substr(8, 1), 10); + const deck = parseInt(group.substr(8, 1), 10); if (value === DOWN) { - var alpha = 1.0 / 8; - var beta = alpha / 32; + const alpha = 1.0 / 8; + const beta = alpha / 32; engine.scratchEnable(deck, 800, JogRPM, alpha, beta); } else { engine.scratchDisable(deck); @@ -400,33 +396,34 @@ ReloopBeatmix24.WheelTouch = function(channel, control, value, status, group) { }; ReloopBeatmix24.WheelTurn = function(channel, control, value, status, group) { - var newValue = value - 64; - var deck = parseInt(group.substr(8, 1), 10); + const newValue = value - 64; + const deck = parseInt(group.substr(8, 1), 10); // In either case, register the movement if (engine.isScratching(deck)) { engine.scratchTick(deck, newValue); // Scratch! } else { - engine.setValue(group, 'jog', newValue / 5); // Pitch bend + engine.setValue(group, "jog", newValue / 5); // Pitch bend } }; // Led Feedback functions // ======================================================== ReloopBeatmix24.AllJogLEDsToggle = function(deck, state, step) { - step = typeof step !== 'undefined' ? step : 1; // default value - for (var j = 0x30; j <= 0x3F; j += step) { + step = typeof step !== "undefined" ? step : 1; // default value + for (let j = 0x30; j <= 0x3F; j += step) { midi.sendShortMsg(deck, j, state); } }; -ReloopBeatmix24.deckLoaded = function(value, group, control) { - var i; +ReloopBeatmix24.deckLoaded = function(value, group, _control) { + let i; switch (group.substr(1, 7)) { - case "Channel": - var channelChan = parseInt(channelRegEx.exec(group)[1]); + case "Channel": + { + const channelChan = parseInt(channelRegEx.exec(group)[1]); if (channelChan <= 4) { - // shut down load button + // shut down load button midi.sendShortMsg(0x90 + channelChan, 0x50, value ? ON : OFF); @@ -438,19 +435,21 @@ ReloopBeatmix24.deckLoaded = function(value, group, control) { delete JogLedLit[group]; } } - break; - case "Sampler": - var samplerChan = parseInt(samplerRegEx.exec(group)[1]); + } + break; + case "Sampler": + { + const samplerChan = parseInt(samplerRegEx.exec(group)[1]); if (samplerChan <= 8) { // We only handle 8 samplers (1 per pad) for (i = 0x91; i <= 0x94; i++) { - // PAD1 Mode A + // PAD1 Mode A midi.sendShortMsg(i, 0x08 - 1 + samplerChan, value ? RED : OFF); // SHIFT+PAD1 Mode A midi.sendShortMsg(i, 0x48 - 1 + samplerChan, value ? RED : OFF); if (samplerChan <= 4) { // Handle first 4 samplers in split mode - // PAD5 Mode A+B (sampler 1 in split mode) + // PAD5 Mode A+B (sampler 1 in split mode) midi.sendShortMsg(i, 0x14 - 1 + samplerChan, value ? RED : OFF); // SHIFT+PAD5 Mode A+B (sampler 1 in split mode) @@ -459,14 +458,15 @@ ReloopBeatmix24.deckLoaded = function(value, group, control) { } } } - break; + } + break; } }; -ReloopBeatmix24.SamplerPlay = function(value, group, control) { - var samplerChan = parseInt(samplerRegEx.exec(group)[1]); +ReloopBeatmix24.SamplerPlay = function(value, group, _control) { + const samplerChan = parseInt(samplerRegEx.exec(group)[1]); if (samplerChan <= 8) { // We only handle 8 samplers (1 per pad) - var ledColor; + let ledColor; if (value) { ledColor = VIOLET; } else { @@ -475,7 +475,7 @@ ReloopBeatmix24.SamplerPlay = function(value, group, control) { // We need to switch off pad lights before changing color otherwise // VIOLET to RED transition does not work well. (???) - for (var i = 0x91; i <= 0x94; i++) { + for (let i = 0x91; i <= 0x94; i++) { // PAD1 Mode A midi.sendShortMsg(i, 0x08 - 1 + samplerChan, OFF); midi.sendShortMsg(i, 0x08 - 1 + samplerChan, ledColor); @@ -494,15 +494,15 @@ ReloopBeatmix24.SamplerPlay = function(value, group, control) { } }; -ReloopBeatmix24.loopDefined = function(value, group, control) { - var channelChan = parseInt(channelRegEx.exec(group)[1]); +ReloopBeatmix24.loopDefined = function(value, group, _control) { + const channelChan = parseInt(channelRegEx.exec(group)[1]); if (channelChan <= 4) { midi.sendShortMsg(0x90 + channelChan, 0x44, value < 0 ? OFF : VIOLET); } }; -ReloopBeatmix24.ChannelPlay = function(value, group, control) { +ReloopBeatmix24.ChannelPlay = function(value, group, _control) { // Keep track of the playing state of each channel to avoid // calling engine.getValue(group, "play") too often if (value) { @@ -513,7 +513,7 @@ ReloopBeatmix24.ChannelPlay = function(value, group, control) { engine.stopTimer(jogWheelTimers[group]); delete jogWheelTimers[group]; JogBlinking[group] = false; - var channelChan = parseInt(channelRegEx.exec(group)[1]); + const channelChan = parseInt(channelRegEx.exec(group)[1]); ReloopBeatmix24.AllJogLEDsToggle(0x90 + channelChan, OFF, 2); engine.trigger(group, "playposition"); // light up jog position led } @@ -524,12 +524,11 @@ ReloopBeatmix24.ChannelPlay = function(value, group, control) { // This function will light jog led and is connected to playposition, // so value here represent the position in the track in the range [-0.14..1.14] // (0 = beginning, 1 = end) -ReloopBeatmix24.JogLed = function(value, group, control) { - +ReloopBeatmix24.JogLed = function(value, group, _control) { // time computation - var trackDuration = engine.getValue(group, "duration"); - var timeLeft = trackDuration * (1.0 - value); - var channelChan = parseInt(channelRegEx.exec(group)[1]); + const trackDuration = engine.getValue(group, "duration"); + const timeLeft = trackDuration * (1.0 - value); + const channelChan = parseInt(channelRegEx.exec(group)[1]); // Start JogWheel blinking if playing and time left < warning time if (channelPlaying[group] && timeLeft <= JogFlashWarningTime) { @@ -554,10 +553,10 @@ ReloopBeatmix24.JogLed = function(value, group, control) { return; } - var timePosition = trackDuration * value; - var rotationNumber = timePosition / RoundTripTime; // number of turn since beginning - var positionInCircle = rotationNumber - Math.floor(rotationNumber); // decimal part - var ledToLight = Math.round(positionInCircle * JogLedNumber); + const timePosition = trackDuration * value; + const rotationNumber = timePosition / RoundTripTime; // number of turn since beginning + const positionInCircle = rotationNumber - Math.floor(rotationNumber); // decimal part + const ledToLight = Math.round(positionInCircle * JogLedNumber); if (JogLedLit[group] === ledToLight) { // exit if there is no change return; } @@ -572,17 +571,17 @@ ReloopBeatmix24.JogLed = function(value, group, control) { }; ReloopBeatmix24.jogLedFlash = function(group, state) { - var chan = parseInt(group.substr(8, 1), 10); + const chan = parseInt(group.substr(8, 1), 10); // toggle all jog leds ReloopBeatmix24.AllJogLEDsToggle(0x90 + chan, state ? OFF : ON, 2); - var timeleft = engine.getValue(group, "duration") * (1.0 - engine.getValue( + const timeleft = engine.getValue(group, "duration") * (1.0 - engine.getValue( group, "playposition")); if (timeleft < JogFlashWarningTime) { // Set timer for leds shut off - var nextTime = (timeleft < JogFlashCriticalTime ? + const nextTime = (timeleft < JogFlashCriticalTime ? JogFlashCriticalInterval : JogFlashWarningInterval); jogWheelTimers[group] = engine.beginTimer(nextTime, "ReloopBeatmix24.jogLedFlash(\"" + group + "\", " + @@ -599,8 +598,8 @@ ReloopBeatmix24.jogLedFlash = function(group, state) { // Effects functions // ======================================================== ReloopBeatmix24.FxModeLedFlash = function(step, mode) { - var i; - var ledValue = (step % 2) ? ON : OFF; + let i; + const ledValue = (step % 2) ? ON : OFF; if (step >= 7) { for (i = 1; i <= 4; i++) { // engine.trigger should be sufficient, but... @@ -608,8 +607,8 @@ ReloopBeatmix24.FxModeLedFlash = function(step, mode) { i + "]_enable"); engine.trigger("[EffectRack1_EffectUnit2]", "group_[Channel" + i + "]_enable"); - // Workaround for bug #1607277 as engine.trigger doesn't work well - var newValue = engine.getValue("[EffectRack1_EffectUnit1]", + // Workaround for issue #8620 as engine.trigger doesn't work well + let newValue = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel" + i + "]_enable"); midi.sendShortMsg(0x90 + i, 0x25, newValue ? ON : OFF); midi.sendShortMsg(0x90 + i, 0x25 + SHIFT, newValue ? ON : OFF); @@ -633,7 +632,7 @@ ReloopBeatmix24.FxModeCallback = function(group, mode) { FxModeLongPressed[group] = true; delete FxModeTimers[group]; // give some visual feedback (blink led 3 times) - for (var i = 0x91; i <= 0x94; i++) { + for (let i = 0x91; i <= 0x94; i++) { midi.sendShortMsg(i, 0x26 - mode, OFF); midi.sendShortMsg(i, 0x26 + SHIFT - mode, OFF); } @@ -646,7 +645,7 @@ ReloopBeatmix24.FxModeCallback = function(group, mode) { // It is mapped to SHIFT + PITCHBEND+/- (FX1 and FX2) ReloopBeatmix24.ActivateFx = function(channel, control, value, status, group) { // Calculate Fx num based on midi control (0x66 for Fx1 and 0x67 for Fx2) - var FxNum = control - 0x65; + const FxNum = control - 0x65; if (value === DOWN) { if (FxModeTimers[group]) { engine.stopTimer(FxModeTimers[group]); @@ -671,8 +670,8 @@ ReloopBeatmix24.ActivateFx = function(channel, control, value, status, group) { }; ReloopBeatmix24.FxKnobTurn = function(channel, control, value, status, group) { - if (FxMode == 1) { - var parameter = control; + if (FxMode === 1) { + const parameter = control; engine.setParameter(group, "parameter" + parameter.toString(), script.absoluteLin(value, 0, 1)); } @@ -681,14 +680,14 @@ ReloopBeatmix24.FxKnobTurn = function(channel, control, value, status, group) { ReloopBeatmix24.ShiftFxKnobTurn = function(channel, control, value, status, group) { - if (FxMode == 1) { - var parameter = 3 + control - SHIFT; + if (FxMode === 1) { + const parameter = 3 + control - SHIFT; engine.setParameter(group, "parameter" + parameter.toString(), script.absoluteLin(value, 0, 1)); } else { - var effectUnit = parseInt(group.substr(23, 1), 10); - var Effect = control - SHIFT; - var storeIndex = "FX" + Effect.toString() + "U" + effectUnit.toString(); + const effectUnit = parseInt(group.substr(23, 1), 10); + const Effect = control - SHIFT; + const storeIndex = "FX" + Effect.toString() + "U" + effectUnit.toString(); if (storeIndex in previousValue) { if (value - previousValue[storeIndex] > 5) { engine.setValue("[EffectRack1_EffectUnit" + effectUnit + @@ -735,8 +734,8 @@ ReloopBeatmix24.ShiftFxKnobOnOff = function(channel, control, value, status, gro }; ReloopBeatmix24.FxEncoderTurn = function(channel, control, value, status, group) { - var newValue = value - 0x40; - if (FxMode == 1) { + const newValue = value - 0x40; + if (FxMode === 1) { engine.setValue(group, newValue > 0 ? "mix_up" : "mix_down", 1); } else { engine.setValue(group, newValue > 0 ? "super1_up" : "super1_down", 1); @@ -745,8 +744,8 @@ ReloopBeatmix24.FxEncoderTurn = function(channel, control, value, status, group) ReloopBeatmix24.ShiftFxEncoderTurn = function(channel, control, value, status, group) { - var newValue = value - 0x40; - if (FxMode == 1) { + const newValue = value - 0x40; + if (FxMode === 1) { engine.setValue(group, "chain_selector", newValue); } else { engine.setValue(group, newValue > 0 ? "mix_up" : "mix_down", 1); diff --git a/res/controllers/common-hid-packet-parser.js b/res/controllers/common-hid-packet-parser.js index c62addda783..986e693fed1 100644 --- a/res/controllers/common-hid-packet-parser.js +++ b/res/controllers/common-hid-packet-parser.js @@ -384,7 +384,7 @@ class HIDPacket { * Can only pack bits and byte values, patches welcome. * * @todo Implement multi byte bit vector outputs - * @param {Uint8Array} data Data received as InputReport from the device + * @param {Uint8Array} data Data to be send as OutputReport to the device * @param {packetField} field Object that describes a field inside of a packet, which can often * mapped to a Mixxx control. */ @@ -393,18 +393,16 @@ class HIDPacket { console.error(`HIDPacket.pack - Parsing packed value: invalid pack format ${field.pack}`); return; } - const bytes = this.packSizes[field.pack]; - const signed = this.signedPackFormats.includes(field.pack); if (field.type === "bitvector") { const bitVector = /** @type {HIDBitVector} */ (field.value); - if (bytes > 1) { + if (this.packSizes[field.pack] > 1) { console.error("HIDPacket.pack - Packing multibyte bit vectors not yet supported"); return; } - for (const bit_id in bitVector.bits) { - const bit = bitVector.bits[bit_id]; - data[field.offset] = data[field.offset] | bit.value; + HIDController.fastForIn(bitVector.bits, (bit) => { + data[field.offset] |= bitVector.bits[bit].value; } + ); return; } @@ -415,17 +413,28 @@ class HIDPacket { return; } - for (let byte_index = 0; byte_index < bytes; byte_index++) { - const index = field.offset + byte_index; - if (signed) { - if (value >= 0) { - data[index] = (value >> (byte_index * 8)) & 255; - } else { - data[index] = 255 - ((-(value + 1) >> (byte_index * 8)) & 255); - } - } else { - data[index] = (value >> (byte_index * 8)) & 255; - } + const dataView = new DataView(data.buffer); + switch (field.pack) { + case "b": + dataView.setInt8(field.offset, value); + break; + case "B": + dataView.setUint8(field.offset, value); + break; + case "h": + dataView.setInt16(field.offset, value, true); + break; + case "H": + dataView.setUint16(field.offset, value, true); + break; + case "i": + dataView.setInt32(field.offset, value, true); + break; + case "I": + dataView.setUint32(field.offset, value, true); + break; + default: + // Impossible, because range checked at beginning of the function } } /** @@ -444,30 +453,24 @@ class HIDPacket { * @returns {number} Value for the field in data, represented according the fields packing type */ unpack(data, field) { - - if (!(field.pack in this.packSizes)) { + const dataView = new DataView(data.buffer); + switch (field.pack) { + case "b": + return dataView.getInt8(field.offset); + case "B": + return dataView.getUint8(field.offset); + case "h": + return dataView.getInt16(field.offset, true); + case "H": + return dataView.getUint16(field.offset, true); + case "i": + return dataView.getInt32(field.offset, true); + case "I": + return dataView.getUint32(field.offset, true); + default: console.error(`HIDPacket.unpack - Parsing packed value: invalid pack format ${field.pack}`); return undefined; } - const bytes = this.packSizes[field.pack]; - const signed = this.signedPackFormats.includes(field.pack); - - let value = 0; - for (let field_byte = 0; field_byte < bytes; field_byte++) { - if (data[field.offset + field_byte] === 255 && field_byte === 4) { - value += 0; - } else { - value += data[field.offset + field_byte] * Math.pow(2, (field_byte * 8)); - } - } - if (signed) { - const max_value = Math.pow(2, bytes * 8); - const split = max_value / 2 - 1; - if (value > split) { - value = value - max_value; - } - } - return value; } /** * Find HID packet group matching name. @@ -599,8 +602,12 @@ class HIDPacket { } const bitVector = /** @type {HIDBitVector} */ (field.value); const bit_id = `${group}.${name}`; - for (const bit_name in bitVector.bits) { - const bit = bitVector.bits[bit_name]; + + // Fast loop implementation over bitvector.bits object + const bitVectorKeyArr = Object.keys(bitVector.bits); + let bitVectorKeyIdx = bitVectorKeyArr.length; + while (bitVectorKeyIdx--) { + const bit = bitVector.bits[bitVectorKeyArr[bitVectorKeyIdx]]; if (bit.id === bit_id) { return bit; } @@ -782,7 +789,7 @@ class HIDPacket { * - H unsigned short (Uint16 Little-Endian) * - i signed integer (Int32 Little-Endian) * - I unsigned integer (Uint32 Little-Endian) - * @param {number} bitmask A bitwise mask of up to 32 bit. All bits set to'1' in this mask are + * @param {number} [bitmask=undefined] A bitwise mask of up to 32 bit. All bits set to'1' in this mask are * considered. * @param {fieldChangeCallback} [callback=undefined] Callback function for the control */ @@ -959,7 +966,8 @@ class HIDPacket { return undefined; } const bitVector = /** @type {HIDBitVector} */ (field.value); - for (const bit_id in bitVector.bits) { + + HIDController.fastForIn(bitVector.bits, (bit_id) => { const bit = bitVector.bits[bit_id]; const new_value = (bit.bitmask & value) >> bit.bit_offset; if (bit.value !== undefined && bit.value !== new_value) { @@ -967,6 +975,7 @@ class HIDPacket { } bit.value = new_value; } + ); return bits; } /** @@ -985,26 +994,37 @@ class HIDPacket { */ const field_changes = {}; - for (const group_name in this.groups) { - const group = this.groups[group_name]; - for (const field_id in group) { - const field = group[field_id]; + // Fast loop implementation over this.groups object + const groupKeyArr = Object.keys(this.groups); + let groupKeyIdx = groupKeyArr.length; + while (groupKeyIdx--) { + const group = this.groups[groupKeyArr[groupKeyIdx]]; + + // Fast loop implementation over group object + const fieldKeyArr = Object.keys(group); + let fieldKeyIdx = fieldKeyArr.length; + while (fieldKeyIdx--) { + const field = group[fieldKeyArr[fieldKeyIdx]]; + if (field === undefined) { continue; } const value = this.unpack(data, field); if (value === undefined) { - console.error(`HIDPacket.parse - Parsing packet field value for ${field_id}`); + console.error(`HIDPacket.parse - Parsing packet field value for ${group}.${field}`); return; } if (field.type === "bitvector") { // Bitvector deltas are checked in parseBitVector - const changed_bits = this.parseBitVector(field, value); - for (const bit_name in changed_bits) { - field_changes[bit_name] = changed_bits[bit_name]; + const changedBits = this.parseBitVector(field, value); + + + HIDController.fastForIn(changedBits, (changedBit) => { + field_changes[changedBit] = changedBits[changedBit]; } + ); } else if (field.type === "control") { if (field.value === value && field.mindelta !== undefined) { @@ -1057,12 +1077,17 @@ class HIDPacket { } } - for (const group_name in this.groups) { + HIDController.fastForIn(this.groups, (group_name) => { const group = this.groups[group_name]; - for (const field_name in group) { - this.pack(data, group[field_name]); + + HIDController.fastForIn(group, (field_name) => { + const field = group[field_name]; + + this.pack(data, field); } + ); } + ); if (debug) { let packet_string = ""; @@ -1117,6 +1142,14 @@ class HIDController { */ this.OutputPackets = {}; + /** + * A map to determine the output Bit or bytewise field by group and name, + * across all OutputPackets + * + * @type {Map} + */ + this.OutputFieldLookup = new Map(); + /** * Default input packet name: can be modified for controllers * which can swap modes (wiimote for example) @@ -1405,42 +1438,13 @@ class HIDController { /** * Find Output control matching give group and name * - * @todo The current implementation of this often called function is very slow and does not - * scale, due to several nested loops. * @param {string} m_group Mapped group, must be a valid Mixxx control group name e.g. "[Channel1]" * @param {string} m_name Name of mapped control, must be a valid Mixxx control name "VuMeter" * @returns {bitObject|packetField} Bit or bytewise field - Returns undefined if output field * can't be found. */ getOutputField(m_group, m_name) { - for (const packet_name in this.OutputPackets) { - const packet = this.OutputPackets[packet_name]; - for (const group_name in packet.groups) { - const group = packet.groups[group_name]; - for (const field_name in group) { - const field = group[field_name]; - if (field.type === "bitvector") { - for (const bit_id in field.value.bits) { - const bit = field.value.bits[bit_id]; - if (bit.mapped_group === m_group && bit.mapped_name === m_name) { - return bit; - } - if (bit.group === m_group && bit.name === m_name) { - return bit; - } - } - continue; - } - if (field.mapped_group === m_group && field.mapped_name === m_name) { - return field; - } - if (field.group === m_group && field.name === m_name) { - return field; - } - } - } - } - return undefined; + return this.OutputFieldLookup.get([m_group, m_name].toString()); } /** * Find input packet matching given name. @@ -1658,6 +1662,20 @@ class HIDController { for (const bit_id in field.value.bits) { const bit = field.value.bits[bit_id]; bit.packet = packet; + // Fill lookup map + if (bit.mapped_group && bit.mapped_name) { + this.OutputFieldLookup.set([bit.mapped_group, bit.mapped_name].toString(), bit); + } + if (bit.group && bit.name) { + this.OutputFieldLookup.set([bit.group, bit.name].toString(), bit); + } + } + } else { + if (field.mapped_group && field.mapped_name) { + this.OutputFieldLookup.set([field.mapped_group, field.mapped_name].toString(), field); + } + if (field.group && field.name) { + this.OutputFieldLookup.set([field.group, field.name].toString(), field); } } } @@ -1678,9 +1696,13 @@ class HIDController { if (this.InputPackets === undefined) { return; } - for (const name in this.InputPackets) { + + // Fast loop implementation over this.InputPackets object + const InputPacketsKeyArr = Object.keys(this.InputPackets); + let InputPacketsIdx = InputPacketsKeyArr.length; + while (InputPacketsIdx--) { /** @type {HIDPacket} */ - let packet = this.InputPackets[name]; + let packet = this.InputPackets[InputPacketsKeyArr[InputPacketsIdx]]; // When the device uses ReportIDs to enumerate the reports, hidapi // prepends the report ID to the data sent to Mixxx. If the device @@ -1748,16 +1770,16 @@ class HIDController { * @param {Object.} delta */ processIncomingPacket(packet, delta) { - /** @type {packetField} */ - for (const name in delta) { - // @ts-ignore ignoredControlChanges should be defined in the users mapping + + HIDController.fastForIn(delta, (field_name) => { + // @ts-ignore ignoredControlChanges should be defined in the users mapping // see EKS-Otus.js for an example if (this.ignoredControlChanges !== undefined && - // @ts-ignore - this.ignoredControlChanges.indexOf(name) !== -1) { - continue; + // @ts-ignore + this.ignoredControlChanges.indexOf(field_name) !== -1) { + return; // continue loop - by returning to fastForIn } - const field = delta[name]; + const field = delta[field_name]; if (field.type === "button") { // Button/Boolean field this.processButton(field); @@ -1768,6 +1790,7 @@ class HIDController { console.warn(`HIDController.processIncomingPacket - Unknown field ${field.name} type ${field.type}`); } } + ); } /** * Get active group for this field @@ -2298,6 +2321,23 @@ class HIDController { field.toggle = toggle_value << field.bit_offset; field.packet.send(); } + /** + * Fast loop implementation over object + * + * Don't use 'continue' and 'break' don't work as in normal loops, + * because body is a function + * 'return' statements in the body function behaves as 'continue' in normal loops + * + * @param {Object.} object + * @param {function (string):void } body + */ + static fastForIn(object, body) { + const objKeyArray = Object.keys(object); + let objKeyArrayIdx = objKeyArray.length; + while (objKeyArrayIdx--) { + body(objKeyArray[objKeyArrayIdx]); + } + } } // Add class HIDController to the Global JavaScript object // @ts-ignore Same identifier for class and instance needed for backward compatibility diff --git a/res/linux/org.mixxx.Mixxx.metainfo.xml b/res/linux/org.mixxx.Mixxx.metainfo.xml index 3b9d95d8ab5..0c511bbeeac 100644 --- a/res/linux/org.mixxx.Mixxx.metainfo.xml +++ b/res/linux/org.mixxx.Mixxx.metainfo.xml @@ -96,11 +96,11 @@ Do not edit it manually. --> - + - +

Cover Art @@ -538,7 +538,7 @@

  • Fix synchronization of main cue point/position #4137 - lp1937074 + #10478 #4153
  • @@ -1029,7 +1029,7 @@ #10762 #4884 #10802 - lp1983764 + #10801 #4899 #8817 #10868 @@ -1745,7 +1745,7 @@
  • Numark DJ2GO2: Fix sliders and knobs #4835 - lp:1948596 + #10586
  • Numark DJ2Go2: Support HotCue clear with pad @@ -1946,7 +1946,7 @@
  • Preserve file creation time when writing metadata on Windows #4586 - lp1955314 + #10619
  • Fix handling of file extension when importing and exporting sampler settings @@ -2046,12 +2046,12 @@
  • Add support for HiDPI scale factors of 125% and 175% (only with Qt 5.14+) - lp1938102 + #10485 #4161
  • Fix unhandled exception when parsing corrupt Rekordbox PDB files - lp1933853 + #10452 #4040
  • @@ -2060,7 +2060,7 @@
  • Fix bad phase seek when starting from preroll - lp1930143 + #10423 #4093
  • @@ -2077,7 +2077,7 @@
  • Fix wrong track being recorded in History - lp1933991 + #10454 #4041 #4059 #4107 @@ -2150,12 +2150,12 @@
  • Fix Auto DJ skipping tracks randomly #4319 - lp1941989 + #10505
  • Fix high CPU load due to extremely high internal sync clock values #4312 - lp1943320 + #10520
  • Fix preference option for re-analyzing beatgrids imported from other software @@ -2684,7 +2684,7 @@
  • Fix Pioneer DDJ-SB2 controller mapping auto tempo going to infinity bug #2559 - lp:1846403 + #9838
  • Fix Numark Mixtrack Pro 3 controller mapping inverted FX on/off control diff --git a/res/skins/Deere/style-mac.qss b/res/skins/Deere/style-mac.qss index c255b7b0ed8..93b1d59fdf4 100644 --- a/res/skins/Deere/style-mac.qss +++ b/res/skins/Deere/style-mac.qss @@ -1,5 +1,5 @@ /* push skin settings Close button to the left so it's not in - the same screen position as the Open button. Fixes lp1795663 + the same screen position as the Open button. Fixes #9461 "settings panel disappears instantly after opening it in Tango & Deere skin" */ #SkinSettingsTop { padding-right: 27px; diff --git a/res/skins/Tango/style-mac.qss b/res/skins/Tango/style-mac.qss index fb037d2c57e..82156130e5b 100644 --- a/res/skins/Tango/style-mac.qss +++ b/res/skins/Tango/style-mac.qss @@ -1,5 +1,5 @@ /* push skin settings Close button to the left so it's not in - the same screen position as the Open button. Fixes lp1795663 + the same screen position as the Open button. Fixes #9461 "settings panel disappears instantly after opening it in Tango & Deere skin" */ #SkinSettingsHeader { padding-right: 27px; diff --git a/src/analyzer/analyzerwaveform.cpp b/src/analyzer/analyzerwaveform.cpp index 1ba5c2b7871..e3505abdd1b 100644 --- a/src/analyzer/analyzerwaveform.cpp +++ b/src/analyzer/analyzerwaveform.cpp @@ -154,7 +154,7 @@ void AnalyzerWaveform::createFilters(mixxx::audio::SampleRate sampleRate) { m_filter[Low] = new EngineFilterBessel4Low(sampleRate, 600); m_filter[Mid] = new EngineFilterBessel4Band(sampleRate, 600, 4000); m_filter[High] = new EngineFilterBessel4High(sampleRate, 4000); - // settle filters for silence in preroll to avoids ramping (Bug #1406389) + // settle filters for silence in preroll to avoids ramping (Issue #7776) for (int i = 0; i < FilterCount; ++i) { m_filter[i]->assumeSettled(); } diff --git a/src/control/controlproxy.h b/src/control/controlproxy.h index bc70f71e9d9..69f8bd67860 100644 --- a/src/control/controlproxy.h +++ b/src/control/controlproxy.h @@ -13,7 +13,7 @@ /// Do not (re-)connect slots during runtime, since this locks the mutex in /// QMetaObject::activate(). /// Be sure that the ControlProxy is created and deleted from the same -/// thread, otherwise a pending signal may lead to a segfault (Bug #1406124). +/// thread, otherwise a pending signal may lead to a segfault (Issue #7773). /// Parent it to the the creating object to achieve this. class ControlProxy : public QObject { Q_OBJECT @@ -42,7 +42,7 @@ class ControlProxy : public QObject { // the requested ConnectionType is working as desired. // We try to avoid direct connections if not requested // since you cannot safely delete an object with a pending - // direct connection. This fixes bug Bug #1406124 + // direct connection. This fixes issue #7773 // requested: Auto -> COP = Auto / SCO = Auto // requested: Direct -> COP = Direct / SCO = Direct // requested: Queued -> COP = Queued / SCO = Auto diff --git a/src/controllers/dlgcontrollerlearning.cpp b/src/controllers/dlgcontrollerlearning.cpp index 19afa3cb3ad..04ff5a81b6f 100644 --- a/src/controllers/dlgcontrollerlearning.cpp +++ b/src/controllers/dlgcontrollerlearning.cpp @@ -281,7 +281,7 @@ void DlgControllerLearning::slotMessageReceived(unsigned char status, // NOTE(rryan): We intend to use MidiKey(status, control) here rather than // setting fields individually since we will use the MidiKey with an input - // mapping. See Bug #1532297 + // mapping. See Issue #8432 MidiKey key(status, control); // Ignore all standard MIDI System Real-Time Messages because they diff --git a/src/coreservices.cpp b/src/coreservices.cpp index 6d150284316..dc7e95b98a3 100644 --- a/src/coreservices.cpp +++ b/src/coreservices.cpp @@ -419,7 +419,7 @@ void CoreServices::initialize(QApplication* pApp) { supportedFileSuffixes.join(",")); // Scan the library directory. Do this after the skinloader has - // loaded a skin, see Bug #1047435 + // loaded a skin, see issue #6625 if (rescan || hasChanged_MusicDir || m_pSettingsManager->shouldRescanLibrary()) { m_pTrackCollectionManager->startLibraryScan(); } diff --git a/src/engine/controls/cuecontrol.cpp b/src/engine/controls/cuecontrol.cpp index 24f50667fcf..f1272d47a61 100644 --- a/src/engine/controls/cuecontrol.cpp +++ b/src/engine/controls/cuecontrol.cpp @@ -135,104 +135,78 @@ CueControl::CueControl(const QString& group, CueControl::~CueControl() { delete m_pCuePoint; delete m_pCueMode; - delete m_pCueSet; - delete m_pCueClear; - delete m_pCueGoto; - delete m_pCueGotoAndPlay; - delete m_pCuePlay; - delete m_pCueGotoAndStop; - delete m_pCuePreview; - delete m_pCueCDJ; - delete m_pCueDefault; - delete m_pPlayStutter; - delete m_pCueIndicator; - delete m_pPlayIndicator; - delete m_pPlayLatched; - delete m_pIntroStartPosition; - delete m_pIntroStartEnabled; - delete m_pIntroStartSet; - delete m_pIntroStartClear; - delete m_pIntroStartActivate; - delete m_pIntroEndPosition; - delete m_pIntroEndEnabled; - delete m_pIntroEndSet; - delete m_pIntroEndClear; - delete m_pIntroEndActivate; - delete m_pOutroStartPosition; - delete m_pOutroStartEnabled; - delete m_pOutroStartSet; - delete m_pOutroStartClear; - delete m_pOutroStartActivate; - delete m_pOutroEndPosition; - delete m_pOutroEndEnabled; - delete m_pOutroEndSet; - delete m_pOutroEndClear; - delete m_pOutroEndActivate; - delete m_pVinylControlEnabled; - delete m_pVinylControlMode; - delete m_pHotcueFocus; - delete m_pHotcueFocusColorPrev; - delete m_pHotcueFocusColorNext; qDeleteAll(m_hotcueControls); } void CueControl::createControls() { - m_pCueSet = new ControlPushButton(ConfigKey(m_group, "cue_set")); + m_pCueSet = std::make_unique(ConfigKey(m_group, "cue_set")); m_pCueSet->setButtonMode(ControlPushButton::TRIGGER); - m_pCueClear = new ControlPushButton(ConfigKey(m_group, "cue_clear")); + m_pCueClear = std::make_unique(ConfigKey(m_group, "cue_clear")); m_pCueClear->setButtonMode(ControlPushButton::TRIGGER); - m_pCueGoto = new ControlPushButton(ConfigKey(m_group, "cue_goto")); - m_pCueGotoAndPlay = new ControlPushButton(ConfigKey(m_group, "cue_gotoandplay")); - m_pCuePlay = new ControlPushButton(ConfigKey(m_group, "cue_play")); - m_pCueGotoAndStop = new ControlPushButton(ConfigKey(m_group, "cue_gotoandstop")); - m_pCuePreview = new ControlPushButton(ConfigKey(m_group, "cue_preview")); - m_pCueCDJ = new ControlPushButton(ConfigKey(m_group, "cue_cdj")); - m_pCueDefault = new ControlPushButton(ConfigKey(m_group, "cue_default")); - m_pPlayStutter = new ControlPushButton(ConfigKey(m_group, "play_stutter")); - - m_pPlayLatched = new ControlObject(ConfigKey(m_group, "play_latched")); + m_pCueGoto = std::make_unique(ConfigKey(m_group, "cue_goto")); + m_pCueGotoAndPlay = std::make_unique(ConfigKey(m_group, "cue_gotoandplay")); + m_pCuePlay = std::make_unique(ConfigKey(m_group, "cue_play")); + m_pCueGotoAndStop = std::make_unique(ConfigKey(m_group, "cue_gotoandstop")); + m_pCuePreview = std::make_unique(ConfigKey(m_group, "cue_preview")); + m_pCueCDJ = std::make_unique(ConfigKey(m_group, "cue_cdj")); + m_pCueDefault = std::make_unique(ConfigKey(m_group, "cue_default")); + m_pPlayStutter = std::make_unique(ConfigKey(m_group, "play_stutter")); + + m_pPlayLatched = std::make_unique(ConfigKey(m_group, "play_latched")); m_pPlayLatched->setReadOnly(); - m_pCueIndicator = new ControlIndicator(ConfigKey(m_group, "cue_indicator")); - m_pPlayIndicator = new ControlIndicator(ConfigKey(m_group, "play_indicator")); + m_pCueIndicator = std::make_unique(ConfigKey(m_group, "cue_indicator")); + m_pPlayIndicator = std::make_unique(ConfigKey(m_group, "play_indicator")); - m_pIntroStartPosition = new ControlObject(ConfigKey(m_group, "intro_start_position")); + m_pIntroStartPosition = std::make_unique( + ConfigKey(m_group, "intro_start_position")); m_pIntroStartPosition->set(Cue::kNoPosition); - m_pIntroStartEnabled = new ControlObject(ConfigKey(m_group, "intro_start_enabled")); + m_pIntroStartEnabled = std::make_unique( + ConfigKey(m_group, "intro_start_enabled")); m_pIntroStartEnabled->setReadOnly(); - m_pIntroStartSet = new ControlPushButton(ConfigKey(m_group, "intro_start_set")); - m_pIntroStartClear = new ControlPushButton(ConfigKey(m_group, "intro_start_clear")); - m_pIntroStartActivate = new ControlPushButton(ConfigKey(m_group, "intro_start_activate")); - m_pIntroEndPosition = new ControlObject(ConfigKey(m_group, "intro_end_position")); + m_pIntroStartSet = std::make_unique(ConfigKey(m_group, "intro_start_set")); + m_pIntroStartClear = std::make_unique( + ConfigKey(m_group, "intro_start_clear")); + m_pIntroStartActivate = std::make_unique( + ConfigKey(m_group, "intro_start_activate")); + m_pIntroEndPosition = std::make_unique(ConfigKey(m_group, "intro_end_position")); m_pIntroEndPosition->set(Cue::kNoPosition); - m_pIntroEndEnabled = new ControlObject(ConfigKey(m_group, "intro_end_enabled")); + m_pIntroEndEnabled = std::make_unique(ConfigKey(m_group, "intro_end_enabled")); m_pIntroEndEnabled->setReadOnly(); - m_pIntroEndSet = new ControlPushButton(ConfigKey(m_group, "intro_end_set")); - m_pIntroEndClear = new ControlPushButton(ConfigKey(m_group, "intro_end_clear")); - m_pIntroEndActivate = new ControlPushButton(ConfigKey(m_group, "intro_end_activate")); + m_pIntroEndSet = std::make_unique(ConfigKey(m_group, "intro_end_set")); + m_pIntroEndClear = std::make_unique(ConfigKey(m_group, "intro_end_clear")); + m_pIntroEndActivate = std::make_unique( + ConfigKey(m_group, "intro_end_activate")); - m_pOutroStartPosition = new ControlObject(ConfigKey(m_group, "outro_start_position")); + m_pOutroStartPosition = std::make_unique( + ConfigKey(m_group, "outro_start_position")); m_pOutroStartPosition->set(Cue::kNoPosition); - m_pOutroStartEnabled = new ControlObject(ConfigKey(m_group, "outro_start_enabled")); + m_pOutroStartEnabled = std::make_unique( + ConfigKey(m_group, "outro_start_enabled")); m_pOutroStartEnabled->setReadOnly(); - m_pOutroStartSet = new ControlPushButton(ConfigKey(m_group, "outro_start_set")); - m_pOutroStartClear = new ControlPushButton(ConfigKey(m_group, "outro_start_clear")); - m_pOutroStartActivate = new ControlPushButton(ConfigKey(m_group, "outro_start_activate")); - m_pOutroEndPosition = new ControlObject(ConfigKey(m_group, "outro_end_position")); + m_pOutroStartSet = std::make_unique(ConfigKey(m_group, "outro_start_set")); + m_pOutroStartClear = std::make_unique( + ConfigKey(m_group, "outro_start_clear")); + m_pOutroStartActivate = std::make_unique( + ConfigKey(m_group, "outro_start_activate")); + m_pOutroEndPosition = std::make_unique(ConfigKey(m_group, "outro_end_position")); m_pOutroEndPosition->set(Cue::kNoPosition); - m_pOutroEndEnabled = new ControlObject(ConfigKey(m_group, "outro_end_enabled")); + m_pOutroEndEnabled = std::make_unique(ConfigKey(m_group, "outro_end_enabled")); m_pOutroEndEnabled->setReadOnly(); - m_pOutroEndSet = new ControlPushButton(ConfigKey(m_group, "outro_end_set")); - m_pOutroEndClear = new ControlPushButton(ConfigKey(m_group, "outro_end_clear")); - m_pOutroEndActivate = new ControlPushButton(ConfigKey(m_group, "outro_end_activate")); + m_pOutroEndSet = std::make_unique(ConfigKey(m_group, "outro_end_set")); + m_pOutroEndClear = std::make_unique(ConfigKey(m_group, "outro_end_clear")); + m_pOutroEndActivate = std::make_unique( + ConfigKey(m_group, "outro_end_activate")); - m_pVinylControlEnabled = new ControlProxy(m_group, "vinylcontrol_enabled"); - m_pVinylControlMode = new ControlProxy(m_group, "vinylcontrol_mode"); + m_pVinylControlEnabled = std::make_unique(m_group, "vinylcontrol_enabled"); + m_pVinylControlMode = std::make_unique(m_group, "vinylcontrol_mode"); - m_pHotcueFocus = new ControlObject(ConfigKey(m_group, "hotcue_focus")); + m_pHotcueFocus = std::make_unique(ConfigKey(m_group, "hotcue_focus")); setHotcueFocusIndex(Cue::kNoHotCue); - m_pHotcueFocusColorPrev = new ControlObject(ConfigKey(m_group, "hotcue_focus_color_prev")); - m_pHotcueFocusColorNext = new ControlObject(ConfigKey(m_group, "hotcue_focus_color_next")); + m_pHotcueFocusColorPrev = std::make_unique( + ConfigKey(m_group, "hotcue_focus_color_prev")); + m_pHotcueFocusColorNext = std::make_unique( + ConfigKey(m_group, "hotcue_focus_color_next")); // Create hotcue controls for (int i = 0; i < m_iNumHotCues; ++i) { @@ -243,125 +217,125 @@ void CueControl::createControls() { void CueControl::connectControls() { // Main Cue controls - connect(m_pCueSet, + connect(m_pCueSet.get(), &ControlObject::valueChanged, this, &CueControl::cueSet, Qt::DirectConnection); - connect(m_pCueClear, + connect(m_pCueClear.get(), &ControlObject::valueChanged, this, &CueControl::cueClear, Qt::DirectConnection); - connect(m_pCueGoto, + connect(m_pCueGoto.get(), &ControlObject::valueChanged, this, &CueControl::cueGoto, Qt::DirectConnection); - connect(m_pCueGotoAndPlay, + connect(m_pCueGotoAndPlay.get(), &ControlObject::valueChanged, this, &CueControl::cueGotoAndPlay, Qt::DirectConnection); - connect(m_pCuePlay, + connect(m_pCuePlay.get(), &ControlObject::valueChanged, this, &CueControl::cuePlay, Qt::DirectConnection); - connect(m_pCueGotoAndStop, + connect(m_pCueGotoAndStop.get(), &ControlObject::valueChanged, this, &CueControl::cueGotoAndStop, Qt::DirectConnection); - connect(m_pCuePreview, + connect(m_pCuePreview.get(), &ControlObject::valueChanged, this, &CueControl::cuePreview, Qt::DirectConnection); - connect(m_pCueCDJ, + connect(m_pCueCDJ.get(), &ControlObject::valueChanged, this, &CueControl::cueCDJ, Qt::DirectConnection); - connect(m_pCueDefault, + connect(m_pCueDefault.get(), &ControlObject::valueChanged, this, &CueControl::cueDefault, Qt::DirectConnection); - connect(m_pPlayStutter, + connect(m_pPlayStutter.get(), &ControlObject::valueChanged, this, &CueControl::playStutter, Qt::DirectConnection); - connect(m_pIntroStartSet, + connect(m_pIntroStartSet.get(), &ControlObject::valueChanged, this, &CueControl::introStartSet, Qt::DirectConnection); - connect(m_pIntroStartClear, + connect(m_pIntroStartClear.get(), &ControlObject::valueChanged, this, &CueControl::introStartClear, Qt::DirectConnection); - connect(m_pIntroStartActivate, + connect(m_pIntroStartActivate.get(), &ControlObject::valueChanged, this, &CueControl::introStartActivate, Qt::DirectConnection); - connect(m_pIntroEndSet, + connect(m_pIntroEndSet.get(), &ControlObject::valueChanged, this, &CueControl::introEndSet, Qt::DirectConnection); - connect(m_pIntroEndClear, + connect(m_pIntroEndClear.get(), &ControlObject::valueChanged, this, &CueControl::introEndClear, Qt::DirectConnection); - connect(m_pIntroEndActivate, + connect(m_pIntroEndActivate.get(), &ControlObject::valueChanged, this, &CueControl::introEndActivate, Qt::DirectConnection); - connect(m_pOutroStartSet, + connect(m_pOutroStartSet.get(), &ControlObject::valueChanged, this, &CueControl::outroStartSet, Qt::DirectConnection); - connect(m_pOutroStartClear, + connect(m_pOutroStartClear.get(), &ControlObject::valueChanged, this, &CueControl::outroStartClear, Qt::DirectConnection); - connect(m_pOutroStartActivate, + connect(m_pOutroStartActivate.get(), &ControlObject::valueChanged, this, &CueControl::outroStartActivate, Qt::DirectConnection); - connect(m_pOutroEndSet, + connect(m_pOutroEndSet.get(), &ControlObject::valueChanged, this, &CueControl::outroEndSet, Qt::DirectConnection); - connect(m_pOutroEndClear, + connect(m_pOutroEndClear.get(), &ControlObject::valueChanged, this, &CueControl::outroEndClear, Qt::DirectConnection); - connect(m_pOutroEndActivate, + connect(m_pOutroEndActivate.get(), &ControlObject::valueChanged, this, &CueControl::outroEndActivate, Qt::DirectConnection); - connect(m_pHotcueFocusColorPrev, + connect(m_pHotcueFocusColorPrev.get(), &ControlObject::valueChanged, this, &CueControl::hotcueFocusColorPrev, Qt::DirectConnection); - connect(m_pHotcueFocusColorNext, + connect(m_pHotcueFocusColorNext.get(), &ControlObject::valueChanged, this, &CueControl::hotcueFocusColorNext, @@ -426,33 +400,33 @@ void CueControl::connectControls() { } void CueControl::disconnectControls() { - disconnect(m_pCueSet, nullptr, this, nullptr); - disconnect(m_pCueClear, nullptr, this, nullptr); - disconnect(m_pCueGoto, nullptr, this, nullptr); - disconnect(m_pCueGotoAndPlay, nullptr, this, nullptr); - disconnect(m_pCuePlay, nullptr, this, nullptr); - disconnect(m_pCueGotoAndStop, nullptr, this, nullptr); - disconnect(m_pCuePreview, nullptr, this, nullptr); - disconnect(m_pCueCDJ, nullptr, this, nullptr); - disconnect(m_pCueDefault, nullptr, this, nullptr); - disconnect(m_pPlayStutter, nullptr, this, nullptr); - - disconnect(m_pIntroStartSet, nullptr, this, nullptr); - disconnect(m_pIntroStartClear, nullptr, this, nullptr); - disconnect(m_pIntroStartActivate, nullptr, this, nullptr); - disconnect(m_pIntroEndSet, nullptr, this, nullptr); - disconnect(m_pIntroEndClear, nullptr, this, nullptr); - disconnect(m_pIntroEndActivate, nullptr, this, nullptr); - - disconnect(m_pOutroStartSet, nullptr, this, nullptr); - disconnect(m_pOutroStartClear, nullptr, this, nullptr); - disconnect(m_pOutroStartActivate, nullptr, this, nullptr); - disconnect(m_pOutroEndSet, nullptr, this, nullptr); - disconnect(m_pOutroEndClear, nullptr, this, nullptr); - disconnect(m_pOutroEndActivate, nullptr, this, nullptr); - - disconnect(m_pHotcueFocusColorPrev, nullptr, this, nullptr); - disconnect(m_pHotcueFocusColorNext, nullptr, this, nullptr); + disconnect(m_pCueSet.get(), nullptr, this, nullptr); + disconnect(m_pCueClear.get(), nullptr, this, nullptr); + disconnect(m_pCueGoto.get(), nullptr, this, nullptr); + disconnect(m_pCueGotoAndPlay.get(), nullptr, this, nullptr); + disconnect(m_pCuePlay.get(), nullptr, this, nullptr); + disconnect(m_pCueGotoAndStop.get(), nullptr, this, nullptr); + disconnect(m_pCuePreview.get(), nullptr, this, nullptr); + disconnect(m_pCueCDJ.get(), nullptr, this, nullptr); + disconnect(m_pCueDefault.get(), nullptr, this, nullptr); + disconnect(m_pPlayStutter.get(), nullptr, this, nullptr); + + disconnect(m_pIntroStartSet.get(), nullptr, this, nullptr); + disconnect(m_pIntroStartClear.get(), nullptr, this, nullptr); + disconnect(m_pIntroStartActivate.get(), nullptr, this, nullptr); + disconnect(m_pIntroEndSet.get(), nullptr, this, nullptr); + disconnect(m_pIntroEndClear.get(), nullptr, this, nullptr); + disconnect(m_pIntroEndActivate.get(), nullptr, this, nullptr); + + disconnect(m_pOutroStartSet.get(), nullptr, this, nullptr); + disconnect(m_pOutroStartClear.get(), nullptr, this, nullptr); + disconnect(m_pOutroStartActivate.get(), nullptr, this, nullptr); + disconnect(m_pOutroEndSet.get(), nullptr, this, nullptr); + disconnect(m_pOutroEndClear.get(), nullptr, this, nullptr); + disconnect(m_pOutroEndActivate.get(), nullptr, this, nullptr); + + disconnect(m_pHotcueFocusColorPrev.get(), nullptr, this, nullptr); + disconnect(m_pHotcueFocusColorNext.get(), nullptr, this, nullptr); for (const auto& pControl : qAsConst(m_hotcueControls)) { disconnect(pControl, nullptr, this, nullptr); @@ -524,6 +498,7 @@ void CueControl::trackLoaded(TrackPointer pNewTrack) { m_pOutroStartEnabled->forceSet(0.0); m_pOutroEndPosition->set(Cue::kNoPosition); m_pOutroEndEnabled->forceSet(0.0); + m_n60dBSoundStartPosition.setValue(Cue::kNoPosition); setHotcueFocusIndex(Cue::kNoHotCue); m_pLoadedTrack.reset(); m_usedSeekOnLoadPosition.setValue(mixxx::audio::kStartFramePos); @@ -686,6 +661,14 @@ void CueControl::loadCuesFromTrack() { active_hotcues.insert(hotcue); break; } + case mixxx::CueType::N60dBSound: { + Cue::StartAndEndPositions pos = pCue->getStartAndEndPosition(); + m_n60dBSoundStartPosition.setValue(pos.startPosition.toEngineSamplePos()); + break; + } + case mixxx::CueType::Beat: + case mixxx::CueType::Jump: + case mixxx::CueType::Invalid: default: break; } @@ -1267,15 +1250,7 @@ void CueControl::hintReader(gsl::not_null pHintList) { appendCueHint(pHintList, pControl->getPosition(), Hint::Type::HotCue); } - TrackPointer pLoadedTrack = m_pLoadedTrack; - if (pLoadedTrack) { - CuePointer pN60dBSound = - pLoadedTrack->findCueByType(mixxx::CueType::N60dBSound); - if (pN60dBSound) { - const mixxx::audio::FramePos frame = pN60dBSound->getPosition(); - appendCueHint(pHintList, frame, Hint::Type::FirstSound); - } - } + appendCueHint(pHintList, m_n60dBSoundStartPosition.getValue(), Hint::Type::FirstSound); appendCueHint(pHintList, m_pIntroStartPosition->get(), Hint::Type::IntroStart); appendCueHint(pHintList, m_pIntroEndPosition->get(), Hint::Type::IntroEnd); appendCueHint(pHintList, m_pOutroStartPosition->get(), Hint::Type::OutroStart); diff --git a/src/engine/controls/cuecontrol.h b/src/engine/controls/cuecontrol.h index a8355c20e3c..6e9bd8baf85 100644 --- a/src/engine/controls/cuecontrol.h +++ b/src/engine/controls/cuecontrol.h @@ -309,50 +309,52 @@ class CueControl : public EngineControl { ControlObject* m_pTrackSamples; ControlObject* m_pCuePoint; ControlObject* m_pCueMode; - ControlPushButton* m_pCueSet; - ControlPushButton* m_pCueClear; - ControlPushButton* m_pCueCDJ; - ControlPushButton* m_pCueDefault; - ControlPushButton* m_pPlayStutter; - ControlIndicator* m_pCueIndicator; - ControlIndicator* m_pPlayIndicator; - ControlObject* m_pPlayLatched; - ControlPushButton* m_pCueGoto; - ControlPushButton* m_pCueGotoAndPlay; - ControlPushButton* m_pCuePlay; - ControlPushButton* m_pCueGotoAndStop; - ControlPushButton* m_pCuePreview; - - ControlObject* m_pIntroStartPosition; - ControlObject* m_pIntroStartEnabled; - ControlPushButton* m_pIntroStartSet; - ControlPushButton* m_pIntroStartClear; - ControlPushButton* m_pIntroStartActivate; - - ControlObject* m_pIntroEndPosition; - ControlObject* m_pIntroEndEnabled; - ControlPushButton* m_pIntroEndSet; - ControlPushButton* m_pIntroEndClear; - ControlPushButton* m_pIntroEndActivate; - - ControlObject* m_pOutroStartPosition; - ControlObject* m_pOutroStartEnabled; - ControlPushButton* m_pOutroStartSet; - ControlPushButton* m_pOutroStartClear; - ControlPushButton* m_pOutroStartActivate; - - ControlObject* m_pOutroEndPosition; - ControlObject* m_pOutroEndEnabled; - ControlPushButton* m_pOutroEndSet; - ControlPushButton* m_pOutroEndClear; - ControlPushButton* m_pOutroEndActivate; - - ControlProxy* m_pVinylControlEnabled; - ControlProxy* m_pVinylControlMode; - - ControlObject* m_pHotcueFocus; - ControlObject* m_pHotcueFocusColorNext; - ControlObject* m_pHotcueFocusColorPrev; + std::unique_ptr m_pCueSet; + std::unique_ptr m_pCueClear; + std::unique_ptr m_pCueCDJ; + std::unique_ptr m_pCueDefault; + std::unique_ptr m_pPlayStutter; + std::unique_ptr m_pCueIndicator; + std::unique_ptr m_pPlayIndicator; + std::unique_ptr m_pPlayLatched; + std::unique_ptr m_pCueGoto; + std::unique_ptr m_pCueGotoAndPlay; + std::unique_ptr m_pCuePlay; + std::unique_ptr m_pCueGotoAndStop; + std::unique_ptr m_pCuePreview; + + std::unique_ptr m_pIntroStartPosition; + std::unique_ptr m_pIntroStartEnabled; + std::unique_ptr m_pIntroStartSet; + std::unique_ptr m_pIntroStartClear; + std::unique_ptr m_pIntroStartActivate; + + std::unique_ptr m_pIntroEndPosition; + std::unique_ptr m_pIntroEndEnabled; + std::unique_ptr m_pIntroEndSet; + std::unique_ptr m_pIntroEndClear; + std::unique_ptr m_pIntroEndActivate; + + std::unique_ptr m_pOutroStartPosition; + std::unique_ptr m_pOutroStartEnabled; + std::unique_ptr m_pOutroStartSet; + std::unique_ptr m_pOutroStartClear; + std::unique_ptr m_pOutroStartActivate; + + std::unique_ptr m_pOutroEndPosition; + std::unique_ptr m_pOutroEndEnabled; + std::unique_ptr m_pOutroEndSet; + std::unique_ptr m_pOutroEndClear; + std::unique_ptr m_pOutroEndActivate; + + ControlValueAtomic m_n60dBSoundStartPosition; + + std::unique_ptr m_pVinylControlEnabled; + std::unique_ptr m_pVinylControlMode; + + std::unique_ptr m_pHotcueFocus; + std::unique_ptr m_pHotcueFocusColorNext; + std::unique_ptr m_pHotcueFocusColorPrev; parented_ptr m_pPassthrough; diff --git a/src/engine/controls/loopingcontrol.cpp b/src/engine/controls/loopingcontrol.cpp index 9968ba18390..de52d76b44e 100644 --- a/src/engine/controls/loopingcontrol.cpp +++ b/src/engine/controls/loopingcontrol.cpp @@ -175,6 +175,9 @@ LoopingControl::LoopingControl(const QString& group, this, &LoopingControl::slotBeatJump, Qt::DirectConnection); m_pCOBeatJumpSize = new ControlObject(ConfigKey(group, "beatjump_size"), true, false, false, 4.0); + m_pCOBeatJumpSize->connectValueChangeRequest(this, + &LoopingControl::slotBeatJumpSizeChangeRequest, + Qt::DirectConnection); m_pCOBeatJumpSizeHalve = new ControlPushButton(ConfigKey(group, "beatjump_size_halve")); connect(m_pCOBeatJumpSizeHalve, @@ -340,7 +343,7 @@ void LoopingControl::slotLoopHalve(double pressed) { return; } - slotBeatLoop(m_pCOBeatLoopSize->get() / 2.0, true, false); + m_pCOBeatLoopSize->set(m_pCOBeatLoopSize->get() / 2.0); } void LoopingControl::slotLoopDouble(double pressed) { @@ -348,7 +351,7 @@ void LoopingControl::slotLoopDouble(double pressed) { return; } - slotBeatLoop(m_pCOBeatLoopSize->get() * 2.0, true, false); + m_pCOBeatLoopSize->set(m_pCOBeatLoopSize->get() * 2.0); } void LoopingControl::process(const double dRate, @@ -1132,7 +1135,7 @@ void LoopingControl::slotBeatLoopActivate(BeatLoopingControl* pBeatLoopControl) // Maintain the current start point if there is an active loop currently // looping. slotBeatLoop will update m_pActiveBeatLoop if applicable. Note, // this used to only maintain the current start point if a beatloop was - // enabled. See Bug #1159243. + // enabled. See Issue #6957. slotBeatLoop(pBeatLoopControl->getSize(), m_bLoopingEnabled, true); } @@ -1429,6 +1432,14 @@ void LoopingControl::slotBeatLoop(double beats, bool keepStartPoint, bool enable void LoopingControl::slotBeatLoopSizeChangeRequest(double beats) { // slotBeatLoop will call m_pCOBeatLoopSize->setAndConfirm if // new beatloop_size is valid + + double maxBeatLoopSize = s_dBeatSizes[sizeof(s_dBeatSizes) / sizeof(s_dBeatSizes[0]) - 1]; + double minBeatLoopSize = s_dBeatSizes[0]; + if ((beats < minBeatLoopSize) || (beats > maxBeatLoopSize)) { + // Don't clamp the value here to not fall out of a measure + return; + } + slotBeatLoop(beats, true, false); } @@ -1495,6 +1506,19 @@ void LoopingControl::slotBeatJump(double beats) { } } +void LoopingControl::slotBeatJumpSizeChangeRequest(double beats) { + // Use same limits as for beat loop size + double maxBeatJumpSize = s_dBeatSizes[sizeof(s_dBeatSizes) / sizeof(s_dBeatSizes[0]) - 1]; + double minBeatJumpSize = s_dBeatSizes[0]; + + if ((beats < minBeatJumpSize) || (beats > maxBeatJumpSize)) { + // Don't clamp the value here to not fall out of a measure + return; + } + + m_pCOBeatJumpSize->setAndConfirm(beats); +} + void LoopingControl::slotBeatJumpSizeHalve(double pressed) { if (pressed > 0) { m_pCOBeatJumpSize->set(m_pCOBeatJumpSize->get() / 2); diff --git a/src/engine/controls/loopingcontrol.h b/src/engine/controls/loopingcontrol.h index 3f3eebdf7ee..7aa7cebf8a0 100644 --- a/src/engine/controls/loopingcontrol.h +++ b/src/engine/controls/loopingcontrol.h @@ -87,6 +87,7 @@ class LoopingControl : public EngineControl { // Jump forward or backward by beats. void slotBeatJump(double beats); + void slotBeatJumpSizeChangeRequest(double beats); void slotBeatJumpSizeHalve(double pressed); void slotBeatJumpSizeDouble(double pressed); void slotBeatJumpForward(double pressed); diff --git a/src/engine/enginemaster.cpp b/src/engine/enginemaster.cpp index 4b7cbb66f76..01c551b1eb5 100644 --- a/src/engine/enginemaster.cpp +++ b/src/engine/enginemaster.cpp @@ -99,7 +99,7 @@ EngineMaster::EngineMaster( m_pBoothGain = new ControlAudioTaperPot(ConfigKey(group, "booth_gain"), -14, 14, 0.5); // Legacy: the master "gain" control used to be named "volume" in Mixxx - // 1.11.0 and earlier. See Bug #1306253. + // 1.11.0 and earlier. See issue #7413. ControlDoublePrivate::insertAlias(ConfigKey(group, "volume"), ConfigKey(group, "gain")); @@ -117,7 +117,7 @@ EngineMaster::EngineMaster( m_pHeadGain = new ControlAudioTaperPot(ConfigKey(group, "headGain"), -14, 14, 0.5); // Legacy: the headphone "headGain" control used to be named "headVolume" in - // Mixxx 1.11.0 and earlier. See Bug #1306253. + // Mixxx 1.11.0 and earlier. See issue #7413. ControlDoublePrivate::insertAlias(ConfigKey(group, "headVolume"), ConfigKey(group, "headGain")); diff --git a/src/engine/sidechain/enginesidechain.cpp b/src/engine/sidechain/enginesidechain.cpp index ee930a0fcda..f6e6803db75 100644 --- a/src/engine/sidechain/enginesidechain.cpp +++ b/src/engine/sidechain/enginesidechain.cpp @@ -34,7 +34,7 @@ EngineSideChain::EngineSideChain( // a suitable choice since we do semi-realtime tasks // in the sidechain thread. To get reliable timing, it's important // that this work be prioritized over the GUI and non-realtime tasks. See - // discussion on Bug #1270583 and Bug #1194543. + // discussion on issue #7272 and https://bugs.launchpad.net/mixxx/1.11/+bug/1194543. start(QThread::HighPriority); } diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp index 36d0661a9fa..9b5bc1d7d27 100644 --- a/src/library/autodj/autodjfeature.cpp +++ b/src/library/autodj/autodjfeature.cpp @@ -63,7 +63,7 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary, m_iAutoDJPlaylistId); // Connect loadTrackToPlayer signal as a queued connection to make sure all callbacks of a - // previous load attempt have been called (lp1941743) + // previous load attempt have been called #10504. connect(m_pAutoDJProcessor, &AutoDJProcessor::loadTrackToPlayer, this, diff --git a/src/library/basesqltablemodel.cpp b/src/library/basesqltablemodel.cpp index 709f77718f5..a972b6392f4 100644 --- a/src/library/basesqltablemodel.cpp +++ b/src/library/basesqltablemodel.cpp @@ -236,7 +236,7 @@ void BaseSqlTableModel::select() { } // Remove all the rows from the table after(!) the query has been - // executed successfully. See Bug #1090888. + // executed successfully. See issue #6782. // TODO(rryan) we could edit the table in place instead of clearing it? clearRows(); diff --git a/src/library/dao/trackdao.cpp b/src/library/dao/trackdao.cpp index 5d2459160b1..41d5f07bdd6 100644 --- a/src/library/dao/trackdao.cpp +++ b/src/library/dao/trackdao.cpp @@ -2152,7 +2152,7 @@ void TrackDAO::detectCoverArtForTracksWithoutCover(volatile const bool* pCancel, } // We quickly iterate through the results to prevent blocking the database - // for other operations. Bug #1399981. + // for other operations. Issue #7713. while (query.next()) { if (*pCancel) { return; diff --git a/src/main.cpp b/src/main.cpp index 3b5a4a1058a..02506d1397c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -156,7 +156,7 @@ int main(int argc, char * argv[]) { // Create the ErrorDialogHandler in the main thread, otherwise it will be // created in the thread of the first caller to instance(), which may not be - // the main thread. Bug #1748636. + // the main thread. Issue #9130. ErrorDialogHandler::instance(); #ifdef __APPLE__ diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp index f2a6b217083..04e422bc968 100644 --- a/src/mixer/basetrackplayer.cpp +++ b/src/mixer/basetrackplayer.cpp @@ -457,7 +457,7 @@ void BaseTrackPlayerImpl::slotLoadTrack(TrackPointer pNewTrack, bool bPlay) { // await slotTrackLoaded()/slotLoadFailed() // emit this before pEngineBuffer->loadTrack() to avoid receiving - // unexpected slotTrackLoaded() before, in case the track is still cached (lp1941743) + // unexpected slotTrackLoaded() before, in case the track is still cached #10504. emit loadingTrack(pNewTrack, pOldTrack); // Request a new track from EngineBuffer diff --git a/src/mixxxmainwindow.cpp b/src/mixxxmainwindow.cpp index 2b1d92da248..4f0e39b4ee9 100644 --- a/src/mixxxmainwindow.cpp +++ b/src/mixxxmainwindow.cpp @@ -906,7 +906,7 @@ void MixxxMainWindow::slotViewFullScreen(bool toggle) { showFullScreen(); #ifdef __LINUX__ // Fix for "No menu bar with ubuntu unity in full screen mode" (issues - // #885890 and #1076789. Before touching anything here, please read + // #6072 and #6689. Before touching anything here, please read // those bugs. // Set this attribute instead of calling setNativeMenuBar(false), see // https://github.com/mixxxdj/mixxx/issues/11320 diff --git a/src/skin/legacy/legacyskinparser.cpp b/src/skin/legacy/legacyskinparser.cpp index 7566c9ae21b..bed31f694df 100644 --- a/src/skin/legacy/legacyskinparser.cpp +++ b/src/skin/legacy/legacyskinparser.cpp @@ -2114,7 +2114,7 @@ void LegacySkinParser::commonWidgetSetup(const QDomNode& node, // setupWidget since a BindProperty connection to the display parameter can // cause the widget to be polished (i.e. style computed) before it is // ready. The most common case is that the object name has not yet been set - // in setupWidget. See Bug #1285836. + // in setupWidget. See issue #7328. if (allowConnections) { setupConnections(node, pBaseWidget); } diff --git a/src/skin/legacy/tooltips.cpp b/src/skin/legacy/tooltips.cpp index 095b46b16bb..38158ab2517 100644 --- a/src/skin/legacy/tooltips.cpp +++ b/src/skin/legacy/tooltips.cpp @@ -323,7 +323,7 @@ void Tooltips::addStandardTooltips() { << tr("Auto: Sets how much to reduce the music volume when the volume of active microphones rises above threshold.") << tr("Manual: Sets how much to reduce the music volume, when talkover is activated regardless of volume of microphone inputs."); - QString changeAmount = tr("Change the step-size in the Preferences -> Interface menu."); + QString changeAmount = tr("Change the step-size in the Preferences -> Decks menu."); add("rate_perm_up_rate_perm_up_small") << tr("Raise Pitch") << QString("%1: %2").arg(leftClick, tr("Sets the pitch higher.")) diff --git a/src/soundio/sounddeviceportaudio.cpp b/src/soundio/sounddeviceportaudio.cpp index 31a98db7449..08e0c826302 100644 --- a/src/soundio/sounddeviceportaudio.cpp +++ b/src/soundio/sounddeviceportaudio.cpp @@ -938,7 +938,7 @@ int SoundDevicePortAudio::callbackProcessClkRef( #ifdef __WINDOWS__ // We need to refresh the denormals flags every callback since some // driver + API combinations will reset them (known: DirectSound + Realtec) - // Fixes Bug #1495047 + // Fixes issue #8220 // (Both calls are very fast) _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON); _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); diff --git a/src/test/enginebuffertest.cpp b/src/test/enginebuffertest.cpp index a68355c9158..1c006dd7b56 100644 --- a/src/test/enginebuffertest.cpp +++ b/src/test/enginebuffertest.cpp @@ -363,7 +363,7 @@ TEST_F(EngineBufferE2ETest, SeekTest) { TEST_F(EngineBufferE2ETest, SoundTouchReverseTest) { // This test must not crash when changing to reverse while pitch is tweaked - // Testing bug #1458263 + // Testing issue #8061 ControlObject::set(ConfigKey("[Master]", "keylock_engine"), static_cast(EngineBuffer::KeylockEngine::SoundTouch)); ControlObject::set(ConfigKey(m_sGroup1, "pitch"), -1); @@ -377,7 +377,7 @@ TEST_F(EngineBufferE2ETest, SoundTouchReverseTest) { TEST_F(EngineBufferE2ETest, RubberbandReverseTest) { // This test must not crash when changing to reverse while pitch is tweaked - // Testing bug #1458263 + // Testing issue #8061 ControlObject::set(ConfigKey("[Master]", "keylock_engine"), static_cast(EngineBuffer::KeylockEngine::RubberBandFaster)); ControlObject::set(ConfigKey(m_sGroup1, "pitch"), -1); @@ -391,7 +391,7 @@ TEST_F(EngineBufferE2ETest, RubberbandReverseTest) { TEST_F(EngineBufferE2ETest, CueGotoAndStopTest) { // Be sure, that the Crossfade buffer is processed only once - // Bug #1504838 + // Issue #8251 ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); ProcessBuffer(); ControlObject::set(ConfigKey(m_sGroup1, "cue_gotoandstop"), 1.0); @@ -402,7 +402,7 @@ TEST_F(EngineBufferE2ETest, CueGotoAndStopTest) { TEST_F(EngineBufferE2ETest, CueGotoAndPlayTest) { // Be sure, cue seek is not overwritten by quantization seek - // Bug #1504503 + // Issue #8249 ControlObject::set(ConfigKey(m_sGroup1, "quantize"), 1.0); ControlObject::set(ConfigKey(m_sGroup1, "cue_point"), 0.0); m_pChannel1->getEngineBuffer()->queueNewPlaypos( @@ -416,7 +416,7 @@ TEST_F(EngineBufferE2ETest, CueGotoAndPlayTest) { TEST_F(EngineBufferE2ETest, CueStartPlayTest) { // Be sure, cue seek is not overwritten by quantization seek - // Bug #1504851 + // Issue #8252 ControlObject::set(ConfigKey(m_sGroup1, "play"), 1.0); ProcessBuffer(); ControlObject::set(ConfigKey(m_sGroup1, "start_play"), 1.0); @@ -427,7 +427,7 @@ TEST_F(EngineBufferE2ETest, CueStartPlayTest) { TEST_F(EngineBufferE2ETest, CueGotoAndPlayDenon) { // Be sure, cue point is not moved - // enable Denon mode Bug #1504934 + // enable Denon mode issue #8254 ControlObject::set(ConfigKey(m_sGroup1, "cue_mode"), 2.0); // CUE_MODE_DENON m_pChannel1->getEngineBuffer()->queueNewPlaypos( mixxx::audio::FramePos(500), EngineBuffer::SEEK_EXACT); diff --git a/src/test/enginesynctest.cpp b/src/test/enginesynctest.cpp index df82852e1d0..5d7287c23ba 100644 --- a/src/test/enginesynctest.cpp +++ b/src/test/enginesynctest.cpp @@ -2184,7 +2184,7 @@ TEST_F(EngineSyncTest, SyncPhaseToPlayingNonSyncDeck) { mixxx::BeatsPointer pBeats3 = mixxx::Beats::fromConstTempo( m_pTrack3->getSampleRate(), mixxx::audio::kStartFramePos, mixxx::Bpm(140)); m_pTrack3->trySetBeats(pBeats3); - // This will sync to the first deck here and not the second (lp1784185) + // This will sync to the first deck here and not the second #9397 pButtonSyncEnabled3->set(1.0); EXPECT_TRUE(isSoftLeader(m_sGroup3)); ProcessBuffer(); @@ -2743,7 +2743,7 @@ TEST_F(EngineSyncTest, ScratchEndOtherPlayingTrackStayInPhase) { } TEST_F(EngineSyncTest, SyncWithoutBeatgrid) { - // this tests bug lp1783020, notresetting rate when other deck has no beatgrid + // this tests issue #9391, notresetting rate when other deck has no beatgrid mixxx::BeatsPointer pBeats1 = mixxx::Beats::fromConstTempo( m_pTrack1->getSampleRate(), mixxx::audio::kStartFramePos, mixxx::Bpm(128)); m_pTrack1->trySetBeats(pBeats1); diff --git a/src/test/globaltrackcache_test.cpp b/src/test/globaltrackcache_test.cpp index 07b9cf99096..aab7823b91d 100644 --- a/src/test/globaltrackcache_test.cpp +++ b/src/test/globaltrackcache_test.cpp @@ -33,7 +33,7 @@ class TrackTitleThread: public QThread { auto track = GlobalTrackCacheLocker().lookupTrackById(trackId); if (track) { ASSERT_EQ(trackId, track->getId()); - // lp1744550: Accessing the track from multiple threads is + // #9097: Accessing the track from multiple threads is // required to cause a SIGSEGV if (track->getTitle().isEmpty()) { track->setTitle( @@ -147,7 +147,7 @@ TEST_F(GlobalTrackCacheTest, concurrentDelete) { const auto testFile = mixxx::FileInfo(getTestDir().filePath(kTestFile)); - // lp1744550: A decent number of iterations is needed to reliably + // #9097: A decent number of iterations is needed to reliably // reveal potential race conditions while evicting tracks from // the cache! // NOTE(2019-12-14, uklotzde): On Travis and macOS executing 10_000 @@ -174,7 +174,7 @@ TEST_F(GlobalTrackCacheTest, concurrentDelete) { track = GlobalTrackCacheLocker().lookupTrackById(trackId); EXPECT_TRUE(static_cast(track)); - // lp1744550: Accessing the track from multiple threads is + // #9097: Accessing the track from multiple threads is // required to cause a SIGSEGV track->setArtist(QString("Artist %1").arg(QString::number(i))); diff --git a/src/test/looping_control_test.cpp b/src/test/looping_control_test.cpp index ef05bc79b1f..ec6668aa969 100644 --- a/src/test/looping_control_test.cpp +++ b/src/test/looping_control_test.cpp @@ -67,6 +67,10 @@ class LoopingControlTest : public MockedEngineBackendTest { m_pButtonBeatLoopActivate = std::make_unique( m_sGroup1, "beatloop_activate"); m_pBeatJumpSize = std::make_unique(m_sGroup1, "beatjump_size"); + m_pButtonBeatJumpSizeDouble = std::make_unique( + m_sGroup1, "beatjump_size_double"); + m_pButtonBeatJumpSizeHalve = std::make_unique( + m_sGroup1, "beatjump_size_halve"); m_pButtonBeatJumpForward = std::make_unique( m_sGroup1, "beatjump_forward"); m_pButtonBeatJumpBackward = std::make_unique( @@ -121,6 +125,8 @@ class LoopingControlTest : public MockedEngineBackendTest { std::unique_ptr m_pBeatLoopSize; std::unique_ptr m_pButtonBeatLoopActivate; std::unique_ptr m_pBeatJumpSize; + std::unique_ptr m_pButtonBeatJumpSizeHalve; + std::unique_ptr m_pButtonBeatJumpSizeDouble; std::unique_ptr m_pButtonBeatJumpForward; std::unique_ptr m_pButtonBeatJumpBackward; std::unique_ptr m_pButtonBeatLoopRoll1Activate; @@ -712,6 +718,55 @@ TEST_F(LoopingControlTest, BeatLoopSize_IsSetByNumberedControl) { EXPECT_EQ(2.0, m_pBeatLoopSize->get()); } +TEST_F(LoopingControlTest, BeatLoopSize_SetRangeCheck) { + // Set BeatLoopSize to the maximum allowed value of 512 + m_pBeatLoopSize->set(512.0); + EXPECT_EQ(512, m_pBeatLoopSize->get()); + + m_pBeatLoopSize->set(150.0); + EXPECT_EQ(150, m_pBeatLoopSize->get()); + + // Set BeatLoopSize to a value above the allowed maximum of 512 -> This must be ignored + m_pBeatLoopSize->set(513.0); + EXPECT_EQ(150, m_pBeatLoopSize->get()); + + // Double BeatLoopSize (the result is 300 which is in the allowed range) + m_pButtonLoopDouble->set(1.0); + m_pButtonLoopDouble->set(0.0); + EXPECT_EQ(300.0, m_pBeatLoopSize->get()); + + // Double BeatLoopSize (the result would be 600 which is above the allowed + // maximum of 512 -> This must be ignored) + m_pButtonLoopDouble->set(1.0); + m_pButtonLoopDouble->set(0.0); + EXPECT_EQ(300.0, m_pBeatLoopSize->get()); + + // Set BeatLoopSize to the minimum allowed value + m_pBeatLoopSize->set(1 / 32.0); + EXPECT_EQ(1 / 32.0, m_pBeatLoopSize->get()); + + m_pBeatLoopSize->set(1 / 10.0); + EXPECT_EQ(1 / 10.0, m_pBeatLoopSize->get()); + + // Set BeatLoopSize to a value below the allowed minimum of 1/32 -> This must be ignored + m_pBeatLoopSize->set(1 / 33.0); + EXPECT_EQ(1 / 10.0, m_pBeatLoopSize->get()); + + m_pBeatLoopSize->set(0); + EXPECT_EQ(1 / 10.0, m_pBeatLoopSize->get()); + + // Halve BeatLoopSize (the result is 1/20 which is in the allowed range) + m_pButtonLoopHalve->set(1.0); + m_pButtonLoopHalve->set(0.0); + EXPECT_EQ(1 / 20.0, m_pBeatLoopSize->get()); + + // Halve BeatLoopSize (the result would be 1/40 which is below the allowed + // minimum of 1/32 -> This must be ignored) + m_pButtonLoopHalve->set(1.0); + m_pButtonLoopHalve->set(0.0); + EXPECT_EQ(1 / 20.0, m_pBeatLoopSize->get()); +} + TEST_F(LoopingControlTest, BeatLoopSize_SetDoesNotStartLoop) { m_pTrack1->trySetBpm(120.0); m_pBeatLoopSize->set(16.0); @@ -814,6 +869,55 @@ TEST_F(LoopingControlTest, LegacyBeatLoopControl) { EXPECT_EQ(6.0, m_pBeatLoopSize->get()); } +TEST_F(LoopingControlTest, BeatjumpSize_SetRangeCheck) { + // Set BeatJumpSize to the maximum allowed value + m_pBeatJumpSize->set(512.0); + EXPECT_EQ(512, m_pBeatJumpSize->get()); + + m_pBeatJumpSize->set(150.0); + EXPECT_EQ(150, m_pBeatJumpSize->get()); + + // Set BeatJumpSize to a value above the allowed maximum of 512 -> This must be ignored + m_pBeatJumpSize->set(513.0); + EXPECT_EQ(150, m_pBeatJumpSize->get()); + + // Double BeatJumpSize (the result is 300 which is in the allowed range) + m_pButtonBeatJumpSizeDouble->set(1.0); + m_pButtonBeatJumpSizeDouble->set(0.0); + EXPECT_EQ(300.0, m_pBeatJumpSize->get()); + + // Double BeatJumpSize (the result would be 600 which is above the allowed + // maximum of 512-> This must be ignored) + m_pButtonBeatJumpSizeDouble->set(1.0); + m_pButtonBeatJumpSizeDouble->set(0.0); + EXPECT_EQ(300.0, m_pBeatJumpSize->get()); + + // Set BeatJumpSize to the minimum allowed value + m_pBeatJumpSize->set(1 / 32.0); + EXPECT_EQ(1 / 32.0, m_pBeatJumpSize->get()); + + m_pBeatJumpSize->set(1 / 10.0); + EXPECT_EQ(1 / 10.0, m_pBeatJumpSize->get()); + + // Set BeatJumpSize to a value below the allowed minimum of 1/32 -> This must be ignored + m_pBeatJumpSize->set(1 / 33.0); + EXPECT_EQ(1 / 10.0, m_pBeatJumpSize->get()); + + m_pBeatJumpSize->set(0); + EXPECT_EQ(1 / 10.0, m_pBeatJumpSize->get()); + + // Halve BeatJumpSize (the result is 1/20 which is in the allowed range) + m_pButtonBeatJumpSizeHalve->set(1.0); + m_pButtonBeatJumpSizeHalve->set(0.0); + EXPECT_EQ(1 / 20.0, m_pBeatJumpSize->get()); + + // Halve BeatJumpSize (the result would be 1/40 which is below the allowed + // minimum of 1/32 -> This must be ignored) + m_pButtonBeatJumpSizeHalve->set(1.0); + m_pButtonBeatJumpSizeHalve->set(0.0); + EXPECT_EQ(1 / 20.0, m_pBeatJumpSize->get()); +} + TEST_F(LoopingControlTest, Beatjump_JumpsByBeats) { const auto bpm = mixxx::Bpm{120}; m_pTrack1->trySetBpm(bpm); diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index ab186aff53f..14c4071d576 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -873,7 +873,7 @@ TEST_F(SearchQueryParserTest, CrateFilterWithOther){ TEST_F(SearchQueryParserTest, CrateFilterWithCrateFilterAndNegation){ // User's search term - QString searchTermA = "testA'1"; // Also a test if "'" is escaped lp1789728 + QString searchTermA = "testA'1"; // Also a test if "'" is escaped #9419 QString searchTermAEsc = "testA''1"; QString searchTermB = "testB"; diff --git a/src/track/track.cpp b/src/track/track.cpp index d28a02b7e4c..20bb6dbb0b2 100644 --- a/src/track/track.cpp +++ b/src/track/track.cpp @@ -181,7 +181,7 @@ void Track::replaceMetadataFromSource( m_record.getMetadata().getTrackInfo().getReplayGain(); // Need to set BPM after sample rate since beat grid creation depends on - // knowing the sample rate. Bug #1020438. + // knowing the sample rate #6559. auto beatsAndBpmModified = false; if (importedBpm.isValid() && (!m_pBeats || diff --git a/src/util/widgetrendertimer.h b/src/util/widgetrendertimer.h index 25fc2f3cc8a..d137fb98d79 100644 --- a/src/util/widgetrendertimer.h +++ b/src/util/widgetrendertimer.h @@ -12,7 +12,7 @@ // - inactivityTimeout: The timeout after which the widget's render timer is // deactivated. // -// This class was created in response to Launchpad Bug #1793015. With Qt 4, we +// This class was created in response to issue #9437. With Qt 4, we // would simply call QWidget::update in response to input events that required // re-rendering widgets, relying on Qt to batch them together and deliver them // at a reasonable frequency. On macOS, the behavior of QWidget::update in Qt 5 diff --git a/src/waveform/waveformwidgetfactory.cpp b/src/waveform/waveformwidgetfactory.cpp index 1c60114418c..75654e7871c 100644 --- a/src/waveform/waveformwidgetfactory.cpp +++ b/src/waveform/waveformwidgetfactory.cpp @@ -728,7 +728,7 @@ void WaveformWidgetFactory::swap() { // Don't swap invalid / invisible widgets or widgets with an // unexposed window. Prevents continuous log spew of // "QOpenGLContext::swapBuffers() called with non-exposed - // window, behavior is undefined" on Qt5. See Bug #1779487. + // window, behavior is undefined" on Qt5. See issue #9360. if (!shouldRenderWaveform(pWaveformWidget)) { continue; } diff --git a/src/widget/wbeatspinbox.cpp b/src/widget/wbeatspinbox.cpp index c41dc7da094..9e8986a8130 100644 --- a/src/widget/wbeatspinbox.cpp +++ b/src/widget/wbeatspinbox.cpp @@ -54,25 +54,14 @@ void WBeatSpinBox::stepBy(int steps) { QString temp = text(); int cursorPos = lineEdit()->cursorPosition(); if (validate(temp, cursorPos) == QValidator::Acceptable) { - double editValue = valueFromText(temp); - newValue = editValue * pow(2, steps); - if (newValue < minimum() || newValue > maximum()) { - // don't clamp the value here to not fall out of a measure - newValue = editValue; - } + newValue = valueFromText(temp) * pow(2, steps); } else { // here we have an unacceptable edit, going back to the old value first newValue = oldValue; } // Do not call QDoubleSpinBox::setValue directly in case // the new value of the ControlObject needs to be confirmed. - // Curiously, m_valueControl.set() does not cause slotControlValueChanged - // to execute for beatjump_size, so call QDoubleSpinBox::setValue in this function. m_valueControl.set(newValue); - double coValue = m_valueControl.get(); - if (coValue != value()) { - setValue(coValue); - } selectAll(); } diff --git a/src/widget/wsearchlineedit.cpp b/src/widget/wsearchlineedit.cpp index 087879acc08..130aa8982ac 100644 --- a/src/widget/wsearchlineedit.cpp +++ b/src/widget/wsearchlineedit.cpp @@ -311,13 +311,13 @@ QString WSearchLineEdit::getSearchText() const { if (isEnabled()) { DEBUG_ASSERT(!currentText().isNull()); QString text = currentText(); - QLineEdit* pEdit = lineEdit(); QCompleter* pCompleter = completer(); - if (pCompleter && pEdit && pEdit->hasSelectedText()) { + if (pCompleter && hasSelectedText()) { if (text.startsWith(pCompleter->completionPrefix()) && - pCompleter->completionPrefix().size() == pEdit->cursorPosition()) { - // Search for the entered text until the user has confirmed the - // completion by -> or enter + pCompleter->completionPrefix().size() == lineEdit()->cursorPosition()) { + // Search for the entered text until the user has accepted the + // completion by pressing Enter or changed/deselected the selected + // completion text with Right or Left key return pCompleter->completionPrefix(); } } @@ -387,17 +387,22 @@ void WSearchLineEdit::keyPressEvent(QKeyEvent* keyEvent) { } break; case Qt::Key_Left: - case Qt::Key_Right: + case Qt::Key_Right: { + // Both keys may change or clear the selection (suggested completion). + const bool hadSelectedTextBeforeKeyPressed = hasSelectedText(); QComboBox::keyPressEvent(keyEvent); - slotTriggerSearch(); + if (hadSelectedTextBeforeKeyPressed && !hasSelectedText()) { + // Selection is removed, search the full text now. + triggerSearchDebounced(); + } return; + } case Qt::Key_Enter: case Qt::Key_Return: { if (slotClearSearchIfClearButtonHasFocus()) { return; } - QLineEdit* pEdit = lineEdit(); - if (pEdit && pEdit->hasSelectedText()) { + if (hasSelectedText()) { QComboBox::keyPressEvent(keyEvent); slotTriggerSearch(); return; @@ -517,6 +522,12 @@ void WSearchLineEdit::slotRestoreSearch(const QString& text) { enableSearch(text); } +void WSearchLineEdit::triggerSearchDebounced() { + DEBUG_ASSERT(m_debouncingTimer.isSingleShot()); + DEBUG_ASSERT(s_debouncingTimeoutMillis >= kMinDebouncingTimeoutMillis); + m_debouncingTimer.start(s_debouncingTimeoutMillis); +} + void WSearchLineEdit::slotTriggerSearch() { #if ENABLE_TRACE_LOG kLogger.trace() @@ -768,21 +779,13 @@ void WSearchLineEdit::slotTextChanged(const QString& text) { << text; #endif // ENABLE_TRACE_LOG m_queryEmitted = false; - m_debouncingTimer.stop(); if (!isEnabled()) { + m_debouncingTimer.stop(); setTextBlockSignals(kDisabledText); return; } updateClearAndDropdownButton(text); - DEBUG_ASSERT(m_debouncingTimer.isSingleShot()); - if (s_debouncingTimeoutMillis > 0) { - m_debouncingTimer.start(s_debouncingTimeoutMillis); - } else { - // Don't (re-)activate the timer if the timeout is invalid. - // Disabling the timer permanently by setting the timeout - // to an invalid value is an expected and valid use case. - DEBUG_ASSERT(!m_debouncingTimer.isActive()); - } + triggerSearchDebounced(); m_saveTimer.start(kSaveTimeoutMillis); } @@ -797,10 +800,12 @@ void WSearchLineEdit::slotSetShortcutFocus() { // Use the same font as the library table and the sidebar void WSearchLineEdit::slotSetFont(const QFont& font) { setFont(font); - if (lineEdit()) { - lineEdit()->setFont(font); - // Decreasing the font doesn't trigger a resizeEvent, - // so we immediately refresh the controls manually. - updateClearAndDropdownButton(getSearchText()); - } + lineEdit()->setFont(font); + // Decreasing the font doesn't trigger a resizeEvent, + // so we immediately refresh the controls manually. + updateClearAndDropdownButton(getSearchText()); +} + +bool WSearchLineEdit::hasSelectedText() const { + return lineEdit()->hasSelectedText(); } diff --git a/src/widget/wsearchlineedit.h b/src/widget/wsearchlineedit.h index ccc4ed769bc..87737927cd9 100644 --- a/src/widget/wsearchlineedit.h +++ b/src/widget/wsearchlineedit.h @@ -90,6 +90,8 @@ class WSearchLineEdit : public QComboBox, public WBaseWidget { void updateCompleter(); void deleteSelectedComboboxItem(); void deleteSelectedListItem(); + void triggerSearchDebounced(); + bool hasSelectedText() const; inline int findCurrentTextIndex() { return findData(currentText(), Qt::DisplayRole); diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 2fa1d34a366..36537afdd78 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -554,8 +554,8 @@ void WTrackTableView::mouseMoveEvent(QMouseEvent* pEvent) { // called every time the mouse is moved -- kain88 May 2012 if (pEvent->buttons() != Qt::LeftButton) { // Needed for mouse-tracking to fire entered() events. If we call this - // outside of this if statement then we get 'ghost' drags. See Bug - // #1008737 + // outside of this if statement then we get 'ghost' drags. See issue + // #6507 WLibraryTableView::mouseMoveEvent(pEvent); return; } diff --git a/tools/debian_buildenv_qt6.sh b/tools/debian_buildenv_qt6.sh new file mode 100755 index 00000000000..5089f28427b --- /dev/null +++ b/tools/debian_buildenv_qt6.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# This script works with Debian, Ubuntu, and derivatives. +# shellcheck disable=SC1091 +set -o pipefail + +case "$1" in + name) + echo "No build environment name required for Debian based distros." >&2 + echo "This script installs the build dependencies via apt using the \"setup\" option." >&2 + ;; + + setup) + source /etc/lsb-release 2>/dev/null + case "${DISTRIB_CODENAME}" in + bionic) # Ubuntu 18.04 LTS + PACKAGES_EXTRA=( + libmp4v2-dev + ) + ;; + *) # libmp4v2 was removed from Debian 10 & Ubuntu 20.04 due to lack of maintenance, so use FFMPEG instead + PACKAGES_EXTRA=( + libavformat-dev + ) + esac + + sudo apt-get update + + # If jackd2 is installed as per dpkg database, install libjack-jackd2-dev. + # This avoids a package deadlock, resulting in jackd2 being removed, and jackd1 being installed, + # to satisfy portaudio19-dev's need for a jackd dev package. In short, portaudio19-dev needs a + # jackd dev library, so let's give it one.. + if [ "$(dpkg-query -W -f='${Status}' jackd2 2>/dev/null | grep -c "ok installed")" -eq 1 ]; + then + sudo apt-get install libjack-jackd2-dev; + fi + + + sudo apt-get install -y --no-install-recommends -- \ + ccache \ + cmake \ + clazy \ + clang-tidy \ + debhelper \ + devscripts \ + docbook-to-man \ + dput \ + fonts-open-sans \ + fonts-ubuntu \ + g++ \ + lcov \ + libchromaprint-dev \ + libdistro-info-perl \ + libebur128-dev \ + libfaad-dev \ + libfftw3-dev \ + libflac-dev \ + libgl1-mesa-dev \ + libhidapi-dev \ + libid3tag0-dev \ + liblilv-dev \ + libmad0-dev \ + libmodplug-dev \ + libmp3lame-dev \ + libmsgsl-dev \ + libopus-dev \ + libopusfile-dev \ + libportmidi-dev \ + libprotobuf-dev \ + libqt6core5compat6-dev\ + libqt6opengl6-dev \ + libqt6sql6-sqlite \ + libqt6svg6-dev \ + librubberband-dev \ + libshout-idjc-dev \ + libsndfile1-dev \ + libsoundtouch-dev \ + libsqlite3-dev \ + libssl-dev \ + libtag1-dev \ + libudev-dev \ + libupower-glib-dev \ + libusb-1.0-0-dev \ + libwavpack-dev \ + lv2-dev \ + markdown \ + portaudio19-dev \ + protobuf-compiler \ + qtkeychain-qt6-dev \ + qt6-declarative-dev \ + qml-module-qtquick-controls \ + qml-module-qtquick-controls2 \ + qml-module-qt-labs-qmlmodels \ + qml-module-qtquick-shapes \ + "${PACKAGES_EXTRA[@]}" + ;; + *) + echo "Usage: $0 [options]" + echo "" + echo "options:" + echo " help Displays this help." + echo " name Displays the name of the required build environment." + echo " setup Installs the build environment." + ;; +esac