diff --git a/res/controllers/Numark N4.midi.xml b/res/controllers/Numark N4.midi.xml
index 649b78c6968a..d030912476a5 100644
--- a/res/controllers/Numark N4.midi.xml
+++ b/res/controllers/Numark N4.midi.xml
@@ -1,817 +1,2460 @@
-
-
- Numark N4
- dj.stuartbrand
- MIDI Mapping for Numark N4
- http://www.mixxx.org/forums/viewtopic.php?f=7&t=3450
-
-
-
-
-
-
-
- 0xb1
- 0x20
- [Channel1]
- NumarkN4.jogWheel
-
-
-
-
-
-
- 0x82
- 0x10
- [Channel2]
- NumarkN4.cue
-
-
-
-
-
-
- 0x80
- 0x8
- [Playlist]
- LoadSelectedIntoFirstStopped
-
-
-
-
-
-
- 0x81
- 0x10
- [Channel1]
- NumarkN4.cue
-
-
-
-
-
-
- 0x92
- 0x6
- [Channel1]
- NumarkN4.menuNext
-
-
-
-
-
-
- 0x82
- 0x2c
- [Channel2]
- NumarkN4.touch
-
-
-
-
-
-
- 0x93
- 0xf
- [Channel1]
- beatsync
-
-
-
-
-
-
- 0x91
- 0x6
- [Channel1]
- NumarkN4.menuPrev
-
-
-
-
-
-
- 0x93
- 0x13
- [Channel1]
- flanger
-
-
-
-
-
-
- 0x92
- 0xf
- [Channel2]
- beatsync
-
-
-
-
-
-
- 0x81
- 0x2c
- [Channel1]
- NumarkN4.touch
-
-
-
-
-
-
- 0x92
- 0x10
- [Channel2]
- cue_default
-
-
-
-
-
-
- 0x92
- 0x11
- [Channel2]
- play
-
-
-
-
-
-
- 0x92
- 0x13
- [Channel2]
- flanger
-
-
-
-
-
-
- 0xb0
- 0x44
- [Playlist]
- NumarkN4.SelectTrack
-
-
-
-
-
-
- 0x90
- 0x8
- [Playlist]
- LoadSelectedIntoFirstStopped
-
-
-
-
-
-
- 0x93
- 0x1b
- [Channel2]
- keylock
-
-
-
-
-
-
- 0x91
- 0xf
- [Channel1]
- beatsync
-
-
-
-
-
-
- 0x92
- 0x15
- [Sampler3]
- play
-
-
-
-
-
-
- 0x91
- 0x10
- [Channel1]
- NumarkN4.cue
-
-
-
-
-
-
- 0x92
- 0x16
- [Sampler4]
- play
-
-
-
-
-
-
- 0x91
- 0x11
- [Channel1]
- play
-
-
-
-
-
-
- 0x93
- 0x1e
- [Channel2]
- bpm
-
-
-
-
-
-
- 0x91
- 0x13
- [Channel1]
- flanger
-
-
-
-
-
-
- 0x90
- 0x31
- [Channel1]
- NumarkN4.headcue
-
-
-
-
-
-
- 0x80
- 0x31
- [Channel1]
- NumarkN4.headcue
-
-
-
-
-
-
- 0x90
- 0x32
- [Channel2]
- NumarkN4.headcue
-
-
-
-
-
-
- 0x80
- 0x32
- [Channel2]
- NumarkN4.headcue
-
-
-
-
-
-
- 0x92
- 0x1b
- [Channel2]
- keylock
-
-
-
-
-
-
- 0x91
- 0x15
- [Sampler1]
- play
-
-
-
-
-
-
- 0x91
- 0x16
- [Sampler2]
- play
-
-
-
-
-
-
- 0x92
- 0x1e
- [Channel2]
- bpm
-
-
-
-
-
-
- 0x80
- 0x35
- [Channel1]
- hotcue_1_activate
-
-
-
-
-
-
- 0x80
- 0x36
- [Channel2]
- hotcue_1_activate
-
-
-
-
-
-
- 0x80
- 0x37
- [Channel1]
- hotcue_2_activate
-
-
-
-
-
-
- 0x93
- 0x27
- [Channel1]
- loop_in
-
-
-
-
-
-
- 0x92
- 0x21
- [Channel2]
- NumarkN4.toggleScratchMode
-
-
-
-
-
-
- 0x91
- 0x1b
- [Channel1]
- keylock
-
-
-
-
-
-
- 0x80
- 0x38
- [Channel2]
- hotcue_2_activate
-
-
-
-
-
-
- 0x93
- 0x28
- [Channel1]
- loop_out
-
-
-
-
-
-
- 0x80
- 0x39
- [Channel1]
- hotcue_3_activate
-
-
-
-
-
-
- 0x93
- 0x29
- [Channel1]
- reloop_exit
-
-
-
-
-
-
- 0x80
- 0x3a
- [Channel2]
- hotcue_3_activate
-
-
-
-
-
-
- 0x91
- 0x1e
- [Channel1]
- bpm
-
-
-
-
-
-
- 0x80
- 0x3b
- [Channel1]
- hotcue_4_activate
-
-
-
-
-
-
- 0x80
- 0x3c
- [Channel2]
- hotcue_4_activate
-
-
-
-
-
-
- 0x92
- 0x27
- [Channel2]
- loop_in
-
-
-
-
-
-
- 0x91
- 0x21
- [Channel1]
- NumarkN4.toggleScratchMode
-
-
-
-
-
-
- 0x92
- 0x28
- [Channel2]
- loop_out
-
-
-
-
-
-
- 0x92
- 0x29
- [Channel2]
- reloop_exit
-
-
-
-
-
-
- 0x92
- 0x2c
- [Channel2]
- NumarkN4.touch
-
-
-
-
-
-
- 0x91
- 0x27
- [Channel1]
- loop_in
-
-
-
-
-
-
- 0x91
- 0x28
- [Channel1]
- loop_out
-
-
-
-
-
-
- 0x91
- 0x29
- [Channel1]
- reloop_exit
-
-
-
-
-
-
- 0x91
- 0x2c
- [Channel1]
- NumarkN4.touch
-
-
-
-
-
-
- 0xb4
- 0x1
- [Channel2]
- rate
-
-
-
-
-
+
+
+
+ Numark N4
+ Swiftb0y
+ 4 channel MIDI Mapping for Numark N4
+
+
+
+
+
+
+
+
+
+
+
+ [Library]
+ NumarkN4.Mixer.navigationEncoderTick.input
+ 0xB0
+ 0x44
+
+
+
+
+
+ [Library]
+ NumarkN4.Mixer.navigationEncoderButton.input
+ 0x80
+ 0x08
+
+
+
+
+
+ [Library]
+ NumarkN4.Mixer.navigationEncoderButton.input
+ 0x90
+ 0x08
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].orientationButtonLeft.input
+ 0x90
+ 0x35
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].orientationButtonRight.input
+ 0x90
+ 0x36
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].orientationButtonLeft.input
+ 0x90
+ 0x37
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].orientationButtonRight.input
+ 0x90
+ 0x38
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].orientationButtonLeft.input
+ 0x90
+ 0x39
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].orientationButtonRight.input
+ 0x90
+ 0x3A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].orientationButtonLeft.input
+ 0x90
+ 0x3B
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].orientationButtonRight.input
+ 0x90
+ 0x3C
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].orientationButtonLeft.input
+ 0x80
+ 0x35
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].orientationButtonRight.input
+ 0x80
+ 0x36
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].orientationButtonLeft.input
+ 0x80
+ 0x37
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].orientationButtonRight.input
+ 0x80
+ 0x38
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].orientationButtonLeft.input
+ 0x80
+ 0x39
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].orientationButtonRight.input
+ 0x80
+ 0x3A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].orientationButtonLeft.input
+ 0x80
+ 0x3B
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].orientationButtonRight.input
+ 0x80
+ 0x3C
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnEffect1.input
+ 0x91
+ 0x13
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnEffect1.input
+ 0x92
+ 0x13
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnEffect1.input
+ 0x93
+ 0x13
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnEffect1.input
+ 0x94
+ 0x13
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnEffect2.input
+ 0x91
+ 0x14
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnEffect2.input
+ 0x92
+ 0x14
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnEffect2.input
+ 0x93
+ 0x14
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnEffect2.input
+ 0x94
+ 0x14
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnSample3.input
+ 0x91
+ 0x15
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnSample3.input
+ 0x92
+ 0x15
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnSample3.input
+ 0x93
+ 0x15
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnSample3.input
+ 0x94
+ 0x15
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnSample4.input
+ 0x91
+ 0x16
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnSample4.input
+ 0x92
+ 0x16
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnSample4.input
+ 0x93
+ 0x16
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnSample4.input
+ 0x94
+ 0x16
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnEffect1.input
+ 0x81
+ 0x13
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnEffect1.input
+ 0x82
+ 0x13
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnEffect1.input
+ 0x83
+ 0x13
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnEffect1.input
+ 0x84
+ 0x13
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnEffect2.input
+ 0x81
+ 0x14
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnEffect2.input
+ 0x82
+ 0x14
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnEffect2.input
+ 0x83
+ 0x14
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnEffect2.input
+ 0x84
+ 0x14
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnSample3.input
+ 0x81
+ 0x15
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnSample3.input
+ 0x82
+ 0x15
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnSample3.input
+ 0x83
+ 0x15
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnSample3.input
+ 0x84
+ 0x15
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.btnSample4.input
+ 0x81
+ 0x16
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.btnSample4.input
+ 0x82
+ 0x16
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.btnSample4.input
+ 0x83
+ 0x16
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.btnSample4.input
+ 0x84
+ 0x16
+
+
+
+
-
- 0xb3
- 0x1
- [Channel1]
- rate
-
-
-
-
-
-
- 0x90
- 0x35
- [Channel1]
- hotcue_1_activate
-
-
-
-
-
-
- 0x90
- 0x36
- [Channel2]
- hotcue_1_activate
-
-
-
-
-
-
- 0x90
- 0x37
- [Channel1]
- hotcue_2_activate
-
-
-
-
-
-
- 0x90
- 0x38
- [Channel2]
- hotcue_2_activate
-
-
-
-
-
-
- 0x90
- 0x39
- [Channel1]
- hotcue_3_activate
-
-
-
-
-
-
- 0x90
- 0x3a
- [Channel2]
- hotcue_3_activate
-
-
-
-
-
-
- 0xb2
- 0x1
- [Channel2]
- rate
-
-
-
-
-
-
- 0x90
- 0x3b
- [Channel1]
- hotcue_4_activate
-
-
-
-
-
-
- 0x90
- 0x3c
- [Channel2]
- hotcue_4_activate
-
-
-
-
-
-
- 0xb1
- 0x1
- [Channel1]
- rate
-
-
-
-
-
-
- 0xb0
- 0x7
- [Master]
- crossfader
-
-
-
-
-
-
- 0xb0
- 0x8
- [Channel1]
- volume
-
-
-
-
-
-
- 0xb0
- 0x9
- [Channel1]
- filterLow
-
-
-
-
-
-
- 0xb0
- 0xa
- [Channel1]
- filterMid
-
-
-
-
-
-
- 0xb0
- 0xb
- [Channel1]
- filterHigh
-
-
-
-
-
-
- 0xb0
- 0xc
- [Channel1]
- pregain
-
-
-
-
-
-
- 0xb0
- 0xd
- [Channel2]
- volume
-
-
-
-
-
-
- 0xb0
- 0xe
- [Channel2]
- filterLow
-
-
-
-
-
-
- 0xb0
- 0xf
- [Channel2]
- filterMid
-
-
-
-
-
-
- 0xb0
- 0x10
- [Channel2]
- filterHigh
-
-
-
-
-
-
- 0xb0
- 0x11
- [Channel2]
- pregain
-
-
-
-
-
-
- 0xb0
- 0x12
- [Master]
- headMix
-
-
-
-
-
-
- 0xb2
- 0x20
- [Channel2]
- NumarkN4.jogWheel
-
-
-
-
-
-
-
-
-
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[0].input
+ 0x91
+ 0x27
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[0].input
+ 0x92
+ 0x27
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[0].input
+ 0x93
+ 0x27
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[0].input
+ 0x94
+ 0x27
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[1].input
+ 0x91
+ 0x28
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[1].input
+ 0x92
+ 0x28
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[1].input
+ 0x93
+ 0x28
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[1].input
+ 0x94
+ 0x28
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[2].input
+ 0x91
+ 0x29
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[2].input
+ 0x92
+ 0x29
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[2].input
+ 0x93
+ 0x29
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[2].input
+ 0x94
+ 0x29
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[3].input
+ 0x91
+ 0x2A
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[3].input
+ 0x92
+ 0x2A
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[3].input
+ 0x93
+ 0x2A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[3].input
+ 0x94
+ 0x2A
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[0].input
+ 0x81
+ 0x27
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[0].input
+ 0x82
+ 0x27
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[0].input
+ 0x83
+ 0x27
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[0].input
+ 0x84
+ 0x27
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[1].input
+ 0x81
+ 0x28
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[1].input
+ 0x82
+ 0x28
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[1].input
+ 0x83
+ 0x28
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[1].input
+ 0x84
+ 0x28
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[2].input
+ 0x81
+ 0x29
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[2].input
+ 0x82
+ 0x29
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[2].input
+ 0x83
+ 0x29
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[2].input
+ 0x84
+ 0x29
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.hotcueButtons[3].input
+ 0x81
+ 0x2A
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.hotcueButtons[3].input
+ 0x82
+ 0x2A
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.hotcueButtons[3].input
+ 0x83
+ 0x2A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.hotcueButtons[3].input
+ 0x84
+ 0x2A
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.encFxParam1.input
+ 0xB1
+ 0x57
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.encFxParam1.input
+ 0xB2
+ 0x57
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.encFxParam1.input
+ 0xB3
+ 0x57
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.encFxParam1.input
+ 0xB4
+ 0x57
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.encFxParam2.input
+ 0xB1
+ 0x58
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.encFxParam2.input
+ 0xB2
+ 0x58
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.encFxParam2.input
+ 0xB3
+ 0x58
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.encFxParam2.input
+ 0xB4
+ 0x58
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.encSample3.input
+ 0xB1
+ 0x59
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.encSample3.input
+ 0xB2
+ 0x59
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.encSample3.input
+ 0xB3
+ 0x59
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.encSample3.input
+ 0xB4
+ 0x59
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].topContainer.encSample4.input
+ 0xB1
+ 0x5A
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].topContainer.encSample4.input
+ 0xB2
+ 0x5A
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].topContainer.encSample4.input
+ 0xB3
+ 0x5A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].topContainer.encSample4.input
+ 0xB4
+ 0x5A
+
+
+
+
+
+ [Master]
+ NumarkN4.Mixer.pflVuMeter
+ 0xB0
+ 0x5C
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].loadButton.input
+ 0x91
+ 0x06
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].loadButton.input
+ 0x92
+ 0x06
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].loadButton.input
+ 0x93
+ 0x06
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].loadButton.input
+ 0x94
+ 0x06
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].loadButton.input
+ 0x81
+ 0x06
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].loadButton.input
+ 0x82
+ 0x06
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].loadButton.input
+ 0x83
+ 0x06
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].loadButton.input
+ 0x84
+ 0x06
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pflButton.input
+ 0x90
+ 0x31
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pflButton.input
+ 0x90
+ 0x32
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pflButton.input
+ 0x90
+ 0x33
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pflButton.input
+ 0x90
+ 0x34
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pflButton.input
+ 0x80
+ 0x31
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pflButton.input
+ 0x80
+ 0x32
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pflButton.input
+ 0x80
+ 0x33
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pflButton.input
+ 0x80
+ 0x34
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].cueButton.input
+ 0x91
+ 0x10
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].cueButton.input
+ 0x92
+ 0x10
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].cueButton.input
+ 0x93
+ 0x10
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].cueButton.input
+ 0x94
+ 0x10
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].cueButton.input
+ 0x81
+ 0x10
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].cueButton.input
+ 0x82
+ 0x10
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].cueButton.input
+ 0x83
+ 0x10
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].cueButton.input
+ 0x84
+ 0x10
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].searchButton.input
+ 0x91
+ 0x21
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].searchButton.input
+ 0x92
+ 0x21
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].searchButton.input
+ 0x93
+ 0x21
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].searchButton.input
+ 0x94
+ 0x21
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].searchButton.input
+ 0x81
+ 0x21
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].searchButton.input
+ 0x82
+ 0x21
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].searchButton.input
+ 0x83
+ 0x21
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].searchButton.input
+ 0x84
+ 0x21
+
+
+
+
+
+ [Mixer Profile]
+ NumarkN4.Mixer.changeCrossfaderContour.input
+ 0x90
+ 0x4B
+
+
+
+
+
+ [Mixer Profile]
+ NumarkN4.Mixer.changeCrossfaderContour.input
+ 0x80
+ 0x4B
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Mixer.channelInputSwitcherL.input
+ 0x90
+ 0x49
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Mixer.channelInputSwitcherR.input
+ 0x90
+ 0x4A
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Mixer.channelInputSwitcherL.input
+ 0x80
+ 0x49
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Mixer.channelInputSwitcherR.input
+ 0x80
+ 0x4A
+
+
+
+
+
+ [Master]
+ NumarkN4.Mixer.deckChangeL.input
+ 0xB0
+ 0x50
+
+
+
+ handles deck assignment led feedback right
+
+
+ [Master]
+ NumarkN4.Mixer.deckChangeR.input
+ 0xB0
+ 0x51
+
+
+
+ handles deck assignment led feedback left
+
+
+ [Channel1]
+ NumarkN4.Decks[1].playButton.input-
+ 0x91
+ 0x11
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].playButton.input
+ 0x92
+ 0x11
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].playButton.input-
+ 0x93
+ 0x11
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].playButton.input
+ 0x94
+ 0x11
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].playButton.input-
+ 0x81
+ 0x11
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].playButton.input
+ 0x82
+ 0x11
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].playButton.input-
+ 0x83
+ 0x11
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].playButton.input
+ 0x84
+ 0x11
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].syncButton.input
+ 0x91
+ 0x0F
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].syncButton.input
+ 0x92
+ 0x0F
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].syncButton.input
+ 0x93
+ 0x0F
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].syncButton.input
+ 0x94
+ 0x0F
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].syncButton.input
+ 0x81
+ 0x0F
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].syncButton.input
+ 0x82
+ 0x0F
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].syncButton.input
+ 0x83
+ 0x0F
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].syncButton.input
+ 0x84
+ 0x0F
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].tapButton.input
+ 0x91
+ 0x1E
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].tapButton.input
+ 0x92
+ 0x1E
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].tapButton.input
+ 0x93
+ 0x1E
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].tapButton.input
+ 0x94
+ 0x1E
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].tapButton.input
+ 0x81
+ 0x1E
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].tapButton.input
+ 0x82
+ 0x1E
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].tapButton.input
+ 0x83
+ 0x1E
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].tapButton.input
+ 0x84
+ 0x1E
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].keylockButton.input
+ 0x91
+ 0x1B
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].keylockButton.input
+ 0x92
+ 0x1B
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].keylockButton.input
+ 0x93
+ 0x1B
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].keylockButton.input
+ 0x94
+ 0x1B
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].keylockButton.input
+ 0x81
+ 0x1B
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].keylockButton.input
+ 0x82
+ 0x1B
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].keylockButton.input
+ 0x83
+ 0x1B
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].keylockButton.input
+ 0x84
+ 0x1B
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pitchRange.input
+ 0x91
+ 0x1A
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pitchRange.input
+ 0x92
+ 0x1A
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pitchRange.input
+ 0x93
+ 0x1A
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pitchRange.input
+ 0x94
+ 0x1A
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].jogWheelScratchEnable.input
+ 0x91
+ 0x2C
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].jogWheelScratchEnable.input
+ 0x81
+ 0x2C
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].jogWheelScratchEnable.input
+ 0x92
+ 0x2C
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].jogWheelScratchEnable.input
+ 0x82
+ 0x2C
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].jogWheelScratchEnable.input
+ 0x93
+ 0x2C
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].jogWheelScratchEnable.input
+ 0x83
+ 0x2C
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].jogWheelScratchEnable.input
+ 0x94
+ 0x2C
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].jogWheelScratchEnable.input
+ 0x84
+ 0x2C
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].jogWheelTurn.input
+ 0xB1
+ 0x20
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].jogWheelTurn.input
+ 0xB2
+ 0x20
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].jogWheelTurn.input
+ 0xB3
+ 0x20
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].jogWheelTurn.input
+ 0xB4
+ 0x20
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].shiftButton.input
+ 0x91
+ 0x12
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].shiftButton.input
+ 0x81
+ 0x12
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].shiftButton.input
+ 0x92
+ 0x12
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].shiftButton.input
+ 0x82
+ 0x12
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].shiftButton.input
+ 0x93
+ 0x12
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].shiftButton.input
+ 0x83
+ 0x12
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].shiftButton.input
+ 0x94
+ 0x12
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].shiftButton.input
+ 0x84
+ 0x12
+
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pitchBendMinus.input
+ 0x91
+ 0x18
+
+
+
+ pitchBendMinus left on
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pitchBendMinus.input
+ 0x92
+ 0x18
+
+
+
+ pitchBendMinus right on
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pitchBendMinus.input
+ 0x81
+ 0x18
+
+
+
+ pitchBendMinus right off
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pitchBendMinus.input
+ 0x82
+ 0x18
+
+
+
+ pitchBendMinus right off
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pitchBendPlus.input
+ 0x91
+ 0x19
+
+
+
+ pitchBendPlus left on
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pitchBendPlus.input
+ 0x92
+ 0x19
+
+
+
+ pitchBendPlus right on
+
+
+ [Channel1]
+ NumarkN4.Decks[1].pitchBendPlus.input
+ 0x81
+ 0x19
+
+
+
+ pitchBendPlus left off
+
+
+ [Channel2]
+ NumarkN4.Decks[2].pitchBendPlus.input
+ 0x82
+ 0x19
+
+
+
+ pitchBendPlus right off
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pitchBendMinus.input
+ 0x93
+ 0x18
+
+
+
+ pitchBendMinus left on
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pitchBendMinus.input
+ 0x94
+ 0x18
+
+
+
+ pitchBendMinus right on
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pitchBendMinus.input
+ 0x83
+ 0x18
+
+
+
+ pitchBendMinus right off
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pitchBendMinus.input
+ 0x84
+ 0x18
+
+
+
+ pitchBendMinus right off
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pitchBendPlus.input
+ 0x93
+ 0x19
+
+
+
+ pitchBendPlus left on
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pitchBendPlus.input
+ 0x94
+ 0x19
+
+
+
+ pitchBendPlus right on
+
+
+ [Channel3]
+ NumarkN4.Decks[3].pitchBendPlus.input
+ 0x83
+ 0x19
+
+
+
+ pitchBendPlus left off
+
+
+ [Channel4]
+ NumarkN4.Decks[4].pitchBendPlus.input
+ 0x84
+ 0x19
+
+
+
+ pitchBendPlus right off
+
+
+
+ [Master]
+ crossfader
+ 0xB0
+ 0x07
+
+
+
+
+
+
+ [Master]
+ crossfader
+ 0xB0
+ 0x27
+
+
+
+
+
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[1].inputLSB
+ 0xB0
+ 0x29
+
+
+
+ Channel1 EQ_LOW LSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[1].inputMSB
+ 0xB0
+ 0x09
+
+
+
+ Channel1 EQ_LOW MSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[1].inputLSB
+ 0xB0
+ 0x2E
+
+
+
+ Channel2 EQ_LOW LSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[1].inputMSB
+ 0xB0
+ 0x0E
+
+
+
+ Channel2 EQ_LOW MSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[1].inputLSB
+ 0xB0
+ 0x34
+
+
+
+ Channel3 EQ_LOW LSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[1].inputMSB
+ 0xB0
+ 0x14
+
+
+
+ Channel3 EQ_LOW MSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[1].inputLSB
+ 0xB0
+ 0x39
+
+
+
+
+ Channel4 EQ_LOW LSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[1].inputMSB
+ 0xB0
+ 0x19
+
+
+
+ Channel4 EQ_LOW MSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[2].inputLSB
+ 0xB0
+ 0x2A
+
+
+
+ Channel1 EQ_MID LSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[2].inputMSB
+ 0xB0
+ 0x0A
+
+
+
+ Channel1 EQ_MID MSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[2].inputLSB
+ 0xB0
+ 0x2F
+
+
+
+ Channel2 EQ_MID LSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[2].inputMSB
+ 0xB0
+ 0x0F
+
+
+
+ Channel2 EQ_MID MSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[2].inputLSB
+ 0xB0
+ 0x35
+
+
+
+ Channel3 EQ_MID LSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[2].inputMSB
+ 0xB0
+ 0x15
+
+
+
+ Channel3 EQ_MID MSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[2].inputLSB
+ 0xB0
+ 0x3A
+
+
+
+ Channel4 EQ_MID LSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[2].inputMSB
+ 0xB0
+ 0x1A
+
+
+
+ Channel4 EQ_MID MSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[3].inputLSB
+ 0xB0
+ 0x2B
+
+
+
+ Channel1 EQ_HIGH LSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].eqKnobs[3].inputMSB
+ 0xB0
+ 0x0B
+
+
+
+ Channel1 EQ_HIGH MSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[3].inputLSB
+ 0xB0
+ 0x30
+
+
+
+ Channel2 EQ_HIGH LSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].eqKnobs[3].inputMSB
+ 0xB0
+ 0x10
+
+
+
+ Channel2 EQ_HIGH MSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[3].inputLSB
+ 0xB0
+ 0x36
+
+
+
+ Channel3 EQ_HIGH LSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].eqKnobs[3].inputMSB
+ 0xB0
+ 0x16
+
+
+
+ Channel3 EQ_HIGH MSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[3].inputLSB
+ 0xB0
+ 0x3B
+
+
+
+ Channel4 EQ_HIGH LSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].eqKnobs[3].inputMSB
+ 0xB0
+ 0x1B
+
+
+
+ Channel4 EQ_HIGH MSB
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].gainKnob.inputLSB
+ 0xB0
+ 0x2C
+
+
+
+ Channel1 GAIN LSB
+
+
+ [EqualizerRack1_[Channel1]_Effect1]
+ NumarkN4.Decks[1].gainKnob.inputMSB
+ 0xB0
+ 0x0C
+
+
+
+ Channel1 GAIN MSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].gainKnob.inputLSB
+ 0xB0
+ 0x31
+
+
+
+ Channel2 GAIN LSB
+
+
+ [EqualizerRack1_[Channel2]_Effect1]
+ NumarkN4.Decks[2].gainKnob.inputMSB
+ 0xB0
+ 0x11
+
+
+
+ Channel2 GAIN MSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].gainKnob.inputLSB
+ 0xB0
+ 0x37
+
+
+
+ Channel3 GAIN LSB
+
+
+ [EqualizerRack1_[Channel3]_Effect1]
+ NumarkN4.Decks[3].gainKnob.inputMSB
+ 0xB0
+ 0x17
+
+
+
+ Channel3 GAIN MSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].gainKnob.inputLSB
+ 0xB0
+ 0x3C
+
+
+
+ Channel4 GAIN LSB
+
+
+ [EqualizerRack1_[Channel4]_Effect1]
+ NumarkN4.Decks[4].gainKnob.inputMSB
+ 0xB0
+ 0x1C
+
+
+
+ Channel4 GAIN MSB
+
+
+
+ [Channel1]
+ volume
+ 0xB0
+ 0x28
+
+
+
+
+ Channel1 Volume LSB
+
+
+ [Channel1]
+ volume
+ 0xB0
+ 0x08
+
+
+
+
+ Channel1 Volume MSB
+
+
+ [Channel2]
+ volume
+ 0xB0
+ 0x2D
+
+
+
+
+ Channel2 Volume LSB
+
+
+ [Channel2]
+ volume
+ 0xB0
+ 0x0D
+
+
+
+
+ Channel2 Volume MSB
+
+
+ [Channel3]
+ volume
+ 0xB0
+ 0x33
+
+
+
+
+ Channel3 Volume LSB
+
+
+ [Channel3]
+ volume
+ 0xB0
+ 0x13
+
+
+
+
+ Channel3 Volume MSB
+
+
+ [Channel4]
+ volume
+ 0xB0
+ 0x38
+
+
+
+
+ Channel4 Volume LSB
+
+
+ [Channel4]
+ volume
+ 0xB0
+ 0x18
+
+
+
+
+ Channel4 Volume MSB
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].bpmSlider.inputMSB
+ 0xB1
+ 0x01
+
+
+
+
+
+ [Channel1]
+ NumarkN4.Decks[1].bpmSlider.inputLSB
+ 0xB1
+ 0x21
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].bpmSlider.inputMSB
+ 0xB2
+ 0x01
+
+
+
+
+
+ [Channel2]
+ NumarkN4.Decks[2].bpmSlider.inputLSB
+ 0xB2
+ 0x21
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].bpmSlider.inputMSB
+ 0xB3
+ 0x01
+
+
+
+
+
+ [Channel3]
+ NumarkN4.Decks[3].bpmSlider.inputLSB
+ 0xB3
+ 0x21
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].bpmSlider.inputMSB
+ 0xB4
+ 0x01
+
+
+
+
+
+ [Channel4]
+ NumarkN4.Decks[4].bpmSlider.inputLSB
+ 0xB4
+ 0x21
+
+
+
+
+
+
+
diff --git a/res/controllers/Numark-N4-scripts.js b/res/controllers/Numark-N4-scripts.js
index 186b0578ac04..2172a594f7d0 100644
--- a/res/controllers/Numark-N4-scripts.js
+++ b/res/controllers/Numark-N4-scripts.js
@@ -1,213 +1,681 @@
-NumarkN4 = new Controller();
-
-NumarkN4.currentDeck = function (group) {
- if (group == "[Channel1]")
- return 0;
- else if (group == "[Channel2]")
- return 1;
- print("Invalid group : " + group);
- return -1; // error
-}
+var NumarkN4 = {};
-NumarkN4.currentDeck2 = function (group) {
- if (group == "[Channel1]")
- return "[Channel1]";
- else if (group == "[Channel2]")
- return "[Channel2]";
-
- print("Invalid group : " + group);
- return -1; // error
-}
+NumarkN4.scratchSettings = {
+ 'alpha': 1.0 / 8,
+ 'beta': 1.0 / 8 / 32,
+ 'jogResolution': 600,
+ 'vinylSpeed': 33 + 1 / 3,
+};
-NumarkN4.init = function(id) { // called when the MIDI device is opened & set up
- NumarkN4.id = id; // Store the ID of this device for later use
- midi.sendShortMsg(0xb0, 0x39, 0x01);
- //midi.sendShortMsg(0xB0, 0x39, 0x00);
- NumarkN4.directoryMode = false;
-
- NumarkN4.scratchMode = [false, false];
- NumarkN4.scratchTimer = [-1, -1];
-
- NumarkN4.manualLooping = [false, false];
- NumarkN4.touched = [false, false];
-
- NumarkN4.leds = [
- // Common
- { "directory": 0x73, "file": 0x72 },
- // Deck 1
-//0x11 = deck 3 light
-//0x1e = deck 1 triangle light
-//0x1f = deck 2 triangle light
-//0x20 = deck 3 triangle light
-//0x28 = deck 4 light
-//0x39 = all lights around the outside
-//0x40 = headphone cue button 1
-//0x41 = headphone cue button 2
-//0x42 = headphone cue button 3
-//0x44 = vid fade 1 deck 1
-//0x45 = vid fade 1 deck 2
-//0x46 = vid fade 2 deck 1
-//0x47 = vid fade 2 deck 2
-//0x48 = vid fade 3 deck 1
-//0x49 = vid fade 3 deck 2
-//0x4a = vid fade 4 deck 1
-//0x4b = vid fade 4 deck 2
-//0x50 = deck 1/3
-//0x51 = deck 2/4
-//0x52 =
-
- { "rate": 0x70, "scratchMode": 0x39, "manualLoop": 0x61, "loopIn": 0x53, "loopOut": 0x54, "reLoop": 0x55 },
- // Deck 2
- { "rate": 0x71, "scratchMode": 0x30, "manualLoop": 0x62, "loopIn": 0x56, "loopOut": 0x57, "reLoop": 0x58 }
- ];
- NumarkN4.setLED(NumarkN4.leds[0]["file"], true);
-}
+NumarkN4.searchAmplification = 5; // multiplier for the jogwheel when the search button is held down.
-NumarkN4.setLED = function(value, status) {
- if (status) {
- status = 0x64;
- } else {
- status = 0x00;
- }
- midi.sendShortMsg(0xB0, value, status);
-}
+NumarkN4.warnAfterTime = 30; // Acts like the "End of Track warning" setting within the waveform settings.
-NumarkN4.light = function(channel, control, value, status, group) {
+NumarkN4.blinkInterval=1000; //blinkInterval for the triangular Leds over the channels in milliseconds.
-midi.sendShortMsg(0xbf, value, 0x7f);
+NumarkN4.encoderResolution=0.05; // 1/encoderResolution = number of steps going from 0% to 100%
-}
+NumarkN4.resetHotCuePageOnTrackLoad=true; // resets the page of the Hotcue back to 1 after loading a new track.
-NumarkN4.scratch_sensitivity = 80;
-
-NumarkN4.jogWheel = function(channel, control, value, status, group) {
- var deck = NumarkN4.groupToDeck(group);
- var adjustedJog = parseFloat(value);
- var posNeg = 1;
- if (adjustedJog > 63) { // Counter-clockwise
- posNeg = -1;
- adjustedJog = value - 128;
- }
-
- if (NumarkN4.scratchMode[deck-1]) {
- if (NumarkN4.scratchTimer[deck-1] == -1) {
- engine.scratchEnable(deck, 128, 33+1/3, 1.0/8, (1.0/8)/32);
- } else {
- engine.stopTimer(NumarkN4.scratchTimer[deck-1]);
- }
- engine.scratchTick(deck, adjustedJog);
- NumarkN4.scratchTimer[deck-1] = engine.beginTimer(20, "NumarkN4.jogWheelStopScratch(" + deck + ")", true);
- } else {
- var gammaInputRange = 23; // Max jog speed
- var maxOutFraction = 0.5; // Where on the curve it should peak; 0.5 is half-way
- var sensitivity = 0.5; // Adjustment gamma
- var gammaOutputRange = 3; // Max rate change
- if (engine.getValue(group,"play")) {
- adjustedJog = posNeg * gammaOutputRange * Math.pow(Math.abs(adjustedJog) / (gammaInputRange * maxOutFraction), sensitivity);
- } else {
- adjustedJog = gammaOutputRange * adjustedJog / (gammaInputRange * maxOutFraction);
- }
- engine.setValue(group, "jog", adjustedJog);
- }
-}
+NumarkN4.cueReverseRoll=true;
-NumarkN4.jogWheelStopScratch = function(deck) {
- NumarkN4.scratchTimer[deck-1] = -1;
- engine.scratchDisable(deck);
-}
+// possible ranges (0.0..3.0 where 0.06=6%)
+NumarkN4.rateRanges = [0, // default (gets set via script later; don't modifify)
+ 0.06,// one semitone
+ 0.24,// for maximum freedom
+ ];
-NumarkN4.toggleScratchMode = function(channel, control, value, status, group) {
- var deck = NumarkN4.groupToDeck(group);
- // Toggle setting and light
- if (value) {
- if (NumarkN4.scratchMode[deck-1]) {
- NumarkN4.scratchMode[deck-1] = false;
- } else {
- NumarkN4.scratchMode[deck-1] = true;
- }
-
- //NumarkN4.setLED(NumarkN4.leds[deck]["scratchMode"], NumarkN4.scratchMode[deck-1]);
- }
+//
+// CONSTANTS DO NOT CHANGE (if you don't know what you are doing)
+//
+NumarkN4.QueryStatusMessage=[0xF0,0x00,0x01,0x3F,0x7F,0x47,0x60,0x00,0x01,0x54,0x01,0x00,0x00,0x00,0x00,0xF7];
+//NumarkN4.ShutoffSequence=[0xF0,0x00,0x01,0x3F,0x7F,0x47,0xB0,0x39,0x00,0x01,0xF7]; // Invalid Midibyte?
-}
+NumarkN4.vinylTouched = [false,false,false,false];
+NumarkN4.globalShift = false;
-NumarkN4.groupToDeck = function(group) {
- var matches = group.match(/^\[Channel(\d+)\]$/);
- if (matches == null) {
- return -1;
- } else {
- return matches[1];
- }
-}
-NumarkN4.SelectTrack = function(channel, control, value, status, group) {
- if (value == 0x01) {
- engine.setValue("[Playlist]","SelectNextTrack",1);
- }
- if (value == 0x7F) {
- engine.setValue("[Playlist]","SelectPrevTrack",1);
- }
-}
+components.Encoder.prototype.input = function (channel, control, value, status, group) {
+ this.inSetParameter(
+ this.inGetParameter()+(
+ (value===0x01)?
+ NumarkN4.encoderResolution:
+ -NumarkN4.encoderResolution
+ )
+ );
+};
-NumarkN4.menuNext = function (channel, control, value, status, group) {
- if (value == 0x7F) {
- engine.setValue("[Playlist]","SelectNextPlaylist",1);
- }
+components.Component.prototype.send = function (value) {
+ // This Override is supposed to make integration automatic assignment of elements easier.
+ // Right now it just allows specifying the input and output bytes (even though the input bytes dont do anything right now.)
+ if (this.midi === undefined || this.midi[0] === undefined || this.midi[1] === undefined) {
+ return;
+ }
+ if (this.midi[2]===undefined){//check if output channel/type not explicitly defined
+ this.midi[2]=this.midi[0];
+ }
+ if (this.midi[3]===undefined){//check if output control not explicitly defined
+ this.midi[3]=this.midi[1];
+ }
+ midi.sendShortMsg(this.midi[2], this.midi[3], value);
+ if (this.sendShifted) {
+ if (this.shiftChannel) {
+ midi.sendShortMsg(this.midi[2] + this.shiftOffset, this.midi[3], value);
+ } else if (this.shiftControl) {
+ midi.sendShortMsg(this.midi[2], this.midi[3] + this.shiftOffset, value);
+ }
+ }
+};
-}
-NumarkN4.menuPrev = function (channel, control, value, status, group) {
- if (value == 0x7F) {
- engine.setValue("[Playlist]","SelectPrevPlaylist",1);
- }
-}
+NumarkN4.init = function (id) {
+ NumarkN4.xFaderSettings = {
+ mode: engine.getValue("[Mixer Profile]", "xFaderMode"),
+ curve: engine.getValue("[Mixer Profile]","xFaderCurve"),
+ calibration: engine.getValue("[Mixer Profile]","xFaderCalibration")
+ }
+ NumarkN4.setCrossfaderSettings(NumarkN4.xFaderSettings);
+ NumarkN4.rateRanges[0]=engine.getValue("[Channel1]","rateRange");
+ NumarkN4.Decks=[];
+ for (var i=1;i<=4;i++){
+ // Array is based on 1 because it makes more sense in the XML
+ NumarkN4.Decks[i] = new NumarkN4.Deck(i);
-NumarkN4.cue = function (channel, control, value, status, group) {
- var currentlyPlaying = engine.getValue(NumarkN4.currentDeck2(group),"play");
- if ((currentlyPlaying == 1) & (value == 0x7F)) {
- engine.setValue(NumarkN4.currentDeck2(group),"cue_default",1);
- }
- else if ((currentlyPlaying == 0) & (value == 0x7F)) {
- engine.setValue(NumarkN4.currentDeck2(group),"cue_default",1);
- }
- else {
- engine.setValue(NumarkN4.currentDeck2(group),"cue_default",0);
- }
-}
+ }
-NumarkN4.touch = function (channel, control, value, status, group) {
-var deck = NumarkN4.groupToDeck(group);
-var currentlyPlaying = engine.getValue(NumarkN4.currentDeck2(group),"play");
- if ((currentlyPlaying == 1) & (value == 0x7F & (NumarkN4.touched[deck-1] == false))) {
- engine.setValue(NumarkN4.currentDeck2(group),"play",0);
- NumarkN4.touched[deck-1] = true;
- }
- if ((currentlyPlaying == 0) & (value == 0x00) & (NumarkN4.touched[deck-1] == true)) {
- engine.setValue(NumarkN4.currentDeck2(group),"play",1);
- NumarkN4.touched[deck-1] = false;
- }
-}
+ NumarkN4.Mixer = new NumarkN4.MixerTemplate();
-//0x40 = headphone cue button 1
-//0x41 = headphone cue button 2
-NumarkN4.headcue = function (channel, control, value, status, group) {
-var deck = NumarkN4.groupToDeck(group);
-//head 1 on
-if ((status == 0x90) & (control == 0x31)){
-midi.sendShortMsg(0xB0, 0x41, 0x00);
-engine.setValue(NumarkN4.currentDeck2(group),"pfl",1);
-}
-//head 1 off
-if ((status == 0x80) & (control == 0x31)){
-engine.setValue(NumarkN4.currentDeck2(group),"pfl",0);
-}
-//head 2
-if ((status == 0x90) & (control == 0x32)){
-midi.sendShortMsg(0xB0, 0x40, 0x00);
-engine.setValue(NumarkN4.currentDeck2(group),"pfl",1);
-}
-//head 2 off
-if ((status == 0x80) & (control == 0x32)){
-engine.setValue(NumarkN4.currentDeck2(group),"pfl",0);
-}
+ //query controller for component status
+ midi.sendSysexMsg(NumarkN4.QueryStatusMessage,NumarkN4.QueryStatusMessage.length)
+
+};
+
+NumarkN4.setCrossfaderSettings = function (settingsStruct) {
+ engine.setValue("[Mixer Profile]","xFaderMode",settingsStruct.mode);
+ engine.setValue("[Mixer Profile]","xFaderCurve",settingsStruct.curve);
+ engine.setValue("[Mixer Profile]","xFaderCalibration",settingsStruct.calibration);
}
+
+NumarkN4.topContainer = function (channel) {
+ this.group = '[Channel'+channel+']';
+ var theContainer = this;
+
+ this.btnEffect1 = new components.Button({
+ midi: [0x90+channel,0x13,0xB0+channel,0x0B],
+ shift: function () {
+ this.group="[EffectRack1_EffectUnit1]";
+ this.type=components.Button.prototype.types.toggle;
+ this.inKey="group_[Channel"+channel+"]_enable";
+ this.outKey="group_[Channel"+channel+"]_enable";
+ },
+ unshift: function () {
+ this.group=theContainer.group;
+ this.type=components.Button.prototype.types.push;
+ this.inKey="loop_in";
+ this.outKey="loop_in";
+ },
+ });
+ this.btnEffect2 = new components.Button({
+ midi: [0x90+channel,0x14,0xB0+channel,0x0C],
+ shift: function () {
+ this.group="[EffectRack1_EffectUnit2]";
+ this.type=components.Button.prototype.types.toggle;
+ this.inKey="group_[Channel"+channel+"]_enable";
+ this.outKey="group_[Channel"+channel+"]_enable";
+ },
+ unshift: function () {
+ this.group=theContainer.group;
+ this.type=components.Button.prototype.types.push;
+ this.inKey="loop_out";
+ this.outKey="loop_out";
+ },
+ });
+ this.btnSample3 = new components.Button({
+ midi: [0x90+channel,0x15,0xB0+channel,0x0D],
+ shift: function () {
+ this.type=components.Button.prototype.types.toggle;
+ this.inKey="slip_enabled";
+ this.outKey="slip_enabled";
+ },
+ unshift: function () {
+ this.type=components.Button.prototype.types.push;
+ this.inKey="beatloop_activate";
+ this.outKey="beatloop_activate";
+ },
+ });
+ this.btnSample4 = new components.Button({
+ midi: [0x90+channel,0x16,0xB0+channel,0x0E],
+ outKey: "loop_enabled",
+ shift: function () {
+ this.type=components.Button.prototype.types.toggle;
+ this.inKey="reloop_andstop";
+ },
+ unshift: function () {
+ this.type=components.Button.prototype.types.push;
+ this.inKey="reloop_toggle";
+ },
+ });
+ // custom Hotcue Buttons
+ this.hotcueButtons=[];
+
+ for (var counter=0;counter<=3;counter++){
+ this.hotcueButtons[counter] = new components.HotcueButton({
+ midi: [0x90+channel,0x27+counter,0xB0+channel,0x18+counter],
+ number: counter+1,
+ });
+ }
+ this.encFxParam1 = new components.Encoder({
+ midi:[0xB0+channel,0x57],
+ group: "[EffectRack1_EffectUnit1]",
+ shift: function () {
+ this.inKey="mix";
+ },
+ unshift: function () {
+ this.inKey="super1";
+ },
+ });
+ this.encFxParam2 = new components.Encoder({
+ midi:[0xB0+channel,0x58],
+ group: "[EffectRack1_EffectUnit2]",
+ shift: function () {
+ this.inKey="mix";
+ },
+ unshift: function () {
+ this.inKey="super1";
+ },
+ });
+ this.encSample3 = new components.Encoder({
+ midi: [0xB0+channel,0x5A],
+ hotCuePage: 0,
+ applyHotcuePage: function (layer, displayFeedback) {
+ // ES3 doesn't allow default values in the function signature
+ // Could be replaced after migration to QJSEngine by "displayFeedback=true"
+ // in the function argments.
+ if (displayFeedback == undefined) {
+ displayFeedback = true;
+ }
+ layer = Math.max(Math.min(layer,3),0); // clamp layer value to [0;3] range
+ this.hotCuePage = layer;
+ if (this.timer !== 0) {
+ engine.stopTimer(this.timer);
+ this.timer = 0;
+ }
+ var number = 0;
+ for (var i=0;i normalized offset
+ inValueScale: function (value) {
+ if (value > this.max*0.469970703125 && value < this.max*0.506591796875) {
+ return (value + this.max*0.015625) / this.max;
+ } else {
+ return value / this.max;
+ }
+ },
+ });
+ }
+ // for some reason the gainKnobs don't suffer the same issues as the EQKnobs
+ this.gainKnob = new components.Pot({
+ midi: [0xB0, 0x2C + 5*(channel-1)],
+ shift: function () {
+ this.group="[QuickEffectRack1_"+theDeck.group+"]";
+ this.inKey="super1";
+ },
+ unshift: function () {
+ this.group=theDeck.group;
+ this.inKey="pregain";
+ }
+ })
+ this.shiftButton = new components.Button({
+ midi: [0x90+channel,0x12,0xB0+channel,0x15],
+ type: components.Button.prototype.types.powerWindow,
+ state: false, //custom property
+ inToggle: function () {
+ this.state=!this.state;
+ if (this.state) {
+ theDeck.shift();
+ NumarkN4.Mixer.shift();
+ } else {
+ theDeck.unshift();
+ NumarkN4.Mixer.unshift();
+ }
+ this.output(this.state);
+ theDeck.topContainer.reconnectComponents(function (component) {
+ if (component.group === undefined) {
+ component.group = this.group;
+ }
+ });
+ },
+ });
+
+ // NOTE: THE ORIENATION BUTTONS BEHAVE REALLY WIERD AND THE FOLLOWING IS REALLY CONFUSING BUT WORKS!
+ this.orientationButtonLeft = new components.Button({
+ midi:[0x90,0x32+channel*2,0xB0,0x42+channel*2],
+ key: "orientation",
+ input: function (channel, control, value, status, group) {
+ if (!this.ignoreNext) {
+ if (value===0x7F) {
+ this.inSetValue(0);
+ theDeck.orientationButtonRight.ignoreNextOff = true;
+ this.ignoreNextOff=false;
+ } else if (!this.ignoreNextOff && value===0x00) {
+ this.inSetValue(1);
+ }
+ } else {this.ignoreNext=false;}
+ },
+ output: function (value, group, control) {
+ this.send(value===0?0x7F:0x00);
+ this.ignoreNext=true;
+ if (value===0){theDeck.orientationButtonRight.ignoreNextOff = true;}
+ },
+ });
+ this.orientationButtonRight = new components.Button({
+ midi:[0x90,0x33+channel*2,0xB0,0x43+channel*2],
+ key: "orientation",
+ input: function (channel, control, value, status, group) {
+ if (!this.ignoreNext) {
+ if (value===0x7F) {
+ this.inSetValue(2);
+ theDeck.orientationButtonLeft.ignoreNextOff = true;
+ this.ignoreNextOff=false;
+ } else if (!this.ignoreNextOff && value===0x00) {
+ this.inSetValue(1);
+ }
+ } else {this.ignoreNext=false;}
+ },
+ output: function (value, group, control) {
+ this.send(value===2?0x7F:0x00);
+ if (value===2){theDeck.orientationButtonLeft.ignoreNextOff = true;}
+ this.ignoreNext=true;
+ },
+ });
+
+ this.pflButton = new components.Button({
+ midi: [0x90,0x30+channel,0xB0,0x3F+channel],
+ key: "pfl",
+ // The controller echos every change to the pfl lights which would cause
+ // an infinite feedback loop (flicker)
+ // this workaround uses a timer (100ms) to ignore the echoing messages.
+ flickerSafetyTimeout: true,
+ input: function (channel, control, value, status, group) {
+ if (this.flickerSafetyTimeout) {
+ this.flickerSafetyTimeout=false;
+ value/=0x7F;
+ if (this.inGetParameter()!==value){
+ this.inSetParameter(value);
+ }
+ engine.beginTimer(100,function () {
+ this.flickerSafetyTimeout=true;
+ },true);
+ }
+ },
+ });
+ this.loadButton = new components.Button({
+ midi:[0x90+channel,0x06],
+ shift: function () {this.inKey="eject";},
+ unshift: function () {this.inKey="LoadSelectedTrack";},
+ });
+ this.playButton = new components.PlayButton({
+ midi: [0x90+channel,0x11,0xB0+channel,0x09],
+ });
+
+ this.cueButton = new components.CueButton({
+ midi: [0x90+channel,0x10,0xB0+channel,0x08],
+ reverseRollOnShift: NumarkN4.cueReverseRoll,
+ });
+
+ this.jogWheelScratchEnable = new components.Button({
+ midi:[0x90+channel,0x2C],
+ scratchEnabled:true,
+ input: function (channelmidi, control, value, status, group) {
+ if (this.isPress(channel, control, value, status)&&this.scratchEnabled) {
+ engine.scratchEnable(channel,
+ NumarkN4.scratchSettings.jogResolution,
+ NumarkN4.scratchSettings.vinylSpeed,
+ NumarkN4.scratchSettings.alpha,
+ NumarkN4.scratchSettings.beta);
+ } else {
+ engine.scratchDisable(channel);
+ }
+ },
+ });
+
+ this.searchButton = new components.Button({
+ midi: [0x90+channel,0x00,0xB0+channel,0x12],
+ shift: function () {
+ this.input = function (channelmidi, control, value, status, group) {
+ if (this.isPress(channelmidi, control, value, status)) {
+ theDeck.isSearching=!theDeck.isSearching;
+ this.output(theDeck.isSearching?0x7F:0x00);
+ }
+ };
+ this.output(theDeck.isSearching?0x7F:0x00);
+ },
+ unshift: function () {
+ this.input = function (channelmidi, control, value, status, group) {
+ if (this.isPress(channelmidi, control, value, status)) {
+ theDeck.jogWheelScratchEnable.scratchEnabled=!theDeck.jogWheelScratchEnable.scratchEnabled;
+ this.output(theDeck.jogWheelScratchEnable.scratchEnabled?0x7F:0x00);
+ }
+ };
+ this.output(theDeck.jogWheelScratchEnable.scratchEnabled?0x7F:0x00);
+ },
+ });
+ this.jogWheelTurn = new components.Pot({
+ midi: [0xB0+channel,0x2C],
+ inKey: "jog",
+ group: theDeck.group,
+ input: function (channelmidi, control, value, status, group) {
+ value=(value<0x40?value:value-0x7F); // centers values at 0
+ if (theDeck.isSearching) {value*=NumarkN4.searchAmplification;}
+ if (engine.isScratching(channel)) {
+ engine.scratchTick(channel,value);
+ } else {
+ this.inSetValue(value);
+ }
+ },
+ });
+
+ this.manageChannelIndicator = function () {
+ this.alternating=!this.alternating; //mimics a static variable
+ this.duration=engine.getParameter(theDeck.group, "duration");
+ // checks if the playposition is in the warnTimeFrame
+ if (engine.getParameter(theDeck.group, "playposition") * this.duration > (this.duration - NumarkN4.warnAfterTime)) {
+ midi.sendShortMsg(0xB0,0x1D+channel, this.alternating?0x7F:0x0);
+ } else {
+ midi.sendShortMsg(0xB0,0x1D+channel, 0x7F);
+ }
+ };
+ engine.makeConnection(this.group, "track_loaded", function (value) {
+ if (value === 0) {
+ // track ejected, stop timer and manager
+ engine.stopTimer(theDeck.blinkTimer);
+ theDeck.blinkTimer=0;
+ return; // return early so no new timer gets created.
+ }
+ //timer is more efficent is this case than a callback because it would be called too often.
+ theDeck.blinkTimer=engine.beginTimer(NumarkN4.blinkInterval,theDeck.manageChannelIndicator);
+ });
+ this.pitchBendMinus = new components.Button({
+ midi: [0x90+channel,0x18,0xB0+channel,0x3D],
+ key: "rate_temp_down",
+ shift: function (){
+ this.inkey = "rate_temp_down_small";
+ },
+ unshift: function () {
+ this.inkey = "rate_temp_down";
+ }
+ });
+ this.pitchBendPlus = new components.Button({
+ midi: [0x90+channel,0x19,0xB0+channel,0x3C],
+ key : "rate_temp_up",
+ shift: function (){
+ this.inkey = "rate_temp_up_small";
+ },
+ unshift: function () {
+ this.inkey = "rate_temp_up";
+ }
+ });
+ this.syncButton = new components.SyncButton({
+ midi: [0x90+channel,0x0F,0xB0+channel,0x07],
+ });
+ this.tapButton = new components.Button({
+ midi: [0x90+channel,0x1E,0xB0+channel,0x16],
+ bpm: [],
+ input: function (channelmidi, control, value, status, group) {
+ if (this.isPress(channelmidi, control, value, status)) {
+ bpm.tapButton(channel);
+ }
+ this.output(value);
+ },
+ });
+
+ this.keylockButton = new components.Button({
+ midi: [0x90+channel,0x1B,0xB0+channel,0x10],
+ type: components.Button.prototype.types.toggle,
+ shift: function () {
+ // quantize is already handled by the components syncButton
+ this.inKey="sync_key";
+ this.outKey="sync_key";
+ },
+ unshift: function () {
+ this.inKey="keylock";
+ this.outKey="keylock";
+ }
+ });
+ this.bpmSlider = new components.Pot({
+ midi: [0xB0+channel,0x01,0xB0+channel,0x37], //only specifing input MSB
+ inKey: "rate",
+ group: theDeck.group,
+ invert: false,
+ });
+ this.pitchLedHandler = engine.makeConnection(this.group,"rate",function (value){
+ // Turns on when rate slider is centered
+ midi.sendShortMsg(0xB0+channel, 0x37, value===0 ? 0x7F : 0x00);
+ });
+ this.pitchLedHandler.trigger();
+
+
+ this.pitchRange = new components.Button({
+ midi: [0x90+channel,0x1A,0xB0+channel,0x1C],
+ key: "rateRange",
+ ledState: false,
+ input: function () {
+ if (theDeck.rateRangeEntry===NumarkN4.rateRanges.length){
+ theDeck.rateRangeEntry=0;
+ }
+ this.inSetValue(NumarkN4.rateRanges[theDeck.rateRangeEntry++]);
+ },
+ // NOTE: Just toggles to provide some visual Feedback.
+ output: function () {
+ this.send(this.ledState);
+ this.ledState=!this.ledState;
+ },
+ });
+
+ this.reconnectComponents(function (c) {
+ if (c.group === undefined) {
+ // 'this' inside a function passed to reconnectComponents refers to the ComponentContainer
+ // so 'this' refers to the custom Deck object being constructed
+ c.group = this.currentDeck;
+ }
+ });
+ this.shutdown = function () {
+ this.topContainer.shutdown();
+ this.pitchLedHandler.disconnect();
+ midi.sendShortMsg(0xB0+channel,0x37,0); // turn off pitchLED
+ this.pitchRange.send(0);
+ this.keylockButton.send(0);
+ this.searchButton.send(0);
+ this.tapButton.send(0);
+ this.syncButton.send(0);
+ this.pitchBendPlus.send(0);
+ this.pitchBendMinus.send(0);
+ this.cueButton.send(0);
+ this.playButton.send(0);
+ this.shiftButton.send(0);
+ if (theDeck.blinkTimer != 0) {
+ engine.stopTimer(theDeck.blinkTimer);
+ }
+ midi.sendShortMsg(0xB0,0x1D+channel,0); // turn off small triangle above LOAD button.
+ }
+};
+
+NumarkN4.Deck.prototype = new components.Deck();
+
+NumarkN4.shutdown = function () {
+ for (var i=1;i<=4;i++) {
+ // View Definition of Array for explanation.
+ NumarkN4.Decks[i].shutdown();
+ }
+ // reset crossfader parameters to user preferences.
+ NumarkN4.setCrossfaderSettings(NumarkN4.xFaderSettings);
+ // midi.sendSysexMsg(NumarkN4.ShutoffSequence,NumarkN4.ShutoffSequence.length);
+};