From 8845fc0b70aec9246f603faa20b81ba6cbbca5a1 Mon Sep 17 00:00:00 2001 From: Swiftb0y <12380386+Swiftb0y@users.noreply.github.com> Date: Thu, 17 Nov 2022 23:20:34 +0100 Subject: [PATCH] feat(controllers): add new controller mapping for Numark NS6II --- res/controllers/Numark NS6II.midi.xml | 4952 +++++++++++++++++++++++ res/controllers/Numark-NS6II-scripts.js | 1379 +++++++ 2 files changed, 6331 insertions(+) create mode 100755 res/controllers/Numark NS6II.midi.xml create mode 100755 res/controllers/Numark-NS6II-scripts.js diff --git a/res/controllers/Numark NS6II.midi.xml b/res/controllers/Numark NS6II.midi.xml new file mode 100755 index 000000000000..91b83e906131 --- /dev/null +++ b/res/controllers/Numark NS6II.midi.xml @@ -0,0 +1,4952 @@ + + + + Numark NS6II + Swiftb0y + Mapping for the Numark NS6II controller. It is able to fully communicate with the integrated screens. You can manipulate the Beatgrid of the track via the slicer pad page (since mixxx doesn't have slicer capabilities) + Encoded URL to Mixxx wiki page documenting this controller mapping + + + + + + + + + + + [Channel1] + NS6II.decks[0].play.input + 0x80 + 0x00 + + + + + + [Channel2] + NS6II.decks[1].play.input + 0x81 + 0x00 + + + + + + [Channel3] + NS6II.decks[2].play.input + 0x82 + 0x00 + + + + + + [Channel4] + NS6II.decks[3].play.input + 0x83 + 0x00 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.cues.input + 0x84 + 0x00 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.cues.input + 0x85 + 0x00 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.cues.input + 0x86 + 0x00 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.cues.input + 0x87 + 0x00 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[1].input + 0x88 + 0x00 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[1].input + 0x89 + 0x00 + + + + + + [Channel1] + NS6II.decks[0].play.input + 0x90 + 0x00 + + + + + + [Channel2] + NS6II.decks[1].play.input + 0x91 + 0x00 + + + + + + [Channel3] + NS6II.decks[2].play.input + 0x92 + 0x00 + + + + + + [Channel4] + NS6II.decks[3].play.input + 0x93 + 0x00 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.cues.input + 0x94 + 0x00 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.cues.input + 0x95 + 0x00 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.cues.input + 0x96 + 0x00 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.cues.input + 0x97 + 0x00 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[1].input + 0x98 + 0x00 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[1].input + 0x99 + 0x00 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].knobs[1].input + 0xB8 + 0x00 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].knobs[1].input + 0xB9 + 0x00 + + + + + + [NS6II] + NS6II.mixer.browseSection.libraryNavigation.turn.input + 0xBF + 0x00 + + + + + + [Channel1] + NS6II.decks[0].cue.input + 0x80 + 0x01 + + + + + + [Channel2] + NS6II.decks[1].cue.input + 0x81 + 0x01 + + + + + + [Channel3] + NS6II.decks[2].cue.input + 0x82 + 0x01 + + + + + + [Channel4] + NS6II.decks[3].cue.input + 0x83 + 0x01 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[2].input + 0x88 + 0x01 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[2].input + 0x89 + 0x01 + + + + + + [Channel1] + NS6II.decks[0].cue.input + 0x90 + 0x01 + + + + + + [Channel2] + NS6II.decks[1].cue.input + 0x91 + 0x01 + + + + + + [Channel3] + NS6II.decks[2].cue.input + 0x92 + 0x01 + + + + + + [Channel4] + NS6II.decks[3].cue.input + 0x93 + 0x01 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[2].input + 0x98 + 0x01 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[2].input + 0x99 + 0x01 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].knobs[2].input + 0xB8 + 0x01 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].knobs[2].input + 0xB9 + 0x01 + + + + + + [NS6II] + NS6II.mixer.browseSection.libraryNavigation.turn.input + 0xBF + 0x01 + + + + + + [Channel1] + NS6II.decks[0].sync.input + 0x80 + 0x02 + + + + + + [Channel2] + NS6II.decks[1].sync.input + 0x81 + 0x02 + + + + + + [Channel3] + NS6II.decks[2].sync.input + 0x82 + 0x02 + + + + + + [Channel4] + NS6II.decks[3].sync.input + 0x83 + 0x02 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.cues.input + 0x84 + 0x02 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.cues.input + 0x85 + 0x02 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.cues.input + 0x86 + 0x02 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.cues.input + 0x87 + 0x02 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[3].input + 0x88 + 0x02 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[3].input + 0x89 + 0x02 + + + + + + [NS6II] + NS6II.mixer.channels[0].loadTrackIntoDeck.input + 0x8F + 0x02 + + + + + + [Channel1] + NS6II.decks[0].sync.input + 0x90 + 0x02 + + + + + + [Channel2] + NS6II.decks[1].sync.input + 0x91 + 0x02 + + + + + + [Channel3] + NS6II.decks[2].sync.input + 0x92 + 0x02 + + + + + + [Channel4] + NS6II.decks[3].sync.input + 0x93 + 0x02 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.cues.input + 0x94 + 0x02 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.cues.input + 0x95 + 0x02 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.cues.input + 0x96 + 0x02 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.cues.input + 0x97 + 0x02 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[3].input + 0x98 + 0x02 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[3].input + 0x99 + 0x02 + + + + + + [NS6II] + NS6II.mixer.channels[0].loadTrackIntoDeck.input + 0x9F + 0x02 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].knobs[3].input + 0xB8 + 0x02 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].knobs[3].input + 0xB9 + 0x02 + + + + + + [Channel1] + NS6II.decks[0].sync.input + 0x80 + 0x03 + + + + + + [Channel2] + NS6II.decks[1].sync.input + 0x81 + 0x03 + + + + + + [Channel3] + NS6II.decks[2].sync.input + 0x82 + 0x03 + + + + + + [Channel4] + NS6II.decks[3].sync.input + 0x83 + 0x03 + + + + + + [NS6II] + NS6II.mixer.channels[1].loadTrackIntoDeck.input + 0x8F + 0x03 + + + + + + [Channel1] + NS6II.decks[0].sync.input + 0x90 + 0x03 + + + + + + [Channel2] + NS6II.decks[1].sync.input + 0x91 + 0x03 + + + + + + [Channel3] + NS6II.decks[2].sync.input + 0x92 + 0x03 + + + + + + [Channel4] + NS6II.decks[3].sync.input + 0x93 + 0x03 + + + + + + [NS6II] + NS6II.mixer.channels[1].loadTrackIntoDeck.input + 0x9F + 0x03 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].dryWetKnob.input + 0xB8 + 0x03 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].dryWetKnob.input + 0xB9 + 0x03 + + + + + + [Channel1] + NS6II.decks[0].play.input + 0x80 + 0x04 + + + + + + [Channel2] + NS6II.decks[1].play.input + 0x81 + 0x04 + + + + + + [Channel3] + NS6II.decks[2].play.input + 0x82 + 0x04 + + + + + + [Channel4] + NS6II.decks[3].play.input + 0x83 + 0x04 + + + + + + [Channel1] + NS6II.decks[0].slip.input + 0x84 + 0x04 + + + + + + [Channel2] + NS6II.decks[1].slip.input + 0x85 + 0x04 + + + + + + [Channel3] + NS6II.decks[2].slip.input + 0x86 + 0x04 + + + + + + [Channel4] + NS6II.decks[3].slip.input + 0x87 + 0x04 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].effectFocusButton.input + 0x88 + 0x04 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].effectFocusButton.input + 0x89 + 0x04 + + + + + + [NS6II] + NS6II.mixer.channels[2].loadTrackIntoDeck.input + 0x8F + 0x04 + + + + + + [Channel1] + NS6II.decks[0].play.input + 0x90 + 0x04 + + + + + + [Channel2] + NS6II.decks[1].play.input + 0x91 + 0x04 + + + + + + [Channel3] + NS6II.decks[2].play.input + 0x92 + 0x04 + + + + + + [Channel4] + NS6II.decks[3].play.input + 0x93 + 0x04 + + + + + + [Channel1] + NS6II.decks[0].slip.input + 0x94 + 0x04 + + + + + + [Channel2] + NS6II.decks[1].slip.input + 0x95 + 0x04 + + + + + + [Channel3] + NS6II.decks[2].slip.input + 0x96 + 0x04 + + + + + + [Channel4] + NS6II.decks[3].slip.input + 0x97 + 0x04 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].effectFocusButton.input + 0x98 + 0x04 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].effectFocusButton.input + 0x99 + 0x04 + + + + + + [NS6II] + NS6II.mixer.channels[2].loadTrackIntoDeck.input + 0x9F + 0x04 + + + + + + [Channel1] + NS6II.decks[0].cue.input + 0x80 + 0x05 + + + + + + [Channel2] + NS6II.decks[1].cue.input + 0x81 + 0x05 + + + + + + [Channel3] + NS6II.decks[2].cue.input + 0x82 + 0x05 + + + + + + [Channel4] + NS6II.decks[3].cue.input + 0x83 + 0x05 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel1.input + 0x88 + 0x05 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel1.input + 0x89 + 0x05 + + + + + + [NS6II] + NS6II.mixer.channels[3].loadTrackIntoDeck.input + 0x8F + 0x05 + + + + + + [Channel1] + NS6II.decks[0].cue.input + 0x90 + 0x05 + + + + + + [Channel2] + NS6II.decks[1].cue.input + 0x91 + 0x05 + + + + + + [Channel3] + NS6II.decks[2].cue.input + 0x92 + 0x05 + + + + + + [Channel4] + NS6II.decks[3].cue.input + 0x93 + 0x05 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel1.input + 0x98 + 0x05 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel1.input + 0x99 + 0x05 + + + + + + [NS6II] + NS6II.mixer.channels[3].loadTrackIntoDeck.input + 0x9F + 0x05 + + + + + + [Channel1] + NS6II.decks[0].jog.inputTouch + 0x80 + 0x06 + + + + + + [Channel2] + NS6II.decks[1].jog.inputTouch + 0x81 + 0x06 + + + + + + [Channel3] + NS6II.decks[2].jog.inputTouch + 0x82 + 0x06 + + + + + + [Channel4] + NS6II.decks[3].jog.inputTouch + 0x83 + 0x06 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel2.input + 0x88 + 0x06 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel2.input + 0x89 + 0x06 + + + + + + [NS6II] + NS6II.mixer.browseSection.libraryNavigation.press.input + 0x8F + 0x06 + + + + + + [Channel1] + NS6II.decks[0].jog.inputTouch + 0x90 + 0x06 + + + + + + [Channel2] + NS6II.decks[1].jog.inputTouch + 0x91 + 0x06 + + + + + + [Channel3] + NS6II.decks[2].jog.inputTouch + 0x92 + 0x06 + + + + + + [Channel4] + NS6II.decks[3].jog.inputTouch + 0x93 + 0x06 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel2.input + 0x98 + 0x06 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel2.input + 0x99 + 0x06 + + + + + + [NS6II] + NS6II.mixer.browseSection.libraryNavigation.press.input + 0x9F + 0x06 + + + + + + [Channel1] + NS6II.decks[0].jog.inputWheel + 0xB0 + 0x06 + + + + + + [Channel2] + NS6II.decks[1].jog.inputWheel + 0xB1 + 0x06 + + + + + + [Channel3] + NS6II.decks[2].jog.inputWheel + 0xB2 + 0x06 + + + + + + [Channel4] + NS6II.decks[3].jog.inputWheel + 0xB3 + 0x06 + + + + + + [Channel1] + NS6II.decks[0].scratch.input + 0x80 + 0x07 + + + + + + [Channel2] + NS6II.decks[1].scratch.input + 0x81 + 0x07 + + + + + + [Channel3] + NS6II.decks[2].scratch.input + 0x82 + 0x07 + + + + + + [Channel4] + NS6II.decks[3].scratch.input + 0x83 + 0x07 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel3.input + 0x88 + 0x07 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel3.input + 0x89 + 0x07 + + + + + + [Channel1] + NS6II.decks[0].scratch.input + 0x90 + 0x07 + + + + + + [Channel2] + NS6II.decks[1].scratch.input + 0x91 + 0x07 + + + + + + [Channel3] + NS6II.decks[2].scratch.input + 0x92 + 0x07 + + + + + + [Channel4] + NS6II.decks[3].scratch.input + 0x93 + 0x07 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel3.input + 0x98 + 0x07 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel3.input + 0x99 + 0x07 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel4.input + 0x88 + 0x08 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel4.input + 0x89 + 0x08 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableOnChannelButtons.Channel4.input + 0x98 + 0x08 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableOnChannelButtons.Channel4.input + 0x99 + 0x08 + + + + + + [Master] + NS6II.mixer.crossfader.input + 0xBF + 0x08 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.slider.input + 0x84 + 0x09 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.slider.input + 0x85 + 0x09 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.slider.input + 0x86 + 0x09 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.slider.input + 0x87 + 0x09 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.slider.input + 0x94 + 0x09 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.slider.input + 0x95 + 0x09 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.slider.input + 0x96 + 0x09 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.slider.input + 0x97 + 0x09 + + + + + + [Channel1] + NS6II.decks[0].pitch.inputMSB + 0xB0 + 0x09 + + + + + + [Channel2] + NS6II.decks[1].pitch.inputMSB + 0xB1 + 0x09 + + + + + + [Channel3] + NS6II.decks[2].pitch.inputMSB + 0xB2 + 0x09 + + + + + + [Channel4] + NS6II.decks[3].pitch.inputMSB + 0xB3 + 0x09 + + + + + + [Mixer Profile] + NS6II.mixer.crossfaderContour.input + 0xBF + 0x09 + + + + + + [Channel1] + NS6II.decks[0].pitchBendPlus.input + 0x80 + 0x0B + + + + + + [Channel2] + NS6II.decks[1].pitchBendPlus.input + 0x81 + 0x0B + + + + + + [Channel3] + NS6II.decks[2].pitchBendPlus.input + 0x82 + 0x0B + + + + + + [Channel4] + NS6II.decks[3].pitchBendPlus.input + 0x83 + 0x0B + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.sampler.input + 0x84 + 0x0B + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.sampler.input + 0x85 + 0x0B + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.sampler.input + 0x86 + 0x0B + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.sampler.input + 0x87 + 0x0B + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[1].input + 0x88 + 0x0B + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[1].input + 0x89 + 0x0B + + + + + + [Channel1] + NS6II.decks[0].pitchBendPlus.input + 0x90 + 0x0B + + + + + + [Channel2] + NS6II.decks[1].pitchBendPlus.input + 0x91 + 0x0B + + + + + + [Channel3] + NS6II.decks[2].pitchBendPlus.input + 0x92 + 0x0B + + + + + + [Channel4] + NS6II.decks[3].pitchBendPlus.input + 0x93 + 0x0B + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.sampler.input + 0x94 + 0x0B + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.sampler.input + 0x95 + 0x0B + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.sampler.input + 0x96 + 0x0B + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.sampler.input + 0x97 + 0x0B + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[1].input + 0x98 + 0x0B + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[1].input + 0x99 + 0x0B + + + + + + [Channel1] + NS6II.decks[0].pitchBendMinus.input + 0x80 + 0x0C + + + + + + [Channel2] + NS6II.decks[1].pitchBendMinus.input + 0x81 + 0x0C + + + + + + [Channel3] + NS6II.decks[2].pitchBendMinus.input + 0x82 + 0x0C + + + + + + [Channel4] + NS6II.decks[3].pitchBendMinus.input + 0x83 + 0x0C + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[2].input + 0x88 + 0x0C + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[2].input + 0x89 + 0x0C + + + + + + [Channel1] + NS6II.decks[0].pitchBendMinus.input + 0x90 + 0x0C + + + + + + [Channel2] + NS6II.decks[1].pitchBendMinus.input + 0x91 + 0x0C + + + + + + [Channel3] + NS6II.decks[2].pitchBendMinus.input + 0x92 + 0x0C + + + + + + [Channel4] + NS6II.decks[3].pitchBendMinus.input + 0x93 + 0x0C + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[2].input + 0x98 + 0x0C + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[2].input + 0x99 + 0x0C + + + + + + [Channel1] + NS6II.decks[0].bleep.input + 0x80 + 0x0D + + + + + + [Channel2] + NS6II.decks[1].bleep.input + 0x81 + 0x0D + + + + + + [Channel3] + NS6II.decks[2].bleep.input + 0x82 + 0x0D + + + + + + [Channel4] + NS6II.decks[3].bleep.input + 0x83 + 0x0D + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[3].input + 0x88 + 0x0D + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[3].input + 0x89 + 0x0D + + + + + + [Channel1] + NS6II.decks[0].bleep.input + 0x90 + 0x0D + + + + + + [Channel2] + NS6II.decks[1].bleep.input + 0x91 + 0x0D + + + + + + [Channel3] + NS6II.decks[2].bleep.input + 0x92 + 0x0D + + + + + + [Channel4] + NS6II.decks[3].bleep.input + 0x93 + 0x0D + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].enableButtons[3].input + 0x98 + 0x0D + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].enableButtons[3].input + 0x99 + 0x0D + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.loop.input + 0x84 + 0x0E + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.loop.input + 0x85 + 0x0E + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.loop.input + 0x86 + 0x0E + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.loop.input + 0x87 + 0x0E + + + + + + [NS6II] + NS6II.mixer.browseSection.view.input + 0x8F + 0x0E + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.loop.input + 0x94 + 0x0E + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.loop.input + 0x95 + 0x0E + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.loop.input + 0x96 + 0x0E + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.loop.input + 0x97 + 0x0E + + + + + + [NS6II] + NS6II.mixer.browseSection.view.input + 0x9F + 0x0E + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.sampler.input + 0x84 + 0x0F + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.sampler.input + 0x85 + 0x0F + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.sampler.input + 0x86 + 0x0F + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.sampler.input + 0x87 + 0x0F + + + + + + [NS6II] + NS6II.mixer.browseSection.area.input + 0x8F + 0x0F + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.sampler.input + 0x94 + 0x0F + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.sampler.input + 0x95 + 0x0F + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.sampler.input + 0x96 + 0x0F + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.sampler.input + 0x97 + 0x0F + + + + + + [NS6II] + NS6II.mixer.browseSection.area.input + 0x9F + 0x0F + + + + + + [Channel1] + NS6II.decks[0].bleep.input + 0x80 + 0x10 + + + + + + [Channel2] + NS6II.decks[1].bleep.input + 0x81 + 0x10 + + + + + + [Channel3] + NS6II.decks[2].bleep.input + 0x82 + 0x10 + + + + + + [Channel4] + NS6II.decks[3].bleep.input + 0x83 + 0x10 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.auto.input + 0x84 + 0x10 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.auto.input + 0x85 + 0x10 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.auto.input + 0x86 + 0x10 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.auto.input + 0x87 + 0x10 + + + + + + [Channel1] + NS6II.decks[0].bleep.input + 0x90 + 0x10 + + + + + + [Channel2] + NS6II.decks[1].bleep.input + 0x91 + 0x10 + + + + + + [Channel3] + NS6II.decks[2].bleep.input + 0x92 + 0x10 + + + + + + [Channel4] + NS6II.decks[3].bleep.input + 0x93 + 0x10 + + + + + + [Channel1] + NS6II.decks[0].padUnit.modeSelectors.auto.input + 0x94 + 0x10 + + + + + + [Channel2] + NS6II.decks[1].padUnit.modeSelectors.auto.input + 0x95 + 0x10 + + + + + + [Channel3] + NS6II.decks[2].padUnit.modeSelectors.auto.input + 0x96 + 0x10 + + + + + + [Channel4] + NS6II.decks[3].padUnit.modeSelectors.auto.input + 0x97 + 0x10 + + + + + + [NS6II] + NS6II.mixer.browseSection.back.input + 0x8F + 0x11 + + + + + + [NS6II] + NS6II.mixer.browseSection.back.input + 0x9F + 0x11 + + + + + + [NS6II] + NS6II.mixer.browseSection.back.input + 0x8F + 0x12 + + + + + + [NS6II] + NS6II.mixer.browseSection.back.input + 0x9F + 0x12 + + + + + + [NS6II] + NS6II.mixer.browseSection.view.input + 0x8F + 0x13 + + + + + + [NS6II] + NS6II.mixer.browseSection.view.input + 0x9F + 0x13 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[0].input + 0x84 + 0x14 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[0].input + 0x85 + 0x14 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[0].input + 0x86 + 0x14 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[0].input + 0x87 + 0x14 + + + + + + [NS6II] + NS6II.mixer.browseSection.lprep.input + 0x8F + 0x14 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[0].input + 0x94 + 0x14 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[0].input + 0x95 + 0x14 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[0].input + 0x96 + 0x14 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[0].input + 0x97 + 0x14 + + + + + + [NS6II] + NS6II.mixer.browseSection.lprep.input + 0x9F + 0x14 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[1].input + 0x84 + 0x15 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[1].input + 0x85 + 0x15 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[1].input + 0x86 + 0x15 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[1].input + 0x87 + 0x15 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[1].input + 0x94 + 0x15 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[1].input + 0x95 + 0x15 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[1].input + 0x96 + 0x15 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[1].input + 0x97 + 0x15 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[2].input + 0x84 + 0x16 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[2].input + 0x85 + 0x16 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[2].input + 0x86 + 0x16 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[2].input + 0x87 + 0x16 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[2].input + 0x94 + 0x16 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[2].input + 0x95 + 0x16 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[2].input + 0x96 + 0x16 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[2].input + 0x97 + 0x16 + + + + + + [Channel1] + NS6II.mixer.channels[0].preGain.input + 0xB0 + 0x16 + + + + + + [Channel2] + NS6II.mixer.channels[1].preGain.input + 0xB1 + 0x16 + + + + + + [Channel3] + NS6II.mixer.channels[2].preGain.input + 0xB2 + 0x16 + + + + + + [Channel4] + NS6II.mixer.channels[3].preGain.input + 0xB3 + 0x16 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[0].input + 0x80 + 0x17 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[0].input + 0x81 + 0x17 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[0].input + 0x82 + 0x17 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[0].input + 0x83 + 0x17 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[3].input + 0x84 + 0x17 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[3].input + 0x85 + 0x17 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[3].input + 0x86 + 0x17 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[3].input + 0x87 + 0x17 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[0].input + 0x90 + 0x17 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[0].input + 0x91 + 0x17 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[0].input + 0x92 + 0x17 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[0].input + 0x93 + 0x17 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[3].input + 0x94 + 0x17 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[3].input + 0x95 + 0x17 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[3].input + 0x96 + 0x17 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[3].input + 0x97 + 0x17 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqKnobs[0].input + 0xB0 + 0x17 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqKnobs[0].input + 0xB1 + 0x17 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqKnobs[0].input + 0xB2 + 0x17 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqKnobs[0].input + 0xB3 + 0x17 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[1].input + 0x80 + 0x18 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[1].input + 0x81 + 0x18 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[1].input + 0x82 + 0x18 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[1].input + 0x83 + 0x18 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[4].input + 0x84 + 0x18 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[4].input + 0x85 + 0x18 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[4].input + 0x86 + 0x18 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[4].input + 0x87 + 0x18 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[1].input + 0x90 + 0x18 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[1].input + 0x91 + 0x18 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[1].input + 0x92 + 0x18 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[1].input + 0x93 + 0x18 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[4].input + 0x94 + 0x18 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[4].input + 0x95 + 0x18 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[4].input + 0x96 + 0x18 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[4].input + 0x97 + 0x18 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqKnobs[1].input + 0xB0 + 0x18 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqKnobs[1].input + 0xB1 + 0x18 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqKnobs[1].input + 0xB2 + 0x18 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqKnobs[1].input + 0xB3 + 0x18 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[2].input + 0x80 + 0x19 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[2].input + 0x81 + 0x19 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[2].input + 0x82 + 0x19 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[2].input + 0x83 + 0x19 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[5].input + 0x84 + 0x19 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[5].input + 0x85 + 0x19 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[5].input + 0x86 + 0x19 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[5].input + 0x87 + 0x19 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqCaps[2].input + 0x90 + 0x19 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqCaps[2].input + 0x91 + 0x19 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqCaps[2].input + 0x92 + 0x19 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqCaps[2].input + 0x93 + 0x19 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[5].input + 0x94 + 0x19 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[5].input + 0x95 + 0x19 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[5].input + 0x96 + 0x19 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[5].input + 0x97 + 0x19 + + + + + + [Channel1] + NS6II.mixer.channels[0].eqKnobs[2].input + 0xB0 + 0x19 + + + + + + [Channel2] + NS6II.mixer.channels[1].eqKnobs[2].input + 0xB1 + 0x19 + + + + + + [Channel3] + NS6II.mixer.channels[2].eqKnobs[2].input + 0xB2 + 0x19 + + + + + + [Channel4] + NS6II.mixer.channels[3].eqKnobs[2].input + 0xB3 + 0x19 + + + + + + [Channel1] + NS6II.mixer.channels[0].filterCap.input + 0x80 + 0x1A + + + + + + [Channel2] + NS6II.mixer.channels[1].filterCap.input + 0x81 + 0x1A + + + + + + [Channel3] + NS6II.mixer.channels[2].filterCap.input + 0x82 + 0x1A + + + + + + [Channel4] + NS6II.mixer.channels[3].filterCap.input + 0x83 + 0x1A + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[6].input + 0x84 + 0x1A + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[6].input + 0x85 + 0x1A + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[6].input + 0x86 + 0x1A + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[6].input + 0x87 + 0x1A + + + + + + [Channel1] + NS6II.mixer.channels[0].filterCap.input + 0x90 + 0x1A + + + + + + [Channel2] + NS6II.mixer.channels[1].filterCap.input + 0x91 + 0x1A + + + + + + [Channel3] + NS6II.mixer.channels[2].filterCap.input + 0x92 + 0x1A + + + + + + [Channel4] + NS6II.mixer.channels[3].filterCap.input + 0x93 + 0x1A + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[6].input + 0x94 + 0x1A + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[6].input + 0x95 + 0x1A + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[6].input + 0x96 + 0x1A + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[6].input + 0x97 + 0x1A + + + + + + [Channel1] + NS6II.mixer.channels[0].filter.input + 0xB0 + 0x1A + + + + + + [Channel2] + NS6II.mixer.channels[1].filter.input + 0xB1 + 0x1A + + + + + + [Channel3] + NS6II.mixer.channels[2].filter.input + 0xB2 + 0x1A + + + + + + [Channel4] + NS6II.mixer.channels[3].filter.input + 0xB3 + 0x1A + + + + + + [Channel1] + NS6II.mixer.channels[0].pfl.input + 0x80 + 0x1B + + + + + + [Channel2] + NS6II.mixer.channels[1].pfl.input + 0x81 + 0x1B + + + + + + [Channel3] + NS6II.mixer.channels[2].pfl.input + 0x82 + 0x1B + + + + + + [Channel4] + NS6II.mixer.channels[3].pfl.input + 0x83 + 0x1B + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[7].input + 0x84 + 0x1B + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[7].input + 0x85 + 0x1B + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[7].input + 0x86 + 0x1B + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[7].input + 0x87 + 0x1B + + + + + + [NS6II] + NS6II.mixer.browseSection.lprep.input + 0x8F + 0x1B + + + + + + [Channel1] + NS6II.mixer.channels[0].pfl.input + 0x90 + 0x1B + + + + + + [Channel2] + NS6II.mixer.channels[1].pfl.input + 0x91 + 0x1B + + + + + + [Channel3] + NS6II.mixer.channels[2].pfl.input + 0x92 + 0x1B + + + + + + [Channel4] + NS6II.mixer.channels[3].pfl.input + 0x93 + 0x1B + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[7].input + 0x94 + 0x1B + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[7].input + 0x95 + 0x1B + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[7].input + 0x96 + 0x1B + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[7].input + 0x97 + 0x1B + + + + + + [NS6II] + NS6II.mixer.browseSection.lprep.input + 0x9F + 0x1B + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[0].input + 0x84 + 0x1C + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[0].input + 0x85 + 0x1C + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[0].input + 0x86 + 0x1C + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[0].input + 0x87 + 0x1C + + + + + + [Master] + NS6II.mixer.splitCue.input + 0x8F + 0x1C + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[0].input + 0x94 + 0x1C + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[0].input + 0x95 + 0x1C + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[0].input + 0x96 + 0x1C + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[0].input + 0x97 + 0x1C + + + + + + [Master] + NS6II.mixer.splitCue.input + 0x9F + 0x1C + + + + + + [Channel1] + NS6II.mixer.channels[0].volume.input + 0xB0 + 0x1C + + + + + + [Channel2] + NS6II.mixer.channels[1].volume.input + 0xB1 + 0x1C + + + + + + [Channel1] + NS6II.mixer.channels[2].volume.input + 0xB2 + 0x1C + + + + + + [Channel4] + NS6II.mixer.channels[3].volume.input + 0xB3 + 0x1C + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[1].input + 0x84 + 0x1D + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[1].input + 0x85 + 0x1D + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[1].input + 0x86 + 0x1D + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[1].input + 0x87 + 0x1D + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[1].input + 0x94 + 0x1D + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[1].input + 0x95 + 0x1D + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[1].input + 0x96 + 0x1D + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[1].input + 0x97 + 0x1D + + + + + + [Channel1] + NS6II.mixer.channels[0].crossfaderOrientation.input + 0x80 + 0x1E + + + + + + [Channel2] + NS6II.mixer.channels[1].crossfaderOrientation.input + 0x81 + 0x1E + + + + + + [Channel3] + NS6II.mixer.channels[2].crossfaderOrientation.input + 0x82 + 0x1E + + + + + + [Channel4] + NS6II.mixer.channels[3].crossfaderOrientation.input + 0x83 + 0x1E + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[2].input + 0x84 + 0x1E + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[2].input + 0x85 + 0x1E + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[2].input + 0x86 + 0x1E + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[2].input + 0x87 + 0x1E + + + + + + [NS6II] + NS6II.mixer.browseSection.area.input + 0x8F + 0x1E + + + + + + [Channel1] + NS6II.mixer.channels[0].crossfaderOrientation.input + 0x90 + 0x1E + + + + + + [Channel2] + NS6II.mixer.channels[1].crossfaderOrientation.input + 0x91 + 0x1E + + + + + + [Channel3] + NS6II.mixer.channels[2].crossfaderOrientation.input + 0x92 + 0x1E + + + + + + [Channel4] + NS6II.mixer.channels[3].crossfaderOrientation.input + 0x93 + 0x1E + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[2].input + 0x94 + 0x1E + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[2].input + 0x95 + 0x1E + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[2].input + 0x96 + 0x1E + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[2].input + 0x97 + 0x1E + + + + + + [NS6II] + NS6II.mixer.browseSection.area.input + 0x9F + 0x1E + + + + + + [Channel1] + NS6II.decks[0].slip.input + 0x80 + 0x1F + + + + + + [Channel2] + NS6II.decks[1].slip.input + 0x81 + 0x1F + + + + + + [Channel3] + NS6II.decks[2].slip.input + 0x82 + 0x1F + + + + + + [Channel4] + NS6II.decks[3].slip.input + 0x83 + 0x1F + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[3].input + 0x84 + 0x1F + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[3].input + 0x85 + 0x1F + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[3].input + 0x86 + 0x1F + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[3].input + 0x87 + 0x1F + + + + + + [Channel1] + NS6II.decks[0].slip.input + 0x90 + 0x1F + + + + + + [Channel2] + NS6II.decks[1].slip.input + 0x91 + 0x1F + + + + + + [Channel3] + NS6II.decks[2].slip.input + 0x92 + 0x1F + + + + + + [Channel4] + NS6II.decks[3].slip.input + 0x93 + 0x1F + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[3].input + 0x94 + 0x1F + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[3].input + 0x95 + 0x1F + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[3].input + 0x96 + 0x1F + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[3].input + 0x97 + 0x1F + + + + + + [Channel1] + NS6II.decks[0].shiftButton.input + 0x80 + 0x20 + + + + + + [Channel2] + NS6II.decks[1].shiftButton.input + 0x81 + 0x20 + + + + + + [Channel3] + NS6II.decks[2].shiftButton.input + 0x82 + 0x20 + + + + + + [Channel4] + NS6II.decks[3].shiftButton.input + 0x83 + 0x20 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[4].input + 0x84 + 0x20 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[4].input + 0x85 + 0x20 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[4].input + 0x86 + 0x20 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[4].input + 0x87 + 0x20 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[1].input + 0x88 + 0x20 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[1].input + 0x89 + 0x20 + + + + + + [Channel1] + NS6II.decks[0].shiftButton.input + 0x90 + 0x20 + + + + + + [Channel2] + NS6II.decks[1].shiftButton.input + 0x91 + 0x20 + + + + + + [Channel3] + NS6II.decks[2].shiftButton.input + 0x92 + 0x20 + + + + + + [Channel4] + NS6II.decks[3].shiftButton.input + 0x93 + 0x20 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[4].input + 0x94 + 0x20 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[4].input + 0x95 + 0x20 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[4].input + 0x96 + 0x20 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[4].input + 0x97 + 0x20 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[1].input + 0x98 + 0x20 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[1].input + 0x99 + 0x20 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[5].input + 0x84 + 0x21 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[5].input + 0x85 + 0x21 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[5].input + 0x86 + 0x21 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[5].input + 0x87 + 0x21 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[2].input + 0x88 + 0x21 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[2].input + 0x89 + 0x21 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[5].input + 0x94 + 0x21 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[5].input + 0x95 + 0x21 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[5].input + 0x96 + 0x21 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[5].input + 0x97 + 0x21 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[2].input + 0x98 + 0x21 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[2].input + 0x99 + 0x21 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[6].input + 0x84 + 0x22 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[6].input + 0x85 + 0x22 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[6].input + 0x86 + 0x22 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[6].input + 0x87 + 0x22 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[3].input + 0x88 + 0x22 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[3].input + 0x89 + 0x22 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[6].input + 0x94 + 0x22 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[6].input + 0x95 + 0x22 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[6].input + 0x96 + 0x22 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[6].input + 0x97 + 0x22 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].fxCaps[3].input + 0x98 + 0x22 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].fxCaps[3].input + 0x99 + 0x22 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[7].input + 0x84 + 0x23 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[7].input + 0x85 + 0x23 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[7].input + 0x86 + 0x23 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[7].input + 0x87 + 0x23 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.pads[7].input + 0x94 + 0x23 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.pads[7].input + 0x95 + 0x23 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.pads[7].input + 0x96 + 0x23 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.pads[7].input + 0x97 + 0x23 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.parameterLeft.input + 0x84 + 0x28 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.parameterLeft.input + 0x85 + 0x28 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.parameterLeft.input + 0x86 + 0x28 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.parameterLeft.input + 0x87 + 0x28 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.parameterLeft.input + 0x94 + 0x28 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.parameterLeft.input + 0x95 + 0x28 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.parameterLeft.input + 0x96 + 0x28 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.parameterLeft.input + 0x97 + 0x28 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.parameterRight.input + 0x84 + 0x29 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.parameterRight.input + 0x85 + 0x29 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.parameterRight.input + 0x86 + 0x29 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.parameterRight.input + 0x87 + 0x29 + + + + + + [Channel1] + NS6II.decks[0].padUnit.padsContainer.parameterRight.input + 0x94 + 0x29 + + + + + + [Channel2] + NS6II.decks[1].padUnit.padsContainer.parameterRight.input + 0x95 + 0x29 + + + + + + [Channel3] + NS6II.decks[2].padUnit.padsContainer.parameterRight.input + 0x96 + 0x29 + + + + + + [Channel4] + NS6II.decks[3].padUnit.padsContainer.parameterRight.input + 0x97 + 0x29 + + + + + + [Channel1] + NS6II.decks[0].pitch.inputLSB + 0xB0 + 0x29 + + + + + + [Channel2] + NS6II.decks[1].pitch.inputLSB + 0xB1 + 0x29 + + + + + + [Channel3] + NS6II.decks[2].pitch.inputLSB + 0xB2 + 0x29 + + + + + + [Channel4] + NS6II.decks[3].pitch.inputLSB + 0xB3 + 0x29 + + + + + + [Channel1] + NS6II.decks[0].pitchBendPlus.input + 0x80 + 0x2B + + + + + + [Channel2] + NS6II.decks[1].pitchBendPlus.input + 0x81 + 0x2B + + + + + + [Channel3] + NS6II.decks[2].pitchBendPlus.input + 0x82 + 0x2B + + + + + + [Channel4] + NS6II.decks[3].pitchBendPlus.input + 0x83 + 0x2B + + + + + + [Channel1] + NS6II.decks[0].pitchBendPlus.input + 0x90 + 0x2B + + + + + + [Channel2] + NS6II.decks[1].pitchBendPlus.input + 0x91 + 0x2B + + + + + + [Channel3] + NS6II.decks[2].pitchBendPlus.input + 0x92 + 0x2B + + + + + + [Channel4] + NS6II.decks[3].pitchBendPlus.input + 0x93 + 0x2B + + + + + + [Channel1] + NS6II.decks[0].stripSearch.inputMSB + 0xB0 + 0x2B + + + + + + [Channel2] + NS6II.decks[1].stripSearch.inputMSB + 0xB1 + 0x2B + + + + + + [Channel3] + NS6II.decks[2].stripSearch.inputMSB + 0xB2 + 0x2B + + + + + + [Channel4] + NS6II.decks[3].stripSearch.inputMSB + 0xB3 + 0x2B + + + + + + [Channel1] + NS6II.decks[0].pitchBendMinus.input + 0x80 + 0x2C + + + + + + [Channel2] + NS6II.decks[1].pitchBendMinus.input + 0x81 + 0x2C + + + + + + [Channel3] + NS6II.decks[2].pitchBendMinus.input + 0x82 + 0x2C + + + + + + [Channel4] + NS6II.decks[3].pitchBendMinus.input + 0x83 + 0x2C + + + + + + [Channel1] + NS6II.decks[0].pitchBendMinus.input + 0x90 + 0x2C + + + + + + [Channel2] + NS6II.decks[1].pitchBendMinus.input + 0x91 + 0x2C + + + + + + [Channel3] + NS6II.decks[2].pitchBendMinus.input + 0x92 + 0x2C + + + + + + [Channel4] + NS6II.decks[3].pitchBendMinus.input + 0x93 + 0x2C + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].mixMode.input + 0x88 + 0x41 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].mixMode.input + 0x89 + 0x41 + + + + + + [EffectRack1_EffectUnit1] + NS6II.EffectUnits[1].mixMode.input + 0x98 + 0x41 + + + + + + [EffectRack1_EffectUnit2] + NS6II.EffectUnits[2].mixMode.input + 0x99 + 0x41 + + + + + + [Channel1] + NS6II.decks[0].scratch.input + 0x80 + 0x46 + + + + + + [Channel2] + NS6II.decks[1].scratch.input + 0x81 + 0x46 + + + + + + [Channel3] + NS6II.decks[2].scratch.input + 0x82 + 0x46 + + + + + + [Channel4] + NS6II.decks[3].scratch.input + 0x83 + 0x46 + + + + + + [Channel1] + NS6II.decks[0].scratch.input + 0x90 + 0x46 + + + + + + [Channel2] + NS6II.decks[1].scratch.input + 0x91 + 0x46 + + + + + + [Channel3] + NS6II.decks[2].scratch.input + 0x92 + 0x46 + + + + + + [Channel4] + NS6II.decks[3].scratch.input + 0x93 + 0x46 + + + + + + [Channel1] + NS6II.decks[0].stripSearch.inputLSB + 0xB0 + 0x4B + + + + + + [Channel2] + NS6II.decks[1].stripSearch.inputLSB + 0xB1 + 0x4B + + + + + + [Channel3] + NS6II.decks[2].stripSearch.inputLSB + 0xB2 + 0x4B + + + + + + [Channel4] + NS6II.decks[3].stripSearch.inputLSB + 0xB3 + 0x4B + + + + + + [Channel3] + NS6II.mixer.extInputChannel3.input + 0x9F + 0x57 + + + + + + [NS6II] + NS6II.knobCapBehavior.input + 0x9F + 0x59 + + + + + + [NS6II] + NS6II.filterKnobBehavior.input + 0x9F + 0x5A + + + + + + [Channel4] + NS6II.mixer.extInputChannel4.input + 0x9F + 0x60 + + + + + + [Channel1] + NS6II.deckWatcherInput + 0x90 + 0x08 + + + + + + [Channel2] + NS6II.deckWatcherInput + 0x91 + 0x08 + + + + + + [Channel3] + NS6II.deckWatcherInput + 0x92 + 0x08 + + + + + + [Channel4] + NS6II.deckWatcherInput + 0x93 + 0x08 + + + + + + + NS6II.PCSelectorInput + 0x8F + 0x3C + + + + + + + NS6II.PCSelectorInput + 0x9F + 0x3C + + + + + + + NS6II.PCSelectorInput + 0x8F + 0x3D + + + + + + + NS6II.PCSelectorInput + 0x9F + 0x3D + + + + + + + + diff --git a/res/controllers/Numark-NS6II-scripts.js b/res/controllers/Numark-NS6II-scripts.js new file mode 100755 index 000000000000..5d65ee6fb66b --- /dev/null +++ b/res/controllers/Numark-NS6II-scripts.js @@ -0,0 +1,1379 @@ +/* + +Reverse Engineering notes: + Platter: 1000 steps/revolution + Dual-precision elements: search strips, pitch + (CC: 0x06 setup display controls) + CC: 0x0E set fine pitch of display + CC: Ox3F set track duration leds + CC: 0x06 set platter pos led + CC: 0x75 (val: 0 turn off all leds, !0 turn all on) (LEDs surface) + CC: 0x7F (val: 0 turn all of, val: !0 turn all elements on) (Display) + on: 0x09 pitch up led (0: off, 1: dimm, 2: full); + on: 0x0A pitch down led (sam vals as pitch up); + on: 0x51 pitch led 0; + on: 0x0D KeyLock display; + on: 0x0E pitch range value; + CC: 0x1F channel VuMeter: 1: off, 1: 1, 21: 2, 41: 3, 61: 4, 81: 5 (clipping) + CC: 0x7E individual setting of some display elements (solo element)? + ON: channel=0xF control=0x3C left PC1/PC2 val: 0x00 (lost control), 0x7F, (gained control) + ON: channel=0xF control=0x3D right PC1/PC2 val: 0x00 (lost control), 0x7F, (gained control) + + Master VUMeters: is set by controller + PAD_COLORS: color channels (r,g,b) encoded in two bits each to form velocity value (0b0rrbbgg) + BPM Display: + Absolute BPM Syx: 0x00,0x20,0x7f,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + Least-significant-Nibble of Last 5 bytes are responsible for the display value + Pitch_percentage_change syx: 0x00,0x20,0x7f,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + Pitch_change_ratio: 0.1bpm=10 offset 5 => 100*bpm (so it hits right in the middle) + Pitch_percentage_change 0%: 0x00,0x20,0x7f,,0xf,0xf,0xf,0xf,0xd,0x5 + set pitch percentage by + get 2's complement of d: (~d + 1 >>> 0) + + pitch range: + midi: ["note_on", note=0x0E, velocity=|bpm|] (abs(bpm) = 100bpm=100velocity) + Time Display: + Set Current Time Syx: 0x00,0x20,0x7f,0x01,0x04,0x08,0x00,0x00,0x00,0x00,0x00,0x00 + Set Track duration syx: 0x00,0x20,0x7f,0x01,0x03,0x08,0x00,0x00,0x00,0x00,0x00,0x00 + Set Track duration syx: 0x00,0x20,0x7f,0x01,0x03,0x08,0x00,0x04,0x0a,0x07,0x03,0x07 + syx[3] = channel (1-based) + switch time display: ["note_on",control=0x46,velocity] only 0x00 || 0x7F (0x00 display elapsed) + Least-significant-Nibble of Last 5 bytes are responsible for the display value + 6bit value increase in sysex = 1ms timer increase on display +*/ + +var NS6II = {}; + +// UserSettings +NS6II.RATE_RANGES = [0.04, 0.08, 0.10, 0.16, 0.24, 0.50, 0.90, 1.00,]; + +NS6II.NAVIGATION_ENCODER_ACCELERATION = 5; + +NS6II.DEFAULT_LOOP_ROOT_SIZE = 1; + +NS6II.USE_BUTTON_BACKLIGHT = true; + +// Globals + +NS6II.SCRATCH_SETTINGS = { + alpha: 1/8, + beta: 0.125/32, +}; + +NS6II.PAD_COLORS = { + OFF: 0, + RED: {FULL: 48, DIMM: 32, DIMMER: 16}, + YELLOW: {FULL: 60, DIMM: 40}, + GREEN: {FULL: 12, DIMM: 8}, + CELESTE: {FULL: 15, DIMM: 10}, + BLUE: {FULL: 3, DIMM: 2}, + PURPLE: {FULL: 59, DIMM: 34}, + PINK: {FULL: 58, DIMM: 37}, + ORANGE: {FULL: 56, DIMM: 36}, + WHITE: {FULL: 63, DIMM: 42}, +}; + + +NS6II.SERATO_SYX_PREFIX = [0x00, 0x20, 0x7f]; + +components.Button.prototype.off = NS6II.USE_BUTTON_BACKLIGHT ? 0x01 : 0x00; + +components.HotcueButton.prototype.off = NS6II.PAD_COLORS.OFF; +components.HotcueButton.prototype.sendShifted = true; +components.HotcueButton.prototype.shiftControl = true; +components.HotcueButton.prototype.shiftOffset = 8; +components.HotcueButton.prototype.outConnect = false; + +components.SamplerButton.prototype.sendShifted = true; +components.SamplerButton.prototype.shiftControl = true; +components.SamplerButton.prototype.shiftOffset = 8; +components.HotcueButton.prototype.outConnect = false; + +NS6II.mixxxColorToDeviceColorCode = function(colorObj) { + var red = (colorObj.red & 0xC0) >> 2; + var green = (colorObj.green & 0xC0) >> 4; + var blue = (colorObj.blue & 0xC0) >> 6; + return (red | green | blue); +}; + +NS6II.hardwareColorToHex = function(colorcode) { + var red = (colorcode & 0x30) << 18; + var green = (colorcode & 0x0C) << 12; + var blue = (colorcode & 0x03) << 6; + return (red | green | blue); +}; + + +NS6II.padColorMapper = new ColorMapper(_.keyBy(_.range(0, 64), NS6II.hardwareColorToHex)); + +NS6II.physicalSliderPositions = { + left: 0.5, + right: 0.5, +}; + +NS6II.CyclingArrayView = function(indexable, startIndex) { + this.indexable = indexable; + this.index = startIndex || 0; + this.advanceBy = _.bind(function(n) { + this.index = NS6II.posMod(this.index + n, this.indexable.length); + return this.current(); + }, this); + this.next = _.bind(function() { + return this.advanceBy(1); + }, this); + this.previous = _.bind(function() { + return this.advanceBy(-1); + }, this); + this.current = _.bind(function() { + return this.indexable[this.index]; + }, this); +}; + +/** + * creates an this.isPress guarded input handler + * @param {(value: number) => void} func callback that is called on ButtonDown + */ +NS6II.makeButtonDownInputHandler = function(func) { + return function(channel, control, value, status, _group) { + var isPress = this.isPress(channel, control, value, status); + this.output(isPress); + if (!isPress) { + return; + } + func.call(this, value); + }; +}; + +NS6II.posMod = function(n, m) { + return ((n % m) + m) % m; +}; + +NS6II.Deck = function(channelOffset) { + var theDeck = this; + var deckNumber = channelOffset + 1; + this.group = "[Channel" + deckNumber + "]"; + + var makeSliderPosAccessors = function() { + var lr = channelOffset % 2 === 0 ? "left" : "right"; + return { + setter: function(pos) { + NS6II.physicalSliderPositions[lr] = pos; + }, + getter: function() { + return NS6II.physicalSliderPositions[lr]; + } + }; + }; + + var sliderPosAccessors = makeSliderPosAccessors(); + + this.slip = new components.Button({ + midi: [0x90+channelOffset, 0x1F], + // shift: [0x90+channelOffset,0x04], + type: components.Button.prototype.types.toggle, + unshift: function() { + this.inKey = "slip_enabled"; + this.outKey = this.inKey; + }, + shift: function() { + // use repeat instead of quantize since that + // is already handled by the SyncButton + this.inKey = "repeat"; + this.outKey = this.inKey; + }, + }); + + // also known as "censor" + this.bleep = new components.Button({ + midi: [0x90 + channelOffset, 0x10], + // shift: [0x90+channelOffset,0x0D] + unshift: function() { + this.inKey = "reverseroll"; + this.outKey = this.inKey; + this.type = components.Button.prototype.types.push; + }, + shift: function() { + this.inKey = "keylock"; + this.outKey = this.inKey; + this.type = components.Button.prototype.types.toggle; + }, + }); + + var takeoverLEDValues = { + OFF: 0, + DIMM: 1, + FULL: 2, + }; + var takeoverLEDControls = { + up: 0x09, + center: 0x51, + down: 0x0A, + }; + + // TODO fix me: this suffers from the UP leds being on after startup + // seems to be a components.Pot or Mixxx issue. + this.takeoverLeds = new components.Component({ + midi: [0x90 + channelOffset, takeoverLEDControls.center], + outKey: "rate", + off: 0, + output: function(softwareSliderPosition) { + // rate slider centered? + this.send(softwareSliderPosition === 0 ? takeoverLEDValues.FULL : takeoverLEDValues.OFF); + + var distance2Brightness = function(distance) { + // src/controllers/softtakeover.cpp + // SoftTakeover::kDefaultTakeoverThreshold = 3.0 / 128; + var takeoverThreshold = 3 / 128; + if (distance > takeoverThreshold && distance < 0.10) { + return takeoverLEDValues.DIMM; + } else if (distance >= 0.10) { + return takeoverLEDValues.FULL; + } else { + return takeoverLEDValues.OFF; + } + }; + + var normalizedPhysicalSliderPosition = sliderPosAccessors.getter()*2 - 1; + var distance = Math.abs(normalizedPhysicalSliderPosition - softwareSliderPosition); + var directionLedBrightness = distance2Brightness(distance); + + if (normalizedPhysicalSliderPosition > softwareSliderPosition) { + midi.sendShortMsg(this.midi[0], takeoverLEDControls.up, takeoverLEDValues.OFF); + midi.sendShortMsg(this.midi[0], takeoverLEDControls.down, directionLedBrightness); + } else { + midi.sendShortMsg(this.midi[0], takeoverLEDControls.down, takeoverLEDValues.OFF); + midi.sendShortMsg(this.midi[0], takeoverLEDControls.up, directionLedBrightness); + } + }, + }); + + // features 14-bit precision + this.pitch = new components.Pot({ + midi: [0xB0 + channelOffset, 0x9], + // LSB: [0x90+channelOffset,0x29] + group: theDeck.group, + inKey: "rate", + invert: true, + inSetParameter: function(value) { + + sliderPosAccessors.setter(value); + + engine.setParameter(this.group, this.inKey, value); + + theDeck.takeoverLeds.trigger(); + + }, + }); + var rates = new NS6II.CyclingArrayView(NS6II.RATE_RANGES); + this.pitchBendPlus = new components.Button({ + midi: [0x90 + channelOffset, 0x0B], + // shift: [0x90+channelOffset,0x2B] + unshift: function() { + this.inKey = "rate_temp_up"; + this.input = components.Button.prototype.input; + }, + shift: function() { + this.inKey = "rateRange"; + this.input = NS6II.makeButtonDownInputHandler(function() { + this.inSetValue(rates.next()); + }); + }, + outConnect: false, + }); + this.pitchBendMinus = new components.Button({ + midi: [0x90 + channelOffset, 0x0C], + // shift: [0x90+channelOffset,0x2C] + unshift: function() { + this.inKey = "rate_temp_down"; + this.input = components.Button.prototype.input; + }, + shift: function() { + this.inKey = "rateRange"; + this.input = NS6II.makeButtonDownInputHandler(function() { + this.inSetValue(rates.previous()); + }); + }, + outConnect: false, + }); + this.shiftButton = new components.Button({ + midi: [0x90 + channelOffset, 0x20], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + NS6II.mixer.shift(); + NS6II.EffectUnits[channelOffset % 2 + 1].shift(); + theDeck.shift(); + } else { + NS6II.mixer.unshift(); + NS6II.EffectUnits[channelOffset % 2 + 1].unshift(); + theDeck.unshift(); + } + }, + }); + + this.sync = new components.SyncButton({ + midi: [0x90 + channelOffset, 0x02], + // shift: [0x90+channelOffset,0x03] + }); + + this.play = new components.PlayButton({ + midi: [0x90 + channelOffset, 0x00], + // shift: [0x90+channelOffset,0x04] + }); + this.cue = new components.CueButton({ + midi: [0x90 + channelOffset, 0x01], + // shift: [0x90+channelOffset,0x05] + }); + + // midi: [0xB0 + channelOffset, 0x06], + this.jog = new components.JogWheelBasic({ + deck: deckNumber, + wheelResolution: 1000, // measurement (1000) wasn't producing accurate results (alt: 1073) + // engine.getValue(this.group, "vinylcontrol_speed_type"), + alpha: NS6II.SCRATCH_SETTINGS.alpha, + beta: NS6II.SCRATCH_SETTINGS.beta, + }); + + this.stripSearch = new components.Pot({ + midi: [0xB0 + channelOffset, 0x4D], // no feedback + // input MSB: [0xB0+deck,0x2F] LSB + group: theDeck.group, + inKey: "playposition", + shift: function() { + this.inSetParameter = components.Pot.prototype.inSetParameter; + }, + unshift: function() { + this.inSetParameter = function(value) { + // only allow searching when deck is not playing. + if (!engine.getParameter(this.group, "play")) { + engine.setParameter(this.group, this.inKey, value); + } + }; + }, + }); + this.scratch = new components.Button({ + midi: [0x90 + channelOffset, 0x07], + // shift: [0x90+channelOffset,0x46] + timerMode: false, + unshift: function() { + this.input = NS6II.makeButtonDownInputHandler; + this.input = function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + theDeck.jog.vinylMode = !theDeck.jog.vinylMode; + this.output(theDeck.jog.vinylMode); + } + }; + this.output(theDeck.jog.vinylMode); + }, + shift: function() { + this.input = function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + // toggle between time_elapsed/_remaining display mode + this.timerMode = !this.timerMode; + midi.sendShortMsg(0x90 + channelOffset, 0x46, this.timerMode ? 0x7F : 0x00); + } + }; + }, + }); + + this.display = new NS6II.Display(channelOffset, this); + + this.padUnit = new NS6II.PadModeContainers.ModeSelector(channelOffset+4, this.group); + + this.reconnectComponents(function(c) { + if (c.group === undefined) { + c.group = theDeck.group; + } + }); +}; + +NS6II.Deck.prototype = new components.Deck(); + +// JS implementation of engine/enginexfader.cpp:getPowerCalibration (8005e8cc81f7da91310bfc9088802bf5228a2d43) +NS6II.getPowerCalibration = function(transform) { + return Math.pow(0.5, 1.0/transform); +}; + +// JS implementation of util/rescaler.h:linearToOneByX (a939d976b12b4261f8ba14f7ba5e1f2ce9664342) +NS6II.linearToOneByX = function(input, inMin, inMax, outMax) { + var outRange = outMax - 1; + var inRange = inMax - inMin; + return outMax / (((inMax - input) / inRange * outRange) + 1); +}; + + +NS6II.MixerContainer = function() { + this.channels = []; + for (var i = 0; i < 4; i++) { + this.channels[i] = new NS6II.Channel(i); + } + this.crossfader = new components.Pot({ + midi: [0xBF, 0x08], + group: "[Master]", + inKey: "crossfader", + }); + this.splitCue = new components.Button({ + // There is a bug in Firmware v1.0.4 which causes the headsplit + // control to be sent inverted when the controller status is sent + // (either on PC1/PC2 switch or when requested via sysex). + // Numark is aware of the issue but they don't seem to be interested + // in fixing it, so this implements a workaround. + invertNext: function() { + this._invertNext = true; + this._timerHandle = engine.beginTimer(200, function() { + this._invertNext = false; + }, true); + }, + _invertNext: false, + midi: [0x9F, 0x1C], + group: "[Master]", + inKey: "headSplit", + isPress: function(channelmidi, control, value, status) { + var pressed = components.Button.prototype.isPress.call(this, channelmidi, control, value, status); + return this._invertNext ? !pressed : pressed; + } + }); + this.crossfaderContour = new components.Pot({ + midi: [0xBF, 0x09], + input: function(_channelMidi, _control, value, _status, _group) { + // mimic preferences/dialog/dlgprefcrossfader.cpp:slotUpdateXFader + var transform = NS6II.linearToOneByX(value, 0, 0x7F, 999.6); + engine.setValue("[Mixer Profile]", "xFaderCurve", transform); + var calibration = NS6II.getPowerCalibration(transform); + engine.setValue("[Mixer Profile]", "xFaderCalibration", calibration); + }, + }); + this.extInputChannel3 = new components.Button({ + midi: [0x9F, 0x57], + group: "[Channel3]", + max: 2, + inKey: "mute" + }); + this.extInputChannel4 = new components.Button({ + midi: [0x9F, 0x60], + group: "[Channel4]", + max: 2, + inKey: "mute" + }); + + this.browseSection = new NS6II.BrowseSection(); +}; + +NS6II.MixerContainer.prototype = new components.ComponentContainer(); + +/** + * Serialize a Number into the controller compatible format used in sysex messages + * @param {Number} number + * @param {boolean} signed specify if the value can be negative. + * @returns {Array} array of length that can be used to build sysex payloads + */ +NS6II.numberToSysex = function(number, signed, precision) { + var out = Array(precision); + // build 2's complement in case number is negative + if (number < 0) { + number = ((~Math.abs(number|0) + 1) >>> 0); + } + // split nibbles of number into array + for (var i = out.length; i; i--) { + out[i-1] = number & 0xF; + number = number >> 4; + } + // set signed bit in sysex payload + if (signed) { + out[0] = (number < 0) ? 0x07 : 0x08; + } + return out; +}; +NS6II.sendSysexMessage = function(channel, location, payload) { + var msg = [0xF0].concat(NS6II.SERATO_SYX_PREFIX, channel, location, payload, 0xF7); + midi.sendSysexMsg(msg, msg.length); +}; + + +NS6II.DisplayElement = function(options) { + components.Component.call(this, options); +}; + +NS6II.DisplayElement.prototype = new components.Component({ + send: function(payload) { + if (this.loc !== undefined && this.loc.deck !== undefined && this.loc.control !== undefined) { + NS6II.sendSysexMessage(this.loc.deck, this.loc.control, payload); + } else { + components.Component.prototype.send.call(this, payload); + } + }, + shutdown: function() { + this.output(this.off); + }, +}); + + +NS6II.Display = function(channelOffset) { + var channel = (channelOffset + 1); + var deck = "[Channel" + channel + "]"; + + // optimization so frequently updated controls don't have to poll seldom + // updated controls each time. + var deckInfoCache = { + // seconds + duration: 0, + // stored as 1% = 100 + rate: 0, + trackLoaded: false, + // stored as rotations per second instead of rpm. + vinylControlSpeedTypeRatio: 0, + }; + + var vinylControlSpeedTypeConnection = engine.makeConnection(deck, "vinylcontrol_speed_type", function(value) { + deckInfoCache.vinylControlSpeedTypeRatio = value/60; + }); + vinylControlSpeedTypeConnection.trigger(); + + this.keylockUI = new NS6II.DisplayElement({ + midi: [0x90 + channelOffset, 0x0D], + outKey: "keylock", + off: 0x00, + on: 0x7F, + }); + + this.rateRangeUI = new NS6II.DisplayElement({ + midi: [0x90 + channelOffset, 0x0E], + outKey: "rateRange", + off: 0, + outValueScale: function(value) { + deckInfoCache.rate = value * 10000; + return Math.round(value * 100); + } + }); + + this.bpmUI = new NS6II.DisplayElement({ + loc: {deck: channel, control: 0x01}, + outKey: "bpm", + off: 0, + outValueScale: function(value) { + return NS6II.numberToSysex(value * 100, false, 6); + }, + }); + + this.rateChangePercentageUI = new NS6II.DisplayElement({ + loc: {deck: channel, control: 0x02}, + outKey: "rate", + outValueScale: function(value) { + return NS6II.numberToSysex( + value * deckInfoCache.rate, + true, + 6 + ); + }, + }); + + this.durationUI = new NS6II.DisplayElement({ + loc: {deck: channel, control: 0x3}, + outKey: "duration", + outValueScale: function(value) { + deckInfoCache.duration = value; + return NS6II.numberToSysex(value*62.5, true, 7); + }, + }); + + this.timeElapsedUI = new NS6II.DisplayElement({ + loc: {deck: channel, control: 0x04}, + outKey: "playposition", + outValueScale: function(playpos) { + var elapsedTime = deckInfoCache.duration * playpos; + return NS6II.numberToSysex( + elapsedTime*62.5, // arbitrary controller specific scaling factor + true, // signed int + 7 + ); + }, + }); + + this.playPositionRingUI = new NS6II.DisplayElement({ + midi: [0xB0 + channelOffset, 0x3F], + outKey: "playposition", + max: 0x7F, + off: 0x00, + outValueScale: function(playpos) { + // check if track is loaded because playpos value is 0.5 when there isn't a track loaded. + return deckInfoCache.trackLoaded ? + Math.round(playpos * this.max) : + this.off; + }, + }); + + this.vinylStickerPositionUI = new NS6II.DisplayElement({ + midi: [0xB0 + channelOffset, 0x06], + outKey: "playposition", + max: 0x7F, + off: 0x00, + outValueScale: function(playpos) { + var elapsedTime = deckInfoCache.duration * playpos; + return NS6II.posMod(elapsedTime * deckInfoCache.vinylControlSpeedTypeRatio, 1) * this.max; + }, + }); + + this.deckLoadedConnection = engine.makeConnection(deck, "track_loaded", function(value) { + deckInfoCache.trackLoaded = value; + }); + this.deckLoadedConnection.trigger(); + +}; + +NS6II.Display.prototype = new components.ComponentContainer(); + +NS6II.PadMode = function(channelOffset) { + components.ComponentContainer.call(this, {}); + + this.constructPads = _.bind(function(constructPad) { + this.pads = _.map(this.pads, function(_, padIndex) { + return constructPad(padIndex); + }); + }, this); + // this is a workaround for components, forEachComponent only iterates + // over ownProperties, so these have to constructed by the constructor here + // instead of being merged by the ComponentContainer constructor + this.pads = Array(8); + this.parameterLeft = new components.Button({ + midi: [0x90 + channelOffset, 0x28], + outConnect: false, + input: function(_channelmidi, _control, _value, _status, _group) { + // do nothing + }, + }); + this.parameterRight = new components.Button({ + midi: [0x90 + channelOffset, 0x29], + outConnect: false, + input: function(_channelmidi, _control, _value, _status, _group) { + // do nothing + }, + }); +}; +NS6II.PadMode.prototype = new components.ComponentContainer(); + +NS6II.Pad = function(options) { + components.Button.call(this, options); +}; +NS6II.Pad.prototype = new components.Button({ + // grey could be an alternative as well as a backlight color. + off: NS6II.USE_BUTTON_BACKLIGHT ? NS6II.PAD_COLORS.RED.DIMMER : NS6II.PAD_COLORS.OFF, + outConnect: false, + sendShifted: true, + shiftControl: true, + shiftOffset: 8, +}); + +NS6II.PadModeContainers = {}; + +NS6II.PadModeContainers.HotcuesRegular = function(channelOffset) { + + NS6II.PadMode.call(this, channelOffset); + + this.constructPads(function(i) { + return new components.HotcueButton({ + midi: [0x90 + channelOffset, 0x14 + i], + // shift: [0x94+channelOffset,0x1b+i], + number: i + 1, + colorMapper: NS6II.padColorMapper, + // sendRGB: function(colorObj) { + // this.send(NS6II.mixxxColorToDeviceColorCode(colorObj)); + // }, + off: NS6II.PAD_COLORS.OFF, + }); + }); +}; +NS6II.PadModeContainers.HotcuesRegular.prototype = new NS6II.PadMode(); + +NS6II.PadModeContainers.LoopAuto = function(channelOffset) { + + NS6II.PadMode.call(this, channelOffset); + + var theContainer = this; + this.currentBaseLoopSize = NS6II.DEFAULT_LOOP_ROOT_SIZE; + + var changeLoopSize = function(loopSize) { + // clamp loop_size to [-5;7] + theContainer.currentBaseLoopSize = Math.min(Math.max(-5, loopSize), 7); + _.forEach(theContainer.pads, function(c, i) { + if (c instanceof components.Component) { + c.disconnect(); + var loopSize = Math.pow(2, theContainer.currentBaseLoopSize + i); + c.inKey = "beatloop_" + loopSize + "_toggle"; + c.outKey = "beatloop_" + loopSize + "_enabled"; + c.connect(); + c.trigger(); + } + }); + }; + + this.constructPads(function(i) { + return new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x14 + i], + on: NS6II.PAD_COLORS.RED.FULL, + off: NS6II.PAD_COLORS.RED.DIMM, + // key is set by changeLoopSize() + }); + }); + + this.parameterLeft = new components.Button({ + midi: [0x90 + channelOffset, 0x28], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseLoopSize - 1); + } + }, + }); + this.parameterRight = new components.Button({ + midi: [0x90 + channelOffset, 0x29], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseLoopSize + 1); + } + }, + }); + changeLoopSize(NS6II.DEFAULT_LOOP_ROOT_SIZE); +}; + +NS6II.PadModeContainers.LoopAuto.prototype = new NS6II.PadMode(); + + +NS6II.PadModeContainers.BeatJump = function(channelOffset) { + + NS6II.PadMode.call(this, channelOffset); + + var theContainer = this; + this.currentBaseJumpExponent = NS6II.DEFAULT_LOOP_ROOT_SIZE; + + var changeLoopSize = function(loopSize) { + theContainer.currentBaseJumpExponent = _.clamp(loopSize, -5, 2); + + var applyToComponent = function(component, key) { + if (!(component instanceof components.Component)) { + return; + } + component.disconnect(); + component.inKey = key; + component.outKey = component.inKey; + component.connect(); + component.trigger(); + }; + for (var i = 0; i < 4; i++) { + var size = Math.pow(2, theContainer.currentBaseJumpExponent + i); + applyToComponent(theContainer.pads[i], "beatjump_" + size + "_forward"); + applyToComponent(theContainer.pads[i+4], "beatjump_" + size + "_backward"); + } + }; + + this.constructPads(function(i) { + return new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x14 + i], + on: NS6II.PAD_COLORS.GREEN.FULL, + off: NS6II.PAD_COLORS.GREEN.DIMM, + // key is set by changeLoopSize() + }); + }); + this.parameterLeft = new components.Button({ + midi: [0x90 + channelOffset, 0x28], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseJumpExponent - 1); + } + }, + }); + this.parameterRight = new components.Button({ + midi: [0x90 + channelOffset, 0x29], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseJumpExponent + 1); + } + }, + }); + + changeLoopSize(NS6II.DEFAULT_LOOP_ROOT_SIZE); +}; + +NS6II.PadModeContainers.BeatJump.prototype = new NS6II.PadMode(); + +NS6II.PadModeContainers.LoopRoll = function(channelOffset) { + NS6II.PadMode.call(this, channelOffset); + var theContainer = this; + this.currentBaseLoopSize = NS6II.DEFAULT_LOOP_ROOT_SIZE; + + var changeLoopSize = function(loopSize) { + // clamp loopSize to [-5;7] + theContainer.currentBaseLoopSize = Math.min(Math.max(-5, loopSize), 7); + var i = 0; + _.forEach(theContainer.pads, function(c) { + if (c instanceof components.Component) { + c.disconnect(); + c.inKey = "beatlooproll_" + Math.pow(2, theContainer.currentBaseLoopSize + (i++)) + "_activate"; + c.outKey = c.inKey; + c.connect(); + c.trigger(); + } + }); + }; + + this.constructPads(function(i) { + return new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x14 + i], + on: NS6II.PAD_COLORS.GREEN.FULL, + off: NS6II.PAD_COLORS.GREEN.DIMM, + type: components.Button.prototype.types.toggle, + // key is set by changeLoopSize() + }); + }); + this.parameterLeft = new components.Button({ + midi: [0x90 + channelOffset, 0x28], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseLoopSize - 1); + } + }, + }); + this.parameterRight = new components.Button({ + midi: [0x90 + channelOffset, 0x29], + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + changeLoopSize(theContainer.currentBaseLoopSize + 1); + } + }, + }); + + changeLoopSize(NS6II.DEFAULT_LOOP_ROOT_SIZE); +}; + +NS6II.PadModeContainers.LoopRoll.prototype = new NS6II.PadMode(); + +NS6II.PadModeContainers.LoopControl = function(channelOffset) { + NS6II.PadMode.call(this, channelOffset); + this.pads[0] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x14], + key: "loop_in", + on: NS6II.PAD_COLORS.BLUE.FULL, + off: NS6II.PAD_COLORS.BLUE.DIMM, + }); + this.pads[1] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x15], + key: "loop_out", + on: NS6II.PAD_COLORS.BLUE.FULL, + off: NS6II.PAD_COLORS.BLUE.DIMM + }); + this.pads[2] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x16], + key: "beatloop_activate", + on: NS6II.PAD_COLORS.GREEN.FULL, + off: NS6II.PAD_COLORS.GREEN.DIMM, + }); + this.pads[3] = new components.LoopToggleButton({ + midi: [0x90 + channelOffset, 0x17], + on: NS6II.PAD_COLORS.GREEN.FULL, + off: NS6II.PAD_COLORS.GREEN.DIMM, + }); + this.pads[4] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x19], + key: "beatjump_backward", + on: NS6II.PAD_COLORS.ORANGE.FULL, + off: NS6II.PAD_COLORS.ORANGE.DIMM, + }); + this.pads[5] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x18], + key: "beatjump_forward", + on: NS6II.PAD_COLORS.ORANGE.FULL, + off: NS6II.PAD_COLORS.ORANGE.DIMM, + }); + this.pads[6] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x1A], + key: "loop_halve", + on: NS6II.PAD_COLORS.RED.FULL, + off: NS6II.PAD_COLORS.RED.DIMM, + }); + this.pads[7] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x1B], + key: "loop_double", + on: NS6II.PAD_COLORS.RED.FULL, + off: NS6II.PAD_COLORS.RED.DIMM, + }); +}; +NS6II.PadModeContainers.LoopControl.prototype = new NS6II.PadMode(); + +NS6II.PadModeContainers.SamplerNormal = function(channelOffset) { + NS6II.PadMode.call(this, channelOffset); + this.constructPads(function(i) { + return new components.SamplerButton({ + midi: [0x90 + channelOffset, 0x14 + i], + number: i + 1, + empty: NS6II.PAD_COLORS.OFF, + playing: NS6II.PAD_COLORS.WHITE.FULL, + loaded: NS6II.PAD_COLORS.WHITE.DIMM, + }); + }); +}; +NS6II.PadModeContainers.SamplerNormal.prototype = new NS6II.PadMode(); + +NS6II.PadModeContainers.SamplerVelocity = function(channelOffset) { + NS6II.PadMode.call(this, channelOffset); + + this.constructPads(function(i) { + return new components.SamplerButton({ + midi: [0x90 + channelOffset, 0x14 + i], + number: i + 1, + empty: NS6II.PAD_COLORS.OFF, + playing: NS6II.PAD_COLORS.PINK.FULL, + loaded: NS6II.PAD_COLORS.PINK.DIMM, + volumeByVelocity: true, + }); + }); +}; + +NS6II.PadModeContainers.SamplerVelocity.prototype = new NS6II.PadMode(); + + +NS6II.PadModeContainers.BeatgridSettings = function(channelOffset) { + + NS6II.PadMode.call(this, channelOffset); + + // Same layout as waveform customization in LateNight + // except pads[4] (bottom left button) + + this.pads[0] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x14], + key: "beats_translate_curpos", + on: NS6II.PAD_COLORS.RED.FULL, + off: NS6II.PAD_COLORS.RED.DIMM, + }); + this.pads[1] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x15], + key: "beats_translate_earlier", + on: NS6II.PAD_COLORS.ORANGE.FULL, + off: NS6II.PAD_COLORS.ORANGE.DIMM, + }); + this.pads[2] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x16], + key: "beats_translate_later", + on: NS6II.PAD_COLORS.ORANGE.FULL, + off: NS6II.PAD_COLORS.ORANGE.DIMM, + }); + this.pads[3] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x17], + key: "shift_cues_later", + on: NS6II.PAD_COLORS.BLUE.FULL, + off: NS6II.PAD_COLORS.BLUE.DIMM, + }); + this.pads[4] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x18], + key: "bpm_tap", + on: NS6II.PAD_COLORS.GREEN.FULL, + off: NS6II.PAD_COLORS.GREEN.DIMM, + }); + this.pads[5] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x19], + key: "beats_adjust_faster", + on: NS6II.PAD_COLORS.YELLOW.FULL, + off: NS6II.PAD_COLORS.YELLOW.DIMM, + }); + this.pads[6] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x1A], + key: "beats_adjust_slower", + on: NS6II.PAD_COLORS.YELLOW.FULL, + off: NS6II.PAD_COLORS.YELLOW.DIMM, + }); + this.pads[7] = new NS6II.Pad({ + midi: [0x90 + channelOffset, 0x1B], + key: "shift_cues_earlier", + on: NS6II.PAD_COLORS.BLUE.FULL, + off: NS6II.PAD_COLORS.BLUE.DIMM, + }); +}; + +NS6II.PadModeContainers.BeatgridSettings.prototype = new NS6II.PadMode(); + + +NS6II.PadModeContainers.ModeSelector = function(channelOffset, group) { + var theSelector = this; + + var updateSelectorLeds = function() { + _.forEach(theSelector.modeSelectors, function(selector) { + selector.trigger(); + }); + }; + + var setPads = function(padInstance) { + if (padInstance === theSelector.padsContainer) { + return; + } + theSelector.padsContainer.forEachComponent(function(component) { + component.disconnect(); + }); + theSelector.padsContainer = padInstance; + updateSelectorLeds(); + theSelector.padsContainer.reconnectComponents(function(c) { + if (c.group === undefined) { + c.group = group; + } + }); + }; + + + var makeModeSelectorInputHandler = function(control, padInstances) { + return new components.Button({ + midi: [0x90 + channelOffset, control], + padInstances: new NS6II.CyclingArrayView(padInstances), + input: function(channelmidi, control, value, status, _group) { + if (this.isPress(channelmidi, control, value, status)) { + return; + } + if (this.padInstances.current() === theSelector.padsContainer) { + setPads(this.padInstances.next()); + } else { + this.padInstances.index = 0; + setPads(this.padInstances.current()); + } + }, + outValueScale: function(active) { + if (!active) { + return this.off; + } + switch (this.padInstances.index) { + case 0: return 0x04; // solid on + case 1: return 0x02; // blink on/off + case 2: return 0x03; // blink 3x + default: return this.off; + } + }, + trigger: function() { + this.output(this.padInstances.indexable.indexOf(theSelector.padsContainer) !== -1); + }, + }); + }; + + var startupModeInstance = new NS6II.PadModeContainers.HotcuesRegular(channelOffset); + + this.modeSelectors = { + cues: makeModeSelectorInputHandler(0x00 /*shift: 0x02*/, [startupModeInstance]), + auto: makeModeSelectorInputHandler(0x10, [new NS6II.PadModeContainers.LoopAuto(channelOffset), new NS6II.PadModeContainers.LoopRoll(channelOffset)]), + loop: makeModeSelectorInputHandler(0x0E, [new NS6II.PadModeContainers.LoopControl(channelOffset)]), + sampler: makeModeSelectorInputHandler(0x0B /*shift: 0x0F*/, [new NS6II.PadModeContainers.SamplerNormal(channelOffset), new NS6II.PadModeContainers.SamplerVelocity(channelOffset)]), + slider: makeModeSelectorInputHandler(0x09, [new NS6II.PadModeContainers.BeatJump(channelOffset), new NS6II.PadModeContainers.BeatgridSettings(channelOffset)]), + }; + + this.padsContainer = new NS6II.PadMode(channelOffset); + setPads(startupModeInstance); +}; + +NS6II.PadModeContainers.ModeSelector.prototype = new components.ComponentContainer(); + +NS6II.Channel = function(channelOffset) { + var deck = "[Channel" + (channelOffset+1) + "]"; + // var theChannel = this; + this.loadTrackIntoDeck = new components.Button({ + midi: [0x9F, 0x02 + channelOffset], + // midi: [0x90 + channelOffset, 0x17], + group: deck, + shift: function() { + this.inKey = "eject"; + this.outKey = this.inKey; + }, + unshift: function() { + this.inKey = "LoadSelectedTrack"; + this.outKey = this.inKey; + }, + }); + // used to determine whether vumeter on the controller would change + // so messages get only when that is the case. + var lastVuLevel = 0; + this.vuMeterLevelConnection = engine.makeConnection(deck, "VuMeter", function(value) { + // check if channel is peaking and increase value so that the peaking led gets lit as well + // (the vumeter and the peak led are driven by the same control) (values > 81 light up the peakLED as well) + + // convert high res value to 5 LED resolution + value = Math.floor(value*4) + engine.getValue(deck, "PeakIndicator"); + if (value === lastVuLevel) { + // return early if vumeter has not changed (on the controller) + return; + } else { + lastVuLevel = value; + } + midi.sendShortMsg(0xB0 + channelOffset, 0x1F, value * 20); + }); + this.preGain = new components.Pot({ + midi: [0xB0 + channelOffset, 0x16], + softTakeover: false, + group: deck, + inKey: "pregain" + }); + this.eqKnobs = _.map(Array(3), function(_, i) { + return new components.Pot({ + midi: [0xB0 + channelOffset, 0x16 + i], + softTakeover: false, + group: "[EqualizerRack1_" + deck + "_Effect1]", + inKey: "parameter" + (3-i), + }); + }); + this.eqCaps = _.map(Array(3), function(_, i) { + return new components.Button({ + midi: [0x90 + channelOffset, 0x16 + i], + group: "[EqualizerRack1_" + deck + "_Effect1]", + inKey: "button_parameter" + (3-i), + isPress: function(_midiChannel, _control, value, _status) { + return NS6II.knobCapBehavior.state > 1 && value > 0; + } + }); + }); + this.filter = new components.Pot({ + midi: [0xB0 + channelOffset, 0x1A], + softTakeover: false, + group: "[QuickEffectRack1_" + deck + "]", + inKey: "super1", + }); + + // Unused ATM + this.filterCap = new components.Button({ + // midi: [0x90 + channelOffset, 0x1A], + // group: "[QuickEffectRack1_" + deck + "_Effect1]", + // inKey: "enabled", + input: function() {}, + }); + + this.pfl = new components.Button({ + midi: [0x90 + channelOffset, 0x1B], + group: deck, + key: "pfl", + // override off as pfl buttons are always backlit + // and only turn off with a value of 0x00 + off: 0x00, + }); + this.crossfaderOrientation = new components.Component({ + midi: [0x90 + channelOffset, 0x1E], + group: deck, + inKey: "orientation", + inValueScale: function(value) { + // Controller values to represent the orientation and mixxx + // orientation representation don't match. + switch (value) { + case 1: return 0; + case 0: return 1; + case 2: return 2; + default: throw "unreachable!"; + } + }, + }); + + this.volume = new components.Pot({ + midi: [0xB0 + channelOffset, 0x1C], + softTakeover: false, + group: deck, + inKey: "volume", + }); +}; +NS6II.Channel.prototype = new components.ComponentContainer(); + +NS6II.BrowseSection = function() { + this.libraryNavigation = new components.ComponentContainer({ + turn: new components.Encoder({ + midi: [0xBF, 0x00], // shift: [0xBF,0x01] + group: "[Library]", + inKey: "MoveVertical", + shift: function() { + this.stepsize = NS6II.NAVIGATION_ENCODER_ACCELERATION; + }, + unshift: function() { + this.stepsize = 1; + }, + input: function(_midiChannel, _control, value, _status, _group) { + this.inSetValue(value === 0x01 ? this.stepsize : -this.stepsize); + }, + }), + press: new components.Button({ + midi: [0x9F, 0x06], + group: "[Library]", + inKey: "GoToItem", + }), + }); + + /** + * @param {Number} columnIdToSort Value from `[Library], sort_column` docs + */ + var makeSortColumnInputHandler = function(columnIdToSort) { + return NS6II.makeButtonDownInputHandler(function() { + this.inSetValue(columnIdToSort); + }); + }; + var makeSortColumnShiftHandler = function(inputFun) { + return function() { + this.group = "[Library]"; + this.inKey = "sort_column_toggle"; + this.outKey = this.inKey; + this.input = inputFun; + this.type = components.Button.prototype.types.push; + }; + }; + + // subset of https://manual.mixxx.org/2.3/en/chapters/appendix/mixxx_controls.html#control-[Library]-sort_column + var sortColumnTypes = { + bpm: 15, + title: 2, + key: 20, + artist: 1, + }; + + this.view = new components.Button({ + midi: [0x9F, 0x0E], // shift: [0x9F,0x13], + unshift: function() { + this.group = "[Master]"; + this.inKey = "maximize_library"; + this.outKey = this.inKey; + this.input = components.Button.prototype.input; + this.type = components.Button.prototype.types.toggle; + }, + shift: makeSortColumnShiftHandler(makeSortColumnInputHandler(sortColumnTypes.bpm)), + }); + this.back = new components.Button({ + midi: [0x9F, 0x11], // shift: [0x9F,0x12] + unshift: function() { + this.inKey = "MoveFocusBackward"; + this.outKey = this.inKey; + this.input = components.Button.prototype.input; + this.type = components.Button.prototype.types.push; + }, + shift: makeSortColumnShiftHandler(makeSortColumnInputHandler(sortColumnTypes.title)), + }); + this.area = new components.Button({ + midi: [0x9F, 0xF], // shift: [0x9F, 0x1E] + unshift: function() { + this.inKey = "MoveFocusForward"; + this.outKey = this.inKey; + this.input = components.Button.prototype.input; + this.type = components.Button.prototype.types.push; + }, + shift: makeSortColumnShiftHandler(makeSortColumnInputHandler(sortColumnTypes.key)), + }); + this.lprep = new components.Button({ + midi: [0x9F, 0x1B], // shift: [0x9F, 0x14] + unshift: function() { + this.group = "[PreviewDeck1]"; + this.inKey = "LoadSelectedTrack"; + this.outKey = this.inKey; + this.input = components.Button.prototype.input; + this.type = components.Button.prototype.types.push; + }, + shift: makeSortColumnShiftHandler(makeSortColumnInputHandler(sortColumnTypes.artist)), + }); +}; +NS6II.BrowseSection.prototype = new components.ComponentContainer(); + +// TouchFX / TouchAll +NS6II.knobCapBehavior = new components.Button({ + midi: [0x9F, 0x59], + state: 0, + input: function(_midiChannel, _control, value, _status, _group) { + this.state = Math.round(value/64); + }, +}); + + +// FilterRoll / FilterFX +// Unused ATM +NS6II.filterKnobBehavior = new components.Button({ + midi: [0x9F, 0x5A], + state: 0, + input: function(_channel, _control, value, _status, _group) { + this.state = Math.round(value/64); + }, +}); + +NS6II.deckWatcherInput = function(midichannel, _control, _value, _status, _group) { + var deck = midichannel; + var toDeck = NS6II.decks[deck]; + var fromDeck = NS6II.decks[(deck + 2) % 4]; + fromDeck.pitch.disconnect(); + toDeck.pitch.connect(); + toDeck.takeoverLeds.trigger(); +}; + +NS6II.PCSelectorInput = function(_midichannel, _control, value, _status, _group) { + if (value > 0) { + NS6II.mixer.splitCue.invertNext(); + } +}; + +NS6II.EffectUnits = []; +for (var i = 1; i <= 2; i++) { + NS6II.EffectUnits[i] = new components.EffectUnit(i); + NS6II.EffectUnits[i].fxCaps = []; + for (var ii = 0; ii < 3; ii++) { + NS6II.EffectUnits[i].enableButtons[ii + 1].midi = [0x97 + i, ii]; // shift: [0x97+i,0x0B+ii] + NS6II.EffectUnits[i].fxCaps[ii + 1] = new components.Button({ + midi: [0x97 + i, 0x21 + ii], + group: "[EffectRack1_EffectUnit" + NS6II.EffectUnits[i].currentUnitNumber + + "_Effect" + (ii+1) + "]", + inKey: "enabled", + shifted: false, // used to disable fx input while selecting + input: function(midichannel, control, value, status, _group) { + if (NS6II.knobCapBehavior.state > 0) { + this.inSetParameter(this.isPress(midichannel, control, value, status) && !this.shifted); + } + }, + unshift: function() { + this.shifted = false; + }, + shift: function() { + this.shifted = true; + }, + }); + NS6II.EffectUnits[i].knobs[ii + 1].midi = [0xB7 + i, ii]; + } + NS6II.EffectUnits[i].effectFocusButton.midi = [0x97 + i, 0x04]; + NS6II.EffectUnits[i].dryWetKnob.midi = [0xB7 + i, 0x03]; + NS6II.EffectUnits[i].dryWetKnob.input = function(_midichannel, _control, value, _status, _group) { + if (value === 1) { + this.inSetParameter(this.inGetParameter() + 0.04); + } else if (value === 127) { + this.inSetParameter(this.inGetParameter() - 0.04); + } + }; + NS6II.EffectUnits[i].mixMode = new components.Button({ + midi: [0xB7 + i, 0x41], + type: components.Button.prototype.types.toggle, + inKey: "mix_mode", + group: NS6II.EffectUnits[i].group, + }); + for (ii = 0; ii < 4; ii++) { + var channel = "Channel"+(ii + 1); + NS6II.EffectUnits[i].enableOnChannelButtons.addButton(channel); + NS6II.EffectUnits[i].enableOnChannelButtons[channel].midi = [0x97 + i, 0x05 + ii]; + } + NS6II.EffectUnits[i].init(); +} + +NS6II.askControllerStatus = function() { + var controllerStatusSysex = [0xF0, 0x00, 0x20, 0x7F, 0x03, 0x01, 0xF7]; + NS6II.mixer.splitCue.invertNext(); + midi.sendSysexMsg(controllerStatusSysex, controllerStatusSysex.length); +}; + +NS6II.init = function() { + + // force headMix to 0 because it is managed by the controller hardware mixer. + engine.setParameter("[Master]", "headMix", 0); + + NS6II.decks = new components.ComponentContainer(); + for (var i = 0; i < 4; i++) { + NS6II.decks[i] = new NS6II.Deck(i); + } + NS6II.mixer = new NS6II.MixerContainer(); + NS6II.askControllerStatus(); +}; + +NS6II.shutdown = function() { + NS6II.mixer.shutdown(); + NS6II.decks.shutdown(); +}; + +// ES3 Polyfills + +// var Number = {}; +Number.isInteger = function(value) { + return typeof value === "number" && + isFinite(value) && + Math.floor(value) === value; +};