Merge lp:~zestoi/mixxx/controller_scripts into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Zestoi
Status: Merged
Merged at revision: 3213
Proposed branch: lp:~zestoi/mixxx/controller_scripts
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 3109 lines (+3045/-2)
9 files modified
mixxx/res/controllers/DJ-Tech CDJ-101.midi.xml (+196/-0)
mixxx/res/controllers/DJ-Tech DJM-101.midi.xml (+204/-0)
mixxx/res/controllers/DJ-Tech-CDJ-101-scripts.js (+245/-0)
mixxx/res/controllers/DJ-Tech-DJM-101-scripts.js (+110/-0)
mixxx/res/controllers/Hercules DJ Console Mk2.cntrlr.xml (+13/-0)
mixxx/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js (+611/-0)
mixxx/res/controllers/Novation Launchpad.midi.xml (+736/-0)
mixxx/res/controllers/Novation-Launchpad-scripts.js (+819/-0)
mixxx/res/controllers/common-controller-scripts.js (+111/-2)
To merge this branch: bzr merge lp:~zestoi/mixxx/controller_scripts
Reviewer Review Type Date Requested Status
Mixxx Development Team Pending
Review via email: mp+107519@code.launchpad.net

Description of the change

new controller mappings:

* hercules dj console mk2 (hid)
* djtech cdj101
* djtech djm101
* novation launchpad (full led feedback and a "virtual mixer" page)

updates to common-controller-scripts.js:

* new effects functions: script.spinback(), script.brake(), script.spinbackDefault(), script.brakeDefault()

* fix to script.pitch() as it wasn't returning the value from script.midiPitch() only calling it

To post a comment you must log in.
lp:~zestoi/mixxx/controller_scripts updated
3210. By Owen Williams

Fix rate range setting not getting saved properly (float equality testing fail)

3211. By RJ Skerry-Ryan

Use track-ids instead of TrackPointers to keep the recent tracks window.

3212. By RJ Skerry-Ryan

Merging from lp:~zestoi/mixxx/spinback_brake

3213. By RJ Skerry-Ryan

