From 06503c9d938e8b367aa12239702f30bdc195d79e Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 9 Sep 2022 17:55:02 +0200 Subject: [PATCH 01/32] Add mappings for Reloop Mixage --- res/controllers/Reloop-Mixage.midi.xml | 709 +++++++++++++++++++++++ res/controllers/Reloop-Mixage.scripts.js | 366 ++++++++++++ 2 files changed, 1075 insertions(+) create mode 100755 res/controllers/Reloop-Mixage.midi.xml create mode 100755 res/controllers/Reloop-Mixage.scripts.js diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml new file mode 100755 index 00000000000..0b5063ad754 --- /dev/null +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -0,0 +1,709 @@ + + + + Reloop Mixage + Bim Overbohm + Mapping for the Reloop Mixage Interface Edition controller (https://www.reloop.com/reloop-mixage-ie). Should also work on the non-interface version. + https://mixxx.discourse.group/t/reloop-mixage-mapping/14779 + https://github.com/mixxxdj/mixxx/wiki/Reloop%20Mixage + + + + + + + + [Channel2] + Mixage.wheelTurn + 0xB0 + 0x25 + + + + + + [Channel1] + cue_play + 0x90 + 0x0A + + + + + + [Channel1] + sync_enabled + 0x90 + 0x09 + + + + + + [Channel1] + cue_default + 0x90 + 0x0B + + + + + + [Channel2] + sync_enabled + 0x90 + 0x17 + + + + + + [Channel2] + cue_default + 0x90 + 0x19 + + + + + + [Channel2] + cue_play + 0x90 + 0x18 + + + + + + [Channel1] + rate_temp_down + 0x90 + 0x01 + + + + + + [Channel2] + rate_temp_up + 0x90 + 0x10 + + + + + + [Master] + crossfader + 0xB0 + 0x31 + + + + + + [Channel2] + keylock + 0x90 + 0x55 + + + + + + [Channel1] + Mixage.wheelTurn + 0xB0 + 0x24 + + + + + + [Channel1] + keylock + 0x90 + 0x47 + + + + + + [Channel2] + pfl + 0x90 + 0x1C + + + + + + [EffectRack1_EffectUnit1] + Mixage.handleEffectMasterOn + 0x90 + 0x46 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleEffectMasterOn + 0x90 + 0x54 + + + + + + [EffectRack1_EffectUnit1] + Mixage.handleEffectChannelOn + 0x90 + 0x08 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleEffectChannelOn + 0x90 + 0x16 + + + + + + [EffectRack1_EffectUnit1] + Mixage.handleEffectChannelSelect + 0x90 + 0x07 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleEffectChannelSelect + 0x90 + 0x15 + + + + + + [EffectRack1_EffectUnit1] + Mixage.handleEffectDryWet + 0xB0 + 0x21 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleEffectDryWet + 0xB0 + 0x23 + + + + + + [EffectRack1_EffectUnit1] + Mixage.handleEffectSuper + 0xB0 + 0x60 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleEffectSuper + 0xB0 + 0x62 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + parameter1 + 0xB0 + 0x37 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + parameter2 + 0xB0 + 0x36 + + + + + + [EqualizerRack1_[Channel1]_Effect1] + parameter3 + 0xB0 + 0x35 + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter1 + 0xB0 + 0x3D + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter2 + 0xB0 + 0x3C + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter3 + 0xB0 + 0x3B + + + + + + [QuickEffectRack1_[Channel1]] + super1 + 0xB0 + 0x34 + + + + + + [QuickEffectRack1_[Channel2]] + super1 + 0xB0 + 0x3A + + + + + + [Channel1] + play + 0x90 + 0x0C + + + + + + [Channel1] + Mixage.scrollActive + 0x90 + 0x03 + + + + + + [Channel2] + Mixage.scratchActive + 0x90 + 0x12 + + + + + + [Channel1] + loop_in + 0x90 + 0x44 + + + + + + [Channel1] + loop_out + 0x90 + 0x45 + + + + + + [Channel1] + beatloop_activate + 0x90 + 0x05 + + + + + + [Channel1] + reloop_toggle + 0x90 + 0x06 + + + + + + [Channel1] + Mixage.handleBeatMove + 0xB0 + 0x5F + + + + + + [Channel1] + Mixage.handleBeatMoveLength + 0xB0 + 0x20 + + + + + + [Channel1] + Mixage.handleBeatMovePressed + 0x90 + 0x20 + + + + + + [Channel2] + loop_in + 0x90 + 0x52 + + + + + + [Channel2] + loop_out + 0x90 + 0x53 + + + + + + [Channel2] + beatloop_activate + 0x90 + 0x13 + + + + + + [Channel2] + reloop_toggle + 0x90 + 0x14 + + + + + + [Channel2] + Mixage.handleBeatMoveLength + 0xB0 + 0x22 + + + + + + [Channel2] + Mixage.handleBeatMove + 0xB0 + 0x61 + + + + + + [Channel2] + Mixage.handleBeatMovePressed + 0x90 + 0x22 + + + + + + [Channel2] + Mixage.wheelTouch + 0x90 + 0x25 + + + + + + [Channel1] + pregain + 0xB0 + 0x33 + + + + + + [Channel2] + rate_temp_down + 0x90 + 0x0F + + + + + + [Channel1] + rate_temp_up + 0x90 + 0x02 + + + + + + [Channel2] + pregain + 0xB0 + 0x39 + + + + + + [Channel2] + Mixage.scrollActive + 0x90 + 0x11 + + + + + + [Channel1] + Mixage.wheelTouch + 0x90 + 0x24 + + + + + + [Library] + Mixage.handleLibrary + 0x90 + 0x0D + + + + + + [Library] + Mixage.handleLibrary + 0x90 + 0x1B + + + + + + [Library] + Mixage.handleLibrary + 0x90 + 0x4C + + + + + + [Library] + Mixage.handleLibrary + 0x90 + 0x5A + + + + + + [Library] + Mixage.handleLibrary + 0x90 + 0x1F + + + + + + [Library] + Mixage.handleLibrary + 0xB0 + 0x1F + + + + + + [Master] + headMix + 0xB0 + 0x32 + + + + + + [Channel1] + pfl + 0x90 + 0x0E + + + + + + [Channel1] + volume + 0xB0 + 0x38 + + + + + + [Channel2] + rate + 0xE1 + + + + + + [Channel2] + volume + 0xB0 + 0x3E + + + + + + [Channel1] + rate + 0xE0 + + + + + + [Channel2] + play + 0x90 + 0x1A + + + + + + [Channel2] + Mixage.scrollActive + 0x90 + 0x11 + + + + + + [PreviewDeck1] + play + 0x90 + 0x4D + + + + + + [PreviewDeck1] + stop + 0x90 + 0x5B + + + + + + [Channel1] + Mixage.scratchActive + 0x90 + 0x04 + + + + + + [Channel1] + hotcue_1_activate + 0x90 + 0x48 + + + + + + [Channel1] + hotcue_2_activate + 0x90 + 0x49 + + + + + + [Channel1] + hotcue_3_activate + 0x90 + 0x4A + + + + + + [Channel1] + hotcue_4_activate + 0x90 + 0x4B + + + + + + + + \ No newline at end of file diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js new file mode 100755 index 00000000000..a79391b7b60 --- /dev/null +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -0,0 +1,366 @@ +// Name: Reloop Mixage +// Author: Bim Overbohm +// Version: 1.0.1, needs Mixxx 2.1+ + +var Mixage = {}; + +Mixage.updateVUMetersTimer = 0; +Mixage.libraryHideTimer = 0; +Mixage.libraryReducedHideTimeout = 500; +Mixage.libraryHideTimeout = 4000; +Mixage.libraryRemainingTime = 0; +Mixage.scratchPressed = false; +Mixage.scrollPressed = false; +Mixage.scratchByWheelTouch = false; +Mixage.beatMovePressed = false; +Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 +Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 + +Mixage.init = function (/*id, debugging*/) { + Mixage.connectControlsToFunctions('[Channel1]'); + Mixage.connectControlsToFunctions('[Channel2]'); + // all buttons off + for (var i = 0; i < 255; i++) { + midi.sendShortMsg(0x90, i, 0); + } + // start timers for updating the VU meters + Mixage.updateVUMetersTimer = engine.beginTimer(33, Mixage.updateVUMeters); + engine.scratchDisable(1); + engine.scratchDisable(2); + // disable effects for both channels + engine.setValue('[EffectRack1_EffectUnit1]', 'group_[Channel1]_enable', false); + engine.setValue('[EffectRack1_EffectUnit2]', 'group_[Channel1]_enable', false); + engine.setValue('[EffectRack1_EffectUnit1]', 'group_[Channel2]_enable', false); + engine.setValue('[EffectRack1_EffectUnit2]', 'group_[Channel2]_enable', false); +} + +Mixage.shutdown = function () { + engine.stopTimer(Mixage.updateVUMetersTimer); + Mixage.setLibraryMaximized(false); + Mixage.connectControlsToFunctions('[Channel1]', true); + Mixage.connectControlsToFunctions('[Channel2]', true); + // all button LEDs off + for (var i = 0; i < 255; i++) { + midi.sendShortMsg(0x90, i, 0); + } +} + +// Maps channels and their controls to a MIDI control number to toggle their LEDs +Mixage.ledMap = { + '[Channel1]': { + 'cue_indicator': 0x0A, + 'cue_default': 0x0B, + 'play_indicator': 0x0C, + 'pfl': 0x0E, + 'loop_enabled': 0x06, + 'sync_enabled': 0x09, + 'master_on': 0x07, + 'fx_on': 0x08 + }, + '[Channel2]': { + 'cue_indicator': 0x18, + 'cue_default': 0x19, + 'play_indicator': 0x1A, + 'pfl': 0x1C, + 'loop_enabled': 0x14, + 'sync_enabled': 0x17, + 'master_on': 0x15, + 'fx_on': 0x16 + } +}; + +// Maps mixxx controls to a function that toggles their LEDs +Mixage.connectionMap = { + 'cue_indicator': 'Mixage.toggleLED', + 'cue_default': 'Mixage.toggleLED', + 'play_indicator': 'Mixage.handlePlay', + 'pfl': 'Mixage.toggleLED', + 'loop_enabled': 'Mixage.toggleLED', + 'sync_enabled': 'Mixage.toggleLED' +}; + +// Set or remove functions to call when the state of a mixxx control changes +Mixage.connectControlsToFunctions = function (group, remove) { + remove = (typeof remove !== 'undefined') ? remove : false; + for (var control in Mixage.connectionMap) { + engine.connectControl(group, control, Mixage.connectionMap[control], remove) + if (!remove) { + engine.trigger(group, control) + } + } +} + +// Toggle the LED on the MIDI controller by sending a MIDI message +Mixage.toggleLED = function (value, group, control) { + midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1) ? 0x7F : 0); +} + +Mixage.updateVUMeters = function () { + midi.sendShortMsg(0x90, 29, engine.getValue('[Channel1]', 'VuMeter') * 7); + midi.sendShortMsg(0x90, 30, engine.getValue('[Channel2]', 'VuMeter') * 7); +} + +// Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck +Mixage.handlePlay = function (value, group, control) { + Mixage.toggleLED(value, group, control); + engine.setValue('[PreviewDeck1]', 'stop', true); +} + +// Helper function to scroll the playlist +Mixage.scrollLibrary = function (value) { + Mixage.setLibraryMaximized(true); + //engine.setValue('[Library]', 'MoveVertical', value); + engine.setValue('[Playlist]', 'SelectTrackKnob', value); // for Mixxx < 2.1 +} + +// A button for the playlist was pressed +Mixage.handleLibrary = function (channel, control, value, status/*, group*/) { + // "push2browse" button was moved somehow + if (control === 0x1F) { + // "push2browse" button was pushed + if (status == 0x90 && value === 0x7F) { + Mixage.setLibraryMaximized(true); + // stop the currently playing track. if it wasn't playing, start it + if (engine.getValue('[PreviewDeck1]', 'play')) { + engine.setValue('[PreviewDeck1]', 'stop', true); + } + else { + engine.setValue('[PreviewDeck1]', 'LoadSelectedTrackAndPlay', true); + } + } + // "push2browse" button was turned + else if (status === 0xB0) { + var newValue = value - 64; + Mixage.scrollLibrary(newValue); + } + } + // load into deck 1 + else if (control === 0x0D || control === 0x4C) { + if (value === 0x7F) { + engine.setValue('[PreviewDeck1]', 'stop', true); + engine.setValue('[Channel1]', control === 0x4C ? 'LoadSelectedTrackAndPlay' : 'LoadSelectedTrack', true); + Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; + } + } + // load into deck 2 + else if (control === 0x1B || control === 0x5A) { + if (value === 0x7F) { + engine.setValue('[PreviewDeck1]', 'stop', true); + engine.setValue('[Channel2]', control === 0x5A ? 'LoadSelectedTrackAndPlay' : 'LoadSelectedTrack', true); + Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; + } + } +} + +// Set the library visible and hide it when libraryHideTimeOut is reached +Mixage.setLibraryMaximized = function (visible) { + if (visible === true) { + Mixage.libraryRemainingTime = Mixage.libraryHideTimeout; + // maximize library if not maximized already + if (engine.getValue('[Master]', 'maximize_library') !== true) { + engine.setValue('[Master]', 'maximize_library', true); + if (Mixage.libraryHideTimer === 0) { + // timer not running. start it + Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout); + } + } + } + else { + if (Mixage.libraryHideTimer !== 0) { + engine.stopTimer(Mixage.libraryHideTimer); + Mixage.libraryHideTimer = 0; + } + Mixage.libraryRemainingTime = 0; + engine.setValue('[Master]', 'maximize_library', false); + } +} + +Mixage.libraryCheckTimeout = function () { + Mixage.libraryRemainingTime -= Mixage.libraryHideTimeout / 5; + if (Mixage.libraryRemainingTime <= 0) { + engine.stopTimer(Mixage.libraryHideTimer); + Mixage.libraryHideTimer = 0; + Mixage.libraryRemainingTime = 0; + engine.setValue('[Master]', 'maximize_library', false); + } +} + +// The "record" button that enables/disables scratching +Mixage.scratchActive = function (channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 + var deckNr = control === 0x04 ? 1 : 2; + if (value === 0x7F) { + Mixage.scratchPressed = true; + var alpha = 1.0 / 8.0; + var beta = alpha / 32.0; + engine.scratchEnable(deckNr, 620, 20.0/*33.0+1.0/3.0*/, alpha, beta); + } else { + Mixage.scratchPressed = false; + engine.scratchDisable(deckNr); + } +} + +// The "magnifying glass" button that enables/disables playlist scrolling +Mixage.scrollActive = function (channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 + var deckNr = control === 0x03 ? 1 : 2; + Mixage.scrollPressed = value === 0x7F; + if (Mixage.scrollPressed) { + Mixage.setLibraryMaximized(true); + } +} + +// The touch function on the wheels that enables/disables scratching +Mixage.wheelTouch = function (channel, control, value/*, status, group*/) { + // check if scratching through wheel touch is enabled + if (Mixage.scratchByWheelTouch) { + // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 + var deckNr = control - 0x24 + 1; + if (value === 0x7F) { + var alpha = 1.0 / 8; + var beta = alpha / 32.0; + engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); + } else { + engine.scratchDisable(deckNr); + } + } +} + +// The wheel that actually controls the scratching / jogging +Mixage.wheelTurn = function (channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 + var deckNr = control - 0x24 + 1; + // Control centers on 0x40 (64), calculate difference to that value + var newValue = value - 64; + // In either case, register the movement + if (Mixage.scratchPressed) { + engine.scratchTick(deckNr, newValue); // scratch + } + else { + engine.scratchDisable(deckNr); + } + if (Mixage.scrollPressed) { + Mixage.scrollLibrary(newValue); + } + //engine.setValue('[Channel'+deckNr+']', 'jog', newValue); // Pitch bend +} + +// The MASTER button that toggles routing master through effects +Mixage.handleEffectMasterOn = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 + var unitNr = control === 0x46 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle enablement + var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; + var keyString = 'group_[Master]_enable'; + var isEnabled = !engine.getValue(controlString, keyString); + engine.setValue(controlString, keyString, isEnabled); + Mixage.toggleLED(isEnabled ? 1 : 0, '[Channel' + unitNr + ']', 'master_on'); + } +} + +// The FX ON button that toggles routing channel 1/2 through effects +Mixage.handleEffectChannelOn = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x08 controls unit 1, 0x16 unit 2 + var unitNr = control === 0x08 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle enablement + Mixage.effectRackEnabled[unitNr - 1] = !Mixage.effectRackEnabled[unitNr - 1]; + var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + // update controls + var keyString = 'group_[Channel' + unitNr + ']_enable'; + engine.setValue('[EffectRack1_EffectUnit1]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); + engine.setValue('[EffectRack1_EffectUnit2]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + Mixage.toggleLED(isEnabled ? 1 : 0, '[Channel' + unitNr + ']', 'fx_on'); + } +} + +// The FX SEL button that selects which effects are enabled for channel 1/2 +Mixage.handleEffectChannelSelect = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x07 controls unit 1, 0x15 unit 2 + var unitNr = control === 0x07 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle select state + var selected1 = Mixage.effectRackSelected[unitNr - 1][0]; + var selected2 = Mixage.effectRackSelected[unitNr - 1][1]; + if (selected1 && selected2) { + selected1 = true; + selected2 = false; + } + else if (selected1) { + selected1 = false; + selected2 = true; + } + else { + selected1 = true; + selected2 = true; + } + Mixage.effectRackSelected[unitNr - 1][0] = selected1; + Mixage.effectRackSelected[unitNr - 1][1] = selected2; + // update controls + var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + var keyString = 'group_[Channel' + unitNr + ']_enable'; + engine.setValue('[EffectRack1_EffectUnit1]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); + engine.setValue('[EffectRack1_EffectUnit2]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + } +} + +Mixage.handleEffectDryWet = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 + var unitNr = control === 0x21 ? 1 : 2; + // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 + var diff = (value - 64) / 10.0; + // In either case, register the movement + var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; + var dryWetValue = engine.getValue(controlString, 'mix'); + engine.setValue(controlString, 'mix', dryWetValue + diff); +} + +// The PAN rotary control used here for the overall effect super control +Mixage.handleEffectSuper = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x60 controls unit 1, 0x62 unit 2 + var unitNr = control === 0x60 ? 1 : 2; + // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 + var diff = (value - 64) / 10.0; + // In either case, register the movement + var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; + var mixValue = engine.getValue(controlString, 'super1'); + engine.setValue(controlString, 'super1', mixValue + diff); +} + +// The BEAT MOVE rotary control is used as an extra "shift" key when pushed down +Mixage.handleBeatMovePressed = function (channel, control, value/*, status, group*/) { + Mixage.beatMovePressed = value === 0x7f; +} + +Mixage.handleBeatMoveLength = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 + var unitNr = control === 0x20 ? 1 : 2; + var moveDirection = unitNr == 1 ? 1 : -1; + // Control centers on 0x40 (64), calculate difference to that + var diff = (value - 64); + // In either case, register the movement + if (Mixage.beatMovePressed) { + var direction = engine.getParameter('[Channel' + unitNr + ']', 'beatjump_size'); + direction = moveDirection * diff > 0 ? 2 * direction : direction / 2; + engine.setParameter('[Channel' + unitNr + ']', 'beatjump_size', direction); + } + else { + var direction = moveDirection * diff > 0 ? 'loop_double' : 'loop_halve'; + engine.setValue('[Channel' + unitNr + ']', direction, true); + } +} + +Mixage.handleBeatMove = function (channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x5f controls unit 1, 0x61 unit 2 + var unitNr = control === 0x5f ? 1 : 2; + var moveDirection = unitNr == 1 ? 1 : -1; + // Control centers on 0x40 (64), calculate difference to that + var diff = (value - 64); + // In either case, register the movement + var direction = moveDirection * diff > 0 ? 'beatjump_forward' : 'beatjump_backward'; + engine.setValue('[Channel' + unitNr + ']', direction, true); +} From 572a07d3036fc489aa634a2b6b71f2beb6b2e09a Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Mon, 12 Sep 2022 21:38:40 +0200 Subject: [PATCH 02/32] Fix ESlint problems --- res/controllers/Reloop-Mixage.scripts.js | 596 +++++++++++------------ 1 file changed, 291 insertions(+), 305 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index a79391b7b60..d22543827a0 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,6 +1,6 @@ // Name: Reloop Mixage // Author: Bim Overbohm -// Version: 1.0.1, needs Mixxx 2.1+ +// Version: 1.0.2 needs Mixxx 2.1+ var Mixage = {}; @@ -16,351 +16,337 @@ Mixage.beatMovePressed = false; Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 -Mixage.init = function (/*id, debugging*/) { - Mixage.connectControlsToFunctions('[Channel1]'); - Mixage.connectControlsToFunctions('[Channel2]'); - // all buttons off - for (var i = 0; i < 255; i++) { - midi.sendShortMsg(0x90, i, 0); - } - // start timers for updating the VU meters - Mixage.updateVUMetersTimer = engine.beginTimer(33, Mixage.updateVUMeters); - engine.scratchDisable(1); - engine.scratchDisable(2); - // disable effects for both channels - engine.setValue('[EffectRack1_EffectUnit1]', 'group_[Channel1]_enable', false); - engine.setValue('[EffectRack1_EffectUnit2]', 'group_[Channel1]_enable', false); - engine.setValue('[EffectRack1_EffectUnit1]', 'group_[Channel2]_enable', false); - engine.setValue('[EffectRack1_EffectUnit2]', 'group_[Channel2]_enable', false); -} +Mixage.init = function(/*id, debugging*/) { + Mixage.connectControlsToFunctions("[Channel1]"); + Mixage.connectControlsToFunctions("[Channel2]"); + // all buttons off + for (var i = 0; i < 255; i++) { + midi.sendShortMsg(0x90, i, 0); + } + // start timers for updating the VU meters + Mixage.updateVUMetersTimer = engine.beginTimer(33, Mixage.updateVUMeters); + engine.scratchDisable(1); + engine.scratchDisable(2); + // disable effects for both channels + engine.setValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", false); + engine.setValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", false); + engine.setValue("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", false); + engine.setValue("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", false); +}; -Mixage.shutdown = function () { - engine.stopTimer(Mixage.updateVUMetersTimer); - Mixage.setLibraryMaximized(false); - Mixage.connectControlsToFunctions('[Channel1]', true); - Mixage.connectControlsToFunctions('[Channel2]', true); - // all button LEDs off - for (var i = 0; i < 255; i++) { - midi.sendShortMsg(0x90, i, 0); - } -} +Mixage.shutdown = function() { + engine.stopTimer(Mixage.updateVUMetersTimer); + Mixage.setLibraryMaximized(false); + Mixage.connectControlsToFunctions("[Channel1]", true); + Mixage.connectControlsToFunctions("[Channel2]", true); + // all button LEDs off + for (var i = 0; i < 255; i++) { + midi.sendShortMsg(0x90, i, 0); + } +}; // Maps channels and their controls to a MIDI control number to toggle their LEDs Mixage.ledMap = { - '[Channel1]': { - 'cue_indicator': 0x0A, - 'cue_default': 0x0B, - 'play_indicator': 0x0C, - 'pfl': 0x0E, - 'loop_enabled': 0x06, - 'sync_enabled': 0x09, - 'master_on': 0x07, - 'fx_on': 0x08 - }, - '[Channel2]': { - 'cue_indicator': 0x18, - 'cue_default': 0x19, - 'play_indicator': 0x1A, - 'pfl': 0x1C, - 'loop_enabled': 0x14, - 'sync_enabled': 0x17, - 'master_on': 0x15, - 'fx_on': 0x16 - } + "[Channel1]": { + "cue_indicator": 0x0A, + "cue_default": 0x0B, + "play_indicator": 0x0C, + "pfl": 0x0E, + "loop_enabled": 0x06, + "sync_enabled": 0x09, + "master_on": 0x07, + "fx_on": 0x08 + }, + "[Channel2]": { + "cue_indicator": 0x18, + "cue_default": 0x19, + "play_indicator": 0x1A, + "pfl": 0x1C, + "loop_enabled": 0x14, + "sync_enabled": 0x17, + "master_on": 0x15, + "fx_on": 0x16 + } }; // Maps mixxx controls to a function that toggles their LEDs Mixage.connectionMap = { - 'cue_indicator': 'Mixage.toggleLED', - 'cue_default': 'Mixage.toggleLED', - 'play_indicator': 'Mixage.handlePlay', - 'pfl': 'Mixage.toggleLED', - 'loop_enabled': 'Mixage.toggleLED', - 'sync_enabled': 'Mixage.toggleLED' + "cue_indicator": "Mixage.toggleLED", + "cue_default": "Mixage.toggleLED", + "play_indicator": "Mixage.handlePlay", + "pfl": "Mixage.toggleLED", + "loop_enabled": "Mixage.toggleLED", + "sync_enabled": "Mixage.toggleLED" }; // Set or remove functions to call when the state of a mixxx control changes -Mixage.connectControlsToFunctions = function (group, remove) { - remove = (typeof remove !== 'undefined') ? remove : false; - for (var control in Mixage.connectionMap) { - engine.connectControl(group, control, Mixage.connectionMap[control], remove) - if (!remove) { - engine.trigger(group, control) - } - } -} +Mixage.connectControlsToFunctions = function(group, remove) { + remove = (typeof remove !== "undefined") ? remove : false; + for (var control in Mixage.connectionMap) { + engine.connectControl(group, control, Mixage.connectionMap[control], remove); + if (!remove) { + engine.trigger(group, control); + } + } +}; // Toggle the LED on the MIDI controller by sending a MIDI message -Mixage.toggleLED = function (value, group, control) { - midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1) ? 0x7F : 0); -} +Mixage.toggleLED = function(value, group, control) { + midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1) ? 0x7F : 0); +}; -Mixage.updateVUMeters = function () { - midi.sendShortMsg(0x90, 29, engine.getValue('[Channel1]', 'VuMeter') * 7); - midi.sendShortMsg(0x90, 30, engine.getValue('[Channel2]', 'VuMeter') * 7); -} +Mixage.updateVUMeters = function() { + midi.sendShortMsg(0x90, 29, engine.getValue("[Channel1]", "VuMeter") * 7); + midi.sendShortMsg(0x90, 30, engine.getValue("[Channel2]", "VuMeter") * 7); +}; // Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck -Mixage.handlePlay = function (value, group, control) { - Mixage.toggleLED(value, group, control); - engine.setValue('[PreviewDeck1]', 'stop', true); -} +Mixage.handlePlay = function(value, group, control) { + Mixage.toggleLED(value, group, control); + engine.setValue("[PreviewDeck1]", "stop", true); +}; // Helper function to scroll the playlist -Mixage.scrollLibrary = function (value) { - Mixage.setLibraryMaximized(true); - //engine.setValue('[Library]', 'MoveVertical', value); - engine.setValue('[Playlist]', 'SelectTrackKnob', value); // for Mixxx < 2.1 -} +Mixage.scrollLibrary = function(value) { + Mixage.setLibraryMaximized(true); + //engine.setValue('[Library]', 'MoveVertical', value); + engine.setValue("[Playlist]", "SelectTrackKnob", value); // for Mixxx < 2.1 +}; // A button for the playlist was pressed -Mixage.handleLibrary = function (channel, control, value, status/*, group*/) { - // "push2browse" button was moved somehow - if (control === 0x1F) { - // "push2browse" button was pushed - if (status == 0x90 && value === 0x7F) { - Mixage.setLibraryMaximized(true); - // stop the currently playing track. if it wasn't playing, start it - if (engine.getValue('[PreviewDeck1]', 'play')) { - engine.setValue('[PreviewDeck1]', 'stop', true); - } - else { - engine.setValue('[PreviewDeck1]', 'LoadSelectedTrackAndPlay', true); - } - } - // "push2browse" button was turned - else if (status === 0xB0) { - var newValue = value - 64; - Mixage.scrollLibrary(newValue); - } - } - // load into deck 1 - else if (control === 0x0D || control === 0x4C) { - if (value === 0x7F) { - engine.setValue('[PreviewDeck1]', 'stop', true); - engine.setValue('[Channel1]', control === 0x4C ? 'LoadSelectedTrackAndPlay' : 'LoadSelectedTrack', true); - Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; - } - } - // load into deck 2 - else if (control === 0x1B || control === 0x5A) { - if (value === 0x7F) { - engine.setValue('[PreviewDeck1]', 'stop', true); - engine.setValue('[Channel2]', control === 0x5A ? 'LoadSelectedTrackAndPlay' : 'LoadSelectedTrack', true); - Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; - } - } -} +Mixage.handleLibrary = function(channel, control, value, status/*, group*/) { + // "push2browse" button was moved somehow + if (control === 0x1F) { // "push2browse" button was pushed + if (status === 0x90 && value === 0x7F) { + Mixage.setLibraryMaximized(true); + // stop the currently playing track. if it wasn't playing, start it + if (engine.getValue("[PreviewDeck1]", "play")) { + engine.setValue("[PreviewDeck1]", "stop", true); + } else { + engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); + } + } else if (status === 0xB0) { // "push2browse" button was turned + var newValue = value - 64; + Mixage.scrollLibrary(newValue); + } + } else if (control === 0x0D || control === 0x4C) { // load into deck 1 + if (value === 0x7F) { + engine.setValue("[PreviewDeck1]", "stop", true); + engine.setValue("[Channel1]", control === 0x4C ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); + Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; + } + } else if (control === 0x1B || control === 0x5A) { // load into deck 2 + if (value === 0x7F) { + engine.setValue("[PreviewDeck1]", "stop", true); + engine.setValue("[Channel2]", control === 0x5A ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); + Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; + } + } +}; // Set the library visible and hide it when libraryHideTimeOut is reached -Mixage.setLibraryMaximized = function (visible) { - if (visible === true) { - Mixage.libraryRemainingTime = Mixage.libraryHideTimeout; - // maximize library if not maximized already - if (engine.getValue('[Master]', 'maximize_library') !== true) { - engine.setValue('[Master]', 'maximize_library', true); - if (Mixage.libraryHideTimer === 0) { - // timer not running. start it - Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout); - } - } - } - else { - if (Mixage.libraryHideTimer !== 0) { - engine.stopTimer(Mixage.libraryHideTimer); - Mixage.libraryHideTimer = 0; - } - Mixage.libraryRemainingTime = 0; - engine.setValue('[Master]', 'maximize_library', false); - } -} +Mixage.setLibraryMaximized = function(visible) { + if (visible === true) { + Mixage.libraryRemainingTime = Mixage.libraryHideTimeout; + // maximize library if not maximized already + if (engine.getValue("[Master]", "maximize_library") !== true) { + engine.setValue("[Master]", "maximize_library", true); + if (Mixage.libraryHideTimer === 0) { + // timer not running. start it + Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout); + } + } + } else { + if (Mixage.libraryHideTimer !== 0) { + engine.stopTimer(Mixage.libraryHideTimer); + Mixage.libraryHideTimer = 0; + } + Mixage.libraryRemainingTime = 0; + engine.setValue("[Master]", "maximize_library", false); + } +}; -Mixage.libraryCheckTimeout = function () { - Mixage.libraryRemainingTime -= Mixage.libraryHideTimeout / 5; - if (Mixage.libraryRemainingTime <= 0) { - engine.stopTimer(Mixage.libraryHideTimer); - Mixage.libraryHideTimer = 0; - Mixage.libraryRemainingTime = 0; - engine.setValue('[Master]', 'maximize_library', false); - } -} +Mixage.libraryCheckTimeout = function() { + Mixage.libraryRemainingTime -= Mixage.libraryHideTimeout / 5; + if (Mixage.libraryRemainingTime <= 0) { + engine.stopTimer(Mixage.libraryHideTimer); + Mixage.libraryHideTimer = 0; + Mixage.libraryRemainingTime = 0; + engine.setValue("[Master]", "maximize_library", false); + } +}; // The "record" button that enables/disables scratching -Mixage.scratchActive = function (channel, control, value/*, status, group*/) { - // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 - var deckNr = control === 0x04 ? 1 : 2; - if (value === 0x7F) { - Mixage.scratchPressed = true; - var alpha = 1.0 / 8.0; - var beta = alpha / 32.0; - engine.scratchEnable(deckNr, 620, 20.0/*33.0+1.0/3.0*/, alpha, beta); - } else { - Mixage.scratchPressed = false; - engine.scratchDisable(deckNr); - } -} +Mixage.scratchActive = function(channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 + var deckNr = control === 0x04 ? 1 : 2; + if (value === 0x7F) { + Mixage.scratchPressed = true; + var alpha = 1.0 / 8.0; + var beta = alpha / 32.0; + engine.scratchEnable(deckNr, 620, 20.0/*33.0+1.0/3.0*/, alpha, beta); + } else { + Mixage.scratchPressed = false; + engine.scratchDisable(deckNr); + } +}; // The "magnifying glass" button that enables/disables playlist scrolling -Mixage.scrollActive = function (channel, control, value/*, status, group*/) { - // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 - var deckNr = control === 0x03 ? 1 : 2; - Mixage.scrollPressed = value === 0x7F; - if (Mixage.scrollPressed) { - Mixage.setLibraryMaximized(true); - } -} +Mixage.scrollActive = function(channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 + Mixage.scrollPressed = value === 0x7F; + if (Mixage.scrollPressed) { + Mixage.setLibraryMaximized(true); + } +}; // The touch function on the wheels that enables/disables scratching -Mixage.wheelTouch = function (channel, control, value/*, status, group*/) { - // check if scratching through wheel touch is enabled - if (Mixage.scratchByWheelTouch) { - // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control - 0x24 + 1; - if (value === 0x7F) { - var alpha = 1.0 / 8; - var beta = alpha / 32.0; - engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); - } else { - engine.scratchDisable(deckNr); - } - } -} +Mixage.wheelTouch = function(channel, control, value/*, status, group*/) { + // check if scratching through wheel touch is enabled + if (Mixage.scratchByWheelTouch) { + // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 + var deckNr = control - 0x24 + 1; + if (value === 0x7F) { + var alpha = 1.0 / 8; + var beta = alpha / 32.0; + engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); + } else { + engine.scratchDisable(deckNr); + } + } +}; // The wheel that actually controls the scratching / jogging -Mixage.wheelTurn = function (channel, control, value/*, status, group*/) { - // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control - 0x24 + 1; - // Control centers on 0x40 (64), calculate difference to that value - var newValue = value - 64; - // In either case, register the movement - if (Mixage.scratchPressed) { - engine.scratchTick(deckNr, newValue); // scratch - } - else { - engine.scratchDisable(deckNr); - } - if (Mixage.scrollPressed) { - Mixage.scrollLibrary(newValue); - } - //engine.setValue('[Channel'+deckNr+']', 'jog', newValue); // Pitch bend -} +Mixage.wheelTurn = function(channel, control, value/*, status, group*/) { + // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 + var deckNr = control - 0x24 + 1; + // Control centers on 0x40 (64), calculate difference to that value + var newValue = value - 64; + // In either case, register the movement + if (Mixage.scratchPressed) { + engine.scratchTick(deckNr, newValue); // scratch + } else { + engine.scratchDisable(deckNr); + } + if (Mixage.scrollPressed) { + Mixage.scrollLibrary(newValue); + } + //engine.setValue('[Channel'+deckNr+']', 'jog', newValue); // Pitch bend +}; // The MASTER button that toggles routing master through effects -Mixage.handleEffectMasterOn = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 - var unitNr = control === 0x46 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle enablement - var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; - var keyString = 'group_[Master]_enable'; - var isEnabled = !engine.getValue(controlString, keyString); - engine.setValue(controlString, keyString, isEnabled); - Mixage.toggleLED(isEnabled ? 1 : 0, '[Channel' + unitNr + ']', 'master_on'); - } -} +Mixage.handleEffectMasterOn = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 + var unitNr = control === 0x46 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle enablement + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var keyString = "group_[Master]_enable"; + var isEnabled = !engine.getValue(controlString, keyString); + engine.setValue(controlString, keyString, isEnabled); + Mixage.toggleLED(isEnabled ? 1 : 0, "[Channel" + unitNr + "]", "master_on"); + } +}; // The FX ON button that toggles routing channel 1/2 through effects -Mixage.handleEffectChannelOn = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x08 controls unit 1, 0x16 unit 2 - var unitNr = control === 0x08 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle enablement - Mixage.effectRackEnabled[unitNr - 1] = !Mixage.effectRackEnabled[unitNr - 1]; - var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; - // update controls - var keyString = 'group_[Channel' + unitNr + ']_enable'; - engine.setValue('[EffectRack1_EffectUnit1]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); - engine.setValue('[EffectRack1_EffectUnit2]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); - Mixage.toggleLED(isEnabled ? 1 : 0, '[Channel' + unitNr + ']', 'fx_on'); - } -} +Mixage.handleEffectChannelOn = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x08 controls unit 1, 0x16 unit 2 + var unitNr = control === 0x08 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle enablement + Mixage.effectRackEnabled[unitNr - 1] = !Mixage.effectRackEnabled[unitNr - 1]; + var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + // update controls + var keyString = "group_[Channel" + unitNr + "]_enable"; + engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); + engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + Mixage.toggleLED(isEnabled ? 1 : 0, "[Channel" + unitNr + "]", "fx_on"); + } +}; // The FX SEL button that selects which effects are enabled for channel 1/2 -Mixage.handleEffectChannelSelect = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x07 controls unit 1, 0x15 unit 2 - var unitNr = control === 0x07 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle select state - var selected1 = Mixage.effectRackSelected[unitNr - 1][0]; - var selected2 = Mixage.effectRackSelected[unitNr - 1][1]; - if (selected1 && selected2) { - selected1 = true; - selected2 = false; - } - else if (selected1) { - selected1 = false; - selected2 = true; - } - else { - selected1 = true; - selected2 = true; - } - Mixage.effectRackSelected[unitNr - 1][0] = selected1; - Mixage.effectRackSelected[unitNr - 1][1] = selected2; - // update controls - var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; - var keyString = 'group_[Channel' + unitNr + ']_enable'; - engine.setValue('[EffectRack1_EffectUnit1]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); - engine.setValue('[EffectRack1_EffectUnit2]', keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); - } -} +Mixage.handleEffectChannelSelect = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x07 controls unit 1, 0x15 unit 2 + var unitNr = control === 0x07 ? 1 : 2; + // react only on first message / keydown + if (value === 0x7F) { + // check and toggle select state + var selected1 = Mixage.effectRackSelected[unitNr - 1][0]; + var selected2 = Mixage.effectRackSelected[unitNr - 1][1]; + if (selected1 && selected2) { + selected1 = true; + selected2 = false; + } else if (selected1) { + selected1 = false; + selected2 = true; + } else { + selected1 = true; + selected2 = true; + } + Mixage.effectRackSelected[unitNr - 1][0] = selected1; + Mixage.effectRackSelected[unitNr - 1][1] = selected2; + // update controls + var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + var keyString = "group_[Channel" + unitNr + "]_enable"; + engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); + engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + } +}; -Mixage.handleEffectDryWet = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 - var unitNr = control === 0x21 ? 1 : 2; - // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 - var diff = (value - 64) / 10.0; - // In either case, register the movement - var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; - var dryWetValue = engine.getValue(controlString, 'mix'); - engine.setValue(controlString, 'mix', dryWetValue + diff); -} +Mixage.handleEffectDryWet = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 + var unitNr = control === 0x21 ? 1 : 2; + // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 + var diff = (value - 64) / 10.0; + // In either case, register the movement + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var dryWetValue = engine.getValue(controlString, "mix"); + engine.setValue(controlString, "mix", dryWetValue + diff); +}; // The PAN rotary control used here for the overall effect super control -Mixage.handleEffectSuper = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x60 controls unit 1, 0x62 unit 2 - var unitNr = control === 0x60 ? 1 : 2; - // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 - var diff = (value - 64) / 10.0; - // In either case, register the movement - var controlString = '[EffectRack1_EffectUnit' + unitNr + ']'; - var mixValue = engine.getValue(controlString, 'super1'); - engine.setValue(controlString, 'super1', mixValue + diff); -} +Mixage.handleEffectSuper = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x60 controls unit 1, 0x62 unit 2 + var unitNr = control === 0x60 ? 1 : 2; + // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 + var diff = (value - 64) / 10.0; + // In either case, register the movement + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var mixValue = engine.getValue(controlString, "super1"); + engine.setValue(controlString, "super1", mixValue + diff); +}; // The BEAT MOVE rotary control is used as an extra "shift" key when pushed down -Mixage.handleBeatMovePressed = function (channel, control, value/*, status, group*/) { - Mixage.beatMovePressed = value === 0x7f; -} +Mixage.handleBeatMovePressed = function(channel, control, value/*, status, group*/) { + Mixage.beatMovePressed = value === 0x7f; +}; -Mixage.handleBeatMoveLength = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 - var unitNr = control === 0x20 ? 1 : 2; - var moveDirection = unitNr == 1 ? 1 : -1; - // Control centers on 0x40 (64), calculate difference to that - var diff = (value - 64); - // In either case, register the movement - if (Mixage.beatMovePressed) { - var direction = engine.getParameter('[Channel' + unitNr + ']', 'beatjump_size'); - direction = moveDirection * diff > 0 ? 2 * direction : direction / 2; - engine.setParameter('[Channel' + unitNr + ']', 'beatjump_size', direction); - } - else { - var direction = moveDirection * diff > 0 ? 'loop_double' : 'loop_halve'; - engine.setValue('[Channel' + unitNr + ']', direction, true); - } -} +Mixage.handleBeatMoveLength = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 + var unitNr = control === 0x20 ? 1 : 2; + var direction = unitNr === 1 ? 1 : -1; + // Control centers on 0x40 (64), calculate difference to that + var diff = (value - 64); + // In either case, register the movement + if (Mixage.beatMovePressed) { + var loopLength = engine.getParameter("[Channel" + unitNr + "]", "beatjump_size"); + loopLength = direction * diff > 0 ? 2 * loopLength : loopLength / 2; + engine.setParameter("[Channel" + unitNr + "]", "beatjump_size", loopLength); + } else { + var loopScale = direction * diff > 0 ? "loop_double" : "loop_halve"; + engine.setValue("[Channel" + unitNr + "]", loopScale, true); + } +}; -Mixage.handleBeatMove = function (channel, control, value/*, status, group*/) { - // calculate effect unit number from MIDI control. 0x5f controls unit 1, 0x61 unit 2 - var unitNr = control === 0x5f ? 1 : 2; - var moveDirection = unitNr == 1 ? 1 : -1; - // Control centers on 0x40 (64), calculate difference to that - var diff = (value - 64); - // In either case, register the movement - var direction = moveDirection * diff > 0 ? 'beatjump_forward' : 'beatjump_backward'; - engine.setValue('[Channel' + unitNr + ']', direction, true); -} +Mixage.handleBeatMove = function(channel, control, value/*, status, group*/) { + // calculate effect unit number from MIDI control. 0x5f controls unit 1, 0x61 unit 2 + var unitNr = control === 0x5f ? 1 : 2; + var direction = unitNr === 1 ? 1 : -1; + // Control centers on 0x40 (64), calculate difference to that + var diff = (value - 64); + // In either case, register the movement + var position = direction * diff > 0 ? "beatjump_forward" : "beatjump_backward"; + engine.setValue("[Channel" + unitNr + "]", position, true); +}; From e7e23abd00049cee408080cba0ad8d24bb9f7c98 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Mon, 12 Sep 2022 22:18:53 +0200 Subject: [PATCH 03/32] Newline at the end of the file --- res/controllers/Reloop-Mixage.midi.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 0b5063ad754..e29b6734575 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -706,4 +706,4 @@ - \ No newline at end of file + From 73213dc9d53300581c19a205f0bd7726823203cf Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Sat, 17 Sep 2022 11:36:38 +0200 Subject: [PATCH 04/32] Add channel 2 hotcue buttons --- res/controllers/Reloop-Mixage.midi.xml | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index e29b6734575..5faf9eabee4 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -703,6 +703,42 @@ + + [Channel2] + hotcue_1_activate + 0x90 + 0x56 + + + + + + [Channel2] + hotcue_2_activate + 0x90 + 0x57 + + + + + + [Channel2] + hotcue_3_activate + 0x90 + 0x58 + + + + + + [Channel2] + hotcue_4_activate + 0x90 + 0x59 + + + + From 9fbb173541b8aaee4c40d2dc8c52ee96c57a166a Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Fri, 25 Nov 2022 16:57:45 +0100 Subject: [PATCH 05/32] Refactor VU meter updates --- res/controllers/Reloop-Mixage.scripts.js | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index d22543827a0..0b18e0ca4e8 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,10 +1,10 @@ // Name: Reloop Mixage // Author: Bim Overbohm -// Version: 1.0.2 needs Mixxx 2.1+ +// Version: 1.0.3 needs Mixxx 2.1+ var Mixage = {}; -Mixage.updateVUMetersTimer = 0; +Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryReducedHideTimeout = 500; Mixage.libraryHideTimeout = 4000; @@ -19,12 +19,18 @@ Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for Mixage.init = function(/*id, debugging*/) { Mixage.connectControlsToFunctions("[Channel1]"); Mixage.connectControlsToFunctions("[Channel2]"); - // all buttons off + // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); } // start timers for updating the VU meters - Mixage.updateVUMetersTimer = engine.beginTimer(33, Mixage.updateVUMeters); + Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { + midi.sendShortMsg(0x90, 29, val * 7); + }); + Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { + midi.sendShortMsg(0x90, 30, val * 7); + }); + // disable scrating on both decks engine.scratchDisable(1); engine.scratchDisable(2); // disable effects for both channels @@ -35,7 +41,8 @@ Mixage.init = function(/*id, debugging*/) { }; Mixage.shutdown = function() { - engine.stopTimer(Mixage.updateVUMetersTimer); + Mixage.vuMeterConnection[0].disconnect(); + Mixage.vuMeterConnection[1].disconnect(); Mixage.setLibraryMaximized(false); Mixage.connectControlsToFunctions("[Channel1]", true); Mixage.connectControlsToFunctions("[Channel2]", true); @@ -95,11 +102,6 @@ Mixage.toggleLED = function(value, group, control) { midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1) ? 0x7F : 0); }; -Mixage.updateVUMeters = function() { - midi.sendShortMsg(0x90, 29, engine.getValue("[Channel1]", "VuMeter") * 7); - midi.sendShortMsg(0x90, 30, engine.getValue("[Channel2]", "VuMeter") * 7); -}; - // Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck Mixage.handlePlay = function(value, group, control) { Mixage.toggleLED(value, group, control); From 8242c52c6b0d92d9a14647091ed5d45bb3bfca22 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Sun, 19 Mar 2023 14:53:44 +0100 Subject: [PATCH 06/32] Make scratch by touch option actually work --- res/controllers/Reloop-Mixage.scripts.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 0b18e0ca4e8..253971c6ac2 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,9 +1,13 @@ // Name: Reloop Mixage // Author: Bim Overbohm -// Version: 1.0.3 needs Mixxx 2.1+ +// Version: 1.0.4 needs Mixxx 2.1+ var Mixage = {}; +// ----- User-configurable settings ----- +Mixage.scratchByWheelTouch = false; // turn on scratching by touching the wheel instead of having to press the disc button + +// ----- Internal variables (don't touch) ----- Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryReducedHideTimeout = 500; @@ -11,7 +15,6 @@ Mixage.libraryHideTimeout = 4000; Mixage.libraryRemainingTime = 0; Mixage.scratchPressed = false; Mixage.scrollPressed = false; -Mixage.scratchByWheelTouch = false; Mixage.beatMovePressed = false; Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 @@ -186,7 +189,7 @@ Mixage.scratchActive = function(channel, control, value/*, status, group*/) { Mixage.scratchPressed = true; var alpha = 1.0 / 8.0; var beta = alpha / 32.0; - engine.scratchEnable(deckNr, 620, 20.0/*33.0+1.0/3.0*/, alpha, beta); + engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); } else { Mixage.scratchPressed = false; engine.scratchDisable(deckNr); @@ -207,7 +210,7 @@ Mixage.wheelTouch = function(channel, control, value/*, status, group*/) { // check if scratching through wheel touch is enabled if (Mixage.scratchByWheelTouch) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control - 0x24 + 1; + var deckNr = (control - 0x24) + 1; if (value === 0x7F) { var alpha = 1.0 / 8; var beta = alpha / 32.0; @@ -221,18 +224,19 @@ Mixage.wheelTouch = function(channel, control, value/*, status, group*/) { // The wheel that actually controls the scratching / jogging Mixage.wheelTurn = function(channel, control, value/*, status, group*/) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control - 0x24 + 1; + var deckNr = (control - 0x24) + 1; // Control centers on 0x40 (64), calculate difference to that value var newValue = value - 64; // In either case, register the movement - if (Mixage.scratchPressed) { + if (Mixage.scrollPressed) { + Mixage.scrollLibrary(newValue); + return; + } + if (Mixage.scratchPressed || Mixage.scratchByWheelTouch) { engine.scratchTick(deckNr, newValue); // scratch } else { engine.scratchDisable(deckNr); } - if (Mixage.scrollPressed) { - Mixage.scrollLibrary(newValue); - } //engine.setValue('[Channel'+deckNr+']', 'jog', newValue); // Pitch bend }; From b101dccc0a197387cfb4fac11ee6c7f5484da6a0 Mon Sep 17 00:00:00 2001 From: Bim Date: Mon, 20 Mar 2023 21:19:31 +0100 Subject: [PATCH 07/32] Apply some suggestions from code review Co-authored-by: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> --- res/controllers/Reloop-Mixage.scripts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 253971c6ac2..ddc7d1d98f2 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -91,7 +91,7 @@ Mixage.connectionMap = { // Set or remove functions to call when the state of a mixxx control changes Mixage.connectControlsToFunctions = function(group, remove) { - remove = (typeof remove !== "undefined") ? remove : false; + remove = (remove !== undefined) ? remove : false; for (var control in Mixage.connectionMap) { engine.connectControl(group, control, Mixage.connectionMap[control], remove); if (!remove) { @@ -182,7 +182,7 @@ Mixage.libraryCheckTimeout = function() { }; // The "record" button that enables/disables scratching -Mixage.scratchActive = function(channel, control, value/*, status, group*/) { +Mixage.scratchActive = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 var deckNr = control === 0x04 ? 1 : 2; if (value === 0x7F) { From afc62df8a2d0f1d501f024dfd27b2e39e4dd3ed6 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Mon, 20 Mar 2023 21:24:11 +0100 Subject: [PATCH 08/32] Fix unused parameter syntax --- res/controllers/Reloop-Mixage.scripts.js | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index ddc7d1d98f2..e4788140d3b 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -19,7 +19,7 @@ Mixage.beatMovePressed = false; Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 -Mixage.init = function(/*id, debugging*/) { +Mixage.init = function(_id, _debugging) { Mixage.connectControlsToFunctions("[Channel1]"); Mixage.connectControlsToFunctions("[Channel2]"); // all button LEDs off @@ -119,7 +119,7 @@ Mixage.scrollLibrary = function(value) { }; // A button for the playlist was pressed -Mixage.handleLibrary = function(channel, control, value, status/*, group*/) { +Mixage.handleLibrary = function(channel, control, value, status, _group) { // "push2browse" button was moved somehow if (control === 0x1F) { // "push2browse" button was pushed if (status === 0x90 && value === 0x7F) { @@ -197,7 +197,7 @@ Mixage.scratchActive = function(channel, control, value, _status, _group) { }; // The "magnifying glass" button that enables/disables playlist scrolling -Mixage.scrollActive = function(channel, control, value/*, status, group*/) { +Mixage.scrollActive = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 Mixage.scrollPressed = value === 0x7F; if (Mixage.scrollPressed) { @@ -206,7 +206,7 @@ Mixage.scrollActive = function(channel, control, value/*, status, group*/) { }; // The touch function on the wheels that enables/disables scratching -Mixage.wheelTouch = function(channel, control, value/*, status, group*/) { +Mixage.wheelTouch = function(channel, control, value, _status, _group) { // check if scratching through wheel touch is enabled if (Mixage.scratchByWheelTouch) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 @@ -222,7 +222,7 @@ Mixage.wheelTouch = function(channel, control, value/*, status, group*/) { }; // The wheel that actually controls the scratching / jogging -Mixage.wheelTurn = function(channel, control, value/*, status, group*/) { +Mixage.wheelTurn = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 var deckNr = (control - 0x24) + 1; // Control centers on 0x40 (64), calculate difference to that value @@ -241,7 +241,7 @@ Mixage.wheelTurn = function(channel, control, value/*, status, group*/) { }; // The MASTER button that toggles routing master through effects -Mixage.handleEffectMasterOn = function(channel, control, value/*, status, group*/) { +Mixage.handleEffectMasterOn = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 var unitNr = control === 0x46 ? 1 : 2; // react only on first message / keydown @@ -256,7 +256,7 @@ Mixage.handleEffectMasterOn = function(channel, control, value/*, status, group* }; // The FX ON button that toggles routing channel 1/2 through effects -Mixage.handleEffectChannelOn = function(channel, control, value/*, status, group*/) { +Mixage.handleEffectChannelOn = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x08 controls unit 1, 0x16 unit 2 var unitNr = control === 0x08 ? 1 : 2; // react only on first message / keydown @@ -273,7 +273,7 @@ Mixage.handleEffectChannelOn = function(channel, control, value/*, status, group }; // The FX SEL button that selects which effects are enabled for channel 1/2 -Mixage.handleEffectChannelSelect = function(channel, control, value/*, status, group*/) { +Mixage.handleEffectChannelSelect = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x07 controls unit 1, 0x15 unit 2 var unitNr = control === 0x07 ? 1 : 2; // react only on first message / keydown @@ -301,7 +301,7 @@ Mixage.handleEffectChannelSelect = function(channel, control, value/*, status, g } }; -Mixage.handleEffectDryWet = function(channel, control, value/*, status, group*/) { +Mixage.handleEffectDryWet = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 var unitNr = control === 0x21 ? 1 : 2; // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 @@ -313,7 +313,7 @@ Mixage.handleEffectDryWet = function(channel, control, value/*, status, group*/) }; // The PAN rotary control used here for the overall effect super control -Mixage.handleEffectSuper = function(channel, control, value/*, status, group*/) { +Mixage.handleEffectSuper = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x60 controls unit 1, 0x62 unit 2 var unitNr = control === 0x60 ? 1 : 2; // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 @@ -325,11 +325,11 @@ Mixage.handleEffectSuper = function(channel, control, value/*, status, group*/) }; // The BEAT MOVE rotary control is used as an extra "shift" key when pushed down -Mixage.handleBeatMovePressed = function(channel, control, value/*, status, group*/) { +Mixage.handleBeatMovePressed = function(channel, control, value, _status, _group) { Mixage.beatMovePressed = value === 0x7f; }; -Mixage.handleBeatMoveLength = function(channel, control, value/*, status, group*/) { +Mixage.handleBeatMoveLength = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 var unitNr = control === 0x20 ? 1 : 2; var direction = unitNr === 1 ? 1 : -1; @@ -346,7 +346,7 @@ Mixage.handleBeatMoveLength = function(channel, control, value/*, status, group* } }; -Mixage.handleBeatMove = function(channel, control, value/*, status, group*/) { +Mixage.handleBeatMove = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x5f controls unit 1, 0x61 unit 2 var unitNr = control === 0x5f ? 1 : 2; var direction = unitNr === 1 ? 1 : -1; From a51be5eabb1e603d937e9eb633a73fff5fbef257 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Mon, 20 Mar 2023 22:07:03 +0100 Subject: [PATCH 09/32] Add user setting to turn on library auto-maximizing (default off) --- res/controllers/Reloop-Mixage.scripts.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index e4788140d3b..3bf2944b14f 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -5,7 +5,8 @@ var Mixage = {}; // ----- User-configurable settings ----- -Mixage.scratchByWheelTouch = false; // turn on scratching by touching the wheel instead of having to press the disc button +Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the wheel instead of having to press the disc button +Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used // ----- Internal variables (don't touch) ----- Mixage.vuMeterConnection = []; @@ -46,7 +47,6 @@ Mixage.init = function(_id, _debugging) { Mixage.shutdown = function() { Mixage.vuMeterConnection[0].disconnect(); Mixage.vuMeterConnection[1].disconnect(); - Mixage.setLibraryMaximized(false); Mixage.connectControlsToFunctions("[Channel1]", true); Mixage.connectControlsToFunctions("[Channel2]", true); // all button LEDs off @@ -113,8 +113,10 @@ Mixage.handlePlay = function(value, group, control) { // Helper function to scroll the playlist Mixage.scrollLibrary = function(value) { - Mixage.setLibraryMaximized(true); - //engine.setValue('[Library]', 'MoveVertical', value); + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } + //engine.setValue('[Library]', 'MoveVertical', value); // this does not work for me engine.setValue("[Playlist]", "SelectTrackKnob", value); // for Mixxx < 2.1 }; @@ -123,7 +125,9 @@ Mixage.handleLibrary = function(channel, control, value, status, _group) { // "push2browse" button was moved somehow if (control === 0x1F) { // "push2browse" button was pushed if (status === 0x90 && value === 0x7F) { - Mixage.setLibraryMaximized(true); + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } // stop the currently playing track. if it wasn't playing, start it if (engine.getValue("[PreviewDeck1]", "play")) { engine.setValue("[PreviewDeck1]", "stop", true); @@ -200,7 +204,7 @@ Mixage.scratchActive = function(channel, control, value, _status, _group) { Mixage.scrollActive = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 Mixage.scrollPressed = value === 0x7F; - if (Mixage.scrollPressed) { + if (Mixage.scrollPressed && Mixage.autoMaximizeLibrary) { Mixage.setLibraryMaximized(true); } }; From efc42b942c95f75e030090d13885716d096fc8b7 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Tue, 21 Mar 2023 17:37:12 +0100 Subject: [PATCH 10/32] Use makeConnection instead of connectControl --- res/controllers/Reloop-Mixage.scripts.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 3bf2944b14f..9ba0528d3ce 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -81,21 +81,22 @@ Mixage.ledMap = { // Maps mixxx controls to a function that toggles their LEDs Mixage.connectionMap = { - "cue_indicator": "Mixage.toggleLED", - "cue_default": "Mixage.toggleLED", - "play_indicator": "Mixage.handlePlay", - "pfl": "Mixage.toggleLED", - "loop_enabled": "Mixage.toggleLED", - "sync_enabled": "Mixage.toggleLED" + "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], + "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null] }; // Set or remove functions to call when the state of a mixxx control changes Mixage.connectControlsToFunctions = function(group, remove) { remove = (remove !== undefined) ? remove : false; for (var control in Mixage.connectionMap) { - engine.connectControl(group, control, Mixage.connectionMap[control], remove); - if (!remove) { - engine.trigger(group, control); + if (remove) { + Mixage.connectionMap[control][1].disconnect(); + } else { + Mixage.connectionMap[control][1] = engine.makeConnection(group, control, Mixage.connectionMap[control][0]); } } }; From 1a4c71fdee34e30ac9c7423e9db945f04959dddb Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Tue, 21 Mar 2023 17:39:43 +0100 Subject: [PATCH 11/32] Make timeouts user-configurable --- res/controllers/Reloop-Mixage.scripts.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 9ba0528d3ce..a891198a98d 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -7,15 +7,13 @@ var Mixage = {}; // ----- User-configurable settings ----- Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the wheel instead of having to press the disc button Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used +Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized +Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck // ----- Internal variables (don't touch) ----- Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; -Mixage.libraryReducedHideTimeout = 500; -Mixage.libraryHideTimeout = 4000; Mixage.libraryRemainingTime = 0; -Mixage.scratchPressed = false; -Mixage.scrollPressed = false; Mixage.beatMovePressed = false; Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 From 632d69ecd33bb65a5be82d0f28f3e94e6699cc38 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Tue, 21 Mar 2023 17:41:31 +0100 Subject: [PATCH 12/32] Enable LOAD LED as a warning when deck is playing --- res/controllers/Reloop-Mixage.scripts.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index a891198a98d..62fc83f7744 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -59,6 +59,7 @@ Mixage.ledMap = { "cue_indicator": 0x0A, "cue_default": 0x0B, "play_indicator": 0x0C, + "load_indicator": 0x0D, "pfl": 0x0E, "loop_enabled": 0x06, "sync_enabled": 0x09, @@ -69,6 +70,7 @@ Mixage.ledMap = { "cue_indicator": 0x18, "cue_default": 0x19, "play_indicator": 0x1A, + "load_indicator": 0x1B, "pfl": 0x1C, "loop_enabled": 0x14, "sync_enabled": 0x17, @@ -106,8 +108,12 @@ Mixage.toggleLED = function(value, group, control) { // Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck Mixage.handlePlay = function(value, group, control) { + // toggle the play indicator LED Mixage.toggleLED(value, group, control); + // make sure to stop preview deck engine.setValue("[PreviewDeck1]", "stop", true); + // toggle the LOAD button LED for the deck + Mixage.toggleLED(value, group, "load_indicator"); }; // Helper function to scroll the playlist From 1f82e842caba8a8b3e6eddcd8cd2e73eac0cb000 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Tue, 21 Mar 2023 17:43:15 +0100 Subject: [PATCH 13/32] Add dummy array entry to improve code readability --- res/controllers/Reloop-Mixage.scripts.js | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 62fc83f7744..682ae6f49c5 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -15,8 +15,8 @@ Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; Mixage.beatMovePressed = false; -Mixage.effectRackSelected = [[true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 -Mixage.effectRackEnabled = [false, false]; // if effect rack 1/2 is enabled for channel 1/2 +Mixage.effectRackSelected = [[true, false], [true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 +Mixage.effectRackEnabled = [false, false, false]; // if effect rack 1/2 is enabled for channel 1/2 Mixage.init = function(_id, _debugging) { Mixage.connectControlsToFunctions("[Channel1]"); @@ -271,12 +271,12 @@ Mixage.handleEffectChannelOn = function(channel, control, value, _status, _group // react only on first message / keydown if (value === 0x7F) { // check and toggle enablement - Mixage.effectRackEnabled[unitNr - 1] = !Mixage.effectRackEnabled[unitNr - 1]; - var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + Mixage.effectRackEnabled[unitNr] = !Mixage.effectRackEnabled[unitNr]; + var isEnabled = Mixage.effectRackEnabled[unitNr]; // update controls var keyString = "group_[Channel" + unitNr + "]_enable"; - engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); - engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][0]); + engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][1]); Mixage.toggleLED(isEnabled ? 1 : 0, "[Channel" + unitNr + "]", "fx_on"); } }; @@ -288,8 +288,8 @@ Mixage.handleEffectChannelSelect = function(channel, control, value, _status, _g // react only on first message / keydown if (value === 0x7F) { // check and toggle select state - var selected1 = Mixage.effectRackSelected[unitNr - 1][0]; - var selected2 = Mixage.effectRackSelected[unitNr - 1][1]; + var selected1 = Mixage.effectRackSelected[unitNr][0]; + var selected2 = Mixage.effectRackSelected[unitNr][1]; if (selected1 && selected2) { selected1 = true; selected2 = false; @@ -300,13 +300,13 @@ Mixage.handleEffectChannelSelect = function(channel, control, value, _status, _g selected1 = true; selected2 = true; } - Mixage.effectRackSelected[unitNr - 1][0] = selected1; - Mixage.effectRackSelected[unitNr - 1][1] = selected2; + Mixage.effectRackSelected[unitNr][0] = selected1; + Mixage.effectRackSelected[unitNr][1] = selected2; // update controls - var isEnabled = Mixage.effectRackEnabled[unitNr - 1]; + var isEnabled = Mixage.effectRackEnabled[unitNr]; var keyString = "group_[Channel" + unitNr + "]_enable"; - engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][0]); - engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr - 1][1]); + engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][0]); + engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][1]); } }; From aa9922cb900ee4e003381853b8ddd27e400162a8 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Tue, 21 Mar 2023 17:43:57 +0100 Subject: [PATCH 14/32] Completely rework scratching --- res/controllers/Reloop-Mixage.midi.xml | 49 ++++----- res/controllers/Reloop-Mixage.scripts.js | 125 +++++++++++++++-------- 2 files changed, 104 insertions(+), 70 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 5faf9eabee4..6b4ec0da062 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -311,7 +311,7 @@ [Channel1] - Mixage.scrollActive + Mixage.scrollToggle 0x90 0x03 @@ -320,7 +320,25 @@ [Channel2] - Mixage.scratchActive + Mixage.scrollToggle + 0x90 + 0x11 + + + + + + [Channel1] + Mixage.scratchToggle + 0x90 + 0x04 + + + + + + [Channel2] + Mixage.scratchToggle 0x90 0x12 @@ -498,15 +516,6 @@ - - [Channel2] - Mixage.scrollActive - 0x90 - 0x11 - - - - [Channel1] Mixage.wheelTouch @@ -631,15 +640,6 @@ - - [Channel2] - Mixage.scrollActive - 0x90 - 0x11 - - - - [PreviewDeck1] play @@ -658,15 +658,6 @@ - - [Channel1] - Mixage.scratchActive - 0x90 - 0x04 - - - - [Channel1] hotcue_1_activate diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 682ae6f49c5..f49f68be4f8 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -15,16 +15,21 @@ Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; Mixage.beatMovePressed = false; +// Note that the following lists have 3 entries, but we use only 2 decks / effect units. This saves us having to write "deckNr - 1" everywhere... +Mixage.scratchToggleLastState = [0, 0, 0]; // helper array to enable scratch toggling by disc button +Mixage.isScratchActive = [false, false, false]; // true if scratching currently enabled for deck +Mixage.scrollToggleLastState = [0, 0, 0]; // helper array to enable scroll toggling by loupe button +Mixage.isScrollActive = [false, false, false]; // true if scrolling currently enabled for deck Mixage.effectRackSelected = [[true, false], [true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 Mixage.effectRackEnabled = [false, false, false]; // if effect rack 1/2 is enabled for channel 1/2 Mixage.init = function(_id, _debugging) { - Mixage.connectControlsToFunctions("[Channel1]"); - Mixage.connectControlsToFunctions("[Channel2]"); // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); } + Mixage.connectControlsToFunctions("[Channel1]"); + Mixage.connectControlsToFunctions("[Channel2]"); // start timers for updating the VU meters Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 29, val * 7); @@ -32,9 +37,11 @@ Mixage.init = function(_id, _debugging) { Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 30, val * 7); }); - // disable scrating on both decks - engine.scratchDisable(1); - engine.scratchDisable(2); + // initially disable scratching for both decks + if (!Mixage.scratchByWheelTouch) { + engine.scratchDisable(1); + engine.scratchDisable(2); + } // disable effects for both channels engine.setValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", false); engine.setValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", false); @@ -64,7 +71,9 @@ Mixage.ledMap = { "loop_enabled": 0x06, "sync_enabled": 0x09, "master_on": 0x07, - "fx_on": 0x08 + "fx_on": 0x08, + "scratch_active": 0x04, + "scroll_active": 0x03, }, "[Channel2]": { "cue_indicator": 0x18, @@ -75,7 +84,9 @@ Mixage.ledMap = { "loop_enabled": 0x14, "sync_enabled": 0x17, "master_on": 0x15, - "fx_on": 0x16 + "fx_on": 0x16, + "scratch_active": 0x12, + "scroll_active": 0x11 } }; @@ -190,63 +201,95 @@ Mixage.libraryCheckTimeout = function() { } }; -// The "record" button that enables/disables scratching -Mixage.scratchActive = function(channel, control, value, _status, _group) { +// Switch the controller and Mixxx state for scratching +Mixage.setScratching = function(deckNr, active) { + // check if setting changed + if (Mixage.isScratchActive[deckNr] !== active) { + Mixage.isScratchActive[deckNr] = active; + if (active) { + // turn off scrolling first + Mixage.setScrolling(deckNr, false); + } else { + engine.scratchDisable(deckNr); + } + var controlString = "[Channel" + deckNr + "]"; + Mixage.toggleLED(Mixage.isScratchActive[deckNr] ? 1 : 0, controlString, "scratch_active"); + } +}; + +// The "disc" button that enables/disables scratching +Mixage.scratchToggle = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 var deckNr = control === 0x04 ? 1 : 2; - if (value === 0x7F) { - Mixage.scratchPressed = true; - var alpha = 1.0 / 8.0; - var beta = alpha / 32.0; - engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); - } else { - Mixage.scratchPressed = false; - engine.scratchDisable(deckNr); + // check for pressed->release or released->press + if (Mixage.scratchToggleLastState[deckNr] !== value) { + Mixage.scratchToggleLastState[deckNr] = value; + if (value === 0) { + return; + } + Mixage.setScratching(deckNr, !Mixage.isScratchActive[deckNr]); } }; -// The "magnifying glass" button that enables/disables playlist scrolling -Mixage.scrollActive = function(channel, control, value, _status, _group) { - // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 - Mixage.scrollPressed = value === 0x7F; - if (Mixage.scrollPressed && Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); +// Switch the controller and Mixxx state for scrolling +Mixage.setScrolling = function(deckNr, active) { + // check if setting changed + if (Mixage.isScrollActive[deckNr] !== active) { + Mixage.isScrollActive[deckNr] = active; + if (active) { + // turn off scratching first + Mixage.setScratching(deckNr, false); + } else { + engine.scratchDisable(deckNr); + } + var controlString = "[Channel" + deckNr + "]"; + Mixage.toggleLED(Mixage.isScrollActive[deckNr] ? 1 : 0, controlString, "scroll_active"); + } +}; + +// The "loupe" button that enables/disables track scrolling +Mixage.scrollToggle = function(channel, control, value, _status, _group) { + // calculate deck number from MIDI control. 0x03 controls deck 1, 0x12 deck 2 + var deckNr = control === 0x03 ? 1 : 2; + // check for pressed->release or released->press + if (Mixage.scrollToggleLastState[deckNr] !== value) { + Mixage.scrollToggleLastState[deckNr] = value; + if (value === 0) { + return; + } + Mixage.setScrolling(deckNr, !Mixage.isScrollActive[deckNr]); } }; // The touch function on the wheels that enables/disables scratching Mixage.wheelTouch = function(channel, control, value, _status, _group) { - // check if scratching through wheel touch is enabled - if (Mixage.scratchByWheelTouch) { - // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = (control - 0x24) + 1; + // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 + var deckNr = control === 0x24 ? 1 : 2; + // check if scratching or scrolling should be enabled + if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr] || Mixage.isScrollActive[deckNr]) { if (value === 0x7F) { - var alpha = 1.0 / 8; + // turn on scratching or scrolling on this deck + var alpha = Mixage.isScrollActive[deckNr] ? 1.0 / 2.0 : 1.0 / 8.0; var beta = alpha / 32.0; - engine.scratchEnable(deckNr, 620, 33.0 + 1.0 / 3.0, alpha, beta); + var ticksPerRevolution = Mixage.isScrollActive[deckNr] ? 128 : 620; + engine.scratchEnable(deckNr, ticksPerRevolution, 33.0 + 1.0 / 3.0, alpha, beta); } else { engine.scratchDisable(deckNr); } } }; -// The wheel that actually controls the scratching / jogging +// The wheel that actually controls the scratching / jogging / library browsing Mixage.wheelTurn = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = (control - 0x24) + 1; - // Control centers on 0x40 (64), calculate difference to that value + var deckNr = control === 0x24 ? 1 : 2; + // control centers on 0x40 (64), calculate difference to that value var newValue = value - 64; - // In either case, register the movement - if (Mixage.scrollPressed) { - Mixage.scrollLibrary(newValue); - return; - } - if (Mixage.scratchPressed || Mixage.scratchByWheelTouch) { - engine.scratchTick(deckNr, newValue); // scratch + if (engine.isScratching(deckNr)) { + engine.scratchTick(deckNr, newValue); // scratch or scroll deck } else { - engine.scratchDisable(deckNr); + engine.setValue("[Channel" + deckNr + "]", "jog", newValue); // pitch bend deck } - //engine.setValue('[Channel'+deckNr+']', 'jog', newValue); // Pitch bend }; // The MASTER button that toggles routing master through effects From 213132ab5651280b9a35fe2403308b1957b4848c Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Wed, 22 Mar 2023 22:13:07 +0100 Subject: [PATCH 15/32] Restore deck effect states --- res/controllers/Reloop-Mixage.scripts.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index f49f68be4f8..ada4d20a81a 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -30,7 +30,7 @@ Mixage.init = function(_id, _debugging) { } Mixage.connectControlsToFunctions("[Channel1]"); Mixage.connectControlsToFunctions("[Channel2]"); - // start timers for updating the VU meters + // make connection for updating the VU meters Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 29, val * 7); }); @@ -42,11 +42,21 @@ Mixage.init = function(_id, _debugging) { engine.scratchDisable(1); engine.scratchDisable(2); } - // disable effects for both channels - engine.setValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable", false); - engine.setValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable", false); - engine.setValue("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable", false); - engine.setValue("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable", false); + // restore master effect states from user preferences + var isMasterFx1Enabled = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Master]_enable"); + Mixage.toggleLED(isMasterFx1Enabled ? 1 : 0, "[Channel1]", "master_on"); + var isMasterFx2Enabled = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Master]_enable"); + Mixage.toggleLED(isMasterFx2Enabled ? 1 : 0, "[Channel2]", "master_on"); + // restore deck 1 effect states from user preferences + Mixage.effectRackSelected[1][0] = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable"); + Mixage.effectRackSelected[1][1] = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable"); + Mixage.effectRackEnabled[1] = Mixage.effectRackSelected[1][0] || Mixage.effectRackSelected[1][1]; + Mixage.toggleLED(Mixage.effectRackEnabled[1] ? 1 : 0, "[Channel1]", "fx_on"); + // restore deck 2 effect states from user preferences + Mixage.effectRackSelected[2][0] = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable"); + Mixage.effectRackSelected[2][1] = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable"); + Mixage.effectRackEnabled[2] = Mixage.effectRackSelected[2][0] || Mixage.effectRackSelected[2][1]; + Mixage.toggleLED(Mixage.effectRackEnabled[2] ? 1 : 0, "[Channel2]", "fx_on"); }; Mixage.shutdown = function() { From d2706fd024cfbeb71892b132dbb21fc6ada601f1 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Wed, 22 Mar 2023 23:47:49 +0100 Subject: [PATCH 16/32] Remap MASTER button, but disable until Mixxx function is working --- res/controllers/Reloop-Mixage.midi.xml | 8 ++--- res/controllers/Reloop-Mixage.scripts.js | 42 ++++++++++++++---------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 6b4ec0da062..7136f3a5c31 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -139,8 +139,8 @@ - [EffectRack1_EffectUnit1] - Mixage.handleEffectMasterOn + [Channel1] + Mixage.handleDeckSyncMode 0x90 0x46 @@ -148,8 +148,8 @@ - [EffectRack1_EffectUnit2] - Mixage.handleEffectMasterOn + [Channel2] + Mixage.handleDeckSyncMode 0x90 0x54 diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index ada4d20a81a..3095846fd29 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -42,11 +42,11 @@ Mixage.init = function(_id, _debugging) { engine.scratchDisable(1); engine.scratchDisable(2); } - // restore master effect states from user preferences - var isMasterFx1Enabled = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Master]_enable"); - Mixage.toggleLED(isMasterFx1Enabled ? 1 : 0, "[Channel1]", "master_on"); - var isMasterFx2Enabled = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Master]_enable"); - Mixage.toggleLED(isMasterFx2Enabled ? 1 : 0, "[Channel2]", "master_on"); + // restore deck sync master LEDs (function currently not working as of 2.3.3) + //var isDeck1SyncLeader = engine.getValue("[Channel1]", "sync_master"); + //Mixage.toggleLED(isDeck1SyncLeader ? 1 : 0, "[Channel1]", "sync_master"); + //var isDeck2SyncLeader = engine.getValue("[Channel2]", "sync_master"); + //Mixage.toggleLED(isDeck2SyncLeader ? 1 : 0, "[Channel2]", "sync_master"); // restore deck 1 effect states from user preferences Mixage.effectRackSelected[1][0] = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable"); Mixage.effectRackSelected[1][1] = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable"); @@ -80,7 +80,7 @@ Mixage.ledMap = { "pfl": 0x0E, "loop_enabled": 0x06, "sync_enabled": 0x09, - "master_on": 0x07, + "sync_master": 0x07, "fx_on": 0x08, "scratch_active": 0x04, "scroll_active": 0x03, @@ -93,7 +93,7 @@ Mixage.ledMap = { "pfl": 0x1C, "loop_enabled": 0x14, "sync_enabled": 0x17, - "master_on": 0x15, + "sync_master": 0x15, "fx_on": 0x16, "scratch_active": 0x12, "scroll_active": 0x11 @@ -302,19 +302,27 @@ Mixage.wheelTurn = function(channel, control, value, _status, _group) { } }; -// The MASTER button that toggles routing master through effects -Mixage.handleEffectMasterOn = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 - var unitNr = control === 0x46 ? 1 : 2; +// The MASTER button that toggles a deck as sync leader / master +Mixage.handleDeckSyncMode = function(channel, control, value, _status, _group) { + // Function currently not working as of 2.3.3: https://manual.mixxx.org/2.4/gl/chapters/appendix/mixxx_controls.html#control-[ChannelN]-sync_master + // Disable until this is working + return; + /*// calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 + var deckNr = control === 0x46 ? 1 : 2; // react only on first message / keydown if (value === 0x7F) { // check and toggle enablement - var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var keyString = "group_[Master]_enable"; - var isEnabled = !engine.getValue(controlString, keyString); - engine.setValue(controlString, keyString, isEnabled); - Mixage.toggleLED(isEnabled ? 1 : 0, "[Channel" + unitNr + "]", "master_on"); - } + var controlString = "[Channel" + deckNr + "]"; + var keyString = "sync_master"; + var isSyncLeader = !engine.getValue(controlString, keyString); + // if we want to make this deck sync leader, turn off sync leader on the other deck + if (isSyncLeader) { + var otherDeckNr = deckNr === 1 ? 2 : 1; + engine.setValue("[Channel" + otherDeckNr + "]", keyString, false); + } + engine.setValue(controlString, keyString, isSyncLeader); + Mixage.toggleLED(isSyncLeader ? 1 : 0, controlString, keyString); + }*/ }; // The FX ON button that toggles routing channel 1/2 through effects From 549361b6a5a88453453f63022cd6ceb65d50e84a Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 23 Mar 2023 00:13:32 +0100 Subject: [PATCH 17/32] Fix linter issues --- res/controllers/Reloop-Mixage.scripts.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 3095846fd29..48b36e7c432 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -303,10 +303,9 @@ Mixage.wheelTurn = function(channel, control, value, _status, _group) { }; // The MASTER button that toggles a deck as sync leader / master -Mixage.handleDeckSyncMode = function(channel, control, value, _status, _group) { - // Function currently not working as of 2.3.3: https://manual.mixxx.org/2.4/gl/chapters/appendix/mixxx_controls.html#control-[ChannelN]-sync_master - // Disable until this is working - return; +Mixage.handleDeckSyncMode = function(_channel, _control, _value, _status, _group) { + // Function currently not working as of 2.3.3: https://manual.mixxx.org/2.4/gl/chapters/appendix/mixxx_controls.html#control-[ChannelN]-sync_master + // Disable until this is working /*// calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 var deckNr = control === 0x46 ? 1 : 2; // react only on first message / keydown From 4117890139fdd5a921a8b0cad63d8ec5bdaf59c7 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 23 Mar 2023 01:31:53 +0100 Subject: [PATCH 18/32] Add function to scroll through side pane using track select knob --- res/controllers/Reloop-Mixage.midi.xml | 18 +++++++++++ res/controllers/Reloop-Mixage.scripts.js | 39 ++++++++++++------------ 2 files changed, 37 insertions(+), 20 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 7136f3a5c31..03df687d888 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -570,6 +570,15 @@ + + [Library] + Mixage.handleLibrary + 0x90 + 0x5E + + + + [Library] Mixage.handleLibrary @@ -579,6 +588,15 @@ + + [Library] + Mixage.handleLibrary + 0xB0 + 0x5E + + + + [Master] headMix diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 48b36e7c432..716ad946798 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -137,32 +137,31 @@ Mixage.handlePlay = function(value, group, control) { Mixage.toggleLED(value, group, "load_indicator"); }; -// Helper function to scroll the playlist -Mixage.scrollLibrary = function(value) { - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } - //engine.setValue('[Library]', 'MoveVertical', value); // this does not work for me - engine.setValue("[Playlist]", "SelectTrackKnob", value); // for Mixxx < 2.1 -}; - // A button for the playlist was pressed Mixage.handleLibrary = function(channel, control, value, status, _group) { // "push2browse" button was moved somehow - if (control === 0x1F) { // "push2browse" button was pushed - if (status === 0x90 && value === 0x7F) { - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } - // stop the currently playing track. if it wasn't playing, start it - if (engine.getValue("[PreviewDeck1]", "play")) { - engine.setValue("[PreviewDeck1]", "stop", true); + if (control === 0x1F || control === 0x5E) { // "push2browse" button was pushed or turned + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } + if (status === 0x90 && value === 0x7F) { // "push2browse" button was pushed + if (control === 0x5E) { // was shift pressed? + engine.setValue("[Library]", "GoToItem", true); } else { - engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); + // stop the currently playing track. if it wasn't playing, start it + if (engine.getValue("[PreviewDeck1]", "play")) { + engine.setValue("[PreviewDeck1]", "stop", true); + } else { + engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); + } } } else if (status === 0xB0) { // "push2browse" button was turned var newValue = value - 64; - Mixage.scrollLibrary(newValue); + if (control === 0x1F) { // was shift pressed? + engine.setValue("[Playlist]", "SelectTrackKnob", newValue); + } else { + engine.setValue("[Playlist]", "SelectPlaylist", newValue); + } } } else if (control === 0x0D || control === 0x4C) { // load into deck 1 if (value === 0x7F) { @@ -320,7 +319,7 @@ Mixage.handleDeckSyncMode = function(_channel, _control, _value, _status, _group engine.setValue("[Channel" + otherDeckNr + "]", keyString, false); } engine.setValue(controlString, keyString, isSyncLeader); - Mixage.toggleLED(isSyncLeader ? 1 : 0, controlString, keyString); + Mixage.toggleLED(isSyncLeader ? 1 : 0, controlString, keyString); }*/ }; From ff6c8f31f7935a89f3eb3efb31197fdbb20a1620 Mon Sep 17 00:00:00 2001 From: Bim Overbohm Date: Thu, 23 Mar 2023 17:39:07 +0100 Subject: [PATCH 19/32] Fix scratching / scrolling. Make scratch and scroll speed user-adjustable. Map PAN button. Refactor rotatry button presses --- res/controllers/Reloop-Mixage.midi.xml | 26 +++++- res/controllers/Reloop-Mixage.scripts.js | 104 +++++++++++++---------- 2 files changed, 80 insertions(+), 50 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 03df687d888..4f5b764ce94 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -2,7 +2,7 @@ Reloop Mixage - Bim Overbohm + HorstBaerbel Mapping for the Reloop Mixage Interface Edition controller (https://www.reloop.com/reloop-mixage-ie). Should also work on the non-interface version. https://mixxx.discourse.group/t/reloop-mixage-mapping/14779 https://github.com/mixxxdj/mixxx/wiki/Reloop%20Mixage @@ -212,7 +212,25 @@ [EffectRack1_EffectUnit1] - Mixage.handleEffectSuper + Mixage.handleDryWetPressed + 0x90 + 0x21 + + + + + + [EffectRack1_EffectUnit2] + Mixage.handleDryWetPressed + 0x90 + 0x23 + + + + + + [Channel1] + Mixage.handlePan 0xB0 0x60 @@ -220,8 +238,8 @@ - [EffectRack1_EffectUnit2] - Mixage.handleEffectSuper + [Channel2] + Mixage.handlePan 0xB0 0x62 diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 716ad946798..c42c6e6dc52 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,21 +1,24 @@ // Name: Reloop Mixage -// Author: Bim Overbohm +// Author: HorstBaerbel // Version: 1.0.4 needs Mixxx 2.1+ var Mixage = {}; // ----- User-configurable settings ----- -Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the wheel instead of having to press the disc button -Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used -Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized -Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck +Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the jog wheel instead of having to toggle the disc button. Default is false +Mixage.scratchTicksPerRevolution = 620; // Number of jog wheel ticks that make a full revolution when scratching. Reduce to "scratch more" of the track, increase to "scratch less". Default is 620 (measured) +Mixage.jogWheelScrollSpeed = 1.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 +Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used. Default is false +Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized. Default is 4000 +Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck. Default is 500 // ----- Internal variables (don't touch) ----- Mixage.vuMeterConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; -Mixage.beatMovePressed = false; // Note that the following lists have 3 entries, but we use only 2 decks / effect units. This saves us having to write "deckNr - 1" everywhere... +Mixage.isBeatMovePressed = [false, false, false]; +Mixage.isDryWetPressed = [false, false, false]; Mixage.scratchToggleLastState = [0, 0, 0]; // helper array to enable scratch toggling by disc button Mixage.isScratchActive = [false, false, false]; // true if scratching currently enabled for deck Mixage.scrollToggleLastState = [0, 0, 0]; // helper array to enable scroll toggling by loupe button @@ -37,11 +40,6 @@ Mixage.init = function(_id, _debugging) { Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 30, val * 7); }); - // initially disable scratching for both decks - if (!Mixage.scratchByWheelTouch) { - engine.scratchDisable(1); - engine.scratchDisable(2); - } // restore deck sync master LEDs (function currently not working as of 2.3.3) //var isDeck1SyncLeader = engine.getValue("[Channel1]", "sync_master"); //Mixage.toggleLED(isDeck1SyncLeader ? 1 : 0, "[Channel1]", "sync_master"); @@ -274,30 +272,38 @@ Mixage.scrollToggle = function(channel, control, value, _status, _group) { Mixage.wheelTouch = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 var deckNr = control === 0x24 ? 1 : 2; - // check if scratching or scrolling should be enabled - if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr] || Mixage.isScrollActive[deckNr]) { + // check if scratching should be enabled + if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr]) { if (value === 0x7F) { - // turn on scratching or scrolling on this deck - var alpha = Mixage.isScrollActive[deckNr] ? 1.0 / 2.0 : 1.0 / 8.0; + // turn on scratching on this deck + var alpha = 1.0 / 8.0; var beta = alpha / 32.0; - var ticksPerRevolution = Mixage.isScrollActive[deckNr] ? 128 : 620; - engine.scratchEnable(deckNr, ticksPerRevolution, 33.0 + 1.0 / 3.0, alpha, beta); + engine.scratchEnable(deckNr, Mixage.scratchTicksPerRevolution, 33.0 + 1.0 / 3.0, alpha, beta); } else { engine.scratchDisable(deckNr); } } }; -// The wheel that actually controls the scratching / jogging / library browsing +// The wheel that controls the scratching / jogging Mixage.wheelTurn = function(channel, control, value, _status, _group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 var deckNr = control === 0x24 ? 1 : 2; - // control centers on 0x40 (64), calculate difference to that value - var newValue = value - 64; - if (engine.isScratching(deckNr)) { - engine.scratchTick(deckNr, newValue); // scratch or scroll deck - } else { - engine.setValue("[Channel" + deckNr + "]", "jog", newValue); // pitch bend deck + // only enable wheel if functionality has been enabled + if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr] || Mixage.isScrollActive[deckNr]) { + // control centers on 0x40 (64), calculate difference to that value + var newValue = value - 64; + if (Mixage.isScrollActive[deckNr]) { // scroll deck + var controlString = "[Channel" + deckNr + "]"; + var keyString = "playposition";// + newValue > 0 ? "up_small" : "down_small"; + var currentPosition = engine.getValue(controlString, keyString); + var speedFactor = 0.00005; + engine.setValue(controlString, keyString, currentPosition + speedFactor * newValue * Mixage.jogWheelScrollSpeed); + } else if (engine.isScratching(deckNr)) { + engine.scratchTick(deckNr, newValue); // scratch deck + } else { + engine.setValue("[Channel" + deckNr + "]", "jog", newValue); // pitch bend deck + } } }; @@ -369,42 +375,49 @@ Mixage.handleEffectChannelSelect = function(channel, control, value, _status, _g } }; +// The -DRY/WET+ rotary control is used as an extra "shift" key when pushed down +Mixage.handleDryWetPressed = function(channel, control, value, _status, _group) { + // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 + var unitNr = control === 0x21 ? 1 : 2; + Mixage.isDryWetPressed[unitNr] = value === 0x7f; +}; + +// The -DRY/WET+ rotary control used for the effect dry/wet mix Mixage.handleEffectDryWet = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 var unitNr = control === 0x21 ? 1 : 2; - // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 - var diff = (value - 64) / 10.0; - // In either case, register the movement + // control centers on 0x40 (64), calculate difference to that value and scale down + var diff = (value - 64) / 16.0; var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var dryWetValue = engine.getValue(controlString, "mix"); - engine.setValue(controlString, "mix", dryWetValue + diff); + var keyString = Mixage.isDryWetPressed[unitNr] ? "super1" : "mix"; + var dryWetValue = engine.getValue(controlString, keyString); + engine.setValue(controlString, keyString, dryWetValue + diff); }; -// The PAN rotary control used here for the overall effect super control -Mixage.handleEffectSuper = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x60 controls unit 1, 0x62 unit 2 - var unitNr = control === 0x60 ? 1 : 2; - // Control centers on 0x40 (64), calculate difference to that value and multiply by 4 - var diff = (value - 64) / 10.0; - // In either case, register the movement - var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var mixValue = engine.getValue(controlString, "super1"); - engine.setValue(controlString, "super1", mixValue + diff); +// The PAN rotary control used here for panning the master +Mixage.handlePan = function(channel, control, value, _status, _group) { + // control centers on 0x40 (64), calculate difference to that value and scale down + var diff = (value - 64) / 16.0; + var controlString = "[Master]"; + var keyString = "balance"; + var mixValue = engine.getValue(controlString, keyString); + engine.setValue(controlString, keyString, mixValue + diff); }; // The BEAT MOVE rotary control is used as an extra "shift" key when pushed down Mixage.handleBeatMovePressed = function(channel, control, value, _status, _group) { - Mixage.beatMovePressed = value === 0x7f; + // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 + var unitNr = control === 0x20 ? 1 : 2; + Mixage.isBeatMovePressed[unitNr] = value === 0x7f; }; Mixage.handleBeatMoveLength = function(channel, control, value, _status, _group) { // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 var unitNr = control === 0x20 ? 1 : 2; var direction = unitNr === 1 ? 1 : -1; - // Control centers on 0x40 (64), calculate difference to that + // control centers on 0x40 (64), calculate difference to that var diff = (value - 64); - // In either case, register the movement - if (Mixage.beatMovePressed) { + if (Mixage.isBeatMovePressed[unitNr]) { var loopLength = engine.getParameter("[Channel" + unitNr + "]", "beatjump_size"); loopLength = direction * diff > 0 ? 2 * loopLength : loopLength / 2; engine.setParameter("[Channel" + unitNr + "]", "beatjump_size", loopLength); @@ -415,12 +428,11 @@ Mixage.handleBeatMoveLength = function(channel, control, value, _status, _group) }; Mixage.handleBeatMove = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x5f controls unit 1, 0x61 unit 2 + // calculate effect unit number from MIDI control. 0x5F controls unit 1, 0x61 unit 2 var unitNr = control === 0x5f ? 1 : 2; var direction = unitNr === 1 ? 1 : -1; - // Control centers on 0x40 (64), calculate difference to that + // control centers on 0x40 (64), calculate difference to that var diff = (value - 64); - // In either case, register the movement var position = direction * diff > 0 ? "beatjump_forward" : "beatjump_backward"; engine.setValue("[Channel" + unitNr + "]", position, true); }; From 27d63f2534efbe9c197772016cb81cb249f1b12e Mon Sep 17 00:00:00 2001 From: gqzomer Date: Fri, 25 Aug 2023 22:05:34 +0200 Subject: [PATCH 20/32] Initial commit --- res/controllers/Reloop-Mixage.midi.xml | 1111 ++++++++++++++++------ res/controllers/Reloop-Mixage.scripts.js | 557 ++++++----- 2 files changed, 1121 insertions(+), 547 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 4f5b764ce94..537571c4837 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -2,7 +2,7 @@ Reloop Mixage - HorstBaerbel + Gersom Zomer Mapping for the Reloop Mixage Interface Edition controller (https://www.reloop.com/reloop-mixage-ie). Should also work on the non-interface version. https://mixxx.discourse.group/t/reloop-mixage-mapping/14779 https://github.com/mixxxdj/mixxx/wiki/Reloop%20Mixage @@ -12,188 +12,188 @@ - - [Channel2] - Mixage.wheelTurn - 0xB0 - 0x25 - - - - + [Channel1] - cue_play + rate_temp_down 0x90 - 0x0A + 0x01 + [Channel1] - sync_enabled + beats_translate_earlier 0x90 - 0x09 + 0x40 + [Channel1] - cue_default - 0x90 - 0x0B - - - - - - [Channel2] - sync_enabled + rate_temp_up 0x90 - 0x17 + 0x02 + - [Channel2] - cue_default + [Channel1] + beats_translate_later 0x90 - 0x19 + 0x41 + - [Channel2] - cue_play + [Channel1] + Mixage.handleShift 0x90 - 0x18 + 0x2A - + + [Channel1] - rate_temp_down + beatloop_activate 0x90 - 0x01 + 0x05 + - [Channel2] - rate_temp_up + [Channel1] + loop_in 0x90 - 0x10 + 0x44 + - [Master] - crossfader + [Channel1] + Mixage.handleLoopLength 0xB0 - 0x31 + 0x20 - + + - [Channel2] - keylock - 0x90 - 0x55 + [Channel1] + Mixage.handleBeatMove + 0xB0 + 0x5F - + + [Channel1] - Mixage.wheelTurn - 0xB0 - 0x24 + Mixage.handleBeatMovePressed + 0x90 + 0x20 + [Channel1] - keylock + 0x90 - 0x47 + 0x5F + - [Channel2] - pfl - 0x90 - 0x1C + [Channel1] + pregain + 0xB0 + 0x33 + [Channel1] - Mixage.handleDeckSyncMode - 0x90 - 0x46 + + 0xB0 + 0x72 - + + - [Channel2] - Mixage.handleDeckSyncMode - 0x90 - 0x54 + [Channel1] + rate + 0xE0 - + + - [EffectRack1_EffectUnit1] - Mixage.handleEffectChannelOn + [Channel1] + reloop_toggle 0x90 - 0x08 + 0x06 - + + - [EffectRack1_EffectUnit2] - Mixage.handleEffectChannelOn + [Channel1] + loop_out 0x90 - 0x16 + 0x45 - + + - [EffectRack1_EffectUnit1] - Mixage.handleEffectChannelSelect + [Channel1] + Mixage.nextEffect 0x90 0x07 + - [EffectRack1_EffectUnit2] - Mixage.handleEffectChannelSelect + [Channel1] + sync_master 0x90 - 0x15 + 0x46 - + + - [EffectRack1_EffectUnit1] + [Channel1] Mixage.handleEffectDryWet 0xB0 0x21 @@ -201,17 +201,19 @@ + - [EffectRack1_EffectUnit2] - Mixage.handleEffectDryWet + [Channel1] + Mixage.handlePan 0xB0 - 0x23 + 0x60 + - [EffectRack1_EffectUnit1] + [Channel1] Mixage.handleDryWetPressed 0x90 0x21 @@ -219,554 +221,1061 @@ + - [EffectRack1_EffectUnit2] - Mixage.handleDryWetPressed + [Channel1] + 0x90 - 0x23 + 0x60 - + + [Channel1] - Mixage.handlePan + Mixage.handleFxAmount 0xB0 - 0x60 + 0x34 + - [Channel2] - Mixage.handlePan + [Channel1] + Mixage.handleFilter 0xB0 - 0x62 + 0x73 + - [EqualizerRack1_[Channel1]_Effect1] - parameter1 - 0xB0 - 0x37 - - - - - - [EqualizerRack1_[Channel1]_Effect1] - parameter2 - 0xB0 - 0x36 + [Channel1] + + 0x90 + 0x34 + - [EqualizerRack1_[Channel1]_Effect1] - parameter3 - 0xB0 - 0x35 + [Channel1] + + 0x90 + 0x73 + - [EqualizerRack1_[Channel2]_Effect1] - parameter1 - 0xB0 - 0x3D + [Channel1] + Mixage.handleFxPress + 0x90 + 0x08 - + + - [EqualizerRack1_[Channel2]_Effect1] - parameter2 - 0xB0 - 0x3C + [Channel1] + keylock + 0x90 + 0x47 + - [EqualizerRack1_[Channel2]_Effect1] - parameter3 - 0xB0 - 0x3B + [Channel1] + Mixage.scrollToggle + 0x90 + 0x03 - + + - [QuickEffectRack1_[Channel1]] - super1 - 0xB0 - 0x34 + [Channel1] + Mixage.scrollToggle + 0x90 + 0x42 - + + - [QuickEffectRack1_[Channel2]] - super1 - 0xB0 - 0x3A + [Channel1] + Mixage.scratchToggle + 0x90 + 0x04 - + + [Channel1] - play + Mixage.scratchToggle 0x90 - 0x0C + 0x43 - + + [Channel1] - Mixage.scrollToggle + Mixage.wheelTouch 0x90 - 0x03 + 0x24 + - [Channel2] - Mixage.scrollToggle + [Channel1] + Mixage.wheelTouch 0x90 - 0x11 + 0x63 + [Channel1] - Mixage.scratchToggle - 0x90 - 0x04 + Mixage.wheelTurn + 0xB0 + 0x24 + - [Channel2] - Mixage.scratchToggle - 0x90 - 0x12 + [Channel1] + Mixage.wheelTurn + 0xB0 + 0x63 + [Channel1] - loop_in + sync_enabled 0x90 - 0x44 + 0x09 + [Channel1] - loop_out + hotcue_1_activate 0x90 - 0x45 + 0x48 + [Channel1] - beatloop_activate + cue_play 0x90 - 0x05 + 0x0A + [Channel1] - reloop_toggle + hotcue_2_activate 0x90 - 0x06 + 0x49 + [Channel1] - Mixage.handleBeatMove - 0xB0 - 0x5F + cue_default + 0x90 + 0x0B - + + [Channel1] - Mixage.handleBeatMoveLength - 0xB0 - 0x20 + hotcue_3_activate + 0x90 + 0x4A - + + [Channel1] - Mixage.handleBeatMovePressed + play 0x90 - 0x20 + 0x0C - + + - [Channel2] - loop_in + [Channel1] + hotcue_4_activate 0x90 - 0x52 + 0x4B + - [Channel2] - loop_out + [Channel1] + Mixage.handleTrackLoading 0x90 - 0x53 + 0x0D - + + - [Channel2] - beatloop_activate + [Library] + MoveLeft 0x90 - 0x13 + 0x4C + - [Channel2] - reloop_toggle - 0x90 - 0x14 + [EqualizerRack1_[Channel1]_Effect1] + parameter3 + 0xB0 + 0x35 + - [Channel2] - Mixage.handleBeatMoveLength + [Channel1] + 0xB0 - 0x22 + 0x74 - + + - [Channel2] - Mixage.handleBeatMove + [EqualizerRack1_[Channel1]_Effect1] + parameter2 0xB0 - 0x61 + 0x36 - + + - [Channel2] - Mixage.handleBeatMovePressed - 0x90 - 0x22 + [Channel1] + + 0xB0 + 0x75 - + + - [Channel2] - Mixage.wheelTouch - 0x90 - 0x25 + [EqualizerRack1_[Channel1]_Effect1] + parameter1 + 0xB0 + 0x37 - + + [Channel1] - pregain + 0xB0 - 0x33 + 0x76 + - [Channel2] - rate_temp_down + [Channel1] + pfl 0x90 - 0x0F + 0x0E + - [Channel1] - rate_temp_up + [PreviewDeck1] + LoadSelectedTrackAndPlay 0x90 - 0x02 + 0x4D + - [Channel2] - pregain + [Channel1] + volume 0xB0 - 0x39 + 0x38 + [Channel1] - Mixage.wheelTouch - 0x90 - 0x24 + + 0xB0 + 0x77 - + + - [Library] - Mixage.handleLibrary + [Channel2] + rate_temp_down 0x90 - 0x0D + 0x0F - + + - [Library] - Mixage.handleLibrary + [Channel2] + beats_translate_earlier 0x90 - 0x1B + 0x4E - + + - [Library] - Mixage.handleLibrary + [Channel2] + rate_temp_up 0x90 - 0x4C + 0x10 - + + - [Library] - Mixage.handleLibrary + [Channel2] + beats_translate_later 0x90 - 0x5A + 0x4F - + + - [Library] - Mixage.handleLibrary + [Channel2] + Mixage.handleShift 0x90 - 0x1F + 0x2B + - [Library] - Mixage.handleLibrary + [Channel2] + beatloop_activate 0x90 - 0x5E + 0x13 - + + - [Library] - Mixage.handleLibrary - 0xB0 - 0x1F + [Channel2] + loop_in + 0x90 + 0x52 - + + - [Library] - Mixage.handleLibrary + [Channel2] + Mixage.handleLoopLength 0xB0 - 0x5E + 0x22 + - [Master] - headMix + [Channel2] + Mixage.handleBeatMove 0xB0 - 0x32 + 0x61 - + + - [Channel1] - pfl + [Channel2] + Mixage.handleBeatMovePressed 0x90 - 0x0E + 0x22 - + + - [Channel1] - volume - 0xB0 - 0x38 + [Channel2] + + 0x90 + 0x61 + [Channel2] - rate - 0xE1 + pregain + 0xB0 + 0x39 + [Channel2] - volume + 0xB0 - 0x3E + 0x78 + - [Channel1] + [Channel2] rate - 0xE0 + 0xE1 + [Channel2] - play + reloop_toggle 0x90 - 0x1A + 0x14 + - [PreviewDeck1] - play + [Channel2] + loop_out 0x90 - 0x4D + 0x53 + - [PreviewDeck1] - stop + [Channel2] + Mixage.nextEffect 0x90 - 0x5B + 0x15 - + + - [Channel1] - hotcue_1_activate + [Channel2] + sync_master 0x90 - 0x48 + 0x54 + - [Channel1] - hotcue_2_activate - 0x90 - 0x49 + [Channel2] + Mixage.handleEffectDryWet + 0xB0 + 0x23 - + + - [Channel1] - hotcue_3_activate - 0x90 - 0x4A + [Channel2] + Mixage.handlePan + 0xB0 + 0x62 - + + - [Channel1] - hotcue_4_activate + [Channel2] + Mixage.handleDryWetPressed 0x90 - 0x4B + 0x23 - + + [Channel2] - hotcue_1_activate + 0x90 - 0x56 + 0x62 + [Channel2] - hotcue_2_activate + Mixage.handleFxAmount + 0xB0 + 0x3A + + + + + + + [Channel2] + Mixage.handleFilter + 0xB0 + 0x79 + + + + + + + [Channel2] + 0x90 - 0x57 + 0x3A + [Channel2] - hotcue_3_activate + 0x90 - 0x58 + 0x79 + - [Channel2] - hotcue_4_activate + [EffectRack1_EffectUnit2] + group_[Channel2]_enable 0x90 - 0x59 + 0x16 - - + + + [Channel2] + keylock + 0x90 + 0x55 + + + + + + + [Channel2] + Mixage.scrollToggle + 0x90 + 0x11 + + + + + + + [Channel2] + Mixage.scrollToggle + 0x90 + 0x31 + + + + + + + [Channel2] + Mixage.scratchToggle + 0x90 + 0x12 + + + + + + + [Channel2] + Mixage.scratchToggle + 0x90 + 0x51 + + + + + + + [Channel2] + Mixage.wheelTouch + 0x90 + 0x25 + + + + + + + [Channel2] + Mixage.wheelTouch + 0x90 + 0x64 + + + + + + + [Channel2] + Mixage.wheelTurn + 0xB0 + 0x25 + + + + + + + [Channel2] + Mixage.wheelTurn + 0xB0 + 0x64 + + + + + + + [Channel2] + sync_enabled + 0x90 + 0x17 + + + + + + + [Channel2] + hotcue_1_activate + 0x90 + 0x56 + + + + + + + [Channel2] + cue_play + 0x90 + 0x18 + + + + + + + [Channel2] + hotcue_2_activate + 0x90 + 0x57 + + + + + + + [Channel2] + cue_default + 0x90 + 0x19 + + + + + + + [Channel2] + hotcue_3_activate + 0x90 + 0x58 + + + + + + + [Channel2] + play + 0x90 + 0x1A + + + + + + + [Channel2] + hotcue_4_activate + 0x90 + 0x59 + + + + + + + [Channel2] + Mixage.handleTrackLoading + 0x90 + 0x1B + + + + + + + [Library] + MoveRight + 0x90 + 0x5A + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter3 + 0xB0 + 0x3B + + + + + + + [Channel2] + + 0xB0 + 0x7A + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter2 + 0xB0 + 0x3C + + + + + + + [Channel2] + + 0xB0 + 0x7B + + + + + + + [EqualizerRack1_[Channel2]_Effect1] + parameter1 + 0xB0 + 0x3D + + + + + + + [Channel2] + + 0xB0 + 0x7C + + + + + + + [Channel2] + pfl + 0x90 + 0x1C + + + + + + + [PreviewDeck1] + stop + 0x90 + 0x5B + + + + + + + [Channel2] + volume + 0xB0 + 0x3E + + + + + + + [Channel2] + + 0xB0 + 0x7D + + + + + + + [Master] + Mixage.handleTraxPress + 0x90 + 0x1F + + + + + + + [Master] + Mixage.handleTraxPress + 0x90 + 0x5E + + + + + + + [Library] + Mixage.handleTraxTurn + 0xB0 + 0x1F + + + + + + + [Library] + Mixage.handleTraxTurn + 0xB0 + 0x5E + + + + + + + [Master] + headMix + 0xB0 + 0x32 + + + + + + + [Master] + crossfader + 0xB0 + 0x31 + + + + + + + + [EffectRack1_EffectUnit1] + group_[Channel1]_enable + 0x90 + 0x08 + 0.5 + + + [EffectRack1_EffectUnit2] + group_[Channel1]_enable + 0x90 + 0x08 + 0.5 + + + [EffectRack1_EffectUnit3] + group_[Channel1]_enable + 0x90 + 0x08 + 0.5 + + + [EffectRack1_EffectUnit4] + group_[Channel1]_enable + 0x90 + 0x08 + 0.5 + + + [EffectRack1_EffectUnit1] + group_[Channel2]_enable + 0x90 + 0x16 + 0.5 + + + [EffectRack1_EffectUnit2] + group_[Channel2]_enable + 0x90 + 0x16 + 0.5 + + + [EffectRack1_EffectUnit3] + group_[Channel2]_enable + 0x90 + 0x16 + 0.5 + + + [EffectRack1_EffectUnit4] + group_[Channel2]_enable + 0x90 + 0x16 + 0.5 + + + [Channel1] + beats_translate_earlier + 0x90 + 0x01 + 0.5 + + + [Channel1] + beats_translate_later + 0x90 + 0x02 + 0.5 + + + [Channel1] + rate_temp_down + 0x90 + 0x01 + 0.5 + + + [Channel1] + rate_temp_up + 0x90 + 0x02 + 0.5 + + - + \ No newline at end of file diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index c42c6e6dc52..34907929407 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,38 +1,71 @@ // Name: Reloop Mixage // Author: HorstBaerbel -// Version: 1.0.4 needs Mixxx 2.1+ +// Version: 1.0.5 needs Mixxx 2.1+ var Mixage = {}; // ----- User-configurable settings ----- Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the jog wheel instead of having to toggle the disc button. Default is false Mixage.scratchTicksPerRevolution = 620; // Number of jog wheel ticks that make a full revolution when scratching. Reduce to "scratch more" of the track, increase to "scratch less". Default is 620 (measured) -Mixage.jogWheelScrollSpeed = 1.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 +Mixage.jogWheelScrollSpeed = 2.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used. Default is false Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized. Default is 4000 Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck. Default is 500 // ----- Internal variables (don't touch) ----- +var ON = 0x7F, OFF = 0x00, DOWN = 0x7F; +var QUICK_PRESS = 1, DOUBLE_PRESS = 2; + Mixage.vuMeterConnection = []; +Mixage.loopConnection = []; +Mixage.beatConnection = []; +Mixage.fxConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; -// Note that the following lists have 3 entries, but we use only 2 decks / effect units. This saves us having to write "deckNr - 1" everywhere... -Mixage.isBeatMovePressed = [false, false, false]; -Mixage.isDryWetPressed = [false, false, false]; -Mixage.scratchToggleLastState = [0, 0, 0]; // helper array to enable scratch toggling by disc button -Mixage.isScratchActive = [false, false, false]; // true if scratching currently enabled for deck -Mixage.scrollToggleLastState = [0, 0, 0]; // helper array to enable scroll toggling by loupe button -Mixage.isScrollActive = [false, false, false]; // true if scrolling currently enabled for deck -Mixage.effectRackSelected = [[true, false], [true, false], [true, false]]; // if effect rack 1/2 is selected for channel 1/2 -Mixage.effectRackEnabled = [false, false, false]; // if effect rack 1/2 is enabled for channel 1/2 +Mixage.doublePressTimer = 0; + +Mixage.scratchToggleState = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.scrollToggleState = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.scratching = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.isBeatMovePressed = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.syncLeader = { + "[Channel1]": engine.getValue("[Channel1]", "sync_master"), + "[Channel2]": engine.getValue("[Channel2]", "sync_master"), +}; Mixage.init = function(_id, _debugging) { // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); } + + var numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effects"); + var numDecks = engine.getValue("[Master]", "num_decks"); + + print(numDecks); + Mixage.connectControlsToFunctions("[Channel1]"); Mixage.connectControlsToFunctions("[Channel2]"); + + engine.setValue("[EffectRack1_EffectUnit1]", "show_focus", 1); + engine.setValue("[EffectRack1_EffectUnit2]", "show_focus", 1); + // make connection for updating the VU meters Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 29, val * 7); @@ -40,26 +73,75 @@ Mixage.init = function(_id, _debugging) { Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { midi.sendShortMsg(0x90, 30, val * 7); }); - // restore deck sync master LEDs (function currently not working as of 2.3.3) - //var isDeck1SyncLeader = engine.getValue("[Channel1]", "sync_master"); - //Mixage.toggleLED(isDeck1SyncLeader ? 1 : 0, "[Channel1]", "sync_master"); - //var isDeck2SyncLeader = engine.getValue("[Channel2]", "sync_master"); - //Mixage.toggleLED(isDeck2SyncLeader ? 1 : 0, "[Channel2]", "sync_master"); - // restore deck 1 effect states from user preferences - Mixage.effectRackSelected[1][0] = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel1]_enable"); - Mixage.effectRackSelected[1][1] = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Channel1]_enable"); - Mixage.effectRackEnabled[1] = Mixage.effectRackSelected[1][0] || Mixage.effectRackSelected[1][1]; - Mixage.toggleLED(Mixage.effectRackEnabled[1] ? 1 : 0, "[Channel1]", "fx_on"); - // restore deck 2 effect states from user preferences - Mixage.effectRackSelected[2][0] = engine.getValue("[EffectRack1_EffectUnit1]", "group_[Channel2]_enable"); - Mixage.effectRackSelected[2][1] = engine.getValue("[EffectRack1_EffectUnit2]", "group_[Channel2]_enable"); - Mixage.effectRackEnabled[2] = Mixage.effectRackSelected[2][0] || Mixage.effectRackSelected[2][1]; - Mixage.toggleLED(Mixage.effectRackEnabled[2] ? 1 : 0, "[Channel2]", "fx_on"); + + // make connection for showing the beats on the loop button when a loop is active + Mixage.loopConnection[0] = engine.makeConnection("[Channel1]", "loop_enabled", function(value) { + if (value === 1) { + Mixage.beatConnection[0] = engine.makeConnection("[Channel1]", "beat_active", function(value) { + if (engine.getValue("[Channel1]", "beatloop_size") > 0.125) { Mixage.toggleLED(value, "[Channel1]", "loop"); } else { + Mixage.toggleLED(ON, "[Channel1]", "loop"); + } + }); + } else { + Mixage.beatConnection[0].disconnect(); + Mixage.toggleLED(OFF, "[Channel1]", "loop"); + } + }); + Mixage.loopConnection[1] = engine.makeConnection("[Channel2]", "loop_enabled", function(value) { + if (value === 1) { + Mixage.beatConnection[1] = engine.makeConnection("[Channel2]", "beat_active", function(value) { + if (engine.getValue("[Channel2]", "beatloop_size") > 0.125) { Mixage.toggleLED(value, "[Channel2]", "loop"); } else { + Mixage.toggleLED(ON, "[Channel2]", "loop"); + } + }); + } else { + Mixage.beatConnection[1].disconnect(); + Mixage.toggleLED(OFF, "[Channel2]", "loop"); + } + }); + + Mixage.fxConnection[0] = engine.makeConnection("[EffectRack1_EffectUnit1]", "focused_effect", function(val) { + if (val === 0) { + Mixage.toggleLED(OFF, "[Channel1]", "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit1]", "super1"); + } else { + Mixage.toggleLED(ON, "[Channel1]", "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit2_Effect" + val + "]", "meta"); + } + }); + + Mixage.fxConnection[1] = engine.makeConnection("[EffectRack1_EffectUnit2]", "focused_effect", function(val) { + if (val === 0) { + Mixage.toggleLED(OFF, "[Channel2]", "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit1]", "super1"); + } else { + Mixage.toggleLED(ON, "[Channel2]", "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit2_Effect" + val + "]", "meta"); + } + }); + + engine.softTakeover("[EffectRack1_EffectUnit1]", "super1", true); + engine.softTakeover("[EffectRack1_EffectUnit2]", "super1", true); + engine.softTakeover("[QuickEffectRack1_[Channel1]]", "super1", true); + engine.softTakeover("[QuickEffectRack1_[Channel2]]", "super1", true); + + for (var deck = 1; deck <= numDecks; deck++) { + for (var effect = 1; effect < numEffectSlots; effect++) { + var groupString = "[EffectRack1_EffectUnit"+ deck +"_Effect" + effect + "]"; + engine.softTakeover(groupString, "meta", true); + } + } }; Mixage.shutdown = function() { Mixage.vuMeterConnection[0].disconnect(); Mixage.vuMeterConnection[1].disconnect(); + Mixage.loopConnection[0].disconnect(); + Mixage.loopConnection[1].disconnect(); + Mixage.beatConnection[0].disconnect(); + Mixage.beatConnection[1].disconnect(); + Mixage.fxConnection[0].disconnect(); + Mixage.fxConnection[1].disconnect(); Mixage.connectControlsToFunctions("[Channel1]", true); Mixage.connectControlsToFunctions("[Channel2]", true); // all button LEDs off @@ -76,12 +158,16 @@ Mixage.ledMap = { "play_indicator": 0x0C, "load_indicator": 0x0D, "pfl": 0x0E, + "loop": 0x05, "loop_enabled": 0x06, "sync_enabled": 0x09, "sync_master": 0x07, "fx_on": 0x08, + "fx_sel": 0x07, "scratch_active": 0x04, "scroll_active": 0x03, + "rate_temp_up": 0x02, + "rate_temp_down": 0x01, }, "[Channel2]": { "cue_indicator": 0x18, @@ -89,12 +175,16 @@ Mixage.ledMap = { "play_indicator": 0x1A, "load_indicator": 0x1B, "pfl": 0x1C, + "loop": 0x13, "loop_enabled": 0x14, "sync_enabled": 0x17, "sync_master": 0x15, "fx_on": 0x16, + "fx_sel": 0x15, "scratch_active": 0x12, - "scroll_active": 0x11 + "scroll_active": 0x11, + "rate_temp_up": 0x10, + "rate_temp_down": 0x0f, } }; @@ -105,7 +195,7 @@ Mixage.connectionMap = { "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null] + "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], }; // Set or remove functions to call when the state of a mixxx control changes @@ -122,7 +212,7 @@ Mixage.connectControlsToFunctions = function(group, remove) { // Toggle the LED on the MIDI controller by sending a MIDI message Mixage.toggleLED = function(value, group, control) { - midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1) ? 0x7F : 0); + midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1 || value) ? 0x7F : 0); }; // Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck @@ -135,47 +225,6 @@ Mixage.handlePlay = function(value, group, control) { Mixage.toggleLED(value, group, "load_indicator"); }; -// A button for the playlist was pressed -Mixage.handleLibrary = function(channel, control, value, status, _group) { - // "push2browse" button was moved somehow - if (control === 0x1F || control === 0x5E) { // "push2browse" button was pushed or turned - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } - if (status === 0x90 && value === 0x7F) { // "push2browse" button was pushed - if (control === 0x5E) { // was shift pressed? - engine.setValue("[Library]", "GoToItem", true); - } else { - // stop the currently playing track. if it wasn't playing, start it - if (engine.getValue("[PreviewDeck1]", "play")) { - engine.setValue("[PreviewDeck1]", "stop", true); - } else { - engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); - } - } - } else if (status === 0xB0) { // "push2browse" button was turned - var newValue = value - 64; - if (control === 0x1F) { // was shift pressed? - engine.setValue("[Playlist]", "SelectTrackKnob", newValue); - } else { - engine.setValue("[Playlist]", "SelectPlaylist", newValue); - } - } - } else if (control === 0x0D || control === 0x4C) { // load into deck 1 - if (value === 0x7F) { - engine.setValue("[PreviewDeck1]", "stop", true); - engine.setValue("[Channel1]", control === 0x4C ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); - Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; - } - } else if (control === 0x1B || control === 0x5A) { // load into deck 2 - if (value === 0x7F) { - engine.setValue("[PreviewDeck1]", "stop", true); - engine.setValue("[Channel2]", control === 0x5A ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); - Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; - } - } -}; - // Set the library visible and hide it when libraryHideTimeOut is reached Mixage.setLibraryMaximized = function(visible) { if (visible === true) { @@ -208,231 +257,247 @@ Mixage.libraryCheckTimeout = function() { } }; -// Switch the controller and Mixxx state for scratching -Mixage.setScratching = function(deckNr, active) { - // check if setting changed - if (Mixage.isScratchActive[deckNr] !== active) { - Mixage.isScratchActive[deckNr] = active; - if (active) { - // turn off scrolling first - Mixage.setScrolling(deckNr, false); +Mixage.handleTraxPress = function(channel, control, value, status, group) { + if (value === DOWN) { + if (Mixage.doublePressTimer === 0) { // first press + Mixage.doublePressTimer = engine.beginTimer(400, function() { + Mixage.TraxPressCallback(channel, control, value, status, group, QUICK_PRESS); + }, true); + } else { // 2nd press (before timer's out) + engine.stopTimer(Mixage.doublePressTimer); + Mixage.TraxPressCallback(channel, control, value, status, group, DOUBLE_PRESS); + } + } +}; + +Mixage.handleTraxTurn = function(_channel, control, value, _status, _group) { + var newValue = value - 64; + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } + if (control === 0x5E) { // was shift pressed? + engine.setValue("[Playlist]", "SelectPlaylist", newValue); + } else { + engine.setValue("[Playlist]", "SelectTrackKnob", newValue); + } +}; + +Mixage.handleTrackLoading = function(_channel, control, value, _status, group) { + if (value === DOWN) { + engine.setValue("[PreviewDeck1]", "stop", true); + engine.setValue(group, control > 0x1B ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); + Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; + } +}; + +Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, event) { + if (event === QUICK_PRESS) { + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } + if (engine.getValue("[PreviewDeck1]", "play")) { + engine.setValue("[PreviewDeck1]", "stop", true); + } else { + engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); + } + } + if (event === DOUBLE_PRESS) { + engine.setValue(group, "maximize_library", !engine.getValue(group, "maximize_library")); + } + Mixage.doublePressTimer = 0; +}; + +Mixage.nextEffect = function(_channel, _control, value, _status, group) { + var unitNr = script.deckFromGroup(group); + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + //for some reason one more effect slot is returned than visible in the ui, thus the minus 1 + var numEffectSlots = engine.getValue(controlString, "num_effectslots") - 1; + if (value === DOWN) { + if (engine.getValue(controlString, "focused_effect") === numEffectSlots) { + for (var i = 1; i === numEffectSlots; i++) { + var groupString = "[EffectRack1_EffectUnit" + unitNr + "_Effect" + i + "]"; + engine.softTakeoverIgnoreNextValue(groupString, "meta"); + } + engine.softTakeoverIgnoreNextValue(controlString, "super1"); + engine.setValue(controlString, "focused_effect", 0); } else { - engine.scratchDisable(deckNr); + var currentSelection = engine.getValue(controlString, "focused_effect"); + engine.setValue(controlString, "focused_effect", currentSelection + 1); } - var controlString = "[Channel" + deckNr + "]"; - Mixage.toggleLED(Mixage.isScratchActive[deckNr] ? 1 : 0, controlString, "scratch_active"); } }; -// The "disc" button that enables/disables scratching -Mixage.scratchToggle = function(channel, control, value, _status, _group) { - // calculate deck number from MIDI control. 0x04 controls deck 1, 0x12 deck 2 - var deckNr = control === 0x04 ? 1 : 2; - // check for pressed->release or released->press - if (Mixage.scratchToggleLastState[deckNr] !== value) { - Mixage.scratchToggleLastState[deckNr] = value; - if (value === 0) { - return; +Mixage.handleEffectDryWet = function(_channel, _control, value, _status, group) { + var unitNr = script.deckFromGroup(group); + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var diff = (value - 64); // 16.0; + if (Mixage.isBeatMovePressed[group]) { + Mixage.setFxChannels(diff); + } else if (engine.getValue(controlString, "focused_effect") === 0) { + var dryWetValue = engine.getValue(controlString, "mix"); + engine.setValue(controlString, "mix", dryWetValue + (diff / 16.0)); + } else { + var focussedEffect = engine.getValue(controlString, "focused_effect"); + engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "effect_selector", diff); + } +}; + +Mixage.handleDryWetPressed = function(_channel, _control, value, _status, group) { + var unitNr = script.deckFromGroup(group); + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var focussedEffect = engine.getValue(controlString, "focused_effect"); + var numEffectSlots = engine.getValue(controlString, "num_effects"); + if (value === DOWN && focussedEffect !== 0) { + var effectStatus = engine.getValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled"); + engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled", !effectStatus); + } + if (value === DOWN && focussedEffect === 0) { + for (var i = 1; i < numEffectSlots; i++) { + engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + i + "]", "enabled", false); } - Mixage.setScratching(deckNr, !Mixage.isScratchActive[deckNr]); } }; -// Switch the controller and Mixxx state for scrolling -Mixage.setScrolling = function(deckNr, active) { - // check if setting changed - if (Mixage.isScrollActive[deckNr] !== active) { - Mixage.isScrollActive[deckNr] = active; - if (active) { - // turn off scratching first - Mixage.setScratching(deckNr, false); +Mixage.handleFxAmount = function(_channel, _control, value, _status, group) { + var unitNr = script.deckFromGroup(group); + var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; + var focussedEffect = engine.getValue(controlString, "focused_effect"); + if (focussedEffect === 0) { + engine.setValue(controlString, "super1", value / 127); + } else { + engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "meta", value / 127); + } +}; + +Mixage.handleFxPress = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + var numUnits = engine.getValue("[EffectRack1]", "num_effectunits"); + var fxChannel = "group_" + group + "_enable"; + var unitNr = script.deckFromGroup(group); + var enabledFxGroups = []; + + for (var i = 1; i <= numUnits; i++) { + enabledFxGroups.push(engine.getValue("[EffectRack1_EffectUnit" + i + "]", fxChannel)); + } + + if (enabledFxGroups.indexOf(1) !== -1) { + for (var effectUnit = 1; effectUnit <= numUnits; effectUnit++) { + engine.setValue("[EffectRack1_EffectUnit" + effectUnit + "]", fxChannel, false); + } } else { - engine.scratchDisable(deckNr); + engine.setValue("[EffectRack1_EffectUnit" + unitNr + "]", fxChannel, true); + } + } +}; + +// This function is necessary to allow for soft takeover of the filter amount button +// see https://github.com/mixxxdj/mixxx/wiki/Midi-Scripting#soft-takeover +Mixage.handleFilter = function(_channel, _control, value, _status, group) { + engine.setValue("[QuickEffectRack1_"+ group +"]", "super1", value / 127); +}; + +//Handles setting soft takeovers when pressing shift +Mixage.handleShift = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + var unitNr = script.deckFromGroup(group); + engine.softTakeoverIgnoreNextValue("[QuickEffectRack1_"+group+"]", "super1"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit"+unitNr+"]", "super1"); + } +}; + +// The "disc" button that enables/disables scratching +Mixage.scratchToggle = function(_channel, _control, value, _status, group) { + // check for pressed->release or released->press + if (value === DOWN) { + Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; + Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); + if (Mixage.scrollToggleState[group]) { + Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; + Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); } - var controlString = "[Channel" + deckNr + "]"; - Mixage.toggleLED(Mixage.isScrollActive[deckNr] ? 1 : 0, controlString, "scroll_active"); } }; // The "loupe" button that enables/disables track scrolling -Mixage.scrollToggle = function(channel, control, value, _status, _group) { - // calculate deck number from MIDI control. 0x03 controls deck 1, 0x12 deck 2 - var deckNr = control === 0x03 ? 1 : 2; +Mixage.scrollToggle = function(_channel, _control, value, _status, group) { // check for pressed->release or released->press - if (Mixage.scrollToggleLastState[deckNr] !== value) { - Mixage.scrollToggleLastState[deckNr] = value; - if (value === 0) { - return; + if (value === DOWN) { + Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; + Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); + if (Mixage.scratchToggleState[group]) { + Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; + Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); } - Mixage.setScrolling(deckNr, !Mixage.isScrollActive[deckNr]); } }; // The touch function on the wheels that enables/disables scratching -Mixage.wheelTouch = function(channel, control, value, _status, _group) { - // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control === 0x24 ? 1 : 2; +Mixage.wheelTouch = function(_channel, _control, value, _status, group) { + var unitNr = script.deckFromGroup(group); // check if scratching should be enabled - if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr]) { - if (value === 0x7F) { + if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group]) { + if (value === DOWN) { // turn on scratching on this deck var alpha = 1.0 / 8.0; var beta = alpha / 32.0; - engine.scratchEnable(deckNr, Mixage.scratchTicksPerRevolution, 33.0 + 1.0 / 3.0, alpha, beta); + engine.scratchEnable(unitNr, Mixage.scratchTicksPerRevolution, 33.33, alpha, beta); + Mixage.scratching[group] = true; } else { - engine.scratchDisable(deckNr); + engine.scratchDisable(unitNr); + Mixage.scratching[group] = false; } } }; // The wheel that controls the scratching / jogging -Mixage.wheelTurn = function(channel, control, value, _status, _group) { +Mixage.wheelTurn = function(_channel, _control, value, _status, group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 - var deckNr = control === 0x24 ? 1 : 2; + var deckNr = script.deckFromGroup(group); // only enable wheel if functionality has been enabled - if (Mixage.scratchByWheelTouch || Mixage.isScratchActive[deckNr] || Mixage.isScrollActive[deckNr]) { + if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group] || Mixage.scrollToggleState[group]) { // control centers on 0x40 (64), calculate difference to that value var newValue = value - 64; - if (Mixage.isScrollActive[deckNr]) { // scroll deck - var controlString = "[Channel" + deckNr + "]"; - var keyString = "playposition";// + newValue > 0 ? "up_small" : "down_small"; - var currentPosition = engine.getValue(controlString, keyString); + if (Mixage.scrollToggleState[group]) { // scroll deck + var currentPosition = engine.getValue(group, "playposition"); var speedFactor = 0.00005; - engine.setValue(controlString, keyString, currentPosition + speedFactor * newValue * Mixage.jogWheelScrollSpeed); - } else if (engine.isScratching(deckNr)) { + engine.setValue(group, "playposition", currentPosition + speedFactor * newValue * Mixage.jogWheelScrollSpeed); + } else if (Mixage.scratching[group]) { engine.scratchTick(deckNr, newValue); // scratch deck } else { - engine.setValue("[Channel" + deckNr + "]", "jog", newValue); // pitch bend deck + engine.setValue(group, "jog", newValue); // pitch bend deck } } }; -// The MASTER button that toggles a deck as sync leader / master -Mixage.handleDeckSyncMode = function(_channel, _control, _value, _status, _group) { - // Function currently not working as of 2.3.3: https://manual.mixxx.org/2.4/gl/chapters/appendix/mixxx_controls.html#control-[ChannelN]-sync_master - // Disable until this is working - /*// calculate effect unit number from MIDI control. 0x46 controls unit 1, 0x54 unit 2 - var deckNr = control === 0x46 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle enablement - var controlString = "[Channel" + deckNr + "]"; - var keyString = "sync_master"; - var isSyncLeader = !engine.getValue(controlString, keyString); - // if we want to make this deck sync leader, turn off sync leader on the other deck - if (isSyncLeader) { - var otherDeckNr = deckNr === 1 ? 2 : 1; - engine.setValue("[Channel" + otherDeckNr + "]", keyString, false); - } - engine.setValue(controlString, keyString, isSyncLeader); - Mixage.toggleLED(isSyncLeader ? 1 : 0, controlString, keyString); - }*/ -}; - -// The FX ON button that toggles routing channel 1/2 through effects -Mixage.handleEffectChannelOn = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x08 controls unit 1, 0x16 unit 2 - var unitNr = control === 0x08 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle enablement - Mixage.effectRackEnabled[unitNr] = !Mixage.effectRackEnabled[unitNr]; - var isEnabled = Mixage.effectRackEnabled[unitNr]; - // update controls - var keyString = "group_[Channel" + unitNr + "]_enable"; - engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][0]); - engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][1]); - Mixage.toggleLED(isEnabled ? 1 : 0, "[Channel" + unitNr + "]", "fx_on"); - } -}; - -// The FX SEL button that selects which effects are enabled for channel 1/2 -Mixage.handleEffectChannelSelect = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x07 controls unit 1, 0x15 unit 2 - var unitNr = control === 0x07 ? 1 : 2; - // react only on first message / keydown - if (value === 0x7F) { - // check and toggle select state - var selected1 = Mixage.effectRackSelected[unitNr][0]; - var selected2 = Mixage.effectRackSelected[unitNr][1]; - if (selected1 && selected2) { - selected1 = true; - selected2 = false; - } else if (selected1) { - selected1 = false; - selected2 = true; - } else { - selected1 = true; - selected2 = true; - } - Mixage.effectRackSelected[unitNr][0] = selected1; - Mixage.effectRackSelected[unitNr][1] = selected2; - // update controls - var isEnabled = Mixage.effectRackEnabled[unitNr]; - var keyString = "group_[Channel" + unitNr + "]_enable"; - engine.setValue("[EffectRack1_EffectUnit1]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][0]); - engine.setValue("[EffectRack1_EffectUnit2]", keyString, isEnabled && Mixage.effectRackSelected[unitNr][1]); - } -}; - -// The -DRY/WET+ rotary control is used as an extra "shift" key when pushed down -Mixage.handleDryWetPressed = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 - var unitNr = control === 0x21 ? 1 : 2; - Mixage.isDryWetPressed[unitNr] = value === 0x7f; -}; - -// The -DRY/WET+ rotary control used for the effect dry/wet mix -Mixage.handleEffectDryWet = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x21 controls unit 1, 0x25 unit 2 - var unitNr = control === 0x21 ? 1 : 2; - // control centers on 0x40 (64), calculate difference to that value and scale down - var diff = (value - 64) / 16.0; - var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var keyString = Mixage.isDryWetPressed[unitNr] ? "super1" : "mix"; - var dryWetValue = engine.getValue(controlString, keyString); - engine.setValue(controlString, keyString, dryWetValue + diff); -}; - -// The PAN rotary control used here for panning the master -Mixage.handlePan = function(channel, control, value, _status, _group) { - // control centers on 0x40 (64), calculate difference to that value and scale down - var diff = (value - 64) / 16.0; - var controlString = "[Master]"; - var keyString = "balance"; - var mixValue = engine.getValue(controlString, keyString); - engine.setValue(controlString, keyString, mixValue + diff); +Mixage.handleBeatMove = function(_channel, _control, value, _status, group) { + // control centers on 0x40 (64), calculate difference to that + var diff = (value - 64); + var position = diff > 0 ? "beatjump_forward" : "beatjump_backward"; + engine.setValue(group, position, true); }; -// The BEAT MOVE rotary control is used as an extra "shift" key when pushed down -Mixage.handleBeatMovePressed = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 - var unitNr = control === 0x20 ? 1 : 2; - Mixage.isBeatMovePressed[unitNr] = value === 0x7f; +Mixage.handleBeatMovePressed = function(_channel, _control, value, _status, group) { + Mixage.isBeatMovePressed[group] = value === DOWN ? true : false; }; -Mixage.handleBeatMoveLength = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x20 controls unit 1, 0x22 unit 2 - var unitNr = control === 0x20 ? 1 : 2; - var direction = unitNr === 1 ? 1 : -1; +Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { // control centers on 0x40 (64), calculate difference to that var diff = (value - 64); - if (Mixage.isBeatMovePressed[unitNr]) { - var loopLength = engine.getParameter("[Channel" + unitNr + "]", "beatjump_size"); - loopLength = direction * diff > 0 ? 2 * loopLength : loopLength / 2; - engine.setParameter("[Channel" + unitNr + "]", "beatjump_size", loopLength); + if (Mixage.isBeatMovePressed[group]) { + var beatjumpSize = engine.getParameter(group, "beatjump_size"); + var newBeatJumpSize = diff > 0 ? 2 * beatjumpSize : beatjumpSize / 2; + engine.setParameter(group, "beatjump_size", newBeatJumpSize); } else { - var loopScale = direction * diff > 0 ? "loop_double" : "loop_halve"; - engine.setValue("[Channel" + unitNr + "]", loopScale, true); + var loopScale = diff > 0 ? "loop_double" : "loop_halve"; + engine.setValue(group, loopScale, true); + print(engine.getValue(group, "beatloop_size")); } }; -Mixage.handleBeatMove = function(channel, control, value, _status, _group) { - // calculate effect unit number from MIDI control. 0x5F controls unit 1, 0x61 unit 2 - var unitNr = control === 0x5f ? 1 : 2; - var direction = unitNr === 1 ? 1 : -1; - // control centers on 0x40 (64), calculate difference to that - var diff = (value - 64); - var position = direction * diff > 0 ? "beatjump_forward" : "beatjump_backward"; - engine.setValue("[Channel" + unitNr + "]", position, true); -}; +// The PAN rotary control used here for panning the master +Mixage.handlePan = function(_channel, _control, value, _status, _group) { + // control centers on 0x40 (64), calculate difference to that value and scale down + var diff = (value - 64) / 16.0; + var mixValue = engine.getValue("[Master]", "balance"); + engine.setValue("[Master]", "balance", mixValue + diff); +}; \ No newline at end of file From 3c6d42dbfd189fc2c4d7ea52a1a967cb1045c9f6 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Mon, 28 Aug 2023 21:26:56 +0200 Subject: [PATCH 21/32] rewritten most of the init --- res/controllers/Reloop-Mixage.midi.xml | 62 +-------- res/controllers/Reloop-Mixage.scripts.js | 156 +++++++++++++---------- 2 files changed, 89 insertions(+), 129 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 537571c4837..c6298474366 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -832,12 +832,12 @@ - [EffectRack1_EffectUnit2] - group_[Channel2]_enable + [Channel2] + Mixage.handleFxPress 0x90 0x16 - + @@ -1192,62 +1192,6 @@ - - [EffectRack1_EffectUnit1] - group_[Channel1]_enable - 0x90 - 0x08 - 0.5 - - - [EffectRack1_EffectUnit2] - group_[Channel1]_enable - 0x90 - 0x08 - 0.5 - - - [EffectRack1_EffectUnit3] - group_[Channel1]_enable - 0x90 - 0x08 - 0.5 - - - [EffectRack1_EffectUnit4] - group_[Channel1]_enable - 0x90 - 0x08 - 0.5 - - - [EffectRack1_EffectUnit1] - group_[Channel2]_enable - 0x90 - 0x16 - 0.5 - - - [EffectRack1_EffectUnit2] - group_[Channel2]_enable - 0x90 - 0x16 - 0.5 - - - [EffectRack1_EffectUnit3] - group_[Channel2]_enable - 0x90 - 0x16 - 0.5 - - - [EffectRack1_EffectUnit4] - group_[Channel2]_enable - 0x90 - 0x16 - 0.5 - [Channel1] beats_translate_earlier diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 34907929407..7512eca31fb 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -20,10 +20,16 @@ Mixage.vuMeterConnection = []; Mixage.loopConnection = []; Mixage.beatConnection = []; Mixage.fxConnection = []; +Mixage.testConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; Mixage.doublePressTimer = 0; +Mixage.channels = [ + "[Channel1]", + "[Channel2]", +]; + Mixage.scratchToggleState = { "[Channel1]": false, "[Channel2]": false, @@ -44,35 +50,19 @@ Mixage.isBeatMovePressed = { "[Channel2]": false, }; -Mixage.syncLeader = { - "[Channel1]": engine.getValue("[Channel1]", "sync_master"), - "[Channel2]": engine.getValue("[Channel2]", "sync_master"), -}; - Mixage.init = function(_id, _debugging) { // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); } - var numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effects"); - var numDecks = engine.getValue("[Master]", "num_decks"); - - print(numDecks); - - Mixage.connectControlsToFunctions("[Channel1]"); - Mixage.connectControlsToFunctions("[Channel2]"); - - engine.setValue("[EffectRack1_EffectUnit1]", "show_focus", 1); - engine.setValue("[EffectRack1_EffectUnit2]", "show_focus", 1); - // make connection for updating the VU meters - Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { - midi.sendShortMsg(0x90, 29, val * 7); - }); - Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { - midi.sendShortMsg(0x90, 30, val * 7); - }); + // Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { + // midi.sendShortMsg(0x90, 29, val * 7); + // }); + // Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { + // midi.sendShortMsg(0x90, 30, val * 7); + // }); // make connection for showing the beats on the loop button when a loop is active Mixage.loopConnection[0] = engine.makeConnection("[Channel1]", "loop_enabled", function(value) { @@ -100,50 +90,44 @@ Mixage.init = function(_id, _debugging) { } }); - Mixage.fxConnection[0] = engine.makeConnection("[EffectRack1_EffectUnit1]", "focused_effect", function(val) { - if (val === 0) { - Mixage.toggleLED(OFF, "[Channel1]", "fx_sel"); - engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit1]", "super1"); - } else { - Mixage.toggleLED(ON, "[Channel1]", "fx_sel"); - engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit2_Effect" + val + "]", "meta"); - } - }); - - Mixage.fxConnection[1] = engine.makeConnection("[EffectRack1_EffectUnit2]", "focused_effect", function(val) { - if (val === 0) { - Mixage.toggleLED(OFF, "[Channel2]", "fx_sel"); - engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit1]", "super1"); - } else { - Mixage.toggleLED(ON, "[Channel2]", "fx_sel"); - engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit2_Effect" + val + "]", "meta"); - } - }); + var numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effects"); + // var numDecks = engine.getValue("[Master]", "num_decks"); - engine.softTakeover("[EffectRack1_EffectUnit1]", "super1", true); - engine.softTakeover("[EffectRack1_EffectUnit2]", "super1", true); - engine.softTakeover("[QuickEffectRack1_[Channel1]]", "super1", true); - engine.softTakeover("[QuickEffectRack1_[Channel2]]", "super1", true); + Mixage.channels.forEach(function(channel) { + var deck = script.deckFromGroup(channel); + Mixage.connectControlsToFunctions(channel); - for (var deck = 1; deck <= numDecks; deck++) { for (var effect = 1; effect < numEffectSlots; effect++) { var groupString = "[EffectRack1_EffectUnit"+ deck +"_Effect" + effect + "]"; engine.softTakeover(groupString, "meta", true); } - } + + for (var effectUnit = 1; effectUnit <= 4; effectUnit++) { + var fxGroup = "group_"+channel+"_enable"; + Mixage.testConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+effectUnit+"]", fxGroup, function() { Mixage.toggleFxLED(channel); })); + engine.softTakeover("[EffectRack1_EffectUnit"+effectUnit+"]", "super1", true); + engine.setValue("[EffectRack1_EffectUnit"+effectUnit+"]", "show_focus", 1); + } + + Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel]["VuMeter"], val * 7); })); + Mixage.fxConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); + + Mixage.toggleFxLED(channel); + Mixage.handleFxSelect(engine.getValue("[EffectRack1_EffectUnit"+deck+"]", "focused_effect"), channel); + engine.softTakeover("[QuickEffectRack1_"+channel+"]", "super1", true); + }); }; Mixage.shutdown = function() { - Mixage.vuMeterConnection[0].disconnect(); - Mixage.vuMeterConnection[1].disconnect(); - Mixage.loopConnection[0].disconnect(); - Mixage.loopConnection[1].disconnect(); - Mixage.beatConnection[0].disconnect(); - Mixage.beatConnection[1].disconnect(); - Mixage.fxConnection[0].disconnect(); - Mixage.fxConnection[1].disconnect(); + + Mixage.vuMeterConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.loopConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.fxConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.testConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.connectControlsToFunctions("[Channel1]", true); Mixage.connectControlsToFunctions("[Channel2]", true); + // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); @@ -161,13 +145,11 @@ Mixage.ledMap = { "loop": 0x05, "loop_enabled": 0x06, "sync_enabled": 0x09, - "sync_master": 0x07, "fx_on": 0x08, "fx_sel": 0x07, "scratch_active": 0x04, "scroll_active": 0x03, - "rate_temp_up": 0x02, - "rate_temp_down": 0x01, + "VuMeter": 0x1D, }, "[Channel2]": { "cue_indicator": 0x18, @@ -178,34 +160,42 @@ Mixage.ledMap = { "loop": 0x13, "loop_enabled": 0x14, "sync_enabled": 0x17, - "sync_master": 0x15, "fx_on": 0x16, "fx_sel": 0x15, "scratch_active": 0x12, "scroll_active": 0x11, - "rate_temp_up": 0x10, - "rate_temp_down": 0x0f, + "VuMeter": 0x1E, } }; // Maps mixxx controls to a function that toggles their LEDs Mixage.connectionMap = { - "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], - "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "[Channel1]": { + "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], + "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + }, + "[Channel2]": { + "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], + "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + }, }; // Set or remove functions to call when the state of a mixxx control changes Mixage.connectControlsToFunctions = function(group, remove) { remove = (remove !== undefined) ? remove : false; - for (var control in Mixage.connectionMap) { + for (var control in Mixage.connectionMap[group]) { if (remove) { - Mixage.connectionMap[control][1].disconnect(); + Mixage.connectionMap[group][control][1].disconnect(); } else { - Mixage.connectionMap[control][1] = engine.makeConnection(group, control, Mixage.connectionMap[control][0]); + Mixage.connectionMap[group][control][1] = engine.makeConnection(group, control, Mixage.connectionMap[group][control][0]); } } }; @@ -215,6 +205,32 @@ Mixage.toggleLED = function(value, group, control) { midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1 || value) ? 0x7F : 0); }; +Mixage.toggleFxLED = function(group) { + var numUnits = engine.getValue("[EffectRack1]", "num_effectunits"); + var fxChannel = "group_" + group + "_enable"; + var enabledFxGroups = []; + + for (var i = 1; i <= numUnits; i++) { + enabledFxGroups.push(engine.getValue("[EffectRack1_EffectUnit" + i + "]", fxChannel)); + } + + if (enabledFxGroups.indexOf(1) !== -1) { + Mixage.toggleLED(ON, group, "fx_on"); + } else { + Mixage.toggleLED(OFF, group, "fx_on"); + } +}; + +Mixage.handleFxSelect = function(value, group) { + if (value === 0) { + Mixage.toggleLED(OFF, group, "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit1]", "super1"); + } else { + Mixage.toggleLED(ON, group, "fx_sel"); + engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit2_Effect" + value + "]", "meta"); + } +}; + // Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck Mixage.handlePlay = function(value, group, control) { // toggle the play indicator LED From 9d160f583913a143ea49785ad285f5d4fe229bf5 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Tue, 29 Aug 2023 21:46:49 +0200 Subject: [PATCH 22/32] general cleanup and added comments --- res/controllers/Reloop-Mixage.midi.xml | 4 +- res/controllers/Reloop-Mixage.scripts.js | 144 ++++++++++++----------- 2 files changed, 78 insertions(+), 70 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index c6298474366..74eae9886b5 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -2,15 +2,17 @@ Reloop Mixage - Gersom Zomer + HorstBaerbel / gqzomer Mapping for the Reloop Mixage Interface Edition controller (https://www.reloop.com/reloop-mixage-ie). Should also work on the non-interface version. https://mixxx.discourse.group/t/reloop-mixage-mapping/14779 https://github.com/mixxxdj/mixxx/wiki/Reloop%20Mixage + https://www.reloop.com/media/catalog/product/pdf/2/2/4/224964_Reloop_IM.pdf + diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 7512eca31fb..c51b9fa5d6e 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,6 +1,6 @@ // Name: Reloop Mixage -// Author: HorstBaerbel -// Version: 1.0.5 needs Mixxx 2.1+ +// Author: HorstBaerbel / gqzomer +// Version: 1.0.6 needs Mixxx 2.1+ var Mixage = {}; @@ -19,12 +19,15 @@ var QUICK_PRESS = 1, DOUBLE_PRESS = 2; Mixage.vuMeterConnection = []; Mixage.loopConnection = []; Mixage.beatConnection = []; -Mixage.fxConnection = []; -Mixage.testConnection = []; +Mixage.fxOnConnection = []; +Mixage.fxSelectConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; Mixage.doublePressTimer = 0; +Mixage.numEffectUnits = engine.getValue("[EffectRack1]", "num_effectunits"); +Mixage.numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effectslots"); + Mixage.channels = [ "[Channel1]", "[Channel2]", @@ -51,82 +54,61 @@ Mixage.isBeatMovePressed = { }; Mixage.init = function(_id, _debugging) { + // all button LEDs off for (var i = 0; i < 255; i++) { midi.sendShortMsg(0x90, i, 0); } - // make connection for updating the VU meters - // Mixage.vuMeterConnection[0] = engine.makeConnection("[Channel1]", "VuMeter", function(val) { - // midi.sendShortMsg(0x90, 29, val * 7); - // }); - // Mixage.vuMeterConnection[1] = engine.makeConnection("[Channel2]", "VuMeter", function(val) { - // midi.sendShortMsg(0x90, 30, val * 7); - // }); - - // make connection for showing the beats on the loop button when a loop is active - Mixage.loopConnection[0] = engine.makeConnection("[Channel1]", "loop_enabled", function(value) { - if (value === 1) { - Mixage.beatConnection[0] = engine.makeConnection("[Channel1]", "beat_active", function(value) { - if (engine.getValue("[Channel1]", "beatloop_size") > 0.125) { Mixage.toggleLED(value, "[Channel1]", "loop"); } else { - Mixage.toggleLED(ON, "[Channel1]", "loop"); - } - }); - } else { - Mixage.beatConnection[0].disconnect(); - Mixage.toggleLED(OFF, "[Channel1]", "loop"); - } - }); - Mixage.loopConnection[1] = engine.makeConnection("[Channel2]", "loop_enabled", function(value) { - if (value === 1) { - Mixage.beatConnection[1] = engine.makeConnection("[Channel2]", "beat_active", function(value) { - if (engine.getValue("[Channel2]", "beatloop_size") > 0.125) { Mixage.toggleLED(value, "[Channel2]", "loop"); } else { - Mixage.toggleLED(ON, "[Channel2]", "loop"); - } - }); - } else { - Mixage.beatConnection[1].disconnect(); - Mixage.toggleLED(OFF, "[Channel2]", "loop"); - } - }); - - var numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effects"); - // var numDecks = engine.getValue("[Master]", "num_decks"); + print(Mixage.numEffectSlots); + print(Mixage.numEffectUnits); + // Bind controls and make engine connections for each channel in Mixage.channels + // A predefined list with channels is used instead of a for loop to prevent engine connections to be overwritten Mixage.channels.forEach(function(channel) { var deck = script.deckFromGroup(channel); Mixage.connectControlsToFunctions(channel); - for (var effect = 1; effect < numEffectSlots; effect++) { - var groupString = "[EffectRack1_EffectUnit"+ deck +"_Effect" + effect + "]"; + //set soft takeovers for effectslot amount + for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { + var groupString = "[EffectRack1_EffectUnit"+ deck +"_Effect" + effectSlot + "]"; engine.softTakeover(groupString, "meta", true); } - for (var effectUnit = 1; effectUnit <= 4; effectUnit++) { + for (var effectUnit = 1; effectUnit <= Mixage.numEffectUnits; effectUnit++) { var fxGroup = "group_"+channel+"_enable"; - Mixage.testConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+effectUnit+"]", fxGroup, function() { Mixage.toggleFxLED(channel); })); + Mixage.fxOnConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+effectUnit+"]", fxGroup, function() { Mixage.toggleFxLED(channel); })); + + //set soft takeovers for effectunit meta engine.softTakeover("[EffectRack1_EffectUnit"+effectUnit+"]", "super1", true); engine.setValue("[EffectRack1_EffectUnit"+effectUnit+"]", "show_focus", 1); } - Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel]["VuMeter"], val * 7); })); - Mixage.fxConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); + //set soft takeover for filter effect + engine.softTakeover("[QuickEffectRack1_"+channel+"]", "super1", true); + + //make connections for status LEDs + Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel]["vu_meter"], val * 7); })); + Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); + Mixage.loopConnection.push(engine.makeConnection(channel, "loop_enabled", function(value) { Mixage.toggleLoopLED(value, channel); })); + //get current status and set LEDs accordingly Mixage.toggleFxLED(channel); Mixage.handleFxSelect(engine.getValue("[EffectRack1_EffectUnit"+deck+"]", "focused_effect"), channel); - engine.softTakeover("[QuickEffectRack1_"+channel+"]", "super1", true); }); }; Mixage.shutdown = function() { + // Disconnect all engine connections that are present Mixage.vuMeterConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.loopConnection.forEach(function(connection) { connection.disconnect(); }); - Mixage.fxConnection.forEach(function(connection) { connection.disconnect(); }); - Mixage.testConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.beatConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.fxSelectConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.fxOnConnection.forEach(function(connection) { connection.disconnect(); }); - Mixage.connectControlsToFunctions("[Channel1]", true); - Mixage.connectControlsToFunctions("[Channel2]", true); + // Disconnect all controls from functions + Mixage.channels.forEach(function(channel) { Mixage.connectControlsToFunctions(channel, true); }); // all button LEDs off for (var i = 0; i < 255; i++) { @@ -149,7 +131,7 @@ Mixage.ledMap = { "fx_sel": 0x07, "scratch_active": 0x04, "scroll_active": 0x03, - "VuMeter": 0x1D, + "vu_meter": 0x1D, }, "[Channel2]": { "cue_indicator": 0x18, @@ -164,7 +146,7 @@ Mixage.ledMap = { "fx_sel": 0x15, "scratch_active": 0x12, "scroll_active": 0x11, - "VuMeter": 0x1E, + "vu_meter": 0x1E, } }; @@ -184,7 +166,7 @@ Mixage.connectionMap = { "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "sync_enabled": [function(v, g, c) { Mixage.toggleLoopLED(v, g, c); }, null], }, }; @@ -205,12 +187,12 @@ Mixage.toggleLED = function(value, group, control) { midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1 || value) ? 0x7F : 0); }; +// Toggles the FX On LED / Off when no effect unit is activated for a channel / On when any effect unit is active for a channel Mixage.toggleFxLED = function(group) { - var numUnits = engine.getValue("[EffectRack1]", "num_effectunits"); var fxChannel = "group_" + group + "_enable"; var enabledFxGroups = []; - for (var i = 1; i <= numUnits; i++) { + for (var i = 1; i <= Mixage.numEffectUnits; i++) { enabledFxGroups.push(engine.getValue("[EffectRack1_EffectUnit" + i + "]", fxChannel)); } @@ -221,6 +203,23 @@ Mixage.toggleFxLED = function(group) { } }; +// Flash the loop LED in time with the beat +Mixage.toggleLoopLED = function(value, group) { + var conNumber = script.deckFromGroup(group) - 1; + if (value === 1) { + Mixage.beatConnection[conNumber] = engine.makeConnection(group, "beat_active", function(value) { + // if the loop length is less than 1/8 of a beat turn on LED to prevent excessive flashing + if (engine.getValue(group, "beatloop_size") > 0.125) { Mixage.toggleLED(value, group, "loop"); } else { + Mixage.toggleLED(ON, group, "loop"); + } + }); + } else { + Mixage.beatConnection[conNumber].disconnect(); + Mixage.toggleLED(OFF, group, "loop"); + } +}; + +// Runs every time the focused_effect for a channel is changed either by controller or mixxx Mixage.handleFxSelect = function(value, group) { if (value === 0) { Mixage.toggleLED(OFF, group, "fx_sel"); @@ -273,6 +272,7 @@ Mixage.libraryCheckTimeout = function() { } }; +// Checks wether the Traxx button is double pressed Mixage.handleTraxPress = function(channel, control, value, status, group) { if (value === DOWN) { if (Mixage.doublePressTimer === 0) { // first press @@ -286,6 +286,7 @@ Mixage.handleTraxPress = function(channel, control, value, status, group) { } }; +// Handles turning of the Traxx button Mixage.handleTraxTurn = function(_channel, control, value, _status, _group) { var newValue = value - 64; if (Mixage.autoMaximizeLibrary) { @@ -298,6 +299,7 @@ Mixage.handleTraxTurn = function(_channel, control, value, _status, _group) { } }; +// Stops a preview that might be playing and loads the selected track regardless Mixage.handleTrackLoading = function(_channel, control, value, _status, group) { if (value === DOWN) { engine.setValue("[PreviewDeck1]", "stop", true); @@ -306,6 +308,8 @@ Mixage.handleTrackLoading = function(_channel, control, value, _status, group) { } }; +// Callback function for handleTraxPress +// previews a track on a quick press and maximize/minimize the library on double press Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, event) { if (event === QUICK_PRESS) { if (Mixage.autoMaximizeLibrary) { @@ -323,11 +327,12 @@ Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, Mixage.doublePressTimer = 0; }; +// Cycle through the effectslots of a channel Mixage.nextEffect = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - //for some reason one more effect slot is returned than visible in the ui, thus the minus 1 - var numEffectSlots = engine.getValue(controlString, "num_effectslots") - 1; + //for some reason one more effect slot is returned than visible in the UI, thus the minus 1 + var numEffectSlots = Mixage.numEffectSlots - 1; if (value === DOWN) { if (engine.getValue(controlString, "focused_effect") === numEffectSlots) { for (var i = 1; i === numEffectSlots; i++) { @@ -343,13 +348,13 @@ Mixage.nextEffect = function(_channel, _control, value, _status, group) { } }; +// Handle turning of the Dry/Wet nob +// control the dry/wet when no effect slot is selected else selects the effect for the currently selected effect slot Mixage.handleEffectDryWet = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; var diff = (value - 64); // 16.0; - if (Mixage.isBeatMovePressed[group]) { - Mixage.setFxChannels(diff); - } else if (engine.getValue(controlString, "focused_effect") === 0) { + if (engine.getValue(controlString, "focused_effect") === 0) { // no effect slot is selected var dryWetValue = engine.getValue(controlString, "mix"); engine.setValue(controlString, "mix", dryWetValue + (diff / 16.0)); } else { @@ -358,46 +363,47 @@ Mixage.handleEffectDryWet = function(_channel, _control, value, _status, group) } }; +// Turns a currently selected effect slot on, if none are selected all effect slots are turned off Mixage.handleDryWetPressed = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; var focussedEffect = engine.getValue(controlString, "focused_effect"); - var numEffectSlots = engine.getValue(controlString, "num_effects"); if (value === DOWN && focussedEffect !== 0) { var effectStatus = engine.getValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled"); engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled", !effectStatus); } - if (value === DOWN && focussedEffect === 0) { - for (var i = 1; i < numEffectSlots; i++) { + if (value === DOWN && focussedEffect === 0) { // no effect slot is selected + for (var i = 1; i < Mixage.numEffectSlots; i++) { engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + i + "]", "enabled", false); } } }; +// Controls the meta for an effect slot if selected, otherwise controls the meta for an effect unit Mixage.handleFxAmount = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; var focussedEffect = engine.getValue(controlString, "focused_effect"); - if (focussedEffect === 0) { + if (focussedEffect === 0) { // no effect slot is selected engine.setValue(controlString, "super1", value / 127); } else { engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "meta", value / 127); } }; +// Turn off any effect units that are enabled for the channel, if none are enabled enable the corresponding effect unit Mixage.handleFxPress = function(_channel, _control, value, _status, group) { if (value === DOWN) { - var numUnits = engine.getValue("[EffectRack1]", "num_effectunits"); var fxChannel = "group_" + group + "_enable"; var unitNr = script.deckFromGroup(group); var enabledFxGroups = []; - for (var i = 1; i <= numUnits; i++) { + for (var i = 1; i <= Mixage.numEffectUnits; i++) { enabledFxGroups.push(engine.getValue("[EffectRack1_EffectUnit" + i + "]", fxChannel)); } if (enabledFxGroups.indexOf(1) !== -1) { - for (var effectUnit = 1; effectUnit <= numUnits; effectUnit++) { + for (var effectUnit = 1; effectUnit <= Mixage.numEffectUnits; effectUnit++) { engine.setValue("[EffectRack1_EffectUnit" + effectUnit + "]", fxChannel, false); } } else { @@ -412,7 +418,7 @@ Mixage.handleFilter = function(_channel, _control, value, _status, group) { engine.setValue("[QuickEffectRack1_"+ group +"]", "super1", value / 127); }; -//Handles setting soft takeovers when pressing shift +// Handles setting soft takeovers when pressing shift Mixage.handleShift = function(_channel, _control, value, _status, group) { if (value === DOWN) { var unitNr = script.deckFromGroup(group); From 9224731b9ad059965adc7214700cbeea45aff78d Mon Sep 17 00:00:00 2001 From: gqzomer Date: Wed, 30 Aug 2023 09:00:49 +0200 Subject: [PATCH 23/32] fixed minor typo --- res/controllers/Reloop-Mixage.scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index c51b9fa5d6e..f4e0dc8269d 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -166,7 +166,7 @@ Mixage.connectionMap = { "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLoopLED(v, g, c); }, null], + "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], }, }; From 12945b088931cf12e232e74012441ae63409fece Mon Sep 17 00:00:00 2001 From: gqzomer Date: Sat, 9 Sep 2023 09:28:08 +0200 Subject: [PATCH 24/32] Added output mappings for Channel2 --- res/controllers/Reloop-Mixage.midi.xml | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 74eae9886b5..f32469b92c0 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -1222,6 +1222,34 @@ 0x02 0.5 + + [Channel2] + beats_translate_earlier + 0x90 + 0x0F + 0.5 + + + [Channel2] + beats_translate_later + 0x90 + 0x10 + 0.5 + + + [Channel2] + rate_temp_down + 0x90 + 0x0F + 0.5 + + + [Channel2] + rate_temp_up + 0x90 + 0x10 + 0.5 + \ No newline at end of file From 52ecffe3fe84a12c3bd9354cc6d07d3bd75a7a86 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Sat, 16 Sep 2023 17:41:10 +0200 Subject: [PATCH 25/32] added additional shift bindings --- res/controllers/Reloop-Mixage.midi.xml | 50 +++++++++++++++++--------- 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index f32469b92c0..533a5189ea0 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -137,7 +137,7 @@ [Channel1] - + pregain 0xB0 0x72 @@ -153,6 +153,15 @@ + + + [Channel1] + rate + 0xE2 + + + + [Channel1] @@ -485,8 +494,8 @@ - [Channel1] - + [EqualizerRack1_[Channel1]_Effect1] + parameter3 0xB0 0x74 @@ -505,8 +514,8 @@ - [Channel1] - + [EqualizerRack1_[Channel1]_Effect1] + parameter2 0xB0 0x75 @@ -525,8 +534,8 @@ - [Channel1] - + [EqualizerRack1_[Channel1]_Effect1] + parameter1 0xB0 0x76 @@ -566,7 +575,7 @@ [Channel1] - + volume 0xB0 0x77 @@ -696,7 +705,7 @@ [Channel2] - + pregain 0xB0 0x78 @@ -712,6 +721,15 @@ + + + [Channel2] + rate + 0xE3 + + + + [Channel2] @@ -1044,8 +1062,8 @@ - [Channel2] - + [EqualizerRack1_[Channel2]_Effect1] + parameter3 0xB0 0x7A @@ -1064,8 +1082,8 @@ - [Channel2] - + [EqualizerRack1_[Channel2]_Effect1] + parameter2 0xB0 0x7B @@ -1084,8 +1102,8 @@ - [Channel2] - + [EqualizerRack1_[Channel2]_Effect1] + parameter1 0xB0 0x7C @@ -1125,7 +1143,7 @@ [Channel2] - + volume 0xB0 0x7D From 871d2e624a85b48eda8ab46c586a93865c863ad1 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Fri, 22 Sep 2023 19:49:21 +0200 Subject: [PATCH 26/32] reworked loop section --- res/controllers/Reloop-Mixage.midi.xml | 20 +-- res/controllers/Reloop-Mixage.scripts.js | 213 +++++++++++++++++++---- 2 files changed, 191 insertions(+), 42 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 533a5189ea0..59ca5f9147d 100755 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -77,11 +77,11 @@ [Channel1] - loop_in + Mixage.handleLoopIn 0x90 0x44 - + @@ -117,11 +117,11 @@ [Channel1] - + Mixage.clearLoop 0x90 0x5F - + @@ -175,11 +175,11 @@ [Channel1] - loop_out + Mixage.handleLoopOut 0x90 0x45 - + @@ -645,11 +645,11 @@ [Channel2] - loop_in + Mixage.handleLoopIn 0x90 0x52 - + @@ -743,11 +743,11 @@ [Channel2] - loop_out + Mixage.handleLoopOut 0x90 0x53 - + diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index f4e0dc8269d..751a72f5d12 100755 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -18,7 +18,6 @@ var QUICK_PRESS = 1, DOUBLE_PRESS = 2; Mixage.vuMeterConnection = []; Mixage.loopConnection = []; -Mixage.beatConnection = []; Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; Mixage.libraryHideTimer = 0; @@ -53,6 +52,21 @@ Mixage.isBeatMovePressed = { "[Channel2]": false, }; +Mixage.adjustLoopIn = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.adjustLoopOut = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.blinkTimer = { + "[Channel1]": {}, + "[Channel2]": {}, +}; + Mixage.init = function(_id, _debugging) { // all button LEDs off @@ -60,9 +74,6 @@ Mixage.init = function(_id, _debugging) { midi.sendShortMsg(0x90, i, 0); } - print(Mixage.numEffectSlots); - print(Mixage.numEffectUnits); - // Bind controls and make engine connections for each channel in Mixage.channels // A predefined list with channels is used instead of a for loop to prevent engine connections to be overwritten Mixage.channels.forEach(function(channel) { @@ -88,9 +99,9 @@ Mixage.init = function(_id, _debugging) { engine.softTakeover("[QuickEffectRack1_"+channel+"]", "super1", true); //make connections for status LEDs - Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel]["vu_meter"], val * 7); })); + Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); + Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(0, channel); })); Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); - Mixage.loopConnection.push(engine.makeConnection(channel, "loop_enabled", function(value) { Mixage.toggleLoopLED(value, channel); })); //get current status and set LEDs accordingly Mixage.toggleFxLED(channel); @@ -103,7 +114,6 @@ Mixage.shutdown = function() { // Disconnect all engine connections that are present Mixage.vuMeterConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.loopConnection.forEach(function(connection) { connection.disconnect(); }); - Mixage.beatConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxSelectConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxOnConnection.forEach(function(connection) { connection.disconnect(); }); @@ -125,7 +135,7 @@ Mixage.ledMap = { "load_indicator": 0x0D, "pfl": 0x0E, "loop": 0x05, - "loop_enabled": 0x06, + "reloop": 0x06, "sync_enabled": 0x09, "fx_on": 0x08, "fx_sel": 0x07, @@ -140,7 +150,7 @@ Mixage.ledMap = { "load_indicator": 0x1B, "pfl": 0x1C, "loop": 0x13, - "loop_enabled": 0x14, + "reloop": 0x14, "sync_enabled": 0x17, "fx_on": 0x16, "fx_sel": 0x15, @@ -157,7 +167,9 @@ Mixage.connectionMap = { "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "loop_enabled": [function(v, g) { Mixage.toggleReloopLED(v, g); }, null], + "loop_in": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], + "loop_out": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], }, "[Channel2]": { @@ -165,16 +177,17 @@ Mixage.connectionMap = { "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "loop_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], + "loop_enabled": [function(v, g) { Mixage.toggleReloopLED(v, g); }, null], + "loop_in": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], + "loop_out": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], }, }; // Set or remove functions to call when the state of a mixxx control changes Mixage.connectControlsToFunctions = function(group, remove) { - remove = (remove !== undefined) ? remove : false; for (var control in Mixage.connectionMap[group]) { - if (remove) { + if (remove !== undefined) { Mixage.connectionMap[group][control][1].disconnect(); } else { Mixage.connectionMap[group][control][1] = engine.makeConnection(group, control, Mixage.connectionMap[group][control][0]); @@ -203,20 +216,145 @@ Mixage.toggleFxLED = function(group) { } }; -// Flash the loop LED in time with the beat -Mixage.toggleLoopLED = function(value, group) { - var conNumber = script.deckFromGroup(group) - 1; - if (value === 1) { - Mixage.beatConnection[conNumber] = engine.makeConnection(group, "beat_active", function(value) { - // if the loop length is less than 1/8 of a beat turn on LED to prevent excessive flashing - if (engine.getValue(group, "beatloop_size") > 0.125) { Mixage.toggleLED(value, group, "loop"); } else { - Mixage.toggleLED(ON, group, "loop"); - } - }); +// Flash the Reloop LED if a loop is set but currently not active +Mixage.toggleReloopLED = function(value, group) { + if (value === 0 && engine.getValue(group, "loop_start_position") !== -1 && engine.getValue(group, "loop_end_position") !== -1) { + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 1000); + Mixage.toggleLED(OFF, group, "loop"); + } else { + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); + Mixage.toggleloopLED(group); + } +}; + +//Turns the loop in and loop LEDs on if a loop end or start position is found, otherwise turn them off +Mixage.toggleloopLED = function(group) { + if (engine.getValue(group, "loop_start_position") !== -1) { + Mixage.toggleLED(ON, group, "loop"); } else { - Mixage.beatConnection[conNumber].disconnect(); Mixage.toggleLED(OFF, group, "loop"); } + + if (engine.getValue(group, "loop_end_position") !== -1) { + Mixage.toggleLED(ON, group, "reloop"); + } else { + Mixage.toggleLED(OFF, group, "reloop"); + } +}; + +//Removes any loop that is currently set on a track +Mixage.clearLoop = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + Mixage.stopLoopAdjust(group); + engine.setValue(group, "loop_end_position", -1); + engine.setValue(group, "loop_start_position", -1); + Mixage.toggleloopLED(group); + } +}; + +//Enable the adjustment of the loop end or start position with the jogwheel +Mixage.startLoopAdjust = function(group, adjustpoint) { + if (adjustpoint === "start") { + Mixage.adjustLoopIn[group] = true; + Mixage.blinkLED(Mixage.ledMap[group].loop, group, 250); + + if (Mixage.adjustLoopOut[group]) { + Mixage.adjustLoopOut[group] = false; + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); + Mixage.toggleLED(ON, group, "reloop"); + } + } + + if (adjustpoint === "end") { + Mixage.adjustLoopOut[group] = true; + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 250); + + if (Mixage.adjustLoopIn[group]) { + Mixage.adjustLoopIn[group] = false; + Mixage.blinkLED(Mixage.ledMap[group].loop, group, 0); + Mixage.toggleLED(ON, group, "loop"); + } + } + + Mixage.toggleLED(OFF, group, "scratch_active"); + Mixage.toggleLED(OFF, group, "scroll_active"); + Mixage.scratchToggleState[group] = false; + Mixage.scrollToggleState[group] = false; +}; + +//Disable the adjustment of the loop end or start position with the jogwheel +Mixage.stopLoopAdjust = function(group, adjustpoint) { + if (adjustpoint === "start" | typeof adjustpoint === "undefined") { + Mixage.adjustLoopIn[group] = false; + Mixage.blinkLED(Mixage.ledMap[group].loop, group, 0); + } + + if (adjustpoint === "end" | typeof adjustpoint === "undefined") { + Mixage.adjustLoopOut[group] = false; + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); + } + + if (engine.getValue(group, "loop_enabled") === 1) { + Mixage.toggleLED(ON, group, "loop"); + Mixage.toggleLED(ON, group, "reloop"); + } +}; + +//set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel +Mixage.handleLoopIn = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + if (Mixage.adjustLoopIn[group]) { + Mixage.stopLoopAdjust(group, "start"); + } else if (engine.getValue(group, "loop_enabled") === 0) { + engine.setValue(group, "loop_in", 1); + } else { + Mixage.startLoopAdjust(group, "start"); + } + } else { + if (engine.getValue(group, "loop_in") === 1) { + engine.setValue(group, "loop_in", 0); + } + } +}; + +//set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel +Mixage.handleLoopOut = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + if (Mixage.adjustLoopOut[group]) { + Mixage.stopLoopAdjust(group, "end"); + } else if (engine.getValue(group, "loop_enabled") === 0) { + engine.setValue(group, "loop_out", 1); + } else { + Mixage.startLoopAdjust(group, "end"); + } + } else { + if (engine.getValue(group, "loop_out") === 1) { + engine.setValue(group, "loop_out", 0); + } + } +}; + +//Start blinking the LED for a given control based on the time parameter, stops blinking a control light if time is set to zero +Mixage.blinkLED = function(control, group, time) { + if (time === 0) { + if (Object.prototype.hasOwnProperty.call(Mixage.blinkTimer[group], control)) { + engine.stopTimer(Mixage.blinkTimer[group][control][0]); + delete Mixage.blinkTimer[group][control]; + midi.sendShortMsg(0x90, control, OFF); + } + } else { + if (Object.prototype.hasOwnProperty.call(Mixage.blinkTimer[group], control)) { + engine.stopTimer(Mixage.blinkTimer[group][control][0]); + midi.sendShortMsg(0x90, control, OFF); + } + + Mixage.blinkTimer[group][control] = []; + Mixage.blinkTimer[group][control][1] = false; + Mixage.blinkTimer[group][control][0] = engine.beginTimer(time, function() { + midi.sendShortMsg(0x90, control, Mixage.blinkTimer[group][control][1] ? ON : OFF); + Mixage.blinkTimer[group][control][1] = !Mixage.blinkTimer[group][control][1]; + }); + } }; // Runs every time the focused_effect for a channel is changed either by controller or mixxx @@ -424,6 +562,8 @@ Mixage.handleShift = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); engine.softTakeoverIgnoreNextValue("[QuickEffectRack1_"+group+"]", "super1"); engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit"+unitNr+"]", "super1"); + } else { + Mixage.stopLoopAdjust(group); } }; @@ -431,6 +571,7 @@ Mixage.handleShift = function(_channel, _control, value, _status, group) { Mixage.scratchToggle = function(_channel, _control, value, _status, group) { // check for pressed->release or released->press if (value === DOWN) { + Mixage.stopLoopAdjust(group); Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); if (Mixage.scrollToggleState[group]) { @@ -444,6 +585,7 @@ Mixage.scratchToggle = function(_channel, _control, value, _status, group) { Mixage.scrollToggle = function(_channel, _control, value, _status, group) { // check for pressed->release or released->press if (value === DOWN) { + Mixage.stopLoopAdjust(group); Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); if (Mixage.scratchToggleState[group]) { @@ -475,10 +617,20 @@ Mixage.wheelTouch = function(_channel, _control, value, _status, group) { Mixage.wheelTurn = function(_channel, _control, value, _status, group) { // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 var deckNr = script.deckFromGroup(group); + var newValue = value - 64; // only enable wheel if functionality has been enabled - if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group] || Mixage.scrollToggleState[group]) { + if (Mixage.adjustLoopIn[group]) { + var newStartPosition = engine.getValue(group, "loop_start_position") + (newValue * 50); + if (newStartPosition < engine.getValue(group, "loop_end_position")) { + engine.setValue(group, "loop_start_position", newStartPosition); + } + } else if (Mixage.adjustLoopOut[group]) { + var newEndPosition = engine.getValue(group, "loop_end_position") + (newValue * 50); + if (newEndPosition > engine.getValue(group, "loop_start_position")) { + engine.setValue(group, "loop_end_position", newEndPosition); + } + } else if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group] || Mixage.scrollToggleState[group]) { // control centers on 0x40 (64), calculate difference to that value - var newValue = value - 64; if (Mixage.scrollToggleState[group]) { // scroll deck var currentPosition = engine.getValue(group, "playposition"); var speedFactor = 0.00005; @@ -492,14 +644,12 @@ Mixage.wheelTurn = function(_channel, _control, value, _status, group) { }; Mixage.handleBeatMove = function(_channel, _control, value, _status, group) { - // control centers on 0x40 (64), calculate difference to that - var diff = (value - 64); - var position = diff > 0 ? "beatjump_forward" : "beatjump_backward"; - engine.setValue(group, position, true); + var beatjumpSize = (value - 64) * engine.getValue(group, "beatjump_size"); + engine.setValue(group, "beatjump", beatjumpSize); }; Mixage.handleBeatMovePressed = function(_channel, _control, value, _status, group) { - Mixage.isBeatMovePressed[group] = value === DOWN ? true : false; + Mixage.isBeatMovePressed[group] = value === DOWN; }; Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { @@ -512,7 +662,6 @@ Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { } else { var loopScale = diff > 0 ? "loop_double" : "loop_halve"; engine.setValue(group, loopScale, true); - print(engine.getValue(group, "beatloop_size")); } }; From 9f761506af559c8b884deb3c89bcc8da453b7b3b Mon Sep 17 00:00:00 2001 From: gqzomer Date: Mon, 16 Oct 2023 20:31:46 +0200 Subject: [PATCH 27/32] changed loop adjust behaviour --- res/controllers/Reloop-Mixage.midi.xml | 26 ++-- res/controllers/Reloop-Mixage.scripts.js | 169 ++++++++++++++++------- 2 files changed, 131 insertions(+), 64 deletions(-) mode change 100755 => 100644 res/controllers/Reloop-Mixage.midi.xml mode change 100755 => 100644 res/controllers/Reloop-Mixage.scripts.js diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml old mode 100755 new mode 100644 index 59ca5f9147d..2079a84992a --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -67,11 +67,11 @@ [Channel1] - beatloop_activate + Mixage.handleLoop 0x90 0x05 - + @@ -107,7 +107,7 @@ [Channel1] - Mixage.handleBeatMovePressed + Mixage.handleLoopLengthPress 0x90 0x20 @@ -117,7 +117,7 @@ [Channel1] - Mixage.clearLoop + Mixage.handleBeatLoopPress 0x90 0x5F @@ -165,11 +165,11 @@ [Channel1] - reloop_toggle + Mixage.handleReloop 0x90 0x06 - + @@ -635,11 +635,11 @@ [Channel2] - beatloop_activate + Mixage.handleLoop 0x90 0x13 - + @@ -675,7 +675,7 @@ [Channel2] - Mixage.handleBeatMovePressed + Mixage.handleLoopLengthPress 0x90 0x22 @@ -685,11 +685,11 @@ [Channel2] - + Mixage.handleBeatLoopPress 0x90 0x61 - + @@ -733,11 +733,11 @@ [Channel2] - reloop_toggle + Mixage.handleReloop 0x90 0x14 - + diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js old mode 100755 new mode 100644 index 751a72f5d12..597f478b369 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -22,7 +22,8 @@ Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; -Mixage.doublePressTimer = 0; +Mixage.traxxPressTimer = 0; +Mixage.loopLengthPressTimer = 0; Mixage.numEffectUnits = engine.getValue("[EffectRack1]", "num_effectunits"); Mixage.numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effectslots"); @@ -47,7 +48,12 @@ Mixage.scratching = { "[Channel2]": false, }; -Mixage.isBeatMovePressed = { +Mixage.loopLengthPressed = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.adjustLoop = { "[Channel1]": false, "[Channel2]": false, }; @@ -243,57 +249,64 @@ Mixage.toggleloopLED = function(group) { }; //Removes any loop that is currently set on a track -Mixage.clearLoop = function(_channel, _control, value, _status, group) { - if (value === DOWN) { - Mixage.stopLoopAdjust(group); - engine.setValue(group, "loop_end_position", -1); - engine.setValue(group, "loop_start_position", -1); - Mixage.toggleloopLED(group); - } +Mixage.clearLoop = function(_channel, _control, _value, _status, group) { + Mixage.stopLoopAdjust(group); + engine.setValue(group, "loop_end_position", -1); + engine.setValue(group, "loop_start_position", -1); + Mixage.toggleReloopLED(OFF, group); }; //Enable the adjustment of the loop end or start position with the jogwheel Mixage.startLoopAdjust = function(group, adjustpoint) { - if (adjustpoint === "start") { + if (adjustpoint === "start" || adjustpoint === undefined) { Mixage.adjustLoopIn[group] = true; Mixage.blinkLED(Mixage.ledMap[group].loop, group, 250); - if (Mixage.adjustLoopOut[group]) { + if (Mixage.adjustLoopOut[group] && adjustpoint === "start") { Mixage.adjustLoopOut[group] = false; Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); Mixage.toggleLED(ON, group, "reloop"); } } - if (adjustpoint === "end") { + if (adjustpoint === "end" || adjustpoint === undefined) { Mixage.adjustLoopOut[group] = true; Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 250); - if (Mixage.adjustLoopIn[group]) { + if (Mixage.adjustLoopIn[group] && adjustpoint === "end") { Mixage.adjustLoopIn[group] = false; Mixage.blinkLED(Mixage.ledMap[group].loop, group, 0); Mixage.toggleLED(ON, group, "loop"); } } - Mixage.toggleLED(OFF, group, "scratch_active"); - Mixage.toggleLED(OFF, group, "scroll_active"); - Mixage.scratchToggleState[group] = false; - Mixage.scrollToggleState[group] = false; + if (Mixage.scratchToggleState[group]) { + Mixage.toggleLED(OFF, group, "scratch_active"); + Mixage.scratchToggleState[group] = false; + } + + if (Mixage.scrollToggleState[group]) { + Mixage.toggleLED(OFF, group, "scroll_active"); + Mixage.scrollToggleState[group] = false; + } }; //Disable the adjustment of the loop end or start position with the jogwheel Mixage.stopLoopAdjust = function(group, adjustpoint) { - if (adjustpoint === "start" | typeof adjustpoint === "undefined") { + if (adjustpoint === "start" | adjustpoint === undefined) { Mixage.adjustLoopIn[group] = false; Mixage.blinkLED(Mixage.ledMap[group].loop, group, 0); } - if (adjustpoint === "end" | typeof adjustpoint === "undefined") { + if (adjustpoint === "end" | adjustpoint === undefined) { Mixage.adjustLoopOut[group] = false; Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); } + if (adjustpoint === undefined) { + Mixage.adjustLoop[group] = false; + } + if (engine.getValue(group, "loop_enabled") === 1) { Mixage.toggleLED(ON, group, "loop"); Mixage.toggleLED(ON, group, "reloop"); @@ -302,33 +315,65 @@ Mixage.stopLoopAdjust = function(group, adjustpoint) { //set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel Mixage.handleLoopIn = function(_channel, _control, value, _status, group) { - if (value === DOWN) { - if (Mixage.adjustLoopIn[group]) { - Mixage.stopLoopAdjust(group, "start"); - } else if (engine.getValue(group, "loop_enabled") === 0) { + if (Mixage.adjustLoop[group]) { + if (Mixage.adjustLoopOut[group] && value === DOWN) { + Mixage.startLoopAdjust(group, "start"); + } else if (Mixage.adjustLoopIn[group] && value === DOWN) { + Mixage.startLoopAdjust(group); + } + } else { + if (value === DOWN) { engine.setValue(group, "loop_in", 1); } else { + engine.setValue(group, "loop_in", 0); + } + } +}; + +Mixage.handleLoop = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { + if (Mixage.adjustLoopOut[group] && value === DOWN) { Mixage.startLoopAdjust(group, "start"); + } else if (Mixage.adjustLoopIn[group] && value === DOWN) { + Mixage.startLoopAdjust(group); } } else { - if (engine.getValue(group, "loop_in") === 1) { - engine.setValue(group, "loop_in", 0); + if (value === DOWN) { + engine.setValue(group, "beatloop_activate", 1); + } else { + engine.setValue(group, "beatloop_activate", 0); + } + } +}; + +Mixage.handleReloop = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { + if (Mixage.adjustLoopIn[group] && value === DOWN) { + Mixage.startLoopAdjust(group, "end"); + } else if (Mixage.adjustLoopOut[group] && value === DOWN) { + Mixage.startLoopAdjust(group); + } + } else { + if (value === DOWN) { + engine.setValue(group, "reloop_toggle", 1); + } else { + engine.setValue(group, "reloop_toggle", 0); } } }; //set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel Mixage.handleLoopOut = function(_channel, _control, value, _status, group) { - if (value === DOWN) { - if (Mixage.adjustLoopOut[group]) { - Mixage.stopLoopAdjust(group, "end"); - } else if (engine.getValue(group, "loop_enabled") === 0) { - engine.setValue(group, "loop_out", 1); - } else { + if (Mixage.adjustLoop[group]) { + if (Mixage.adjustLoopIn[group] && value === DOWN) { Mixage.startLoopAdjust(group, "end"); + } else if (Mixage.adjustLoopOut[group] && value === DOWN) { + Mixage.startLoopAdjust(group); } } else { - if (engine.getValue(group, "loop_out") === 1) { + if (value === DOWN) { + engine.setValue(group, "loop_out", 1); + } else { engine.setValue(group, "loop_out", 0); } } @@ -413,12 +458,12 @@ Mixage.libraryCheckTimeout = function() { // Checks wether the Traxx button is double pressed Mixage.handleTraxPress = function(channel, control, value, status, group) { if (value === DOWN) { - if (Mixage.doublePressTimer === 0) { // first press - Mixage.doublePressTimer = engine.beginTimer(400, function() { + if (Mixage.traxxPressTimer === 0) { // first press + Mixage.traxxPressTimer = engine.beginTimer(400, function() { Mixage.TraxPressCallback(channel, control, value, status, group, QUICK_PRESS); }, true); } else { // 2nd press (before timer's out) - engine.stopTimer(Mixage.doublePressTimer); + engine.stopTimer(Mixage.traxxPressTimer); Mixage.TraxPressCallback(channel, control, value, status, group, DOUBLE_PRESS); } } @@ -462,7 +507,7 @@ Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, if (event === DOUBLE_PRESS) { engine.setValue(group, "maximize_library", !engine.getValue(group, "maximize_library")); } - Mixage.doublePressTimer = 0; + Mixage.traxxPressTimer = 0; }; // Cycle through the effectslots of a channel @@ -562,8 +607,6 @@ Mixage.handleShift = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); engine.softTakeoverIgnoreNextValue("[QuickEffectRack1_"+group+"]", "super1"); engine.softTakeoverIgnoreNextValue("[EffectRack1_EffectUnit"+unitNr+"]", "super1"); - } else { - Mixage.stopLoopAdjust(group); } }; @@ -619,15 +662,18 @@ Mixage.wheelTurn = function(_channel, _control, value, _status, group) { var deckNr = script.deckFromGroup(group); var newValue = value - 64; // only enable wheel if functionality has been enabled - if (Mixage.adjustLoopIn[group]) { - var newStartPosition = engine.getValue(group, "loop_start_position") + (newValue * 50); - if (newStartPosition < engine.getValue(group, "loop_end_position")) { - engine.setValue(group, "loop_start_position", newStartPosition); + if (Mixage.adjustLoop[group]) { + if (Mixage.adjustLoopIn[group]) { + var newStartPosition = engine.getValue(group, "loop_start_position") + (newValue * 100); + if (newStartPosition < engine.getValue(group, "loop_end_position")) { + engine.setValue(group, "loop_start_position", newStartPosition); + } } - } else if (Mixage.adjustLoopOut[group]) { - var newEndPosition = engine.getValue(group, "loop_end_position") + (newValue * 50); - if (newEndPosition > engine.getValue(group, "loop_start_position")) { - engine.setValue(group, "loop_end_position", newEndPosition); + if (Mixage.adjustLoopOut[group]) { + var newEndPosition = engine.getValue(group, "loop_end_position") + (newValue * 100); + if (newEndPosition > engine.getValue(group, "loop_start_position")) { + engine.setValue(group, "loop_end_position", newEndPosition); + } } } else if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group] || Mixage.scrollToggleState[group]) { // control centers on 0x40 (64), calculate difference to that value @@ -643,19 +689,40 @@ Mixage.wheelTurn = function(_channel, _control, value, _status, group) { } }; +Mixage.handleBeatLoopPress = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group] && value === DOWN) { + Mixage.stopLoopAdjust(group); + } else if (value === DOWN) { + Mixage.adjustLoop[group] = true; + Mixage.startLoopAdjust(group); + } +}; + Mixage.handleBeatMove = function(_channel, _control, value, _status, group) { var beatjumpSize = (value - 64) * engine.getValue(group, "beatjump_size"); engine.setValue(group, "beatjump", beatjumpSize); }; -Mixage.handleBeatMovePressed = function(_channel, _control, value, _status, group) { - Mixage.isBeatMovePressed[group] = value === DOWN; +Mixage.handleLoopLengthPress = function(_channel, _control, value, _status, group) { + if (value === DOWN) { + Mixage.loopLengthPressed[group] = true; + Mixage.loopLengthPressTimer = engine.beginTimer(400, function() { + Mixage.loopLengthPressTimer = 0; + }, true); + } else { + Mixage.loopLengthPressed[group] = false; + if (Mixage.loopLengthPressTimer !== 0) { + engine.stopTimer(Mixage.loopLengthPressTimer); + Mixage.loopLengthPressTimer = 0; + Mixage.clearLoop(_channel, _control, value, _status, group); + } + } }; Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { // control centers on 0x40 (64), calculate difference to that var diff = (value - 64); - if (Mixage.isBeatMovePressed[group]) { + if (Mixage.loopLengthPressed[group]) { var beatjumpSize = engine.getParameter(group, "beatjump_size"); var newBeatJumpSize = diff > 0 ? 2 * beatjumpSize : beatjumpSize / 2; engine.setParameter(group, "beatjump_size", newBeatJumpSize); @@ -668,7 +735,7 @@ Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { // The PAN rotary control used here for panning the master Mixage.handlePan = function(_channel, _control, value, _status, _group) { // control centers on 0x40 (64), calculate difference to that value and scale down - var diff = (value - 64) / 16.0; + var diff = (value - 64) / 8.0; var mixValue = engine.getValue("[Master]", "balance"); engine.setValue("[Master]", "balance", mixValue + diff); -}; \ No newline at end of file +}; From d8021669b44d60fb7899b18ce9ffd5b618d4f287 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Sun, 29 Oct 2023 10:48:03 +0100 Subject: [PATCH 28/32] Added 2.4 features and refactored code --- res/controllers/Reloop-Mixage.midi.xml | 41 +- res/controllers/Reloop-Mixage.scripts.js | 586 +++++++++++++---------- 2 files changed, 345 insertions(+), 282 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 2079a84992a..a13381d4faa 100644 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -1,18 +1,19 @@ - + Reloop Mixage - HorstBaerbel / gqzomer - Mapping for the Reloop Mixage Interface Edition controller (https://www.reloop.com/reloop-mixage-ie). Should also work on the non-interface version. + HorstBaerbel & gqzomer + Mapping for the Reloop Mixage Interface Edition MK1, Interface Edition MK2 and Controller Edition. https://mixxx.discourse.group/t/reloop-mixage-mapping/14779 https://github.com/mixxxdj/mixxx/wiki/Reloop%20Mixage - https://www.reloop.com/media/catalog/product/pdf/2/2/4/224964_Reloop_IM.pdf + reloop_mixage + @@ -195,7 +196,7 @@ [Channel1] - sync_master + sync_leader 0x90 0x46 @@ -214,12 +215,12 @@ - [Channel1] - Mixage.handlePan + [QuickEffectRack1_[Channel1]] + chain_preset_selector 0xB0 0x60 - + @@ -234,8 +235,8 @@ - [Channel1] - + [QuickEffectRack1_[Channel1]] + enabled 0x90 0x60 @@ -445,11 +446,11 @@ [Channel1] - play + Mixage.handlePlay 0x90 0x0C - + @@ -763,7 +764,7 @@ [Channel2] - sync_master + sync_leader 0x90 0x54 @@ -782,12 +783,12 @@ - [Channel2] - Mixage.handlePan + [QuickEffectRack1_[Channel2]] + chain_preset_selector 0xB0 0x62 - + @@ -802,8 +803,8 @@ - [Channel2] - + [QuickEffectRack1_[Channel2]] + enabled 0x90 0x62 @@ -1013,11 +1014,11 @@ [Channel2] - play + Mixage.handlePlay 0x90 0x1A - + diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 597f478b369..87bf2ac8f61 100644 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,33 +1,39 @@ // Name: Reloop Mixage // Author: HorstBaerbel / gqzomer -// Version: 1.0.6 needs Mixxx 2.1+ +// Version: 1.1.0 requires Mixxx 2.4 or higher var Mixage = {}; // ----- User-configurable settings ----- Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the jog wheel instead of having to toggle the disc button. Default is false Mixage.scratchTicksPerRevolution = 620; // Number of jog wheel ticks that make a full revolution when scratching. Reduce to "scratch more" of the track, increase to "scratch less". Default is 620 (measured) -Mixage.jogWheelScrollSpeed = 2.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 +Mixage.jogWheelScrollSpeed = 1.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used. Default is false Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized. Default is 4000 Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck. Default is 500 // ----- Internal variables (don't touch) ----- -var ON = 0x7F, OFF = 0x00, DOWN = 0x7F; -var QUICK_PRESS = 1, DOUBLE_PRESS = 2; +// engine connections Mixage.vuMeterConnection = []; Mixage.loopConnection = []; Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; + +// timers Mixage.libraryHideTimer = 0; Mixage.libraryRemainingTime = 0; Mixage.traxxPressTimer = 0; Mixage.loopLengthPressTimer = 0; +Mixage.dryWetPressTimer = 0; -Mixage.numEffectUnits = engine.getValue("[EffectRack1]", "num_effectunits"); -Mixage.numEffectSlots = engine.getValue("[EffectRack1_EffectUnit1]", "num_effectslots"); +// constants +Mixage.numEffectUnits = 4; +Mixage.numEffectSlots = 3; +var ON = 0x7F, OFF = 0x00, DOWN = 0x7F; +var QUICK_PRESS = 1, DOUBLE_PRESS = 2; +// these objects store the state of different buttons and modes Mixage.channels = [ "[Channel1]", "[Channel2]", @@ -43,7 +49,7 @@ Mixage.scrollToggleState = { "[Channel2]": false, }; -Mixage.scratching = { +Mixage.wheelTouched = { "[Channel1]": false, "[Channel2]": false, }; @@ -53,6 +59,16 @@ Mixage.loopLengthPressed = { "[Channel2]": false, }; +Mixage.dryWetPressed = { + "[Channel1]": false, + "[Channel2]": false, +}; + +Mixage.scratchPressed = { + "[Channel1]": false, + "[Channel2]": false, +}; + Mixage.adjustLoop = { "[Channel1]": false, "[Channel2]": false, @@ -73,6 +89,66 @@ Mixage.blinkTimer = { "[Channel2]": {}, }; +// Maps channels and their controls to a MIDI control number to toggle their LEDs +Mixage.ledMap = { + "[Channel1]": { + "cue_indicator": 0x0A, + "cue_default": 0x0B, + "play_indicator": 0x0C, + "load_indicator": 0x0D, + "pfl": 0x0E, + "loop": 0x05, + "reloop": 0x06, + "sync_enabled": 0x09, + "fx_on": 0x08, + "fx_sel": 0x07, + "scratch_active": 0x04, + "scroll_active": 0x03, + "vu_meter": 0x1D, + }, + "[Channel2]": { + "cue_indicator": 0x18, + "cue_default": 0x19, + "play_indicator": 0x1A, + "load_indicator": 0x1B, + "pfl": 0x1C, + "loop": 0x13, + "reloop": 0x14, + "sync_enabled": 0x17, + "fx_on": 0x16, + "fx_sel": 0x15, + "scratch_active": 0x12, + "scroll_active": 0x11, + "vu_meter": 0x1E, + } +}; + +// Maps mixxx controls to a function that toggles their LEDs +Mixage.connectionMap = { + "cue_indicator": {"function": function(v, g, c) { Mixage.toggleLED(v, g, c); }}, + "cue_default": {"function": function(v, g, c) { Mixage.toggleLED(v, g, c); }}, + "play_indicator": {"function": function(v, g, c) { Mixage.toggleLED(v, g, c); Mixage.toggleLED(v, g, "load_indicator"); }}, + "pfl": {"function": function(v, g, c) { Mixage.toggleLED(v, g, c); }}, + "loop_enabled": {"function": function(_v, g) { Mixage.toggleReloopLED(g); }}, + "loop_in": {"function": function(v, g) { if (v === 1) { Mixage.toggleLoopLED(g); } }}, + "loop_out": {"function": function(v, g) { if (v === 1) { Mixage.toggleLoopLED(g); } }}, + "sync_enabled": {"function": function(v, g, c) { Mixage.toggleLED(v, g, c); }}, + "eject": {"function": function(_v, g) { Mixage.eject(g); }}, +}; + +// ----- Internal variables functions ----- + +// Set or remove functions to call when the state of a mixxx control changes +Mixage.connectControlsToFunctions = function(group, remove) { + for (var control in Mixage.connectionMap) { + if (remove !== undefined) { + Mixage.connectionMap[control][group].disconnect(); + } else { + Mixage.connectionMap[control][group] = engine.makeConnection(group, control, Mixage.connectionMap[control].function); + } + } +}; + Mixage.init = function(_id, _debugging) { // all button LEDs off @@ -80,36 +156,37 @@ Mixage.init = function(_id, _debugging) { midi.sendShortMsg(0x90, i, 0); } - // Bind controls and make engine connections for each channel in Mixage.channels + // find controls and make engine connections for each channel in Mixage.channels // A predefined list with channels is used instead of a for loop to prevent engine connections to be overwritten Mixage.channels.forEach(function(channel) { var deck = script.deckFromGroup(channel); Mixage.connectControlsToFunctions(channel); - //set soft takeovers for effectslot amount + // set soft takeovers for effectslot amount for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { var groupString = "[EffectRack1_EffectUnit"+ deck +"_Effect" + effectSlot + "]"; engine.softTakeover(groupString, "meta", true); } for (var effectUnit = 1; effectUnit <= Mixage.numEffectUnits; effectUnit++) { + // make connections for the fx on LEDs var fxGroup = "group_"+channel+"_enable"; Mixage.fxOnConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+effectUnit+"]", fxGroup, function() { Mixage.toggleFxLED(channel); })); - //set soft takeovers for effectunit meta + // set soft takeovers for effectunit meta engine.softTakeover("[EffectRack1_EffectUnit"+effectUnit+"]", "super1", true); engine.setValue("[EffectRack1_EffectUnit"+effectUnit+"]", "show_focus", 1); } - //set soft takeover for filter effect + // set soft takeover for filter effect engine.softTakeover("[QuickEffectRack1_"+channel+"]", "super1", true); - //make connections for status LEDs - Mixage.vuMeterConnection.push(engine.makeConnection(channel, "VuMeter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); - Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(0, channel); })); + // make connections for status LEDs + Mixage.vuMeterConnection.push(engine.makeConnection(channel, "vu_meter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); + Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(channel); })); Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); - //get current status and set LEDs accordingly + // get current status and set LEDs accordingly Mixage.toggleFxLED(channel); Mixage.handleFxSelect(engine.getValue("[EffectRack1_EffectUnit"+deck+"]", "focused_effect"), channel); }); @@ -132,78 +209,9 @@ Mixage.shutdown = function() { } }; -// Maps channels and their controls to a MIDI control number to toggle their LEDs -Mixage.ledMap = { - "[Channel1]": { - "cue_indicator": 0x0A, - "cue_default": 0x0B, - "play_indicator": 0x0C, - "load_indicator": 0x0D, - "pfl": 0x0E, - "loop": 0x05, - "reloop": 0x06, - "sync_enabled": 0x09, - "fx_on": 0x08, - "fx_sel": 0x07, - "scratch_active": 0x04, - "scroll_active": 0x03, - "vu_meter": 0x1D, - }, - "[Channel2]": { - "cue_indicator": 0x18, - "cue_default": 0x19, - "play_indicator": 0x1A, - "load_indicator": 0x1B, - "pfl": 0x1C, - "loop": 0x13, - "reloop": 0x14, - "sync_enabled": 0x17, - "fx_on": 0x16, - "fx_sel": 0x15, - "scratch_active": 0x12, - "scroll_active": 0x11, - "vu_meter": 0x1E, - } -}; - -// Maps mixxx controls to a function that toggles their LEDs -Mixage.connectionMap = { - "[Channel1]": { - "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], - "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "loop_enabled": [function(v, g) { Mixage.toggleReloopLED(v, g); }, null], - "loop_in": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], - "loop_out": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - }, - "[Channel2]": { - "cue_indicator": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "cue_default": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "play_indicator": [function(v, g, c) { Mixage.handlePlay(v, g, c); }, null], - "pfl": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - "loop_enabled": [function(v, g) { Mixage.toggleReloopLED(v, g); }, null], - "loop_in": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], - "loop_out": [function(v, g) { if (v === 1) { Mixage.toggleloopLED(g); } }, null], - "sync_enabled": [function(v, g, c) { Mixage.toggleLED(v, g, c); }, null], - }, -}; - -// Set or remove functions to call when the state of a mixxx control changes -Mixage.connectControlsToFunctions = function(group, remove) { - for (var control in Mixage.connectionMap[group]) { - if (remove !== undefined) { - Mixage.connectionMap[group][control][1].disconnect(); - } else { - Mixage.connectionMap[group][control][1] = engine.makeConnection(group, control, Mixage.connectionMap[group][control][0]); - } - } -}; - // Toggle the LED on the MIDI controller by sending a MIDI message Mixage.toggleLED = function(value, group, control) { - midi.sendShortMsg(0x90, Mixage.ledMap[group][control], (value === 1 || value) ? 0x7F : 0); + midi.sendShortMsg(0x90, Mixage.ledMap[group][control], value ? 0x7F : 0); }; // Toggles the FX On LED / Off when no effect unit is activated for a channel / On when any effect unit is active for a channel @@ -223,18 +231,22 @@ Mixage.toggleFxLED = function(group) { }; // Flash the Reloop LED if a loop is set but currently not active -Mixage.toggleReloopLED = function(value, group) { - if (value === 0 && engine.getValue(group, "loop_start_position") !== -1 && engine.getValue(group, "loop_end_position") !== -1) { - Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 1000); +Mixage.toggleReloopLED = function(group) { + if (engine.getValue(group, "loop_enabled") === 0) { Mixage.toggleLED(OFF, group, "loop"); + Mixage.toggleLED(OFF, group, "reloop"); + + if (engine.getValue(group, "loop_start_position") !== -1 && engine.getValue(group, "loop_end_position") !== -1) { + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 1000); + } } else { Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); - Mixage.toggleloopLED(group); + Mixage.toggleLoopLED(group); } }; -//Turns the loop in and loop LEDs on if a loop end or start position is found, otherwise turn them off -Mixage.toggleloopLED = function(group) { +// Turns the loop in and loop LEDs on if a loop end or start position is found, otherwise turn them off +Mixage.toggleLoopLED = function(group) { if (engine.getValue(group, "loop_start_position") !== -1) { Mixage.toggleLED(ON, group, "loop"); } else { @@ -248,16 +260,28 @@ Mixage.toggleloopLED = function(group) { } }; -//Removes any loop that is currently set on a track +// resets the loop LEDs when a track is ejected +Mixage.eject = function(group) { + if (engine.getValue(group, "play") === 0) { + if (Mixage.adjustLoop[group]) { + Mixage.stopLoopAdjust(); + } else { + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); + Mixage.toggleLED(OFF, group, "loop"); + } + } +}; + +// Removes any loop that is currently set on a track Mixage.clearLoop = function(_channel, _control, _value, _status, group) { - Mixage.stopLoopAdjust(group); engine.setValue(group, "loop_end_position", -1); engine.setValue(group, "loop_start_position", -1); - Mixage.toggleReloopLED(OFF, group); }; -//Enable the adjustment of the loop end or start position with the jogwheel +// Enable the adjustment of the loop end or start position with the jogwheel Mixage.startLoopAdjust = function(group, adjustpoint) { + + // enable adjustment of the loop in point if (adjustpoint === "start" || adjustpoint === undefined) { Mixage.adjustLoopIn[group] = true; Mixage.blinkLED(Mixage.ledMap[group].loop, group, 250); @@ -269,6 +293,7 @@ Mixage.startLoopAdjust = function(group, adjustpoint) { } } + // enable adjustment of the loop out point if (adjustpoint === "end" || adjustpoint === undefined) { Mixage.adjustLoopOut[group] = true; Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 250); @@ -280,18 +305,20 @@ Mixage.startLoopAdjust = function(group, adjustpoint) { } } + // disable scratch mode if active if (Mixage.scratchToggleState[group]) { Mixage.toggleLED(OFF, group, "scratch_active"); Mixage.scratchToggleState[group] = false; } + // disable scroll mode if active if (Mixage.scrollToggleState[group]) { Mixage.toggleLED(OFF, group, "scroll_active"); Mixage.scrollToggleState[group] = false; } }; -//Disable the adjustment of the loop end or start position with the jogwheel +// Disable the adjustment of the loop end or start position with the jogwheel Mixage.stopLoopAdjust = function(group, adjustpoint) { if (adjustpoint === "start" | adjustpoint === undefined) { Mixage.adjustLoopIn[group] = false; @@ -307,97 +334,34 @@ Mixage.stopLoopAdjust = function(group, adjustpoint) { Mixage.adjustLoop[group] = false; } - if (engine.getValue(group, "loop_enabled") === 1) { - Mixage.toggleLED(ON, group, "loop"); - Mixage.toggleLED(ON, group, "reloop"); - } + Mixage.toggleReloopLED(group); }; -//set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel -Mixage.handleLoopIn = function(_channel, _control, value, _status, group) { - if (Mixage.adjustLoop[group]) { - if (Mixage.adjustLoopOut[group] && value === DOWN) { - Mixage.startLoopAdjust(group, "start"); - } else if (Mixage.adjustLoopIn[group] && value === DOWN) { - Mixage.startLoopAdjust(group); - } - } else { - if (value === DOWN) { - engine.setValue(group, "loop_in", 1); - } else { - engine.setValue(group, "loop_in", 0); - } - } -}; - -Mixage.handleLoop = function(_channel, _control, value, _status, group) { - if (Mixage.adjustLoop[group]) { - if (Mixage.adjustLoopOut[group] && value === DOWN) { - Mixage.startLoopAdjust(group, "start"); - } else if (Mixage.adjustLoopIn[group] && value === DOWN) { - Mixage.startLoopAdjust(group); - } - } else { - if (value === DOWN) { - engine.setValue(group, "beatloop_activate", 1); - } else { - engine.setValue(group, "beatloop_activate", 0); - } - } -}; +// Start blinking the LED for a given control based on the time parameter, stops blinking a control light if time is set to zero +// blinking is syncronized with the "indicator_250millis" control and the time parameter is rounded to the closest +Mixage.blinkLED = function(control, group, time) { -Mixage.handleReloop = function(_channel, _control, value, _status, group) { - if (Mixage.adjustLoop[group]) { - if (Mixage.adjustLoopIn[group] && value === DOWN) { - Mixage.startLoopAdjust(group, "end"); - } else if (Mixage.adjustLoopOut[group] && value === DOWN) { - Mixage.startLoopAdjust(group); - } - } else { - if (value === DOWN) { - engine.setValue(group, "reloop_toggle", 1); - } else { - engine.setValue(group, "reloop_toggle", 0); - } + // remove any connection that might be present + if (Object.prototype.hasOwnProperty.call(Mixage.blinkTimer[group], control)) { + Mixage.blinkTimer[group][control].timer.disconnect(); + delete Mixage.blinkTimer[group][control]; + midi.sendShortMsg(0x90, control, OFF); } -}; -//set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel -Mixage.handleLoopOut = function(_channel, _control, value, _status, group) { - if (Mixage.adjustLoop[group]) { - if (Mixage.adjustLoopIn[group] && value === DOWN) { - Mixage.startLoopAdjust(group, "end"); - } else if (Mixage.adjustLoopOut[group] && value === DOWN) { - Mixage.startLoopAdjust(group); - } - } else { - if (value === DOWN) { - engine.setValue(group, "loop_out", 1); - } else { - engine.setValue(group, "loop_out", 0); - } - } -}; + if (time > 0) { // if a time is given start blinking the led + var cycles = Math.round(time / 250); //convert time to cycles of 250ms + Mixage.blinkTimer[group][control] = {}; + Mixage.blinkTimer[group][control].toggle = 0; + Mixage.blinkTimer[group][control].counter = 0; -//Start blinking the LED for a given control based on the time parameter, stops blinking a control light if time is set to zero -Mixage.blinkLED = function(control, group, time) { - if (time === 0) { - if (Object.prototype.hasOwnProperty.call(Mixage.blinkTimer[group], control)) { - engine.stopTimer(Mixage.blinkTimer[group][control][0]); - delete Mixage.blinkTimer[group][control]; - midi.sendShortMsg(0x90, control, OFF); - } - } else { - if (Object.prototype.hasOwnProperty.call(Mixage.blinkTimer[group], control)) { - engine.stopTimer(Mixage.blinkTimer[group][control][0]); - midi.sendShortMsg(0x90, control, OFF); - } + Mixage.blinkTimer[group][control].timer = engine.makeConnection("[App]", "indicator_250ms", function() { + Mixage.blinkTimer[group][control].counter += 1; - Mixage.blinkTimer[group][control] = []; - Mixage.blinkTimer[group][control][1] = false; - Mixage.blinkTimer[group][control][0] = engine.beginTimer(time, function() { - midi.sendShortMsg(0x90, control, Mixage.blinkTimer[group][control][1] ? ON : OFF); - Mixage.blinkTimer[group][control][1] = !Mixage.blinkTimer[group][control][1]; + if (Mixage.blinkTimer[group][control].counter === cycles) { + Mixage.blinkTimer[group][control].toggle = !Mixage.blinkTimer[group][control].toggle; + midi.sendShortMsg(0x90, control, Mixage.blinkTimer[group][control].toggle); + Mixage.blinkTimer[group][control].counter = 0; + } }); } }; @@ -413,16 +377,6 @@ Mixage.handleFxSelect = function(value, group) { } }; -// Toggle the LED on play button and make sure the preview deck stops when starting to play in a deck -Mixage.handlePlay = function(value, group, control) { - // toggle the play indicator LED - Mixage.toggleLED(value, group, control); - // make sure to stop preview deck - engine.setValue("[PreviewDeck1]", "stop", true); - // toggle the LOAD button LED for the deck - Mixage.toggleLED(value, group, "load_indicator"); -}; - // Set the library visible and hide it when libraryHideTimeOut is reached Mixage.setLibraryMaximized = function(visible) { if (visible === true) { @@ -432,7 +386,7 @@ Mixage.setLibraryMaximized = function(visible) { engine.setValue("[Master]", "maximize_library", true); if (Mixage.libraryHideTimer === 0) { // timer not running. start it - Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout); + Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout()); } } } else { @@ -445,6 +399,7 @@ Mixage.setLibraryMaximized = function(visible) { } }; +// hides the library after a given period of inactivity Mixage.libraryCheckTimeout = function() { Mixage.libraryRemainingTime -= Mixage.libraryHideTimeout / 5; if (Mixage.libraryRemainingTime <= 0) { @@ -455,6 +410,129 @@ Mixage.libraryCheckTimeout = function() { } }; +// Callback function for handleTraxPress +// previews a track on a quick press and maximize/minimize the library on double press +Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, event) { + if (event === QUICK_PRESS) { + if (Mixage.autoMaximizeLibrary) { + Mixage.setLibraryMaximized(true); + } + if (engine.getValue("[PreviewDeck1]", "play")) { + engine.setValue("[PreviewDeck1]", "stop", true); + } else { + engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); + } + } + if (event === DOUBLE_PRESS) { + script.toggleControl(group, "maximize_library"); + } + Mixage.traxxPressTimer = 0; +}; + +// toggles the focussed effect or all effect slots in an effect unit on or off +Mixage.toggleEffect = function(group) { + var unitNr = script.deckFromGroup(group); + var effectUnit = "EffectRack1_EffectUnit" + unitNr; + var focusedEffect = engine.getValue("[" + effectUnit +"]", "focused_effect"); + var enabledFxSlots = []; + + if (focusedEffect === 0) { + for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { + enabledFxSlots.push(engine.getValue("[" + effectUnit + "_Effect" + effectSlot + "]", "enabled")); + } + for (effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { + engine.setValue("[" + effectUnit + "_Effect" + effectSlot + "]", "enabled", !(enabledFxSlots.indexOf(1) !== -1)); + } + } else { + script.toggleControl("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focusedEffect + "]", "enabled"); + } +}; + +// ----- functions mapped to buttons ----- + +// selects the loop in point in loop adjustment mode, otherwise trigger "beatloop_activate" +Mixage.handleLoop = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { // loop adjustment mode is active + if (Mixage.adjustLoopOut[group] && value === DOWN) { // loop out is currently being adjusted, switch to loop in + Mixage.startLoopAdjust(group, "start"); + } else if (Mixage.adjustLoopIn[group] && value === DOWN) { // loop in is currently being adjusted switch to loop in and out + Mixage.startLoopAdjust(group); + } + } else { + if (value === DOWN) { // loop adjustment mode is not active + engine.setValue(group, "beatloop_activate", 1); + } else { + engine.setValue(group, "beatloop_activate", 0); + } + } +}; + +// selects the loop out point in loop adjustment mode, otherwise trigger reloop +Mixage.handleReloop = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { // loop adjustment mode is active + if (Mixage.adjustLoopIn[group] && value === DOWN) { // loop in is currently being adjusted, switch to loop out + Mixage.startLoopAdjust(group, "end"); + } else if (Mixage.adjustLoopOut[group] && value === DOWN) { // loop out is currently being adjusted switch to loop in and out + Mixage.startLoopAdjust(group); + } + } else { + if (value === DOWN) { // loop adjustment mode is not active + engine.setValue(group, "reloop_toggle", 1); + } else { + engine.setValue(group, "reloop_toggle", 0); + } + } +}; + +// set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel +Mixage.handleLoopIn = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { // loop adjustment mode is active + if (Mixage.adjustLoopOut[group] && value === DOWN) { // loop out is currently being adjusted, switch to loop in + Mixage.startLoopAdjust(group, "start"); + } else if (Mixage.adjustLoopIn[group] && value === DOWN) { // loop in is currently being adjusted switch to loop in and out + Mixage.startLoopAdjust(group); + } + } else { // loop adjustment mode is not active + if (value === DOWN) { + engine.setValue(group, "loop_in", 1); + } else { + engine.setValue(group, "loop_in", 0); + } + } +}; + +// set a loop in point if none is defined, otherwise enable adjustment of the start position with the jogwheel +Mixage.handleLoopOut = function(_channel, _control, value, _status, group) { + if (Mixage.adjustLoop[group]) { // loop adjustment mode is active + if (Mixage.adjustLoopIn[group] && value === DOWN) { // loop in is currently being adjusted, switch to loop out + Mixage.startLoopAdjust(group, "end"); + } else if (Mixage.adjustLoopOut[group] && value === DOWN) { // loop out is currently being adjusted switch to loop in and out + Mixage.startLoopAdjust(group); + } + } else { + if (value === DOWN) { // loop adjustment mode is not active + engine.setValue(group, "loop_out", 1); + } else { + engine.setValue(group, "loop_out", 0); + } + } +}; + +// Toggle play and make sure the preview deck stops when starting to play in a deck +// brake or softStart a while the scratch toggle button is held +Mixage.handlePlay = function(_channel, _control, value, _status, group) { + var deck = script.deckFromGroup(group); + if (value === DOWN && Mixage.scratchPressed[group]) { // scratch toggle is pressed + if (engine.getValue(group, "play") === 0) { + engine.softStart(deck, true, 1.5); + } else { + engine.brake(deck, true, 0.75); + } + } else if (value === DOWN) { // scratch toggle is not pressed + script.toggleControl(group, "play"); + } +}; + // Checks wether the Traxx button is double pressed Mixage.handleTraxPress = function(channel, control, value, status, group) { if (value === DOWN) { @@ -471,60 +549,39 @@ Mixage.handleTraxPress = function(channel, control, value, status, group) { // Handles turning of the Traxx button Mixage.handleTraxTurn = function(_channel, control, value, _status, _group) { - var newValue = value - 64; + var diff = value - 64; // 0x40 (64) centered control if (Mixage.autoMaximizeLibrary) { Mixage.setLibraryMaximized(true); } if (control === 0x5E) { // was shift pressed? - engine.setValue("[Playlist]", "SelectPlaylist", newValue); + engine.setValue("[Playlist]", "SelectPlaylist", diff); } else { - engine.setValue("[Playlist]", "SelectTrackKnob", newValue); + engine.setValue("[Playlist]", "SelectTrackKnob", diff); } }; // Stops a preview that might be playing and loads the selected track regardless -Mixage.handleTrackLoading = function(_channel, control, value, _status, group) { +Mixage.handleTrackLoading = function(_channel, _control, value, _status, group) { if (value === DOWN) { engine.setValue("[PreviewDeck1]", "stop", true); - engine.setValue(group, control > 0x1B ? "LoadSelectedTrackAndPlay" : "LoadSelectedTrack", true); + engine.setValue(group, "LoadSelectedTrack", true); Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; } }; -// Callback function for handleTraxPress -// previews a track on a quick press and maximize/minimize the library on double press -Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, event) { - if (event === QUICK_PRESS) { - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } - if (engine.getValue("[PreviewDeck1]", "play")) { - engine.setValue("[PreviewDeck1]", "stop", true); - } else { - engine.setValue("[PreviewDeck1]", "LoadSelectedTrackAndPlay", true); - } - } - if (event === DOUBLE_PRESS) { - engine.setValue(group, "maximize_library", !engine.getValue(group, "maximize_library")); - } - Mixage.traxxPressTimer = 0; -}; - -// Cycle through the effectslots of a channel +// Cycle through the effectslots of the effectunit that corresponds to a channel Mixage.nextEffect = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - //for some reason one more effect slot is returned than visible in the UI, thus the minus 1 - var numEffectSlots = Mixage.numEffectSlots - 1; if (value === DOWN) { - if (engine.getValue(controlString, "focused_effect") === numEffectSlots) { - for (var i = 1; i === numEffectSlots; i++) { + if (engine.getValue(controlString, "focused_effect") === Mixage.numEffectSlots) { // after cycling through all effectslot go back to the start + for (var i = 1; i === Mixage.numEffectSlots; i++) { var groupString = "[EffectRack1_EffectUnit" + unitNr + "_Effect" + i + "]"; engine.softTakeoverIgnoreNextValue(groupString, "meta"); } engine.softTakeoverIgnoreNextValue(controlString, "super1"); engine.setValue(controlString, "focused_effect", 0); - } else { + } else { // next effect slot var currentSelection = engine.getValue(controlString, "focused_effect"); engine.setValue(controlString, "focused_effect", currentSelection + 1); } @@ -536,8 +593,10 @@ Mixage.nextEffect = function(_channel, _control, value, _status, group) { Mixage.handleEffectDryWet = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var diff = (value - 64); // 16.0; - if (engine.getValue(controlString, "focused_effect") === 0) { // no effect slot is selected + var diff = (value - 64); // 0x40 (64) centered control + if (Mixage.dryWetPressed[group]) { + engine.setValue(controlString, "chain_preset_selector", diff); + } else if (engine.getValue(controlString, "focused_effect") === 0) { // no effect slot is selected var dryWetValue = engine.getValue(controlString, "mix"); engine.setValue(controlString, "mix", dryWetValue + (diff / 16.0)); } else { @@ -548,16 +607,17 @@ Mixage.handleEffectDryWet = function(_channel, _control, value, _status, group) // Turns a currently selected effect slot on, if none are selected all effect slots are turned off Mixage.handleDryWetPressed = function(_channel, _control, value, _status, group) { - var unitNr = script.deckFromGroup(group); - var controlString = "[EffectRack1_EffectUnit" + unitNr + "]"; - var focussedEffect = engine.getValue(controlString, "focused_effect"); - if (value === DOWN && focussedEffect !== 0) { - var effectStatus = engine.getValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled"); - engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focussedEffect + "]", "enabled", !effectStatus); - } - if (value === DOWN && focussedEffect === 0) { // no effect slot is selected - for (var i = 1; i < Mixage.numEffectSlots; i++) { - engine.setValue("[EffectRack1_EffectUnit" + unitNr + "_Effect" + i + "]", "enabled", false); + if (value === DOWN) { + Mixage.dryWetPressed[group] = true; + Mixage.dryWetPressTimer = engine.beginTimer(400, function() { + Mixage.dryWetPressTimer = 0; + }, true); + } else { + Mixage.dryWetPressed[group] = false; + if (Mixage.dryWetPressTimer !== 0) { + engine.stopTimer(Mixage.dryWetPressTimer); + Mixage.dryWetPressTimer = 0; + Mixage.toggleEffect(group); } } }; @@ -612,8 +672,8 @@ Mixage.handleShift = function(_channel, _control, value, _status, group) { // The "disc" button that enables/disables scratching Mixage.scratchToggle = function(_channel, _control, value, _status, group) { - // check for pressed->release or released->press if (value === DOWN) { + Mixage.scratchPressed[group] = true; Mixage.stopLoopAdjust(group); Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); @@ -621,12 +681,13 @@ Mixage.scratchToggle = function(_channel, _control, value, _status, group) { Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); } + } else { + Mixage.scratchPressed[group] = false; } }; // The "loupe" button that enables/disables track scrolling Mixage.scrollToggle = function(_channel, _control, value, _status, group) { - // check for pressed->release or released->press if (value === DOWN) { Mixage.stopLoopAdjust(group); Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; @@ -641,68 +702,74 @@ Mixage.scrollToggle = function(_channel, _control, value, _status, group) { // The touch function on the wheels that enables/disables scratching Mixage.wheelTouch = function(_channel, _control, value, _status, group) { var unitNr = script.deckFromGroup(group); - // check if scratching should be enabled + + if (value === DOWN) { + Mixage.wheelTouched[group] = true; + } else { + Mixage.wheelTouched[group] = false; + } + if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group]) { if (value === DOWN) { - // turn on scratching on this deck var alpha = 1.0 / 8.0; var beta = alpha / 32.0; engine.scratchEnable(unitNr, Mixage.scratchTicksPerRevolution, 33.33, alpha, beta); - Mixage.scratching[group] = true; } else { engine.scratchDisable(unitNr); - Mixage.scratching[group] = false; } } }; // The wheel that controls the scratching / jogging Mixage.wheelTurn = function(_channel, _control, value, _status, group) { - // calculate deck number from MIDI control. 0x24 controls deck 1, 0x25 deck 2 var deckNr = script.deckFromGroup(group); - var newValue = value - 64; - // only enable wheel if functionality has been enabled - if (Mixage.adjustLoop[group]) { + var diff = value - 64; // 0x40 (64) centered control + if (Mixage.adjustLoop[group]) { // loop adjustment + // triple the adjustment rate if the top of the jogwheel is being touched + var factor = Mixage.wheelTouched[group] ? 100 : 33; if (Mixage.adjustLoopIn[group]) { - var newStartPosition = engine.getValue(group, "loop_start_position") + (newValue * 100); + var newStartPosition = engine.getValue(group, "loop_start_position") + (diff * factor); if (newStartPosition < engine.getValue(group, "loop_end_position")) { engine.setValue(group, "loop_start_position", newStartPosition); } } if (Mixage.adjustLoopOut[group]) { - var newEndPosition = engine.getValue(group, "loop_end_position") + (newValue * 100); + var newEndPosition = engine.getValue(group, "loop_end_position") + (diff * factor); if (newEndPosition > engine.getValue(group, "loop_start_position")) { engine.setValue(group, "loop_end_position", newEndPosition); } } } else if (Mixage.scratchByWheelTouch || Mixage.scratchToggleState[group] || Mixage.scrollToggleState[group]) { - // control centers on 0x40 (64), calculate difference to that value if (Mixage.scrollToggleState[group]) { // scroll deck + // triple the scroll rate if the top of the jogwheel is being touched + var speedFactor = Mixage.wheelTouched[group] ? 0.00020 : 0.000066; var currentPosition = engine.getValue(group, "playposition"); - var speedFactor = 0.00005; - engine.setValue(group, "playposition", currentPosition + speedFactor * newValue * Mixage.jogWheelScrollSpeed); - } else if (Mixage.scratching[group]) { - engine.scratchTick(deckNr, newValue); // scratch deck + engine.setValue(group, "playposition", currentPosition + speedFactor * diff * Mixage.jogWheelScrollSpeed); + } else if (Mixage.wheelTouched[group]) { + engine.scratchTick(deckNr, diff); // scratch deck } else { - engine.setValue(group, "jog", newValue); // pitch bend deck + engine.setValue(group, "jog", diff); // pitch bend deck } } }; +// stop or start loop adjustment mode Mixage.handleBeatLoopPress = function(_channel, _control, value, _status, group) { if (Mixage.adjustLoop[group] && value === DOWN) { Mixage.stopLoopAdjust(group); - } else if (value === DOWN) { + } else if (value === DOWN && engine.getValue(group, "loop_start_position") !== -1 && engine.getValue(group, "loop_end_position") !== -1) { Mixage.adjustLoop[group] = true; Mixage.startLoopAdjust(group); } }; +// move the track or an active loop "beatjump_size" number of beats Mixage.handleBeatMove = function(_channel, _control, value, _status, group) { var beatjumpSize = (value - 64) * engine.getValue(group, "beatjump_size"); engine.setValue(group, "beatjump", beatjumpSize); }; +// clears a loop on a short press, set internal variable to true to adjust "beatjump_size" Mixage.handleLoopLengthPress = function(_channel, _control, value, _status, group) { if (value === DOWN) { Mixage.loopLengthPressed[group] = true; @@ -714,14 +781,17 @@ Mixage.handleLoopLengthPress = function(_channel, _control, value, _status, grou if (Mixage.loopLengthPressTimer !== 0) { engine.stopTimer(Mixage.loopLengthPressTimer); Mixage.loopLengthPressTimer = 0; + if (Mixage.adjustLoop[group]) { + Mixage.stopLoopAdjust(group); + } Mixage.clearLoop(_channel, _control, value, _status, group); } } }; +// changes the loop length if Mixage.loopLengthPressed[group] is false otherwise adjusts the "beatjump_size" Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { - // control centers on 0x40 (64), calculate difference to that - var diff = (value - 64); + var diff = (value - 64); // 0x40 (64) centered control if (Mixage.loopLengthPressed[group]) { var beatjumpSize = engine.getParameter(group, "beatjump_size"); var newBeatJumpSize = diff > 0 ? 2 * beatjumpSize : beatjumpSize / 2; @@ -731,11 +801,3 @@ Mixage.handleLoopLength = function(_channel, _control, value, _status, group) { engine.setValue(group, loopScale, true); } }; - -// The PAN rotary control used here for panning the master -Mixage.handlePan = function(_channel, _control, value, _status, _group) { - // control centers on 0x40 (64), calculate difference to that value and scale down - var diff = (value - 64) / 8.0; - var mixValue = engine.getValue("[Master]", "balance"); - engine.setValue("[Master]", "balance", mixValue + diff); -}; From 6b4e9cbd3d7afb73f2e1b17c527c5ff55754d79c Mon Sep 17 00:00:00 2001 From: gqzomer Date: Fri, 10 Nov 2023 14:22:43 +0100 Subject: [PATCH 29/32] fixed reloop led bug; removed automaximize feature --- res/controllers/Reloop-Mixage.midi.xml | 8 +-- res/controllers/Reloop-Mixage.scripts.js | 67 +++++------------------- 2 files changed, 17 insertions(+), 58 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index a13381d4faa..0b7756c03fb 100644 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -1173,8 +1173,8 @@ - [Library] - Mixage.handleTraxTurn + [Playlist] + Mixage.selectTrack 0xB0 0x1F @@ -1183,8 +1183,8 @@ - [Library] - Mixage.handleTraxTurn + [Playlist] + Mixage.selectPlaylist 0xB0 0x5E diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 87bf2ac8f61..deead1f6d89 100644 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,6 +1,6 @@ // Name: Reloop Mixage // Author: HorstBaerbel / gqzomer -// Version: 1.1.0 requires Mixxx 2.4 or higher +// Version: 1.1.1 requires Mixxx 2.4 or higher var Mixage = {}; @@ -8,9 +8,6 @@ var Mixage = {}; Mixage.scratchByWheelTouch = false; // Set to true to scratch by touching the jog wheel instead of having to toggle the disc button. Default is false Mixage.scratchTicksPerRevolution = 620; // Number of jog wheel ticks that make a full revolution when scratching. Reduce to "scratch more" of the track, increase to "scratch less". Default is 620 (measured) Mixage.jogWheelScrollSpeed = 1.0; // Scroll speed when the jog wheel is used to scroll through the track. The higher, the faster. Default is 1.0 -Mixage.autoMaximizeLibrary = false; // Set to true to automatically max- and minimize the library when the browse button is used. Default is false -Mixage.libraryHideTimeout = 4000; // Time in ms after which the library will automatically minimized. Default is 4000 -Mixage.libraryReducedHideTimeout = 500; // Time in ms after which the library will be minimized after loading a song into a deck. Default is 500 // ----- Internal variables (don't touch) ----- @@ -21,8 +18,6 @@ Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; // timers -Mixage.libraryHideTimer = 0; -Mixage.libraryRemainingTime = 0; Mixage.traxxPressTimer = 0; Mixage.loopLengthPressTimer = 0; Mixage.dryWetPressTimer = 0; @@ -183,7 +178,7 @@ Mixage.init = function(_id, _debugging) { // make connections for status LEDs Mixage.vuMeterConnection.push(engine.makeConnection(channel, "vu_meter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); - Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(channel); })); + Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(channel); })); Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); // get current status and set LEDs accordingly @@ -238,6 +233,8 @@ Mixage.toggleReloopLED = function(group) { if (engine.getValue(group, "loop_start_position") !== -1 && engine.getValue(group, "loop_end_position") !== -1) { Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 1000); + } else { + Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); } } else { Mixage.blinkLED(Mixage.ledMap[group].reloop, group, 0); @@ -377,46 +374,10 @@ Mixage.handleFxSelect = function(value, group) { } }; -// Set the library visible and hide it when libraryHideTimeOut is reached -Mixage.setLibraryMaximized = function(visible) { - if (visible === true) { - Mixage.libraryRemainingTime = Mixage.libraryHideTimeout; - // maximize library if not maximized already - if (engine.getValue("[Master]", "maximize_library") !== true) { - engine.setValue("[Master]", "maximize_library", true); - if (Mixage.libraryHideTimer === 0) { - // timer not running. start it - Mixage.libraryHideTimer = engine.beginTimer(Mixage.libraryHideTimeout / 5, Mixage.libraryCheckTimeout()); - } - } - } else { - if (Mixage.libraryHideTimer !== 0) { - engine.stopTimer(Mixage.libraryHideTimer); - Mixage.libraryHideTimer = 0; - } - Mixage.libraryRemainingTime = 0; - engine.setValue("[Master]", "maximize_library", false); - } -}; - -// hides the library after a given period of inactivity -Mixage.libraryCheckTimeout = function() { - Mixage.libraryRemainingTime -= Mixage.libraryHideTimeout / 5; - if (Mixage.libraryRemainingTime <= 0) { - engine.stopTimer(Mixage.libraryHideTimer); - Mixage.libraryHideTimer = 0; - Mixage.libraryRemainingTime = 0; - engine.setValue("[Master]", "maximize_library", false); - } -}; - // Callback function for handleTraxPress // previews a track on a quick press and maximize/minimize the library on double press Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, event) { if (event === QUICK_PRESS) { - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } if (engine.getValue("[PreviewDeck1]", "play")) { engine.setValue("[PreviewDeck1]", "stop", true); } else { @@ -547,17 +508,16 @@ Mixage.handleTraxPress = function(channel, control, value, status, group) { } }; -// Handles turning of the Traxx button -Mixage.handleTraxTurn = function(_channel, control, value, _status, _group) { +// select track when turning the Traxx button +Mixage.selectTrack = function(_channel, _control, value, _status, _group) { var diff = value - 64; // 0x40 (64) centered control - if (Mixage.autoMaximizeLibrary) { - Mixage.setLibraryMaximized(true); - } - if (control === 0x5E) { // was shift pressed? - engine.setValue("[Playlist]", "SelectPlaylist", diff); - } else { - engine.setValue("[Playlist]", "SelectTrackKnob", diff); - } + engine.setValue("[Playlist]", "SelectTrackKnob", diff); +}; + +// select playlist when turning the Traxx button +Mixage.selectPlaylist = function(_channel, _control, value, _status, _group) { + var diff = value - 64; // 0x40 (64) centered control + engine.setValue("[Playlist]", "SelectPlaylist", diff); }; // Stops a preview that might be playing and loads the selected track regardless @@ -565,7 +525,6 @@ Mixage.handleTrackLoading = function(_channel, _control, value, _status, group) if (value === DOWN) { engine.setValue("[PreviewDeck1]", "stop", true); engine.setValue(group, "LoadSelectedTrack", true); - Mixage.libraryRemainingTime = Mixage.libraryReducedHideTimeout; } }; From afa3990c192ddfb403b844c9a3240a6005a68d7f Mon Sep 17 00:00:00 2001 From: gqzomer Date: Fri, 10 Nov 2023 21:13:36 +0100 Subject: [PATCH 30/32] reworked soft start/brake --- res/controllers/Reloop-Mixage.scripts.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index deead1f6d89..4e1ef550f79 100644 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -21,6 +21,7 @@ Mixage.fxSelectConnection = []; Mixage.traxxPressTimer = 0; Mixage.loopLengthPressTimer = 0; Mixage.dryWetPressTimer = 0; +Mixage.scratchTogglePressTimer = 0; // constants Mixage.numEffectUnits = 4; @@ -633,15 +634,22 @@ Mixage.handleShift = function(_channel, _control, value, _status, group) { Mixage.scratchToggle = function(_channel, _control, value, _status, group) { if (value === DOWN) { Mixage.scratchPressed[group] = true; - Mixage.stopLoopAdjust(group); - Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; - Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); - if (Mixage.scrollToggleState[group]) { - Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; - Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); - } + Mixage.scratchTogglePressTimer = engine.beginTimer(400, function() { + Mixage.scratchTogglePressTimer = 0; + }, true); } else { Mixage.scratchPressed[group] = false; + if (Mixage.scratchTogglePressTimer !== 0) { + engine.stopTimer(Mixage.scratchTogglePressTimer); + Mixage.scratchTogglePressTimer = 0; + Mixage.stopLoopAdjust(group); + Mixage.scratchToggleState[group] = !Mixage.scratchToggleState[group]; + Mixage.toggleLED(Mixage.scratchToggleState[group], group, "scratch_active"); + if (Mixage.scrollToggleState[group]) { + Mixage.scrollToggleState[group] = !Mixage.scrollToggleState[group]; + Mixage.toggleLED(Mixage.scrollToggleState[group], group, "scroll_active"); + } + } } }; From 2a1f0758facfb61ca7e3cd3754c0db2989964882 Mon Sep 17 00:00:00 2001 From: gqzomer Date: Sat, 11 Nov 2023 21:13:47 +0100 Subject: [PATCH 31/32] changed effect toggle --- res/controllers/Reloop-Mixage.midi.xml | 16 ++++----- res/controllers/Reloop-Mixage.scripts.js | 41 +++++++++++++++++++++--- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/res/controllers/Reloop-Mixage.midi.xml b/res/controllers/Reloop-Mixage.midi.xml index 0b7756c03fb..715ac48b7dc 100644 --- a/res/controllers/Reloop-Mixage.midi.xml +++ b/res/controllers/Reloop-Mixage.midi.xml @@ -28,7 +28,7 @@ [Channel1] - beats_translate_earlier + pitch_down 0x90 0x40 @@ -48,7 +48,7 @@ [Channel1] - beats_translate_later + pitch_up 0x90 0x41 @@ -596,7 +596,7 @@ [Channel2] - beats_translate_earlier + pitch_down 0x90 0x4E @@ -616,7 +616,7 @@ [Channel2] - beats_translate_later + pitch_up 0x90 0x4F @@ -1215,14 +1215,14 @@ [Channel1] - beats_translate_earlier + pitch_down 0x90 0x01 0.5 [Channel1] - beats_translate_later + pitch_up 0x90 0x02 0.5 @@ -1243,14 +1243,14 @@ [Channel2] - beats_translate_earlier + pitch_down 0x90 0x0F 0.5 [Channel2] - beats_translate_later + pitch_up 0x90 0x10 0.5 diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 4e1ef550f79..37cdcc34665 100644 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -1,6 +1,6 @@ // Name: Reloop Mixage // Author: HorstBaerbel / gqzomer -// Version: 1.1.1 requires Mixxx 2.4 or higher +// Version: 1.1.2 requires Mixxx 2.4 or higher var Mixage = {}; @@ -16,6 +16,7 @@ Mixage.vuMeterConnection = []; Mixage.loopConnection = []; Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; +Mixage.fxPresetConnection = []; // timers Mixage.traxxPressTimer = 0; @@ -80,6 +81,13 @@ Mixage.adjustLoopOut = { "[Channel2]": false, }; +Mixage.effectSlotState = { + "[EffectRack1_EffectUnit1]": new Array(Mixage.numEffectSlots).fill(1), + "[EffectRack1_EffectUnit2]": new Array(Mixage.numEffectSlots).fill(1), + "[EffectRack1_EffectUnit3]": new Array(Mixage.numEffectSlots).fill(1), + "[EffectRack1_EffectUnit4]": new Array(Mixage.numEffectSlots).fill(1), +}; + Mixage.blinkTimer = { "[Channel1]": {}, "[Channel2]": {}, @@ -181,6 +189,7 @@ Mixage.init = function(_id, _debugging) { Mixage.vuMeterConnection.push(engine.makeConnection(channel, "vu_meter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(channel); })); Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); + // Mixage.fxPresetConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "loaded_chain_preset", function(_v, g) { Mixage.getLoadedPresetEffects(g); })); // get current status and set LEDs accordingly Mixage.toggleFxLED(channel); @@ -195,6 +204,7 @@ Mixage.shutdown = function() { Mixage.loopConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxSelectConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxOnConnection.forEach(function(connection) { connection.disconnect(); }); + Mixage.fxPresetConnection.forEach(function(connection) { connection.disconnect(); }); // Disconnect all controls from functions Mixage.channels.forEach(function(channel) { Mixage.connectControlsToFunctions(channel, true); }); @@ -395,21 +405,42 @@ Mixage.TraxPressCallback = function(_channel, _control, _value, _status, group, Mixage.toggleEffect = function(group) { var unitNr = script.deckFromGroup(group); var effectUnit = "EffectRack1_EffectUnit" + unitNr; - var focusedEffect = engine.getValue("[" + effectUnit +"]", "focused_effect"); + var effectUnitGroup = "["+effectUnit+"]"; + var focusedEffect = engine.getValue(effectUnitGroup, "focused_effect"); var enabledFxSlots = []; if (focusedEffect === 0) { for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { enabledFxSlots.push(engine.getValue("[" + effectUnit + "_Effect" + effectSlot + "]", "enabled")); } - for (effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { - engine.setValue("[" + effectUnit + "_Effect" + effectSlot + "]", "enabled", !(enabledFxSlots.indexOf(1) !== -1)); + + if (enabledFxSlots.indexOf(1) === -1) { + Mixage.effectSlotState[effectUnitGroup].map(function(state, effect) { + engine.setValue("[" + effectUnit + "_Effect" + (effect +1) + "]", "enabled", state); + }); + } else { + Mixage.effectSlotState[effectUnitGroup] = enabledFxSlots; + for (effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { + engine.setValue("[" + effectUnit + "_Effect" + effectSlot + "]", "enabled", 0); + } } } else { - script.toggleControl("[EffectRack1_EffectUnit" + unitNr + "_Effect" + focusedEffect + "]", "enabled"); + script.toggleControl("[" + effectUnitGroup + "_Effect" + focusedEffect + "]", "enabled"); } }; +Mixage.getLoadedPresetEffects = function(effectUnit) { + var loadedFxSlots = []; + + for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { + var effectSlotString = effectUnit.slice(0, -1) + "_Effect" + effectSlot + "]"; + loadedFxSlots.push(engine.getValue(effectSlotString, "loaded")); + engine.setValue(effectSlotString, "enabled", 0); + } + + Mixage.effectSlotState[effectUnit] = loadedFxSlots; +}; + // ----- functions mapped to buttons ----- // selects the loop in point in loop adjustment mode, otherwise trigger "beatloop_activate" From 55a5f295609ba00923c7a25a42770ac685600f2c Mon Sep 17 00:00:00 2001 From: gqzomer Date: Sun, 12 Nov 2023 17:00:17 +0100 Subject: [PATCH 32/32] finalized effect toggle implementation --- res/controllers/Reloop-Mixage.scripts.js | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/res/controllers/Reloop-Mixage.scripts.js b/res/controllers/Reloop-Mixage.scripts.js index 37cdcc34665..95a10271606 100644 --- a/res/controllers/Reloop-Mixage.scripts.js +++ b/res/controllers/Reloop-Mixage.scripts.js @@ -16,7 +16,6 @@ Mixage.vuMeterConnection = []; Mixage.loopConnection = []; Mixage.fxOnConnection = []; Mixage.fxSelectConnection = []; -Mixage.fxPresetConnection = []; // timers Mixage.traxxPressTimer = 0; @@ -84,8 +83,6 @@ Mixage.adjustLoopOut = { Mixage.effectSlotState = { "[EffectRack1_EffectUnit1]": new Array(Mixage.numEffectSlots).fill(1), "[EffectRack1_EffectUnit2]": new Array(Mixage.numEffectSlots).fill(1), - "[EffectRack1_EffectUnit3]": new Array(Mixage.numEffectSlots).fill(1), - "[EffectRack1_EffectUnit4]": new Array(Mixage.numEffectSlots).fill(1), }; Mixage.blinkTimer = { @@ -189,7 +186,6 @@ Mixage.init = function(_id, _debugging) { Mixage.vuMeterConnection.push(engine.makeConnection(channel, "vu_meter", function(val) { midi.sendShortMsg(0x90, Mixage.ledMap[channel].vu_meter, val * 7); })); Mixage.loopConnection.push(engine.makeConnection(channel, "track_loaded", function() { Mixage.toggleReloopLED(channel); })); Mixage.fxSelectConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "focused_effect", function(value) { Mixage.handleFxSelect(value, channel); })); - // Mixage.fxPresetConnection.push(engine.makeConnection("[EffectRack1_EffectUnit"+deck+"]", "loaded_chain_preset", function(_v, g) { Mixage.getLoadedPresetEffects(g); })); // get current status and set LEDs accordingly Mixage.toggleFxLED(channel); @@ -204,7 +200,6 @@ Mixage.shutdown = function() { Mixage.loopConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxSelectConnection.forEach(function(connection) { connection.disconnect(); }); Mixage.fxOnConnection.forEach(function(connection) { connection.disconnect(); }); - Mixage.fxPresetConnection.forEach(function(connection) { connection.disconnect(); }); // Disconnect all controls from functions Mixage.channels.forEach(function(channel) { Mixage.connectControlsToFunctions(channel, true); }); @@ -425,22 +420,10 @@ Mixage.toggleEffect = function(group) { } } } else { - script.toggleControl("[" + effectUnitGroup + "_Effect" + focusedEffect + "]", "enabled"); + script.toggleControl("[" + effectUnit + "_Effect" + focusedEffect + "]", "enabled"); } }; -Mixage.getLoadedPresetEffects = function(effectUnit) { - var loadedFxSlots = []; - - for (var effectSlot = 1; effectSlot <= Mixage.numEffectSlots; effectSlot++) { - var effectSlotString = effectUnit.slice(0, -1) + "_Effect" + effectSlot + "]"; - loadedFxSlots.push(engine.getValue(effectSlotString, "loaded")); - engine.setValue(effectSlotString, "enabled", 0); - } - - Mixage.effectSlotState[effectUnit] = loadedFxSlots; -}; - // ----- functions mapped to buttons ----- // selects the loop in point in loop adjustment mode, otherwise trigger "beatloop_activate"