Merging from lp:~zestoi/mixxx/controller_scripts

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'mixxx/res/controllers/DJ-Tech CDJ-101.midi.xml'
--- mixxx/res/controllers/DJ-Tech CDJ-101.midi.xml 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/DJ-Tech CDJ-101.midi.xml 2012-05-26 14:59:19 +0000
@@ -0,0 +1,196 @@
1<?xml version='1.0' encoding='utf-8'?>
2<MixxxControllerPreset schemaVersion="1">
3 <info>
4 <name>DJTech CDJ 101</name>
5 <author>zestoi</author>
6 <description>Select midi channel 1 or 2 on the CDJ101 to select which deck to control in Mixxx. Hold down the push encoder for additional controls.</description>
7 </info>
8 <controller id="DJ-Tech CDJ-101">
9 <scriptfiles>
10 <file filename="DJ-Tech-CDJ-101-scripts.js" functionprefix="DJTechCDJ101"/>
11 </scriptfiles>
12
13 <controls>
14
15 <!-- midi channel 1 for deck 1 -->
16
17 <!-- play/cue -->
18
19 <control>
20 <group>[Channel1]</group>
21 <key>DJTechCDJ101.play</key>
22 <status>0x90</status>
23 <midino>0x2a</midino>
24 <options>
25 <Script-Binding/>
26 </options>
27 </control>
28
29 <control>
30 <group>[Channel1]</group>
31 <key>DJTechCDJ101.cue</key>
32 <status>0x90</status>
33 <midino>0x2b</midino>
34 <options>
35 <Script-Binding/>
36 </options>
37 </control>
38
39 <!-- jog -->
40
41 <control>
42 <group>[Channel1]</group>
43 <status>0x90</status>
44 <midino>0x20</midino>
45 <key>DJTechCDJ101.jogtouch</key>
46 <options>
47 <Script-Binding/>
48 </options>
49 </control>
50
51 <control>
52 <group>[Channel1]</group>
53 <status>0xb0</status>
54 <midino>0x35</midino>
55 <key>DJTechCDJ101.jogouter</key>
56 <options>
57 <Script-Binding/>
58 </options>
59 </control>
60
61 <control>
62 <group>[Channel1]</group>
63 <status>0xb0</status>
64 <midino>0x36</midino>
65 <key>DJTechCDJ101.jogtop</key>
66 <options>
67 <Script-Binding/>
68 </options>
69 </control>
70
71 <!-- pitch -->
72
73 <control>
74 <status>0xe0</status>
75 <group>[Channel1]</group>
76 <key>DJTechCDJ101.pitch</key>
77 <options>
78 <Script-Binding/>
79 </options>
80 </control>
81
82 <!-- track browse/load -->
83
84 <control>
85 <group>[Channel1]</group>
86 <key>DJTechCDJ101.push</key>
87 <status>0x90</status>
88 <midino>0x1F</midino>
89 <options>
90 <Script-Binding/>
91 </options>
92 </control>
93
94 <control>
95 <group>[Channel1]</group>
96 <key>DJTechCDJ101.browse</key>
97 <status>0xB0</status>
98 <midino>0x38</midino>
99 <options>
100 <Script-Binding/>
101 </options>
102 </control>
103
104 <!-- midi channel 2 for deck 2 -->
105
106 <!-- play/cue -->
107
108 <control>
109 <group>[Channel2]</group>
110 <key>DJTechCDJ101.play</key>
111 <status>0x91</status>
112 <midino>0x2a</midino>
113 <options>
114 <Script-Binding/>
115 </options>
116 </control>
117
118 <control>
119 <group>[Channel2]</group>
120 <key>DJTechCDJ101.cue</key>
121 <status>0x91</status>
122 <midino>0x2b</midino>
123 <options>
124 <Script-Binding/>
125 </options>
126 </control>
127
128 <!-- jog -->
129
130 <control>
131 <group>[Channel2]</group>
132 <status>0x91</status>
133 <midino>0x20</midino>
134 <key>DJTechCDJ101.jogtouch</key>
135 <options>
136 <Script-Binding/>
137 </options>
138 </control>
139
140 <control>
141 <group>[Channel2]</group>
142 <status>0xb1</status>
143 <midino>0x35</midino>
144 <key>DJTechCDJ101.jogouter</key>
145 <options>
146 <Script-Binding/>
147 </options>
148 </control>
149
150 <control>
151 <group>[Channel2]</group>
152 <status>0xb1</status>
153 <midino>0x36</midino>
154 <key>DJTechCDJ101.jogtop</key>
155 <options>
156 <Script-Binding/>
157 </options>
158 </control>
159
160 <!-- pitch -->
161
162 <control>
163 <status>0xe1</status>
164 <group>[Channel2]</group>
165 <key>DJTechCDJ101.pitch</key>
166 <options>
167 <Script-Binding/>
168 </options>
169 </control>
170
171 <!-- track browse/load -->
172
173 <control>
174 <group>[Channel2]</group>
175 <key>DJTechCDJ101.push</key>
176 <status>0x91</status>
177 <midino>0x1F</midino>
178 <options>
179 <Script-Binding/>
180 </options>
181 </control>
182
183 <control>
184 <group>[Channel1]</group>
185 <key>DJTechCDJ101.browse</key>
186 <status>0xB1</status>
187 <midino>0x38</midino>
188 <options>
189 <Script-Binding/>
190 </options>
191 </control>
192
193 </controls>
194
195 </controller>
196</MixxxControllerPreset>
0197
=== added file 'mixxx/res/controllers/DJ-Tech DJM-101.midi.xml'
--- mixxx/res/controllers/DJ-Tech DJM-101.midi.xml 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/DJ-Tech DJM-101.midi.xml 2012-05-26 14:59:19 +0000
@@ -0,0 +1,204 @@
1<?xml version='1.0' encoding='utf-8'?>
2<MixxxControllerPreset schemaVersion="1">
3 <info>
4 <name>DJTech DJM 101</name>
5 <author>zestoi</author>
6 <description>Mapping with full led feedback for the DJTech DJM 101</description>
7 </info>
8 <controller id="DJM-101">
9 <scriptfiles>
10 <file filename="DJ-Tech-DJM-101-scripts.js" functionprefix="DJTechDJM101"/>
11 </scriptfiles>
12 <controls>
13
14 <!-- global controls -->
15
16 <control>
17 <group>[Master]</group>
18 <key>headVolume</key>
19 <status>0xB0</status>
20 <midino>0x45</midino>
21 <options>
22 <normal/>
23 </options>
24 </control>
25 <control>
26 <group>[Master]</group>
27 <key>headMix</key>
28 <status>0xB0</status>
29 <midino>0x44</midino>
30 <options>
31 <normal/>
32 </options>
33 </control>
34
35 <!-- master/pfl vumeter select -->
36
37 <control>
38 <group>[Master]</group>
39 <status>0x90</status>
40 <midino>0x24</midino>
41 <key>DJTechDJM101.vumeter_select_master</key>
42 <options>
43 <Script-Binding/>
44 </options>
45 </control>
46
47 <control>
48 <group>[Master]</group>
49 <status>0x90</status>
50 <midino>0x23</midino>
51 <key>DJTechDJM101.vumeter_select_pfl</key>
52 <options>
53 <Script-Binding/>
54 </options>
55 </control>
56
57 <control>
58 <group>[Master]</group>
59 <key>volume</key>
60 <status>0xB0</status>
61 <midino>0x43</midino>
62 <options>
63 <normal/>
64 </options>
65 </control>
66
67 <control>
68 <group>[Master]</group>
69 <key>crossfader</key>
70 <status>0xB0</status>
71 <midino>0x40</midino>
72 <options>
73 <normal/>
74 </options>
75 </control>
76
77 <!-- channel 1 -->
78
79 <control>
80 <group>[Channel1]</group>
81 <key>pregain</key>
82 <status>0xB0</status>
83 <midino>0x48</midino>
84 <options>
85 <normal/>
86 </options>
87 </control>
88
89 <control>
90 <group>[Channel1]</group>
91 <key>volume</key>
92 <status>0xB0</status>
93 <midino>0x41</midino>
94 <options>
95 <normal/>
96 </options>
97 </control>
98
99 <control>
100 <group>[Channel1]</group>
101 <key>pfl</key>
102 <status>0x90</status>
103 <midino>0x21</midino>
104 <options>
105 <normal/>
106 </options>
107 </control>
108
109 <!-- channel 1 eq -->
110
111 <control>
112 <group>[Channel1]</group>
113 <key>filterHigh</key>
114 <status>0xB0</status>
115 <midino>0x4A</midino>
116 <options>
117 <normal/>
118 </options>
119 </control>
120 <control>
121 <group>[Channel1]</group>
122 <key>filterMid</key>
123 <status>0xB0</status>
124 <midino>0x4E</midino>
125 <options>
126 <normal/>
127 </options>
128 </control>
129 <control>
130 <group>[Channel1]</group>
131 <key>filterLow</key>
132 <status>0xB0</status>
133 <midino>0x4C</midino>
134 <options>
135 <normal/>
136 </options>
137 </control>
138
139 <!-- channel 2 -->
140
141 <control>
142 <group>[Channel2]</group>
143 <key>pregain</key>
144 <status>0xB0</status>
145 <midino>0x4F</midino>
146 <options>
147 <normal/>
148 </options>
149 </control>
150
151 <control>
152 <group>[Channel2]</group>
153 <key>volume</key>
154 <status>0xB0</status>
155 <midino>0x42</midino>
156 <options>
157 <normal/>
158 </options>
159 </control>
160
161 <control>
162 <group>[Channel2]</group>
163 <key>pfl</key>
164 <status>0x90</status>
165 <midino>0x22</midino>
166 <options>
167 <normal/>
168 </options>
169 </control>
170
171 <!-- channel 2 eq -->
172
173 <control>
174 <group>[Channel2]</group>
175 <key>filterHigh</key>
176 <status>0xB0</status>
177 <midino>0x4D</midino>
178 <options>
179 <normal/>
180 </options>
181 </control>
182 <control>
183 <group>[Channel2]</group>
184 <key>filterMid</key>
185 <status>0xB0</status>
186 <midino>0x4B</midino>
187 <options>
188 <normal/>
189 </options>
190 </control>
191 <control>
192 <group>[Channel2]</group>
193 <key>filterLow</key>
194 <status>0xB0</status>
195 <midino>0x49</midino>
196 <options>
197 <normal/>
198 </options>
199 </control>
200
201 </controls>
202 <outputs/>
203 </controller>
204</MixxxControllerPreset>
0205
=== added file 'mixxx/res/controllers/DJ-Tech-CDJ-101-scripts.js'
--- mixxx/res/controllers/DJ-Tech-CDJ-101-scripts.js 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/DJ-Tech-CDJ-101-scripts.js 2012-05-26 14:59:19 +0000
@@ -0,0 +1,245 @@
1/****************************************************************/
2/* DJ-Tech CDJ101 controller script */
3/* For Mixxx version 1.11 */
4/* Author: zestoi */
5/****************************************************************/
6//
7// pitch slider works as you'd expect
8// holding down the push button works as a "shift" to activate secondary functions
9// needs the cdj101 to be on midi channel 1 for deck1 and 2 for deck2
10//
11// track playing:
12//
13// * surface of jog wheel: scratch
14// * edge of jog wheel: tempo bend
15// * shift + edge of jog wheel: fine tempo bend
16//
17// track not playing:
18//
19// * click push button: load a track
20// * surface of jog wheel: scratch thru track
21// * shift + surface of jog wheel: scan through track quickly
22// * edge of jog wheel: jog though track slowly
23// * shift + cue: move beatgrid
24//
25// track playing or not:
26//
27// * rotate push button: navigate tracks
28// * shift + rotate push button: switch between playlists
29// * cue button: default cue behaviour
30// * play: toggle play
31// * shift + play: sync
32//
33
34DJTechCDJ101 = {};
35DJTechCDJ101.pushmaxtime = 200;
36DJTechCDJ101.pushed = false;
37DJTechCDJ101.pushedon = 0;
38DJTechCDJ101.outer2inner = false;
39DJTechCDJ101.scratch_timeout = 100;
40
41DJTechCDJ101.init = function(id) {
42 engine.connectControl("[Channel1]", "play", "DJTechCDJ101.play_feedback_deck1");
43 engine.connectControl("[Channel2]", "play", "DJTechCDJ101.play_feedback_deck2");
44 engine.connectControl("[Channel1]", "cue_default", "DJTechCDJ101.cue_feedback_deck1");
45 engine.connectControl("[Channel2]", "cue_default", "DJTechCDJ101.cue_feedback_deck2");
46}
47
48DJTechCDJ101.shutdown = function() {}
49
50//
51// utility function
52//
53
54DJTechCDJ101.mtime = function()
55{
56 var t = new Date();
57 return t.getTime();
58}
59
60//
61// cue+play led feedback
62//
63
64DJTechCDJ101.play_feedback_deck1 = function(value)
65{
66 midi.sendShortMsg(0x90, 0x2a, value > 0 ? 0x7f : 0);
67}
68
69DJTechCDJ101.play_feedback_deck2 = function(value)
70{
71 midi.sendShortMsg(0x91, 0x2a, value > 0 ? 0x7f : 0);
72}
73
74DJTechCDJ101.cue_feedback_deck1 = function(value)
75{
76 midi.sendShortMsg(0x90, 0x2b, value > 0 ? 0x7f : 0);
77}
78
79DJTechCDJ101.cue_feedback_deck2 = function(value)
80{
81 midi.sendShortMsg(0x91, 0x2b, value > 0 ? 0x7f : 0);
82}
83
84//
85// translate 14bit pitchbend message into pitch control
86//
87
88DJTechCDJ101.pitch = function(channel, lsb, msb, status, group)
89{
90 engine.setValue(group, "rate", script.pitch(lsb, msb, status)); // not working for some reason
91 //engine.setValue(group, "rate", (8192 - (msb << 7 | lsb)) / 8192);
92}
93
94DJTechCDJ101.beatjump = function(group, jump)
95{
96 jump = jump * 120 / engine.getValue(group, "bpm") / engine.getValue(group, "track_samples") * engine.getValue(group, "track_samplerate");
97 engine.setValue(group, "playposition", engine.getValue(group, "playposition") + jump);
98}
99
100//
101// hold down encoder and turn to change playlists
102// turn while not pushed in to scroll through tracks
103// click to load track
104//
105
106DJTechCDJ101.browse = function(channel, control, value, status, group)
107{
108 if (DJTechCDJ101.pushed) {
109 engine.setValue("[Playlist]", value == 0x41 ? "SelectNextPlaylist" : "SelectPrevPlaylist", 1);
110 }
111 else {
112 engine.setValue("[Playlist]", value == 0x41 ? "SelectNextTrack" : "SelectPrevTrack", 1);
113 }
114}
115
116DJTechCDJ101.push = function(channel, control, value, status, group)
117{
118 if (value > 0) {
119 DJTechCDJ101.pushed = true;
120 DJTechCDJ101.pushedon = DJTechCDJ101.mtime();
121 }
122 else {
123
124 //
125 // load selected track if released quickly enough
126 //
127
128 if (DJTechCDJ101.mtime() - DJTechCDJ101.pushedon < DJTechCDJ101.pushmaxtime) {
129 engine.setValue(group, "LoadSelectedTrack", 1);
130 }
131
132 DJTechCDJ101.pushed = false;
133 DJTechCDJ101.pushedon = 0;
134 }
135}
136
137//
138// when deck is not playing and the push button is held, pressing cue will move the beatgrid
139//
140
141DJTechCDJ101.cue = function(channel, control, value, status, group)
142{
143 if (DJTechCDJ101.pushed && !engine.getValue(group, "play")) {
144 engine.setValue(group, "beats_translate_curpos", value > 0 ? 1 : 0);
145 }
146 else {
147 engine.setValue(group, "cue_default", value > 0 ? 1 : 0);
148 }
149}
150
151//
152// when the push button is held, pressing play will sync
153//
154
155DJTechCDJ101.play = function(channel, control, value, status, group)
156{
157 if (DJTechCDJ101.pushed) {
158 engine.setValue(group, "beatsync", value > 0 ? 1 : 0);
159 }
160 else if (value > 0) {
161 //
162 // we want play to toggle
163 //
164
165 engine.setValue(group, "play", !engine.getValue(group, "play"));
166 }
167}
168
169//
170// when deck is playing either enable or disable scratch mode, no action otherwise
171//
172
173DJTechCDJ101.jogtouch = function(channel, control, value, status, group)
174{
175 var deck = parseInt(group.substring(8,9));
176
177 if (value > 0) {
178 engine.scratchEnable(deck, 143, 45, 0.125, 0.125/32);
179 }
180 else {
181 //
182 // don't disable right away in case of spin backs if playing and also morph
183 // outer jog movements into top jog movements during this time
184 //
185
186 if (!engine.getValue(group, "play")) {
187 DJTechCDJ101.finishScratch(deck, false);
188 }
189 else {
190 DJTechCDJ101.outer2inner = true;
191 DJTechCDJ101.scratch_timer = engine.beginTimer(DJTechCDJ101.scratch_timeout, 'DJTechCDJ101.finishScratch(' + deck + ', true)');
192 }
193 }
194}
195
196DJTechCDJ101.finishScratch = function(deck, stop_timer)
197{
198 if (stop_timer) {
199 engine.stopTimer(DJTechCDJ101.scratch_timer);
200 }
201 engine.scratchDisable(deck);
202 DJTechCDJ101.outer2inner = false;
203}
204
205//
206// use outer part of jog to pitchbend when in play mode and fine track seek when not
207//
208
209DJTechCDJ101.jogouter = function(channel, control, value, status, group)
210{
211 //
212 // when touch surface has been release for a short time convert
213 // outer jog movements into surface jog ones for spinbacks etc
214 //
215
216 if (DJTechCDJ101.outer2inner) {
217 return DJTechCDJ101.jogtop(channel, control, value, status, group);
218 }
219
220 //
221 // scale down based on whether we are playing and the shift is held down
222 //
223
224 value = (value - 0x40) / 2;
225 if (DJTechCDJ101.pushed) value /= 2.5;
226 if (!engine.getValue(group, "play")) value /= 2.5;
227 engine.setValue(group, "jog", value);
228}
229
230//
231// track playing: top of jog scratches
232// track not playing: seek thru track (using same scratch ticks and gives more postive response) or seek faster through track when push button held down
233//
234
235DJTechCDJ101.jogtop = function(channel, control, value, status, group)
236{
237 value -= 0x40;
238 if (!engine.getValue(group, "play") && DJTechCDJ101.pushed) {
239 DJTechCDJ101.beatjump(group, value);
240 }
241 else {
242 engine.scratchTick(parseInt(group.substring(8,9)), value);
243 }
244}
245
0246
=== added file 'mixxx/res/controllers/DJ-Tech-DJM-101-scripts.js'
--- mixxx/res/controllers/DJ-Tech-DJM-101-scripts.js 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/DJ-Tech-DJM-101-scripts.js 2012-05-26 14:59:19 +0000
@@ -0,0 +1,110 @@
1/****************************************************************/
2/* DJ-Tech DJM101 controller script */
3/* For Mixxx version 1.11 */
4/* Author: zestoi */
5/****************************************************************/
6
7DJTechDJM101 = {};
8DJTechDJM101.vumeter = {};
9DJTechDJM101.vumeter[1] = 0;
10DJTechDJM101.vumeter[2] = 0;
11
12DJTechDJM101.init = function(id) {
13 DJTechDJM101.vumeter_select(true);
14 engine.connectControl("[Master]", "VuMeterL", "DJTechDJM101.VuMeterMasterL");
15 engine.connectControl("[Master]", "VuMeterR", "DJTechDJM101.VuMeterMasterR");
16 engine.connectControl("[Channel1]", "VuMeter", "DJTechDJM101.VuMeterDeck1");
17 engine.connectControl("[Channel2]", "VuMeter", "DJTechDJM101.VuMeterDeck2");
18 engine.connectControl("[Channel1]", "pfl", "DJTechDJM101.pfl");
19 engine.connectControl("[Channel2]", "pfl", "DJTechDJM101.pfl");
20}
21
22DJTechDJM101.shutdown = function() {}
23
24//
25// change output to vumeter and reset
26//
27
28DJTechDJM101.vumeter_select = function(master)
29{
30 DJTechDJM101.vumeter_master_mode = master;
31 DJTechDJM101.update_vumeter(1, 0);
32 DJTechDJM101.update_vumeter(2, 0);
33}
34
35//
36// select what data is sent to the vumeter
37//
38
39DJTechDJM101.vumeter_select_master = function(channel, control, value, status, group)
40{
41 if (value > 0) {
42 DJTechDJM101.vumeter_select(true);
43 }
44}
45
46DJTechDJM101.vumeter_select_pfl = function(channel, control, value, status, group)
47{
48 if (value > 0) {
49 DJTechDJM101.vumeter_select(false);
50 }
51}
52
53//
54// update a vumeter channel
55//
56
57DJTechDJM101.update_vumeter = function(channel, value)
58{
59 var newval = parseInt(value * 0xf7);
60 if (DJTechDJM101.vumeter[channel] != newval) {
61 DJTechDJM101.vumeter[channel] = newval;
62
63 //
64 // a bit nasty - four different cc's depending on master/pfl mode and which channel
65 //
66
67 midi.sendShortMsg(0xb0, DJTechDJM101.vumeter_master_mode ? 0x4f + channel : 0x51 + channel, newval);
68 }
69}
70
71//
72// only feed the correct levels to each channel of the vumeter
73//
74
75DJTechDJM101.VuMeterMasterL = function(value)
76{
77 if (DJTechDJM101.vumeter_master_mode == false) return;
78 DJTechDJM101.update_vumeter(1, value);
79}
80
81DJTechDJM101.VuMeterMasterR = function(value)
82{
83 if (DJTechDJM101.vumeter_master_mode == false) return;
84 DJTechDJM101.update_vumeter(2, value);
85}
86
87DJTechDJM101.VuMeterDeck1 = function(value)
88{
89 if (DJTechDJM101.vumeter_master_mode == true) return;
90 DJTechDJM101.update_vumeter(1, value);
91}
92
93DJTechDJM101.VuMeterDeck2 = function(value)
94{
95 if (DJTechDJM101.vumeter_master_mode == true) return;
96 DJTechDJM101.update_vumeter(2, value);
97}
98
99//
100// led feedback for headphone cue buttons
101//
102
103DJTechDJM101.pfl = function(value, group)
104{
105 // has to be a noteon msg in both case and seems more reliable issuing 0x7f for 'on' amd 0x0 for 'off'
106 midi.sendShortMsg(0x90, group == "[Channel1]" ? 0x21 : 0x22, value > 0 ? 0x7f : 0);
107}
108
109
110
0111
=== added file 'mixxx/res/controllers/Hercules DJ Console Mk2.cntrlr.xml'
--- mixxx/res/controllers/Hercules DJ Console Mk2.cntrlr.xml 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/Hercules DJ Console Mk2.cntrlr.xml 2012-05-26 14:59:19 +0000
@@ -0,0 +1,13 @@
1<?xml version="1.0" encoding="utf-8"?>
2<MixxxControllerPreset schemaVersion="1">
3 <info>
4 <name>Hercules DJ Console MK2 HID</name>
5 <author>zestoi</author>
6 <description>Native high-resolution HID script for the Hercules DJ Console MK2 controller.</description>
7 </info>
8 <controller id="Hercules DJ Console MK2 HID">
9 <scriptfiles>
10 <file filename="Hercules-DJ-Console-Mk2-hid-scripts.js" functionprefix="HerculesMk2Hid"/>
11 </scriptfiles>
12 </controller>
13</MixxxControllerPreset>
014
=== added file 'mixxx/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js'
--- mixxx/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js 2012-05-26 14:59:19 +0000
@@ -0,0 +1,611 @@
1/****************************************************************/
2/* Hercules DJ Console Mk2 HID controller script */
3/* For Mixxx version 1.11 */
4/* Author: zestoi */
5/****************************************************************/
6
7HerculesMk2Hid = new Controller();
8HerculesMk2Hid.controls = [];
9HerculesMk2Hid.leds = [];
10HerculesMk2Hid.cache_in = [];
11HerculesMk2Hid.cache_out = [];
12HerculesMk2Hid.callbacks = [];
13HerculesMk2Hid.feedbacks = [];
14HerculesMk2Hid.layer = [ "fx", "fx" ]; // fx, hotcue, loop, kill
15HerculesMk2Hid.tempo_scaling = 400;
16HerculesMk2Hid.beatjump_size = 8;
17HerculesMk2Hid.kills = [ { filterHighKill: 0, filterMidKill: 0, filterLowKill: 0 }, { filterHighKill: 0, filterMidKill: 0, filterLowKill: 0 } ];
18HerculesMk2Hid.loop_lengths = [ 0.25, 0.5, 1 ]; // edit to loop size needed
19HerculesMk2Hid.kill_order = [ "filterHighKill", "filterMidKill", "filterLowKill" ]; // edit if needed
20HerculesMk2Hid.scratch_enabled = { "[Channel1]": false, "[Channel2]": false };
21HerculesMk2Hid.jog_skip = { "[Channel1]": true, "[Channel2]": true };
22HerculesMk2Hid.shift = false; // either autobeat button
23
24//
25// the actual mapping is defined in this function
26//
27
28HerculesMk2Hid.init = function() {
29
30 var c = HerculesMk2Hid;
31
32 //
33 // define the hid packet
34 //
35
36 c.define_hid_format();
37
38 //
39 // create the actual mapping
40 // deck controls (will work for any decks as the group is passed in)
41 //
42
43 c.capture("crossfader", "all", function(g, e, v) { engine.setValue(g, e, (v - 128) / 128); });
44
45 c.capture("play", "press", function(g, e, v) { engine.setValue(g, e, !engine.getValue(g, e)); });
46 c.capture("cue_default", "all", function(g, e, v) { engine.setValue(g, e, v); });
47 c.capture("beatsync", "all", function(g, e, v) { HerculesMk2Hid.shift = v > 0; engine.setValue(g, e, v); });
48
49 c.capture("volume", "all", function(g, e, v) { engine.setValue(g, e, v / 256); });
50 c.capture("filterHigh", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
51 c.capture("filterMid", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
52 c.capture("filterLow", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
53
54 c.capture("jog", "all", function(g, e, v, ctrl) {
55 // skip initial jog values
56 if (HerculesMk2Hid.jog_skip[g]) {
57 HerculesMk2Hid.jog_skip[g] = false;
58 return;
59 }
60
61 // scratch mode
62 if (HerculesMk2Hid.scratch_enabled[g]) {
63 engine.scratchTick(parseInt(g.substring(8,9)), ctrl.relative);
64 }
65
66 // fine jog mode when playing
67 else if (engine.getValue(g, "play")) {
68 engine.setValue(g, e, ctrl.relative/2);
69 }
70
71 // track browsing when shift held (sync) and not playing
72 else if (HerculesMk2Hid.shift) {
73 engine.setValue("[Playlist]", "SelectTrackKnob", ctrl.relative);
74 }
75
76 // normal jog mode when not playing
77 else {
78 engine.setValue(g, e, ctrl.relative);
79 }
80 });
81
82 //
83 // double up pitch bend buttons as beatjumps when the track is stopped
84 //
85
86 c.capture("pitchbend_down", "all", function(g, e, v) {
87 if (engine.getValue(g, "play") == 0) {
88 engine.setValue(g, "back", v > 0 ? 1 : 0);
89 }
90 else if (v > 0) {
91 engine.setValue(g, "jog", -3);
92 }
93 });
94
95 c.capture("pitchbend_up", "all", function(g, e, v) {
96 if (engine.getValue(g, "play") == 0) {
97 engine.setValue(g, "fwd", v > 0 ? 1 : 0);
98 }
99 else if (v > 0) {
100 engine.setValue(g, "jog", 3);
101 }
102 });
103
104 //
105 // track browsing - don't use the joystick or track load buttons as they function as a normal mouse too
106 // (map joystick_y/joystick_x/load if you want to use the joystick)
107 //
108
109 c.capture("track_previous_a", "all", c.scroll_tracks);
110 c.capture("track_next_a", "all", c.scroll_tracks);
111 c.capture("track_previous_b", "press", function(g, e, v) { engine.setValue("[Channel1]", "LoadSelectedTrack", 1); });
112 c.capture("track_next_b", "press", function(g, e, v) { engine.setValue("[Channel2]", "LoadSelectedTrack", 1); });
113
114 //
115 // uncomment this code and the function HerculesMk2Hid.scroll_tracks_joystick() below if you really want the joystick
116 // to be used for track browsing and the left/right joystick buttons for track loading
117 //
118
119 /*
120 c.capture("load", "press", function(g, e, v) { engine.setValue(g, "LoadSelectedTrack", 1); });
121
122 c.capture("joystick_y", "all", function(g, e, v) {
123 if (v == 128) {
124 HerculesMk2Hid.direction = 0;
125 if (HerculesMk2Hid.track_timer) {
126 engine.stopTimer(HerculesMk2Hid.track_timer);
127 HerculesMk2Hid.track_timer = null;
128 }
129 }
130 else {
131 if (v > 128) {
132 HerculesMk2Hid.direction = 1;
133 v -= 128;
134 }
135 else {
136 HerculesMk2Hid.direction = -1;
137 v = 128 - v;
138 }
139
140 if (v < 30) v = 30;
141 if (HerculesMk2Hid.track_timer) engine.stopTimer(HerculesMk2Hid.track_timer);
142 HerculesMk2Hid.track_timer = engine.beginTimer(parseInt(5120 / v), 'HerculesMk2Hid.scroll_tracks_joystick');
143 }
144 });
145 */
146
147 //
148 // tempo encoder
149 //
150
151 c.capture("rate", "all", function(g, e, v, ctrl) {
152 var rate = engine.getValue(g, "rate") + ctrl.relative / c.tempo_scaling;
153 if (rate > 1) rate = 1; else if (rate < -1) rate = -1;
154 engine.setValue(g, e, rate);
155 });
156
157 //
158 // enable/disable scratching with the beatlock buttons (as jogs are non touch sensitive)
159 //
160
161 c.capture("beatlock", "press", function(g, e, v) {
162
163 HerculesMk2Hid.scratch_enabled[g] = !HerculesMk2Hid.scratch_enabled[g];
164
165 if (HerculesMk2Hid.scratch_enabled[g]) {
166 engine.scratchEnable(parseInt(g.substring(8,9)), 64, 45, 0.125, 0.125/32);
167 }
168 else {
169 engine.scratchDisable(parseInt(g.substring(8,9)));
170 }
171
172 c.send(g, e, HerculesMk2Hid.scratch_enabled[g] ? 1 : 0);
173 });
174
175 //
176 // toggle between fx, hotcue and loop modes and update leds
177 //
178
179 c.capture("layer_select", "press", function(g, e, v) {
180 var deck = parseInt(g.substring(8,9));
181 c.send(g, "fx", 0);
182 c.send(g, "hotcue", 0);
183 c.send(g, "loop", 0);
184 switch (c.layer[deck-1]) {
185 case "fx": c.layer[deck-1] = "hotcue"; break;
186 case "hotcue": c.layer[deck-1] = "loop"; break;
187 case "loop":
188 c.layer[deck-1] = "kill";
189 c.send(g, "fx", !c.kills[deck-1]['filterHighKill']);
190 c.send(g, "hotcue", !c.kills[deck-1]['filterMidKill']);
191 c.send(g, "loop", !c.kills[deck-1]['filterLowKill']);
192 break;
193 case "kill":
194 c.layer[deck-1] = "fx";
195 }
196 if (c.layer[deck-1] != "kill") {
197 c.send(g, c.layer[deck-1], 1);
198 }
199 });
200
201 c.capture("layer_btn1", "all", function(g, e, v) { c.layer_btn(g, e, v); });
202 c.capture("layer_btn2", "all", function(g, e, v) { c.layer_btn(g, e, v); });
203 c.capture("layer_btn3", "all", function(g, e, v) { c.layer_btn(g, e, v); });
204
205 //
206 // headphone cue
207 //
208
209 c.capture("monitor_a", "all", function(g, e, v) { engine.setValue("[Channel1]", "pfl", v); });
210 c.capture("monitor_b", "all", function(g, e, v) { engine.setValue("[Channel2]", "pfl", v); });
211 c.capture("monitor_both", "all", function(g, e, v) {
212 engine.setValue("[Channel1]", "pfl", v);
213 engine.setValue("[Channel2]", "pfl", v);
214 });
215
216 //
217 // led feedback
218 //
219
220 c.feedback("[Channel1]", "play", function(g, e, v) { c.send(g, e, v); });
221 c.feedback("[Channel2]", "play", function(g, e, v) { c.send(g, e, v); });
222 c.feedback("[Channel1]", "cue_default", function(g, e, v) { c.send(g, e, v); });
223 c.feedback("[Channel2]", "cue_default", function(g, e, v) { c.send(g, e, v); });
224 c.feedback("[Channel1]", "beatsync", function(g, e, v) { c.send(g, e, v); });
225 c.feedback("[Channel2]", "beatsync", function(g, e, v) { c.send(g, e, v); });
226
227 //
228 // kill status
229 //
230
231 c.feedback("[Channel1]", "filterHighKill", c.kill_status);
232 c.feedback("[Channel1]", "filterMidKill", c.kill_status);
233 c.feedback("[Channel1]", "filterLowKill", c.kill_status);
234
235 //
236 // clear/setup any initial leds
237 //
238
239 for (id in c.leds) {
240 c.send(c.leds[id].group, c.leds[id].name, 0);
241 }
242
243 c.send("[Channel1]", "fx", 1);
244 c.send("[Channel2]", "fx", 1);
245}
246
247//
248// map the 6 buttons that control either effects, hotcues, loops or kills
249//
250
251HerculesMk2Hid.layer_btn = function(g, e, v) {
252 var deck = parseInt(g.substring(8,9));
253 var btn = parseInt(e.substring(9,10));
254 switch (HerculesMk2Hid.layer[deck-1]) {
255 case "fx":
256 switch (btn) {
257 case 1:
258 engine.setValue("[Flanger]", "lfoDepth", 1);
259 engine.setValue("[Flanger]", "lfoPeriod", 500000);
260 engine.setValue("[Flanger]", "lfoDelay", 666);
261 engine.setValue(g, "flanger", v > 0);
262 break;
263 case 2:
264 script.spinback(g, v > 0);
265 break;
266 case 3:
267 script.brake(g, v > 0);
268 }
269 break;
270 case "hotcue":
271 engine.setValue(g, "hotcue_" + btn + "_activate", v > 0 ? 1 : 0);
272 break;
273 case "loop":
274 var len = HerculesMk2Hid.loop_lengths[btn-1];
275 engine.setValue(g, "beatloop_" + len + "_toggle", 1);
276 break;
277 case 'kill':
278 if (v > 0) {
279 engine.setValue(g, HerculesMk2Hid.kill_order[btn-1], !engine.getValue(g, HerculesMk2Hid.kill_order[btn-1]));
280 }
281 }
282}
283
284//
285// beatjump - will get out of sync if called while deck is playing
286//
287
288HerculesMk2Hid.beatjump = function(group, jump) {
289 jump = jump * 120 / engine.getValue(group, "bpm") / engine.getValue(group, "track_samples") * engine.getValue(group, "track_samplerate");
290 engine.setValue(group, "playposition", engine.getValue(group, "playposition") + jump);
291}
292
293//
294// playlist scroll nex/previous with auto-repeat when held
295//
296
297HerculesMk2Hid.scroll_tracks = function(g, e, v) {
298 if (v > 0) {
299 engine.setValue("[Playlist]", e == "track_next_a" ? "SelectNextTrack" : "SelectPrevTrack", 1);
300 if (!HerculesMk2Hid.scroll_timer) {
301 HerculesMk2Hid.scroll_timer = engine.beginTimer(150, 'HerculesMk2Hid.scroll_tracks("[Playlist]","' + e + '",' + v + ')');
302 }
303 }
304 else {
305 if (HerculesMk2Hid.scroll_timer) {
306 engine.stopTimer(HerculesMk2Hid.scroll_timer);
307 HerculesMk2Hid.scroll_timer = null;
308 }
309 }
310}
311
312//
313// eq kill status
314//
315
316HerculesMk2Hid.kill_status = function(g, e, v) {
317 var deck = parseInt(g.substring(8,9));
318 HerculesMk2Hid.kills[deck-1][e] = v;
319
320 //
321 // update leds with kill status if we're on that layer
322 //
323
324 if (HerculesMk2Hid.layer[deck-1] == "kill") {
325 switch (e) {
326 case 'filterHighKill': HerculesMk2Hid.send(g, "fx", !v); break;
327 case 'filterMidKill': HerculesMk2Hid.send(g, "hotcue", !v); break;
328 case 'filterLowKill': HerculesMk2Hid.send(g, "loop", !v);
329 }
330 }
331}
332
333/*
334HerculesMk2Hid.scroll_tracks_joystick = function() {
335 engine.setValue("[Playlist]", HerculesMk2Hid.direction > 0 ? "SelectNextTrack" : "SelectPrevTrack", 1);
336}
337*/
338
339
340////////////////////////////////////////////////////////////////////////////////////////////////////
341// define the hid packet to event mapping, could be defined via xml so can be used in multiple mappings
342// naming the controls as much as possible inline with the mixxx engine names makes most mappings trivial
343//
344
345HerculesMk2Hid.define_hid_format = function() {
346
347 var c = HerculesMk2Hid;
348 var pid = 0x1;
349
350 // deck 1
351
352 c.add_control(pid, "play", "[Channel1]", "button", 1, 0x80)
353 c.add_control(pid, "cue_default", "[Channel1]", "button", 2, 0x01)
354 c.add_control(pid, "track_previous_a", "[Channel1]", "button", 2, 0x04)
355 c.add_control(pid, "track_next_a", "[Channel1]", "button", 2, 0x08)
356 c.add_control(pid, "beatsync", "[Channel1]", "button", 2, 0x02)
357 c.add_control(pid, "pitchbend_down", "[Channel1]", "button", 3, 0x08)
358 c.add_control(pid, "pitchbend_up", "[Channel1]", "button", 3, 0x04)
359 c.add_control(pid, "load", "[Channel1]", "button", 4, 0x04)
360 c.add_control(pid, "beatlock", "[Channel1]", "button", 3, 0x20)
361 c.add_control(pid, "source", "[Channel1]", "button", 4, 0x10)
362 c.add_control(pid, "filterLow", "[Channel1]", "fader", 9, 0xff)
363 c.add_control(pid, "filterMid", "[Channel1]", "fader", 10, 0xff)
364 c.add_control(pid, "filterHigh", "[Channel1]", "fader", 11, 0xff)
365 c.add_control(pid, "volume", "[Channel1]", "fader", 13, 0xff)
366 c.add_control(pid, "rate", "[Channel1]", "encoder", 15, 0xff)
367 c.add_control(pid, "jog", "[Channel1]", "encoder", 17, 0xff)
368 c.add_control(pid, "layer_select", "[Channel1]", "button", 1, 0x40)
369 c.add_control(pid, "layer_btn1", "[Channel1]", "button", 2, 0x40)
370 c.add_control(pid, "layer_btn2", "[Channel1]", "button", 2, 0x20)
371 c.add_control(pid, "layer_btn3", "[Channel1]", "button", 2, 0x10)
372
373 // deck 2
374
375 c.add_control(pid, "play", "[Channel2]", "button", 1, 0x02)
376 c.add_control(pid, "cue_default", "[Channel2]", "button", 1, 0x04)
377 c.add_control(pid, "track_previous_b", "[Channel2]", "button", 1, 0x10)
378 c.add_control(pid, "track_next_b", "[Channel2]", "button", 1, 0x20)
379 c.add_control(pid, "beatsync", "[Channel2]", "button", 1, 0x08)
380 c.add_control(pid, "pitchbend_down", "[Channel2]", "button", 3, 0x80)
381 c.add_control(pid, "pitchbend_up", "[Channel2]", "button", 3, 0x40)
382 c.add_control(pid, "load", "[Channel2]", "button", 4, 0x08)
383 c.add_control(pid, "beatlock", "[Channel2]", "button", 4, 0x02)
384 c.add_control(pid, "source", "[Channel2]", "button", 4, 0x20)
385 c.add_control(pid, "filterLow", "[Channel2]", "fader", 6, 0xff)
386 c.add_control(pid, "filterMid", "[Channel2]", "fader", 7, 0xff)
387 c.add_control(pid, "filterHigh", "[Channel2]", "fader", 8, 0xff)
388 c.add_control(pid, "volume", "[Channel2]", "fader", 14, 0xff)
389 c.add_control(pid, "rate", "[Channel2]", "encoder", 16, 0xff)
390 c.add_control(pid, "jog", "[Channel2]", "encoder", 18, 0xff)
391 c.add_control(pid, "layer_select", "[Channel2]", "button", 1, 0x01)
392 c.add_control(pid, "layer_btn1", "[Channel2]", "button", 2, 0x80)
393 c.add_control(pid, "layer_btn2", "[Channel2]", "button", 3, 0x01)
394 c.add_control(pid, "layer_btn3", "[Channel2]", "button", 3, 0x02)
395
396 // master
397
398 c.add_control(pid, "crossfader", "[Master]", "fader", 12, 0xff)
399 c.add_control(pid, "joystick_x", "[Master]", "fader", 19, 0xff)
400 c.add_control(pid, "joystick_y", "[Master]", "fader", 20, 0xff)
401
402 // headphone cue
403
404 c.add_control(pid, "monitor_a", "[Master]", "button", 5, 0x1);
405 c.add_control(pid, "monitor_b", "[Master]", "button", 5, 0x2);
406 //c.add_control(pid, "monitor_both", "[Master]", "button", 5, 0x4);
407 c.add_control(pid, "monitor_both", "[Master]", "button", 5, 0x8);
408
409 // define led feedback
410
411 pid = 0;
412 c.cache_out[pid] = [ pid, 0x0, 0x0, 0x0 ];
413
414 c.add_control(pid, "play", "[Channel1]", "led", 2, 0x01); // blinking: 3, 0x2
415 c.add_control(pid, "cue_default", "[Channel1]", "led", 2, 0x08);
416 c.add_control(pid, "beatsync", "[Channel1]", "led", 2, 0x10);
417 c.add_control(pid, "beatlock", "[Channel1]", "led", 1, 0x01);
418
419 c.add_control(pid, "play", "[Channel2]", "led", 1, 0x40); // blinking: 3, 0x1
420 c.add_control(pid, "cue_default", "[Channel2]", "led", 1, 0x20);
421 c.add_control(pid, "beatsync", "[Channel2]", "led", 2, 0x20);
422 c.add_control(pid, "beatlock", "[Channel2]", "led", 1, 0x02);
423
424 c.add_control(pid, "fx", "[Channel1]", "led", 1, 0x04);
425 c.add_control(pid, "fx", "[Channel2]", "led", 1, 0x08);
426 c.add_control(pid, "hotcue", "[Channel2]", "led", 1, 0x10);
427 c.add_control(pid, "hotcue", "[Channel1]", "led", 1, 0x80);
428 c.add_control(pid, "loop", "[Channel1]", "led", 2, 0x40);
429 c.add_control(pid, "loop", "[Channel2]", "led", 2, 0x80);
430}
431
432////////////////////////////////////////////////////////////////////////////////////////////////////
433// non-specific controller framework to allow hid packets to be defined and processed via
434// callback functions - could/should be in a shared file
435//
436
437HerculesMk2Hid.add_control = function(packetid, name, group, type, offset, mask) {
438 if (type == "led") {
439 HerculesMk2Hid.leds[group + name] = new HerculesMk2Hid.control(packetid, name, group, type, offset, mask);
440 }
441 else {
442 if (HerculesMk2Hid.controls[offset] == undefined) {
443 HerculesMk2Hid.controls[offset] = [];
444 }
445 HerculesMk2Hid.controls[offset].push(new HerculesMk2Hid.control(packetid, name, group, type, offset, mask));
446 }
447}
448
449//
450// bind a function to a modified controller value
451//
452
453HerculesMk2Hid.capture = function(name, values, func) {
454 if (HerculesMk2Hid.callbacks[name] == undefined) {
455 HerculesMk2Hid.callbacks[name] = [ [ values, func ] ];
456 }
457 else {
458 HerculesMk2Hid.callbacks[name].push([ values, func ]);
459 }
460}
461
462//
463// bind a function to feedback from mixxx, callbacks accept args in same order as from capture()
464//
465
466HerculesMk2Hid.feedback = function(g, e, f) {
467 engine.connectControl(g, e, "HerculesMk2Hid.feedbackData");
468 if (HerculesMk2Hid.feedbacks[g + e] == undefined) {
469 HerculesMk2Hid.feedbacks[g + e] = [];
470 }
471 HerculesMk2Hid.feedbacks[g + e].push(f);
472}
473
474//
475// controller feedback: send data to the controller by name and automatically send out the full hid packet needed
476//
477
478HerculesMk2Hid.send = function(g, e, v) {
479 if ((ctrl = this.leds[g + e]) != undefined) {
480
481 //
482 // for the byte in the hid packet that this led control affects, mask out it's old value
483 // and then add in it's new one
484 //
485
486 this.cache_out[ctrl.packetid][ctrl.offset] = this.cache_out[ctrl.packetid][ctrl.offset] & ctrl.maskinv | (v << ctrl.bitshift);
487
488 //
489 // send complete hid packet and update our cache
490 //
491
492 controller.send(this.cache_out[ctrl.packetid], this.cache_out[ctrl.packetid].length, 0);
493 this.cache_out[ctrl.packetid] = this.cache_out[ctrl.packetid];
494 }
495}
496
497//
498// process incoming data from mixxx and call any callbacks
499//
500
501HerculesMk2Hid.feedbackData = function(v, g, e) {
502 if (HerculesMk2Hid.feedbacks[g + e] != undefined) {
503 for (func in HerculesMk2Hid.feedbacks[g + e]) {
504 if (typeof(HerculesMk2Hid.feedbacks[g + e][func]) == "function") {
505 HerculesMk2Hid.feedbacks[g + e][func](g, e, v);
506 }
507 }
508 }
509}
510
511//
512// a single hid control, store last known value and offset/mask to work out the new value from incoming data
513//
514
515HerculesMk2Hid.control = function(packetid, name, group, type, offset, mask) {
516 this.packetid = packetid;
517 this.name = name;
518 this.group = group;
519 this.type = type;
520 this.value = 0;
521 this.relative = 0;
522 this.offset = offset;
523 this.mask = mask;
524 this.maskinv = ~mask;
525 this.bitshift = 0;
526 this.maxval = 255; // needed for encoder, could guess from the mask
527 this.changed = function(value) {
528 value = (value & this.mask) >> this.bitshift;
529 if (this.value == value) {
530 return false;
531 }
532 else {
533 // map to a relative value if it's an encoder, usually +1 or -1
534 if (this.type == 'encoder') {
535 this.relative = value - this.value;
536 if (this.relative > 100) {
537 this.relative -= this.maxval;
538 }
539 else if (this.relative < -100) {
540 this.relative += this.maxval;
541 }
542 }
543 this.value = value;
544 return true;
545 }
546 };
547 while (mask != 0 && (mask & 0x1) == 0) {
548 mask = mask >> 1;
549 this.bitshift++;
550 }
551}
552
553//
554// process incoming data and call any callbacks if their bound controls have changed
555//
556
557HerculesMk2Hid.incomingData = function (data, length) {
558
559 var c = HerculesMk2Hid;
560 var packetid = data[0];
561
562 //
563 // iterate thru each byte and only check controls for that byte if the byte has changed
564 //
565
566 for (i=1; i<length; i++) {
567 if ((c.cache_in[packetid] == undefined || data[i] != c.cache_in[packetid][i]) && c.controls[i] != undefined) {
568
569 //
570 // a byte has changed, check any controls defined in that byte, more efficient
571 // than checking old+new values for all controls
572 //
573
574 for (key in c.controls[i]) {
575 var control = c.controls[i][key];
576 if (typeof(control) == 'object' && control.packetid == data[0] && control.changed(data[i])) {
577
578 //
579 // we found a hid control that has changed value within that byte, check for callbacks
580 //
581
582 var callbacks = c.callbacks[control.name];
583 if (callbacks != undefined) {
584 for (var i=0; i<callbacks.length; i++) {
585 if (typeof(callbacks[i][1]) == 'function') {
586
587 //
588 // check we need to call for this value change: all, press, release
589 //
590
591 if (callbacks[i][0] == "all" ||
592 (callbacks[i][0] == "press" && control.value > 0) ||
593 (callbacks[i][0] == "release" && control.value == 0)) {
594
595 //
596 // call a callback function for this control
597 //
598
599 callbacks[i][1](control.group, control.name, control.value, control);
600 }
601 }
602 }
603 }
604 }
605 }
606 }
607 }
608
609 // store the new raw data
610 c.cache_in[data[0]] = data;
611}
0612
=== added file 'mixxx/res/controllers/Novation Launchpad.midi.xml'
--- mixxx/res/controllers/Novation Launchpad.midi.xml 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/Novation Launchpad.midi.xml 2012-05-26 14:59:19 +0000
@@ -0,0 +1,736 @@
1<?xml version='1.0' encoding='utf-8'?>
2<MixxxControllerPreset schemaVersion="1">
3 <controller id="Novation Launchpad">
4 <info>
5 <name>Novation Launchpad</name>
6 <author>zestoi</author>
7 <description>Multi page mapping for the Novation Launchpad</description>
8 </info>
9 <scriptfiles>
10 <file filename="Novation-Launchpad-scripts.js" functionprefix="NovationLaunchpad"/>
11 </scriptfiles>
12 <controls>
13 <control>
14 <group>[Master]</group>
15 <key>NovationLaunchpad.incomingData</key>
16 <status>0xb0</status>
17 <midino>0x68</midino>
18 <options>
19 <Script-Binding/>
20 </options>
21 </control>
22 <control>
23 <group>[Master]</group>
24 <key>NovationLaunchpad.incomingData</key>
25 <status>0xb0</status>
26 <midino>0x69</midino>
27 <options>
28 <Script-Binding/>
29 </options>
30 </control>
31 <control>
32 <group>[Master]</group>
33 <key>NovationLaunchpad.incomingData</key>
34 <status>0xb0</status>
35 <midino>0x6A</midino>
36 <options>
37 <Script-Binding/>
38 </options>
39 </control>
40 <control>
41 <group>[Master]</group>
42 <key>NovationLaunchpad.incomingData</key>
43 <status>0xb0</status>
44 <midino>0x6B</midino>
45 <options>
46 <Script-Binding/>
47 </options>
48 </control>
49 <control>
50 <group>[Master]</group>
51 <key>NovationLaunchpad.incomingData</key>
52 <status>0xb0</status>
53 <midino>0x6C</midino>
54 <options>
55 <Script-Binding/>
56 </options>
57 </control>
58 <control>
59 <group>[Master]</group>
60 <key>NovationLaunchpad.incomingData</key>
61 <status>0xb0</status>
62 <midino>0x6D</midino>
63 <options>
64 <Script-Binding/>
65 </options>
66 </control>
67 <control>
68 <group>[Master]</group>
69 <key>NovationLaunchpad.incomingData</key>
70 <status>0xb0</status>
71 <midino>0x6E</midino>
72 <options>
73 <Script-Binding/>
74 </options>
75 </control>
76 <control>
77 <group>[Master]</group>
78 <key>NovationLaunchpad.incomingData</key>
79 <status>0xb0</status>
80 <midino>0x6F</midino>
81 <options>
82 <Script-Binding/>
83 </options>
84 </control>
85 <control>
86 <group>[Master]</group>
87 <key>NovationLaunchpad.incomingData</key>
88 <status>0x90</status>
89 <midino>0x8</midino>
90 <options>
91 <Script-Binding/>
92 </options>
93 </control>
94 <control>
95 <group>[Master]</group>
96 <key>NovationLaunchpad.incomingData</key>
97 <status>0x90</status>
98 <midino>0x18</midino>
99 <options>
100 <Script-Binding/>
101 </options>
102 </control>
103 <control>
104 <group>[Master]</group>
105 <key>NovationLaunchpad.incomingData</key>
106 <status>0x90</status>
107 <midino>0x28</midino>
108 <options>
109 <Script-Binding/>
110 </options>
111 </control>
112 <control>
113 <group>[Master]</group>
114 <key>NovationLaunchpad.incomingData</key>
115 <status>0x90</status>
116 <midino>0x38</midino>
117 <options>
118 <Script-Binding/>
119 </options>
120 </control>
121 <control>
122 <group>[Master]</group>
123 <key>NovationLaunchpad.incomingData</key>
124 <status>0x90</status>
125 <midino>0x48</midino>
126 <options>
127 <Script-Binding/>
128 </options>
129 </control>
130 <control>
131 <group>[Master]</group>
132 <key>NovationLaunchpad.incomingData</key>
133 <status>0x90</status>
134 <midino>0x58</midino>
135 <options>
136 <Script-Binding/>
137 </options>
138 </control>
139 <control>
140 <group>[Master]</group>
141 <key>NovationLaunchpad.incomingData</key>
142 <status>0x90</status>
143 <midino>0x68</midino>
144 <options>
145 <Script-Binding/>
146 </options>
147 </control>
148 <control>
149 <group>[Master]</group>
150 <key>NovationLaunchpad.incomingData</key>
151 <status>0x90</status>
152 <midino>0x78</midino>
153 <options>
154 <Script-Binding/>
155 </options>
156 </control>
157 <control>
158 <group>[Master]</group>
159 <key>NovationLaunchpad.incomingData</key>
160 <status>0x90</status>
161 <midino>0x0</midino>
162 <options>
163 <Script-Binding/>
164 </options>
165 </control>
166 <control>
167 <group>[Master]</group>
168 <key>NovationLaunchpad.incomingData</key>
169 <status>0x90</status>
170 <midino>0x1</midino>
171 <options>
172 <Script-Binding/>
173 </options>
174 </control>
175 <control>
176 <group>[Master]</group>
177 <key>NovationLaunchpad.incomingData</key>
178 <status>0x90</status>
179 <midino>0x2</midino>
180 <options>
181 <Script-Binding/>
182 </options>
183 </control>
184 <control>
185 <group>[Master]</group>
186 <key>NovationLaunchpad.incomingData</key>
187 <status>0x90</status>
188 <midino>0x3</midino>
189 <options>
190 <Script-Binding/>
191 </options>
192 </control>
193 <control>
194 <group>[Master]</group>
195 <key>NovationLaunchpad.incomingData</key>
196 <status>0x90</status>
197 <midino>0x4</midino>
198 <options>
199 <Script-Binding/>
200 </options>
201 </control>
202 <control>
203 <group>[Master]</group>
204 <key>NovationLaunchpad.incomingData</key>
205 <status>0x90</status>
206 <midino>0x5</midino>
207 <options>
208 <Script-Binding/>
209 </options>
210 </control>
211 <control>
212 <group>[Master]</group>
213 <key>NovationLaunchpad.incomingData</key>
214 <status>0x90</status>
215 <midino>0x6</midino>
216 <options>
217 <Script-Binding/>
218 </options>
219 </control>
220 <control>
221 <group>[Master]</group>
222 <key>NovationLaunchpad.incomingData</key>
223 <status>0x90</status>
224 <midino>0x7</midino>
225 <options>
226 <Script-Binding/>
227 </options>
228 </control>
229 <control>
230 <group>[Master]</group>
231 <key>NovationLaunchpad.incomingData</key>
232 <status>0x90</status>
233 <midino>0x10</midino>
234 <options>
235 <Script-Binding/>
236 </options>
237 </control>
238 <control>
239 <group>[Master]</group>
240 <key>NovationLaunchpad.incomingData</key>
241 <status>0x90</status>
242 <midino>0x11</midino>
243 <options>
244 <Script-Binding/>
245 </options>
246 </control>
247 <control>
248 <group>[Master]</group>
249 <key>NovationLaunchpad.incomingData</key>
250 <status>0x90</status>
251 <midino>0x12</midino>
252 <options>
253 <Script-Binding/>
254 </options>
255 </control>
256 <control>
257 <group>[Master]</group>
258 <key>NovationLaunchpad.incomingData</key>
259 <status>0x90</status>
260 <midino>0x13</midino>
261 <options>
262 <Script-Binding/>
263 </options>
264 </control>
265 <control>
266 <group>[Master]</group>
267 <key>NovationLaunchpad.incomingData</key>
268 <status>0x90</status>
269 <midino>0x14</midino>
270 <options>
271 <Script-Binding/>
272 </options>
273 </control>
274 <control>
275 <group>[Master]</group>
276 <key>NovationLaunchpad.incomingData</key>
277 <status>0x90</status>
278 <midino>0x15</midino>
279 <options>
280 <Script-Binding/>
281 </options>
282 </control>
283 <control>
284 <group>[Master]</group>
285 <key>NovationLaunchpad.incomingData</key>
286 <status>0x90</status>
287 <midino>0x16</midino>
288 <options>
289 <Script-Binding/>
290 </options>
291 </control>
292 <control>
293 <group>[Master]</group>
294 <key>NovationLaunchpad.incomingData</key>
295 <status>0x90</status>
296 <midino>0x17</midino>
297 <options>
298 <Script-Binding/>
299 </options>
300 </control>
301 <control>
302 <group>[Master]</group>
303 <key>NovationLaunchpad.incomingData</key>
304 <status>0x90</status>
305 <midino>0x20</midino>
306 <options>
307 <Script-Binding/>
308 </options>
309 </control>
310 <control>
311 <group>[Master]</group>
312 <key>NovationLaunchpad.incomingData</key>
313 <status>0x90</status>
314 <midino>0x21</midino>
315 <options>
316 <Script-Binding/>
317 </options>
318 </control>
319 <control>
320 <group>[Master]</group>
321 <key>NovationLaunchpad.incomingData</key>
322 <status>0x90</status>
323 <midino>0x22</midino>
324 <options>
325 <Script-Binding/>
326 </options>
327 </control>
328 <control>
329 <group>[Master]</group>
330 <key>NovationLaunchpad.incomingData</key>
331 <status>0x90</status>
332 <midino>0x23</midino>
333 <options>
334 <Script-Binding/>
335 </options>
336 </control>
337 <control>
338 <group>[Master]</group>
339 <key>NovationLaunchpad.incomingData</key>
340 <status>0x90</status>
341 <midino>0x24</midino>
342 <options>
343 <Script-Binding/>
344 </options>
345 </control>
346 <control>
347 <group>[Master]</group>
348 <key>NovationLaunchpad.incomingData</key>
349 <status>0x90</status>
350 <midino>0x25</midino>
351 <options>
352 <Script-Binding/>
353 </options>
354 </control>
355 <control>
356 <group>[Master]</group>
357 <key>NovationLaunchpad.incomingData</key>
358 <status>0x90</status>
359 <midino>0x26</midino>
360 <options>
361 <Script-Binding/>
362 </options>
363 </control>
364 <control>
365 <group>[Master]</group>
366 <key>NovationLaunchpad.incomingData</key>
367 <status>0x90</status>
368 <midino>0x27</midino>
369 <options>
370 <Script-Binding/>
371 </options>
372 </control>
373 <control>
374 <group>[Master]</group>
375 <key>NovationLaunchpad.incomingData</key>
376 <status>0x90</status>
377 <midino>0x30</midino>
378 <options>
379 <Script-Binding/>
380 </options>
381 </control>
382 <control>
383 <group>[Master]</group>
384 <key>NovationLaunchpad.incomingData</key>
385 <status>0x90</status>
386 <midino>0x31</midino>
387 <options>
388 <Script-Binding/>
389 </options>
390 </control>
391 <control>
392 <group>[Master]</group>
393 <key>NovationLaunchpad.incomingData</key>
394 <status>0x90</status>
395 <midino>0x32</midino>
396 <options>
397 <Script-Binding/>
398 </options>
399 </control>
400 <control>
401 <group>[Master]</group>
402 <key>NovationLaunchpad.incomingData</key>
403 <status>0x90</status>
404 <midino>0x33</midino>
405 <options>
406 <Script-Binding/>
407 </options>
408 </control>
409 <control>
410 <group>[Master]</group>
411 <key>NovationLaunchpad.incomingData</key>
412 <status>0x90</status>
413 <midino>0x34</midino>
414 <options>
415 <Script-Binding/>
416 </options>
417 </control>
418 <control>
419 <group>[Master]</group>
420 <key>NovationLaunchpad.incomingData</key>
421 <status>0x90</status>
422 <midino>0x35</midino>
423 <options>
424 <Script-Binding/>
425 </options>
426 </control>
427 <control>
428 <group>[Master]</group>
429 <key>NovationLaunchpad.incomingData</key>
430 <status>0x90</status>
431 <midino>0x36</midino>
432 <options>
433 <Script-Binding/>
434 </options>
435 </control>
436 <control>
437 <group>[Master]</group>
438 <key>NovationLaunchpad.incomingData</key>
439 <status>0x90</status>
440 <midino>0x37</midino>
441 <options>
442 <Script-Binding/>
443 </options>
444 </control>
445 <control>
446 <group>[Master]</group>
447 <key>NovationLaunchpad.incomingData</key>
448 <status>0x90</status>
449 <midino>0x40</midino>
450 <options>
451 <Script-Binding/>
452 </options>
453 </control>
454 <control>
455 <group>[Master]</group>
456 <key>NovationLaunchpad.incomingData</key>
457 <status>0x90</status>
458 <midino>0x41</midino>
459 <options>
460 <Script-Binding/>
461 </options>
462 </control>
463 <control>
464 <group>[Master]</group>
465 <key>NovationLaunchpad.incomingData</key>
466 <status>0x90</status>
467 <midino>0x42</midino>
468 <options>
469 <Script-Binding/>
470 </options>
471 </control>
472 <control>
473 <group>[Master]</group>
474 <key>NovationLaunchpad.incomingData</key>
475 <status>0x90</status>
476 <midino>0x43</midino>
477 <options>
478 <Script-Binding/>
479 </options>
480 </control>
481 <control>
482 <group>[Master]</group>
483 <key>NovationLaunchpad.incomingData</key>
484 <status>0x90</status>
485 <midino>0x44</midino>
486 <options>
487 <Script-Binding/>
488 </options>
489 </control>
490 <control>
491 <group>[Master]</group>
492 <key>NovationLaunchpad.incomingData</key>
493 <status>0x90</status>
494 <midino>0x45</midino>
495 <options>
496 <Script-Binding/>
497 </options>
498 </control>
499 <control>
500 <group>[Master]</group>
501 <key>NovationLaunchpad.incomingData</key>
502 <status>0x90</status>
503 <midino>0x46</midino>
504 <options>
505 <Script-Binding/>
506 </options>
507 </control>
508 <control>
509 <group>[Master]</group>
510 <key>NovationLaunchpad.incomingData</key>
511 <status>0x90</status>
512 <midino>0x47</midino>
513 <options>
514 <Script-Binding/>
515 </options>
516 </control>
517 <control>
518 <group>[Master]</group>
519 <key>NovationLaunchpad.incomingData</key>
520 <status>0x90</status>
521 <midino>0x50</midino>
522 <options>
523 <Script-Binding/>
524 </options>
525 </control>
526 <control>
527 <group>[Master]</group>
528 <key>NovationLaunchpad.incomingData</key>
529 <status>0x90</status>
530 <midino>0x51</midino>
531 <options>
532 <Script-Binding/>
533 </options>
534 </control>
535 <control>
536 <group>[Master]</group>
537 <key>NovationLaunchpad.incomingData</key>
538 <status>0x90</status>
539 <midino>0x52</midino>
540 <options>
541 <Script-Binding/>
542 </options>
543 </control>
544 <control>
545 <group>[Master]</group>
546 <key>NovationLaunchpad.incomingData</key>
547 <status>0x90</status>
548 <midino>0x53</midino>
549 <options>
550 <Script-Binding/>
551 </options>
552 </control>
553 <control>
554 <group>[Master]</group>
555 <key>NovationLaunchpad.incomingData</key>
556 <status>0x90</status>
557 <midino>0x54</midino>
558 <options>
559 <Script-Binding/>
560 </options>
561 </control>
562 <control>
563 <group>[Master]</group>
564 <key>NovationLaunchpad.incomingData</key>
565 <status>0x90</status>
566 <midino>0x55</midino>
567 <options>
568 <Script-Binding/>
569 </options>
570 </control>
571 <control>
572 <group>[Master]</group>
573 <key>NovationLaunchpad.incomingData</key>
574 <status>0x90</status>
575 <midino>0x56</midino>
576 <options>
577 <Script-Binding/>
578 </options>
579 </control>
580 <control>
581 <group>[Master]</group>
582 <key>NovationLaunchpad.incomingData</key>
583 <status>0x90</status>
584 <midino>0x57</midino>
585 <options>
586 <Script-Binding/>
587 </options>
588 </control>
589 <control>
590 <group>[Master]</group>
591 <key>NovationLaunchpad.incomingData</key>
592 <status>0x90</status>
593 <midino>0x60</midino>
594 <options>
595 <Script-Binding/>
596 </options>
597 </control>
598 <control>
599 <group>[Master]</group>
600 <key>NovationLaunchpad.incomingData</key>
601 <status>0x90</status>
602 <midino>0x61</midino>
603 <options>
604 <Script-Binding/>
605 </options>
606 </control>
607 <control>
608 <group>[Master]</group>
609 <key>NovationLaunchpad.incomingData</key>
610 <status>0x90</status>
611 <midino>0x62</midino>
612 <options>
613 <Script-Binding/>
614 </options>
615 </control>
616 <control>
617 <group>[Master]</group>
618 <key>NovationLaunchpad.incomingData</key>
619 <status>0x90</status>
620 <midino>0x63</midino>
621 <options>
622 <Script-Binding/>
623 </options>
624 </control>
625 <control>
626 <group>[Master]</group>
627 <key>NovationLaunchpad.incomingData</key>
628 <status>0x90</status>
629 <midino>0x64</midino>
630 <options>
631 <Script-Binding/>
632 </options>
633 </control>
634 <control>
635 <group>[Master]</group>
636 <key>NovationLaunchpad.incomingData</key>
637 <status>0x90</status>
638 <midino>0x65</midino>
639 <options>
640 <Script-Binding/>
641 </options>
642 </control>
643 <control>
644 <group>[Master]</group>
645 <key>NovationLaunchpad.incomingData</key>
646 <status>0x90</status>
647 <midino>0x66</midino>
648 <options>
649 <Script-Binding/>
650 </options>
651 </control>
652 <control>
653 <group>[Master]</group>
654 <key>NovationLaunchpad.incomingData</key>
655 <status>0x90</status>
656 <midino>0x67</midino>
657 <options>
658 <Script-Binding/>
659 </options>
660 </control>
661 <control>
662 <group>[Master]</group>
663 <key>NovationLaunchpad.incomingData</key>
664 <status>0x90</status>
665 <midino>0x70</midino>
666 <options>
667 <Script-Binding/>
668 </options>
669 </control>
670 <control>
671 <group>[Master]</group>
672 <key>NovationLaunchpad.incomingData</key>
673 <status>0x90</status>
674 <midino>0x71</midino>
675 <options>
676 <Script-Binding/>
677 </options>
678 </control>
679 <control>
680 <group>[Master]</group>
681 <key>NovationLaunchpad.incomingData</key>
682 <status>0x90</status>
683 <midino>0x72</midino>
684 <options>
685 <Script-Binding/>
686 </options>
687 </control>
688 <control>
689 <group>[Master]</group>
690 <key>NovationLaunchpad.incomingData</key>
691 <status>0x90</status>
692 <midino>0x73</midino>
693 <options>
694 <Script-Binding/>
695 </options>
696 </control>
697 <control>
698 <group>[Master]</group>
699 <key>NovationLaunchpad.incomingData</key>
700 <status>0x90</status>
701 <midino>0x74</midino>
702 <options>
703 <Script-Binding/>
704 </options>
705 </control>
706 <control>
707 <group>[Master]</group>
708 <key>NovationLaunchpad.incomingData</key>
709 <status>0x90</status>
710 <midino>0x75</midino>
711 <options>
712 <Script-Binding/>
713 </options>
714 </control>
715 <control>
716 <group>[Master]</group>
717 <key>NovationLaunchpad.incomingData</key>
718 <status>0x90</status>
719 <midino>0x76</midino>
720 <options>
721 <Script-Binding/>
722 </options>
723 </control>
724 <control>
725 <group>[Master]</group>
726 <key>NovationLaunchpad.incomingData</key>
727 <status>0x90</status>
728 <midino>0x77</midino>
729 <options>
730 <Script-Binding/>
731 </options>
732 </control>
733 </controls>
734 <outputs/>
735 </controller>
736</MixxxControllerPreset>
0737
=== added file 'mixxx/res/controllers/Novation-Launchpad-scripts.js'
--- mixxx/res/controllers/Novation-Launchpad-scripts.js 1970-01-01 00:00:00 +0000
+++ mixxx/res/controllers/Novation-Launchpad-scripts.js 2012-05-26 14:59:19 +0000
@@ -0,0 +1,819 @@
1/****************************************************************/
2/* Novation Launchpad Mapping */
3/* For Mixxx version 1.11 */
4/* Author: zestoi */
5/****************************************************************/
6
7NovationLaunchpad = {
8
9 init: function() {
10
11 //
12 // setup variables and methods
13 //
14
15 this.page = 1;
16 this.shift = 0;
17 this.shift2 = 0;
18 this.callbacks = {};
19 this.feedbacks = {};
20 this.cache = [{}, {}, {}, {}];
21 this.feedback_cache = {};
22 this.toggle_cache = [{}, {}, {}, {}];
23 this.name2control = {};
24 this.control2name = {};
25 this.vumeters = [];
26
27 var self = NovationLaunchpad;
28 this.colors = self.colors();
29 this.capture = self.capture;
30 this.feedback = self.feedback;
31 this.send = self.send;
32 this.button = self.button;
33 this.toggle = self.toggle;
34 this.hotcue = self.hotcue;
35 this.flanger = self.flanger;
36 this.jog = self.jog;
37 this.get = self.get;
38 this.loop = self.loop;
39 this.gator = self.gator;
40 this.set_page = self.set_page;
41 this.vfader = self.vfader;
42 this.vumeter = self.vumeter;
43 this.vumeter_toggle = self.vumeter_toggle;
44 this.playlist = self.playlist;
45
46 //
47 // map the midi config into something more useful
48 //
49
50 var buttons = self.buttons();
51 for (name in buttons) {
52 var type = buttons[name][0];
53 var chan = buttons[name][1];
54 var value = buttons[name][2];
55 var status = (type == 'cc') ? 0xb0 + chan - 1 : 0x90 + chan - 1;
56 this.name2control[name]= [ status, value ];
57 this.control2name["" + status + value] = name; // stringify it
58 }
59
60 //
61 // reset device, enable flashing colors
62 //
63
64 midi.sendShortMsg(0xb0, 0x0, 0x0);
65 midi.sendShortMsg(0xb0, 0x0, 0x28);
66
67 /////////////////////////////////////////////////////////////////////////
68 // button layout mapping starts here
69 /////////////////////////////////////////////////////////////////////////
70
71 // shift buttons
72
73 this.button("arm", "all", 1, 'hi_yellow', 'lo_yellow', '', '', function(g, n, v) { this.shift = v > 0 ? 1 : 0; });
74 this.button("solo", "all", 1, 'hi_yellow', 'lo_yellow', '', '', function(g, n, v) { this.shift2 = v > 0 ? 1 : 0; });
75 this.toggle("mixer", "all", 0, 'hi_red', 'lo_red', '', '', function(g, n, v) { this.set_page(v > 0 ? 2 : 1); });
76 this.toggle("vol", "all", 2, 'hi_red', 'lo_red', '', '', function(g, n, v) { this.vumeter_toggle(v); });
77
78 //// MAIN PAGE ////
79
80 // track navigation
81
82 this.playlist("up", 0, "SelectPrevTrack");
83 this.playlist("down", 0, "SelectNextTrack");
84 this.button("left", "press", 0, 'hi_yellow', 'lo_yellow', "[Playlist]", "SelectPrevPlaylist");
85 this.button("right", "press", 0, 'hi_yellow', 'lo_yellow', "[Playlist]", "SelectNextPlaylist");
86
87 // deck mappings
88
89 for (deck=1; deck<=2; deck++) {
90 var offset = deck == 1 ? 0 : 4;
91 var group = "[Channel" + deck + "]";
92
93 // tracks
94
95 this.toggle("0," + (offset + 0), "all", 1, 'hi_red', 'lo_red', group, "quantize");
96 this.toggle("0," + (offset + 1), "all", 1, 'hi_red', 'lo_red', group, "keylock");
97 this.toggle("0," + (offset + 2), "all", 1, 'hi_red', 'lo_red', group, "pfl");
98 this.button("0," + (offset + 3), "all", 1, 'hi_yellow', 'lo_amber', group, "LoadSelectedTrack");
99
100 // flanger
101
102 this.flanger("1," + (offset + 0), 1, group, 0.5, 1500000, 333);
103 this.flanger("1," + (offset + 1), 1, group, 1, 500000, 666);
104
105 // spinback effect
106
107 this.button("1," + (offset + 2), "all", 1, 'hi_red', 'lo_red', group, "", function(g, n, v) {
108 script.spinback(g, v > 0);
109 });
110
111 // brake effect
112
113 this.button("1," + (offset + 3), "all", 1, 'hi_red', 'lo_red', group, "", function(g, n, v) {
114 script.brake(g, v > 0);
115 });
116
117 // instant loops
118
119 this.loop("2," + (offset + 0), 1, group, 1);
120 this.loop("2," + (offset + 1), 1, group, 0.5);
121 this.loop("2," + (offset + 2), 1, group, 0.25);
122 this.loop("2," + (offset + 3), 1, group, 0.125);
123
124 // loop in or loop half when active
125
126 this.button("3," + (offset + 0), "press", 1, 'hi_green', 'lo_green', group, "", function(g, n, v) {
127 if (engine.getValue(g, "loop_enabled")) {
128 engine.setValue(g, "loop_halve", 1);
129 }
130 else {
131 engine.setValue(g, "loop_in", 1);
132 }
133 });
134
135 // loop out or loop double when active
136
137 this.button("3," + (offset + 1), "press", 1, 'hi_green', 'lo_green', group, "", function(g, n, v) {
138 if (engine.getValue(g, "loop_enabled")) {
139 engine.setValue(g, "loop_double", 1);
140 }
141 else {
142 engine.setValue(g, "loop_out", 1);
143 }
144 });
145
146 // reloop or exit loop
147
148 this.button("3," + (offset + 2), "all", 1, 'hi_green', 'lo_green', group, "reloop_exit");
149
150 // gator effect
151
152 this.gator("3," + (offset + 3), 1, group, 8, 0.7);
153
154 // led feedback for loop in/out buttons to show loop status
155
156 this.feedback(group, "loop_enabled", function(self, g, e, value) {
157 var offset = g == "[Channel1]" ? 0 : 4; // ????
158 self.send("3," + (offset + 0), self.colors[value > 0 ? 'hi_green' : 'lo_green'], page);
159 self.send("3," + (offset + 1), self.colors[value > 0 ? 'hi_green' : 'lo_green'], page);
160 });
161
162 // hotcues or needle drop with shift2 pressed
163
164 this.hotcue("4," + (offset + 0), 1, group, 1);
165 this.hotcue("4," + (offset + 1), 1, group, 2);
166 this.hotcue("4," + (offset + 2), 1, group, 3);
167 this.hotcue("4," + (offset + 3), 1, group, 4);
168 this.hotcue("5," + (offset + 0), 1, group, 5);
169 this.hotcue("5," + (offset + 1), 1, group, 6);
170 this.hotcue("5," + (offset + 2), 1, group, 7);
171 this.hotcue("5," + (offset + 3), 1, group, 8);
172
173 // transport
174
175 this.button("6," + (offset + 0), "all", 1, 'hi_yellow', 'lo_red', group, "cue_default");
176
177 this.button("6," + (offset + 1), "press", 1, 'hi_yellow', 'lo_yellow', group, "rate", function(g, n, v) {
178 engine.setValue(g, n, 0);
179 });
180
181 this.button("6," + (offset + 2), "press", 1, 'hi_yellow', 'lo_yellow', group, "rate_perm_down_small");
182 this.button("6," + (offset + 3), "press", 1, 'hi_yellow', 'lo_yellow', group, "rate_perm_up_small");
183
184 // play button
185 this.toggle("7," + (offset + 0), "press", 1, 'hi_yellow', 'lo_red', group, "play");
186
187 // flash play button when near end of track
188 this.feedback(group, "playposition", function(self, g, e, value) {
189 if (value > 0.9 && engine.getValue(g, "play") > 0) {
190 self.send(g == "[Channel1]" ? "7,0" : "7,4", self.colors['flash_hi_red'], 1);
191 }
192 });
193
194 // sync or move beatgrid when shift is pressed
195
196 this.button("7," + (offset + 1), "all", 1, 'hi_yellow', 'lo_amber', group, "beatsync", function(g, n, v) {
197 if (this.shift > 0)
198 engine.setValue(g, "beats_translate_curpos", v > 0 ? 1 : 0);
199 else
200 engine.setValue(g, n, v > 0 ? 1 : 0);
201 });
202
203 // fwd/rev when not playing unless shift and then fine jog movements for beat gridding, jog when playing, jog more when shift+playing
204
205 this.jog("7," + (offset + 2), 1, group, "back");
206 this.jog("7," + (offset + 3), 1, group, "fwd");
207 }
208
209 //// MIXER PAGE ////
210
211 this.toggle("0,0", "all", 2, 'flash_hi_red', 'lo_red', "[Channel1]", "filterHighKill");
212 this.toggle("0,1", "all", 2, 'flash_hi_red', 'lo_red', "[Channel1]", "filterMidKill");
213 this.toggle("0,2", "all", 2, 'flash_hi_red', 'lo_red', "[Channel1]", "filterLowKill");
214 this.toggle("0,5", "all", 2, 'flash_hi_red', 'lo_red', "[Channel2]", "filterHighKill");
215 this.toggle("0,6", "all", 2, 'flash_hi_red', 'lo_red', "[Channel2]", "filterMidKill");
216 this.toggle("0,7", "all", 2, 'flash_hi_red', 'lo_red', "[Channel2]", "filterLowKill");
217
218 this.vfader(7, 0, 2, 7, 'hi_orange', 'lo_green', "[Channel1]", "filterLow");
219 this.vfader(7, 1, 2, 7, 'hi_orange', 'lo_green', "[Channel1]", "filterMid");
220 this.vfader(7, 2, 2, 7, 'hi_orange', 'lo_green', "[Channel1]", "filterHigh");
221 this.vfader(7, 5, 2, 7, 'hi_orange', 'lo_green', "[Channel2]", "filterLow");
222 this.vfader(7, 6, 2, 7, 'hi_orange', 'lo_green', "[Channel2]", "filterMid");
223 this.vfader(7, 7, 2, 7, 'hi_orange', 'lo_green', "[Channel2]", "filterHigh");
224
225 this.vfader(7, 3, 2, 8, 'hi_yellow', 'lo_red', "[Channel1]", "volume");
226 this.vfader(7, 4, 2, 8, 'hi_yellow', 'lo_red', "[Channel2]", "volume");
227 this.vumeter(7, 3, 2, 8, 'hi_yellow', 'lo_red', "[Channel1]", "VuMeter");
228 this.vumeter(7, 4, 2, 8, 'hi_yellow', 'lo_red', "[Channel2]", "VuMeter");
229
230 /////////////////////////////////////////////////////////////////////////
231 // button layout mapping ends here
232 /////////////////////////////////////////////////////////////////////////
233 },
234
235 //
236 // convert incoming midi to a 'name' and call callbacks (if any)
237 //
238
239 incomingData: function(channel, control, value, status, group) {
240 if ((name = this.control2name["" + status + control]) != undefined) {
241 if (this.callbacks[name] != undefined) {
242 var callbacks = this.callbacks[name];
243 for (var i=0; i<callbacks.length; i++) {
244 if ((callbacks[i][1] == 0 || callbacks[i][1] == this.page) && typeof(callbacks[i][2]) == 'function') {
245
246 //
247 // check we need to call for this value change: all, press, release
248 //
249
250 if (callbacks[i][0] == "all" ||
251 (callbacks[i][0] == "press" && value > 0) ||
252 (callbacks[i][0] == "release" && value == 0)) {
253
254 //
255 // call a callback function for this control
256 //
257
258 callbacks[i][2](this, group, name, value);
259 }
260 }
261 }
262 }
263 }
264 },
265
266 //
267 // gator effect using high eq kill
268 //
269
270 gator: function(name, page, group, rate, depth) {
271 this.button(name, "all", page, 'hi_red', 'lo_red', group, "", function(g, n, v) {
272 var self = NovationLaunchpad;
273 if (typeof(self.gator_timer) != undefined && self.gator_timer != null) {
274 engine.stopTimer(self.gator_timer);
275 self.gator_timer = null;
276 }
277
278 if (v > 0) {
279 if ((bpm = engine.getValue(g, 'bpm')) > 0) {
280 var interval = parseInt(1000 / bpm * 60 / rate);
281 self.gator_direction = false;
282 self.gator_depth = depth;
283 self.gator_timer = engine.beginTimer(interval, 'NovationLaunchpad.process_gator("' + g + '")');
284 }
285 }
286 else {
287 engine.setValue(group, 'filterHighKill', 0);
288 }
289 });
290 },
291
292 //
293 // gator
294 //
295
296 process_gator: function(group) {
297 var self = NovationLaunchpad;
298 self.gator_direction = !self.gator_direction;
299 engine.setValue(group, 'filterHighKill', self.gator_direction ? 1 : 0);
300 },
301
302 //
303 // flanger button
304 //
305
306 flanger: function(name, page, group, depth, period, delay) {
307 this.button(name, "all", page, 'hi_amber', 'lo_amber', group, "flanger", function(g, name, v) {
308 if (v > 0) {
309 engine.setValue("[Flanger]", "lfoDepth", depth);
310 engine.setValue("[Flanger]", "lfoPeriod", period);
311 engine.setValue("[Flanger]", "lfoDelay", delay);
312 }
313 engine.setValue(group, "flanger", v > 0 ? 1 : 0);
314 });
315 },
316
317 loop: function(name, page, group, size) {
318 this.button(name, "all", page, 'hi_yellow', 'lo_yellow', group, "", function(g, name, v) {
319 if (v > 0) {
320 engine.setValue(g, "beatloop_" + size + "_activate", 1);
321 }
322 else {
323 if (engine.getValue(g, "beatloop_" + size + "_enabled")) {
324 engine.setValue(g, "beatloop_" + size + "_toggle", 1);
325 }
326 }
327 });
328 },
329
330 //
331 // track scrolling
332 //
333
334 playlist: function(name, page, action) {
335 this.button(name, "all", page, 'hi_yellow', 'lo_yellow', "[Playlist]", action, function(g, n, v) {
336 var self = NovationLaunchpad;
337 if (typeof(self.playlist_timer) != undefined && self.playlist_timer != null) {
338 engine.stopTimer(self.playlist_timer);
339 self.playlist_timer = null;
340 }
341
342 if (v > 0) {
343 engine.setValue("[Playlist]", action, 1);
344 self.playlist_timer = engine.beginTimer(this.shift > 0 ? 30 : 150, 'NovationLaunchpad.process_playlist("' + action + '")');
345 }
346 });
347 },
348
349 process_playlist: function(name) {
350 engine.setValue("[Playlist]", name, 1);
351 },
352
353 //
354 // map a callback to an event from mixxx
355 //
356
357 feedback: function(g, e, f) {
358 if (g != "" && e != "") {
359 engine.connectControl(g, e, "NovationLaunchpad.feedbackData");
360 if (this.feedbacks[g + e] == undefined) {
361 this.feedbacks[g + e] = [];
362 }
363 this.feedbacks[g + e].push(f);
364 }
365 },
366
367 //
368 // call callbacks from mixxx events
369 //
370
371 feedbackData: function(v, g, e) {
372 this.feedback_cache[g + e] = v;
373 if (this.feedbacks[g + e] != undefined) {
374 for (func in this.feedbacks[g + e]) {
375 if (typeof(this.feedbacks[g + e][func]) == "function") {
376 this.feedbacks[g + e][func](this, g, e, v);
377 }
378 }
379 }
380 },
381
382 //
383 // map a callback to a launchpad button name
384 //
385
386 capture: function(name, values, page, func) {
387 if (this.callbacks[name] == undefined) {
388 this.callbacks[name] = [ [ values, page, func ] ];
389 }
390 else {
391 this.callbacks[name].push([ values, page, func ]);
392 }
393 },
394
395 //
396 // send back to the launchpad for leds by name
397 //
398
399 send: function(name, value, page) {
400 if (page == 0 || this.page == page) {
401 if ((control = this.name2control[name]) != undefined) {
402 if (this.cache[page][name] == value) return;
403 midi.sendShortMsg(control[0], control[1], value);
404 }
405 }
406 this.cache[page][name] = value;
407 },
408
409 //
410 // hold button
411 //
412
413 button: function(name, values, page, on_color, off_color, group, event, callback) {
414
415 // launchpad => mixxx
416
417 this.capture(name, "all", page, function(self, g, name, value) {
418 if (callback == undefined) {
419 engine.setValue(group, event, value);
420 }
421 else if (typeof(callback) == "function") {
422 if (values == "all" || (values == "press" && value > 0) || (values == "release" && value == 0)) {
423 callback(group, event, value);
424 }
425 }
426
427 if (values == "all" || (values == "press" && value > 0) || (values == "release" && value == 0)) {
428 self.send(name, self.colors[value > 0 ? on_color : off_color], page);
429 }
430 });
431
432 // mixxx => launchpad
433
434 this.feedback(group, event, function(self, g, e, value) {
435 self.send(name, self.colors[value > 0 ? on_color : off_color], page);
436 });
437
438 // init led
439
440 this.send(name, this.colors[off_color], page);
441 },
442
443 //
444 // toggle
445 //
446
447 toggle: function(name, values, page, on_color, off_color, group, event, callback) {
448 this.capture(name, "press", page, function(self, g, name, value) {
449 if (typeof(self.toggle_cache[page][name]) == "undefined") {
450 self.toggle_cache[page][name] = 0;
451 }
452 self.toggle_cache[page][name] = self.toggle_cache[page][name] == 0 ? 1 : 0;
453
454 if (callback == undefined) {
455 engine.setValue(group, event, self.toggle_cache[page][name]);
456 }
457 else if (typeof(callback) == "function") {
458 callback(group, event, self.toggle_cache[page][name]);
459 }
460
461 self.send(name, self.colors[self.toggle_cache[page][name] > 0 ? on_color : off_color], page);
462 });
463
464 // mixxx => launchpad
465
466 this.feedback(group, event, function(self, g, e, value) {
467 self.send(name, self.colors[value > 0 ? on_color : off_color], page);
468 self.toggle_cache[page][name] = value > 0 ? 1 : 0;
469 });
470
471 // init led
472
473 this.send(name, this.colors[off_color], page);
474 },
475
476 //
477 // hotcues
478 //
479
480 hotcue: function(name, page, group, num) {
481 this.capture(name, "press", page, function(self, g, name, value) {
482 if (self.shift2) {
483 engine.setValue(group, "playposition", (num-1)/8);
484 }
485 else if (self.shift) {
486 engine.setValue(group, "hotcue_" + num + "_clear", 1);
487 }
488 else {
489 engine.setValue(group, "hotcue_" + num + "_activate", 1);
490 }
491 });
492
493 this.feedback(group, "hotcue_" + num + "_enabled", function(self, g, e, value) {
494 self.send(name, self.colors[value > 0 ? 'hi_red' : 'black'], page);
495 });
496 },
497
498 //
499 // jog
500 //
501
502 jog: function(name, page, group, dir) {
503 this.button(name, "all", page, 'hi_yellow', 'lo_amber', group, "", function(g, n, v) {
504
505 if (dir == "fwd") {
506 mult = 1;
507 rate = "rate_temp_up";
508 }
509 else {
510 mult = -1;
511 rate = "rate_temp_down";
512 }
513
514 if (engine.getValue(g, "play") > 0) {
515 if (this.shift > 0) {
516 engine.setValue(g, rate, v > 0 ? 1 : 0);
517 }
518 else {
519 engine.setValue(g, rate + "_small", v > 0 ? 1 : 0);
520 }
521 }
522 else if (this.shift > 0) {
523 if (v > 0) {
524 engine.setValue(g, 'jog', 0.2 * mult);
525 }
526 }
527 else engine.setValue(g, dir, v);
528 });
529 },
530
531 //
532 // turn a column of pads into a virtual fader
533 //
534
535 vfader: function(y, x, page, nbtns, on_color, off_color, group, action) {
536 var incr = 1 / nbtns;
537
538 // launchpad => mixxx
539
540 for (var btn=0; btn<nbtns; btn++) {
541 this.capture((y-btn)+","+x, "press", page, function(self, g, name, value) {
542 var cap = name.match(/^(\d+),\d+/);
543 var num = y - cap[1] + 1;
544 engine.setValue(group, action, incr * num);
545 });
546 this.send((y-btn)+","+x, this.colors[on_color], page);
547 }
548
549 // mixxx => launchpad
550
551 this.feedback(group, action, function(self, g, e, value) {
552 for (btn=0; btn<nbtns; btn++) {
553 if (value > btn*incr) {
554 self.send((y-btn)+","+x, self.colors[on_color], page);
555 }
556 else {
557 self.send((y-btn)+","+x, self.colors[off_color], page);
558 }
559 }
560 });
561 },
562
563 //
564 // turn a column of pads into a vumeter
565 //
566
567 vumeter: function(y, x, page, nbtns, on_color, off_color, group, action) {
568 var incr = 1 / nbtns;
569 this.vumeters.push([ y, x, page, nbtns, on_color, off_color, group, action ]);
570 this.feedback(group, action, function(self, g, e, value) {
571 if (self.vumeter_shift > 0) {
572 for (btn=0; btn<nbtns; btn++) {
573 if (value > btn*incr) {
574 self.send((y-btn)+","+x, self.colors[on_color], page);
575 }
576 else {
577 self.send((y-btn)+","+x, self.colors[off_color], page);
578 }
579 }
580 }
581 });
582 },
583
584 vumeter_toggle: function(v) {
585 this.vumeter_shift = v > 0 ? 1 : 0;
586
587 //
588 // clear fader leds when enabling vumeter and set back the leds for the volume if disabling
589 //
590
591 for (i in this.vumeters) {
592
593 var value = this.vumeter_shift > 0 ? 0 : this.feedback_cache[ this.vumeters[i][6] + 'volume' ];
594
595 if (value != undefined) {
596 var y = this.vumeters[i][0];
597 var x = this.vumeters[i][1];
598 var page = this.vumeters[i][2];
599 var nbtns = this.vumeters[i][3];
600 var on_color = this.vumeters[i][4];
601 var off_color = this.vumeters[i][5];
602 var incr = 1 / nbtns;
603
604 for (btn=0; btn<nbtns; btn++) {
605 if (value > btn*incr) {
606 this.send((y-btn)+","+x, this.colors[on_color], page);
607 }
608 else {
609 this.send((y-btn)+","+x, this.colors[off_color], page);
610 }
611 }
612 }
613 }
614 },
615
616 //
617 // get the last value sent to a launchpad led
618 //
619
620 get: function(name, page) {
621 if (typeof(this.cache[page][name]) == undefined) {
622 return 0;
623 }
624 else {
625 return this.cache[page][name];
626 }
627 },
628
629 //
630 // set page
631 //
632
633 set_page: function(page) {
634 if (page == this.page) return;
635
636 var updates = {};
637 var flashing = [];
638
639 for (i in this.cache[page]) {
640 if (this.cache[this.page][i] == undefined || this.cache[this.page][i] != this.cache[page][i]) {
641 updates[i] = this.cache[page][i];
642 }
643 }
644
645 for (i in this.cache[this.page]) {
646 if (this.cache[page][i] == undefined) {
647 updates[i] = 0x4; // black with copy bit set
648 }
649 else if (this.cache[this.page][i] != this.cache[page][i] && updates[i] == undefined) {
650 updates[i] = this.cache[page][i];
651 }
652 }
653
654 // select buffer 1
655 midi.sendShortMsg(0xb0, 0x0, 0x31);
656
657 for (i in updates) {
658 if ((control = this.name2control[i]) != undefined) {
659
660 // 0 makes no sense - need 0x4 for black/off
661 if (updates[i] == 0) {
662 updates[i] = 0x4;
663 }
664
665 // send out non-flashing colors with copy bit removed
666 if (updates[i] & 0x4) {
667 midi.sendShortMsg(control[0], control[1], updates[i] & 0xfb);
668 }
669 else {
670 // send out off for this buffer for a flashing color
671 midi.sendShortMsg(control[0], control[1], 0x4);
672 flashing.push([ control[0], control[1], updates[i] ]);
673 }
674 }
675 }
676
677 // select buffer 0
678 midi.sendShortMsg(0xb0, 0x0, 0x34);
679
680 // send out any flashing updates
681 for (i in flashing) {
682 midi.sendShortMsg(flashing[i][0], flashing[i][1], flashing[i][2]);
683 }
684
685 // re-enable internal buffer cycling for flashing colors
686 midi.sendShortMsg(0xb0, 0x0, 0x28);
687
688 this.page = page;
689 },
690
691 //
692 // define colors
693 //
694
695 colors: function() {
696 return {
697 black: 4,
698
699 lo_red: 1 + 4,
700 mi_red: 2 + 4,
701 hi_red: 3 + 4,
702 lo_green: 16 + 4,
703 mi_green: 32 + 4,
704 hi_green: 48 + 4,
705 lo_amber: 17 + 4,
706 mi_amber: 34 + 4,
707 hi_amber: 51 + 4,
708 hi_orange: 35 + 4,
709 lo_orange: 18 + 4,
710 hi_yellow: 50 + 4,
711 lo_yellow: 33 + 4,
712
713 flash_lo_red: 1,
714 flash_mi_red: 2,
715 flash_hi_red: 3,
716 flash_lo_green: 16,
717 flash_mi_green: 32,
718 flash_hi_green: 48,
719 flash_lo_amber: 17,
720 flash_mi_amber: 34,
721 flash_hi_amber: 51,
722 flash_hi_orange: 35,
723 flash_lo_orange: 18,
724 flash_hi_yellow: 50,
725 flash_lo_yellow: 33
726 }
727 },
728
729 //
730 // define midi for all the buttons (as we can't define names in the xml or access that data here)
731 // to create a 90 degree rotated mapping just redefine this list so "0,0" is still top left etc
732 //
733
734 buttons: function() {
735 return {
736 'up': [ 'cc', 1, 0x68 ],
737 'down': [ 'cc', 1, 0x69 ],
738 'left': [ 'cc', 1, 0x6A ],
739 'right': [ 'cc', 1, 0x6B ],
740 'session': [ 'cc', 1, 0x6C ],
741 'user1': [ 'cc', 1, 0x6D ],
742 'user2': [ 'cc', 1, 0x6E ],
743 'mixer': [ 'cc', 1, 0x6F ],
744 'vol': [ 'note', 1, 0x8 ],
745 'pan': [ 'note', 1, 0x18 ],
746 'snda': [ 'note', 1, 0x28 ],
747 'sndb': [ 'note', 1, 0x38 ],
748 'stop': [ 'note', 1, 0x48 ],
749 'trkon': [ 'note', 1, 0x58 ],
750 'solo': [ 'note', 1, 0x68 ],
751 'arm': [ 'note', 1, 0x78 ],
752 '0,0': [ 'note', 1, 0x00 ],
753 '0,1': [ 'note', 1, 0x01 ],
754 '0,2': [ 'note', 1, 0x02 ],
755 '0,3': [ 'note', 1, 0x03 ],
756 '0,4': [ 'note', 1, 0x04 ],
757 '0,5': [ 'note', 1, 0x05 ],
758 '0,6': [ 'note', 1, 0x06 ],
759 '0,7': [ 'note', 1, 0x07 ],
760 '1,0': [ 'note', 1, 0x10 ],
761 '1,1': [ 'note', 1, 0x11 ],
762 '1,2': [ 'note', 1, 0x12 ],
763 '1,3': [ 'note', 1, 0x13 ],
764 '1,4': [ 'note', 1, 0x14 ],
765 '1,5': [ 'note', 1, 0x15 ],
766 '1,6': [ 'note', 1, 0x16 ],
767 '1,7': [ 'note', 1, 0x17 ],
768 '2,0': [ 'note', 1, 0x20 ],
769 '2,1': [ 'note', 1, 0x21 ],
770 '2,2': [ 'note', 1, 0x22 ],
771 '2,3': [ 'note', 1, 0x23 ],
772 '2,4': [ 'note', 1, 0x24 ],
773 '2,5': [ 'note', 1, 0x25 ],
774 '2,6': [ 'note', 1, 0x26 ],
775 '2,7': [ 'note', 1, 0x27 ],
776 '3,0': [ 'note', 1, 0x30 ],
777 '3,1': [ 'note', 1, 0x31 ],
778 '3,2': [ 'note', 1, 0x32 ],
779 '3,3': [ 'note', 1, 0x33 ],
780 '3,4': [ 'note', 1, 0x34 ],
781 '3,5': [ 'note', 1, 0x35 ],
782 '3,6': [ 'note', 1, 0x36 ],
783 '3,7': [ 'note', 1, 0x37 ],
784 '4,0': [ 'note', 1, 0x40 ],
785 '4,1': [ 'note', 1, 0x41 ],
786 '4,2': [ 'note', 1, 0x42 ],
787 '4,3': [ 'note', 1, 0x43 ],
788 '4,4': [ 'note', 1, 0x44 ],
789 '4,5': [ 'note', 1, 0x45 ],
790 '4,6': [ 'note', 1, 0x46 ],
791 '4,7': [ 'note', 1, 0x47 ],
792 '5,0': [ 'note', 1, 0x50 ],
793 '5,1': [ 'note', 1, 0x51 ],
794 '5,2': [ 'note', 1, 0x52 ],
795 '5,3': [ 'note', 1, 0x53 ],
796 '5,4': [ 'note', 1, 0x54 ],
797 '5,5': [ 'note', 1, 0x55 ],
798 '5,6': [ 'note', 1, 0x56 ],
799 '5,7': [ 'note', 1, 0x57 ],
800 '6,0': [ 'note', 1, 0x60 ],
801 '6,1': [ 'note', 1, 0x61 ],
802 '6,2': [ 'note', 1, 0x62 ],
803 '6,3': [ 'note', 1, 0x63 ],
804 '6,4': [ 'note', 1, 0x64 ],
805 '6,5': [ 'note', 1, 0x65 ],
806 '6,6': [ 'note', 1, 0x66 ],
807 '6,7': [ 'note', 1, 0x67 ],
808 '7,0': [ 'note', 1, 0x70 ],
809 '7,1': [ 'note', 1, 0x71 ],
810 '7,2': [ 'note', 1, 0x72 ],
811 '7,3': [ 'note', 1, 0x73 ],
812 '7,4': [ 'note', 1, 0x74 ],
813 '7,5': [ 'note', 1, 0x75 ],
814 '7,6': [ 'note', 1, 0x76 ],
815 '7,7': [ 'note', 1, 0x77 ]
816 };
817 }
818};
819
0820
=== modified file 'mixxx/res/controllers/common-controller-scripts.js'
--- mixxx/res/controllers/common-controller-scripts.js 2012-04-03 11:49:10 +0000
+++ mixxx/res/controllers/common-controller-scripts.js 2012-05-26 14:59:19 +0000
@@ -82,7 +82,7 @@
8282
8383
84script.pitch = function (LSB, MSB, status) {84script.pitch = function (LSB, MSB, status) {
85 script.midiPitch(LSB, MSB, status);85 return script.midiPitch(LSB, MSB, status);
86}86}
8787
88/* -------- ------------------------------------------------------88/* -------- ------------------------------------------------------
@@ -106,6 +106,115 @@
106 return rate;106 return rate;
107}107}
108108
109/* -------- ------------------------------------------------------
110 script.spinbackDefault
111 Purpose: wrapper around spinback() that can be directly mapped
112 from xml for a spinback effect
113 Input: channel, control, value, status, group
114 Output: none
115 -------- ------------------------------------------------------ */
116script.spinbackDefault = function(channel, control, value, status, group) {
117 // disable on note-off or zero value note/cc
118 script.spinback(group, ((status & 0xF0) != 0x80 && value > 0));
119}
120
121/* -------- ------------------------------------------------------
122 script.brakeDefault
123 Purpose: wrapper around brake() that can be directly mapped
124 from xml for a brake effect
125 Input: channel, control, value, status, group
126 Output: none
127 -------- ------------------------------------------------------ */
128script.brakeDefault = function(channel, control, value, status, group) {
129 // disable on note-off or zero value note/cc
130 script.brake(group, ((status & 0xF0) != 0x80 && value > 0));
131}
132
133/* -------- ------------------------------------------------------
134 script.spinback
135 Purpose: Activate or disable a spinback effect on the chosen deck
136 Input: group, enable/disable, [delay], [factor], [inital rate]
137 Output: None
138 -------- ------------------------------------------------------ */
139script.spinback = function(group, activate, factor, rate, delay) {
140 if (factor == undefined) factor = 0.8;
141 if (rate == undefined) rate = -10;
142 if (delay == undefined) delay = 5;
143 script.deckSpinbackBrake(group, activate, factor, rate, delay);
144}
145
146/* -------- ------------------------------------------------------
147 script.brake
148 Purpose: Activate or disable a brake effect on the chosen deck
149 Input: group, enable/disable, [delay], [factor], [inital rate]
150 Output: None
151 -------- ------------------------------------------------------ */
152script.brake = function(group, activate, factor, rate, delay) {
153 if (factor == undefined) factor = 0.95;
154 if (rate == undefined) rate = 1;
155 if (delay == undefined) delay = 0;
156 script.deckSpinbackBrake(group, activate, factor, rate, delay);
157}
158
159script.deckSpinbackBrakeData = {};
160
161script.deckSpinbackBrake = function(group, activate, factor, rate, delay) {
162
163 if (activate != undefined) {
164
165 // store the current settings
166
167 if (script.deckSpinbackBrakeData[group] == undefined) {
168 script.deckSpinbackBrakeData[group] = { timer: null, delay: delay, factor: factor, rate: rate };
169 }
170 else {
171 script.deckSpinbackBrakeData[group].delay = delay;
172 script.deckSpinbackBrakeData[group].factor = factor;
173 script.deckSpinbackBrakeData[group].rate = rate;
174 }
175
176 // kill timer when both enabling or disabling
177
178 if (script.deckSpinbackBrakeData[group].timer != null) {
179 engine.stopTimer(script.deckSpinbackBrakeData[group].timer);
180 script.deckSpinbackBrakeData[group].timer = null;
181 }
182
183 // enable/disable scratch2 mode
184
185 engine.setValue(group, 'scratch2_enable', activate ? 1 : 0);
186
187 if (activate) {
188 // save keylock status and disable it
189 if ((script.deckSpinbackBrakeData[group].keylock = engine.getValue(group, "keylock")) > 0) {
190 engine.setValue(group, "keylock", 0);
191 }
192
193 // setup timer and send first scratch2 'tick' if activating
194 script.deckSpinbackBrakeData[group].timer = engine.beginTimer(50, 'script.deckSpinbackBrake("' + group + '")');
195 engine.setValue(group, 'scratch2', script.deckSpinbackBrakeData[group].rate);
196 }
197
198 // re-enable keylock if needed
199
200 else if (script.deckSpinbackBrakeData[group].keylock) {
201 engine.setValue(group, "keylock", 1);
202 }
203 }
204 else {
205 // being called from a timer
206
207 engine.setValue(group, 'scratch2', script.deckSpinbackBrakeData[group].rate);
208
209 if (script.deckSpinbackBrakeData[group].delay > 0) {
210 script.deckSpinbackBrakeData[group].delay--;
211 }
212 else {
213 script.deckSpinbackBrakeData[group].rate *= script.deckSpinbackBrakeData[group].factor;
214 }
215 }
216}
217
109// bpm - Used for tapping the desired BPM for a deck218// bpm - Used for tapping the desired BPM for a deck
110function bpm() {}219function bpm() {}
111220
@@ -244,4 +353,4 @@
244 }353 }
245}354}
246355
247// ----------------- END Object definitions ----------------------
248\ No newline at end of file356\ No newline at end of file
357// ----------------- END Object definitions ----------------------

Subscribers

People subscribed via source and target branches