summaryrefslogtreecommitdiffstats
path: root/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js
diff options
context:
space:
mode:
authorRJ Ryan <rryan@mixxx.org>2013-06-19 00:46:54 -0400
committerRJ Ryan <rryan@mixxx.org>2013-06-19 00:46:54 -0400
commit25d57b59dff3947212909634864dd82365c9606b (patch)
treef0d0f8a048f8ed2f45c5ff015fc96891662f72f1 /res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js
parente50f9f168fa08f2be6d0f13e8a225bbcc9de09bb (diff)
Moving mixxx/* to the root. A new era begins!
Diffstat (limited to 'res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js')
-rw-r--r--res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js614
1 files changed, 614 insertions, 0 deletions
diff --git a/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js b/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js
new file mode 100644
index 0000000000..0639975292
--- /dev/null
+++ b/res/controllers/Hercules-DJ-Console-Mk2-hid-scripts.js
@@ -0,0 +1,614 @@
+/****************************************************************/
+/* Hercules DJ Console Mk2 HID controller script */
+/* For Mixxx version 1.11 */
+/* Author: zestoi */
+/****************************************************************/
+
+HerculesMk2Hid = new Controller();
+HerculesMk2Hid.controls = [];
+HerculesMk2Hid.leds = [];
+HerculesMk2Hid.cache_in = [];
+HerculesMk2Hid.cache_out = [];
+HerculesMk2Hid.callbacks = [];
+HerculesMk2Hid.feedbacks = [];
+HerculesMk2Hid.layer = [ "fx", "fx" ]; // fx, hotcue, loop, kill
+HerculesMk2Hid.tempo_scaling = 400;
+HerculesMk2Hid.beatjump_size = 8;
+HerculesMk2Hid.kills = [ { filterHighKill: 0, filterMidKill: 0, filterLowKill: 0 }, { filterHighKill: 0, filterMidKill: 0, filterLowKill: 0 } ];
+HerculesMk2Hid.loop_lengths = [ 0.25, 0.5, 1 ]; // edit to loop size needed
+HerculesMk2Hid.kill_order = [ "filterHighKill", "filterMidKill", "filterLowKill" ]; // edit if needed
+HerculesMk2Hid.scratch_enabled = { "[Channel1]": false, "[Channel2]": false };
+HerculesMk2Hid.jog_skip = { "[Channel1]": true, "[Channel2]": true };
+HerculesMk2Hid.shift = false; // either autobeat button
+
+//
+// the actual mapping is defined in this function
+//
+
+HerculesMk2Hid.init = function() {
+
+ var c = HerculesMk2Hid;
+
+ //
+ // define the hid packet
+ //
+
+ c.define_hid_format();
+
+ //
+ // create the actual mapping
+ // deck controls (will work for any decks as the group is passed in)
+ //
+
+ c.capture("crossfader", "all", function(g, e, v) { engine.setValue(g, e, (v - 128) / 128); });
+
+ c.capture("play", "press", function(g, e, v) { engine.setValue(g, e, !engine.getValue(g, e)); });
+ c.capture("cue_default", "all", function(g, e, v) { engine.setValue(g, e, v); });
+ c.capture("beatsync", "all", function(g, e, v) { HerculesMk2Hid.shift = v > 0; engine.setValue(g, e, v); });
+
+ c.capture("volume", "all", function(g, e, v) { engine.setValue(g, e, v / 256); });
+ c.capture("filterHigh", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
+ c.capture("filterMid", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
+ c.capture("filterLow", "all", function(g, e, v) { engine.setValue(g, e, v / 128); });
+
+ c.capture("jog", "all", function(g, e, v, ctrl) {
+ // skip initial jog values
+ if (HerculesMk2Hid.jog_skip[g]) {
+ HerculesMk2Hid.jog_skip[g] = false;
+ return;
+ }
+
+ // scratch mode
+ if (HerculesMk2Hid.scratch_enabled[g]) {
+ engine.scratchTick(parseInt(g.substring(8,9)), ctrl.relative);
+ }
+
+ // fine jog mode when playing
+ else if (engine.getValue(g, "play")) {
+ engine.setValue(g, e, ctrl.relative/2);
+ }
+
+ // track browsing when shift held (sync) and not playing
+ else if (HerculesMk2Hid.shift) {
+ engine.setValue("[Playlist]", "SelectTrackKnob", ctrl.relative);
+ }
+
+ // normal jog mode when not playing
+ else {
+ engine.setValue(g, e, ctrl.relative);
+ }
+ });
+
+ //
+ // double up pitch bend buttons as beatjumps when the track is stopped
+ //
+
+ c.capture("pitchbend_down", "all", function(g, e, v) {
+ if (engine.getValue(g, "play") == 0) {
+ engine.setValue(g, "back", v > 0 ? 1 : 0);
+ }
+ else if (v > 0) {
+ engine.setValue(g, "jog", -3);
+ }
+ });
+
+ c.capture("pitchbend_up", "all", function(g, e, v) {
+ if (engine.getValue(g, "play") == 0) {
+ engine.setValue(g, "fwd", v > 0 ? 1 : 0);
+ }
+ else if (v > 0) {
+ engine.setValue(g, "jog", 3);
+ }
+ });
+
+ //
+ // track browsing - don't use the joystick or track load buttons as they function as a normal mouse too
+ // (map joystick_y/joystick_x/load if you want to use the joystick)
+ //
+
+ c.capture("track_previous_a", "all", c.scroll_tracks);
+ c.capture("track_next_a", "all", c.scroll_tracks);
+ c.capture("track_previous_b", "press", function(g, e, v) { engine.setValue("[Channel1]", "LoadSelectedTrack", 1); });
+ c.capture("track_next_b", "press", function(g, e, v) { engine.setValue("[Channel2]", "LoadSelectedTrack", 1); });
+
+ //
+ // uncomment this code and the function HerculesMk2Hid.scroll_tracks_joystick() below if you really want the joystick
+ // to be used for track browsing and the left/right joystick buttons for track loading
+ //
+
+ /*
+ c.capture("load", "press", function(g, e, v) { engine.setValue(g, "LoadSelectedTrack", 1); });
+
+ c.capture("joystick_y", "all", function(g, e, v) {
+ if (v == 128) {
+ HerculesMk2Hid.direction = 0;
+ if (HerculesMk2Hid.track_timer) {
+ engine.stopTimer(HerculesMk2Hid.track_timer);
+ HerculesMk2Hid.track_timer = null;
+ }
+ }
+ else {
+ if (v > 128) {
+ HerculesMk2Hid.direction = 1;
+ v -= 128;
+ }
+ else {
+ HerculesMk2Hid.direction = -1;
+ v = 128 - v;
+ }
+
+ if (v < 30) v = 30;
+ if (HerculesMk2Hid.track_timer) engine.stopTimer(HerculesMk2Hid.track_timer);
+ HerculesMk2Hid.track_timer = engine.beginTimer(parseInt(5120 / v), 'HerculesMk2Hid.scroll_tracks_joystick');
+ }
+ });
+ */
+
+ //
+ // tempo encoder
+ //
+
+ c.capture("rate", "all", function(g, e, v, ctrl) {
+ var rate = engine.getValue(g, "rate") + ctrl.relative / c.tempo_scaling;
+ if (rate > 1) rate = 1; else if (rate < -1) rate = -1;
+ engine.setValue(g, e, rate);
+ });
+
+ //
+ // enable/disable scratching with the beatlock buttons (as jogs are non touch sensitive)
+ //
+
+ c.capture("beatlock", "press", function(g, e, v) {
+
+ HerculesMk2Hid.scratch_enabled[g] = !HerculesMk2Hid.scratch_enabled[g];
+
+ if (HerculesMk2Hid.scratch_enabled[g]) {
+ engine.scratchEnable(parseInt(g.substring(8,9)), 64, 45, 0.125, 0.125/32);
+ }
+ else {
+ engine.scratchDisable(parseInt(g.substring(8,9)));
+ }
+
+ c.send(g, e, HerculesMk2Hid.scratch_enabled[g] ? 1 : 0);
+ });
+
+ //
+ // toggle between fx, hotcue and loop modes and update leds
+ //
+
+ c.capture("layer_select", "press", function(g, e, v) {
+ var deck = parseInt(g.substring(8,9));
+ c.send(g, "fx", 0);
+ c.send(g, "hotcue", 0);
+ c.send(g, "loop", 0);
+ switch (c.layer[deck-1]) {
+ case "fx": c.layer[deck-1] = "hotcue"; break;
+ case "hotcue": c.layer[deck-1] = "loop"; break;
+ case "loop":
+ c.layer[deck-1] = "kill";
+ c.send(g, "fx", !c.kills[deck-1]['filterHighKill']);
+ c.send(g, "hotcue", !c.kills[deck-1]['filterMidKill']);
+ c.send(g, "loop", !c.kills[deck-1]['filterLowKill']);
+ break;
+ case "kill":
+ c.layer[deck-1] = "fx";
+ }
+ if (c.layer[deck-1] != "kill") {
+ c.send(g, c.layer[deck-1], 1);
+ }
+ });
+
+ c.capture("layer_btn1", "all", function(g, e, v) { c.layer_btn(g, e, v); });
+ c.capture("layer_btn2", "all", function(g, e, v) { c.layer_btn(g, e, v); });
+ c.capture("layer_btn3", "all", function(g, e, v) { c.layer_btn(g, e, v); });
+
+ //
+ // headphone cue
+ //
+
+ c.capture("monitor_a", "all", function(g, e, v) { engine.setValue("[Channel1]", "pfl", v); });
+ c.capture("monitor_b", "all", function(g, e, v) { engine.setValue("[Channel2]", "pfl", v); });
+ c.capture("monitor_both", "all", function(g, e, v) {
+ engine.setValue("[Channel1]", "pfl", v);
+ engine.setValue("[Channel2]", "pfl", v);
+ });
+
+ //
+ // led feedback
+ //
+
+ c.feedback("[Channel1]", "play", function(g, e, v) { c.send(g, e, v); });
+ c.feedback("[Channel2]", "play", function(g, e, v) { c.send(g, e, v); });
+ c.feedback("[Channel1]", "cue_default", function(g, e, v) { c.send(g, e, v); });
+ c.feedback("[Channel2]", "cue_default", function(g, e, v) { c.send(g, e, v); });
+ c.feedback("[Channel1]", "beatsync", function(g, e, v) { c.send(g, e, v); });
+ c.feedback("[Channel2]", "beatsync", function(g, e, v) { c.send(g, e, v); });
+
+ //
+ // kill status
+ //
+
+ c.feedback("[Channel1]", "filterHighKill", c.kill_status);
+ c.feedback("[Channel1]", "filterMidKill", c.kill_status);
+ c.feedback("[Channel1]", "filterLowKill", c.kill_status);
+ c.feedback("[Channel2]", "filterHighKill", c.kill_status);
+ c.feedback("[Channel2]", "filterMidKill", c.kill_status);
+ c.feedback("[Channel2]", "filterLowKill", c.kill_status);
+
+ //
+ // clear/setup any initial leds
+ //
+
+ for (id in c.leds) {
+ c.send(c.leds[id].group, c.leds[id].name, 0);
+ }
+
+ c.send("[Channel1]", "fx", 1);
+ c.send("[Channel2]", "fx", 1);
+}
+
+//
+// map the 6 buttons that control either effects, hotcues, loops or kills
+//
+
+HerculesMk2Hid.layer_btn = function(g, e, v) {
+ var deck = parseInt(g.substring(8,9));
+ var btn = parseInt(e.substring(9,10));
+ switch (HerculesMk2Hid.layer[deck-1]) {
+ case "fx":
+ switch (btn) {
+ case 1:
+ engine.setValue("[Flanger]", "lfoDepth", 1);
+ engine.setValue("[Flanger]", "lfoPeriod", 500000);
+ engine.setValue("[Flanger]", "lfoDelay", 666);
+ engine.setValue(g, "flanger", v > 0);
+ break;
+ case 2:
+ engine.spinback(parseInt(g.substring(8,9)), v > 0);
+ break;
+ case 3:
+ engine.brake(parseInt(g.substring(8,9)), v > 0);
+ }
+ break;
+ case "hotcue":
+ engine.setValue(g, "hotcue_" + btn + "_activate", v > 0 ? 1 : 0);
+ break;
+ case "loop":
+ var len = HerculesMk2Hid.loop_lengths[btn-1];
+ engine.setValue(g, "beatloop_" + len + "_toggle", 1);
+ break;
+ case 'kill':
+ if (v > 0) {
+ engine.setValue(g, HerculesMk2Hid.kill_order[btn-1], !engine.getValue(g, HerculesMk2Hid.kill_order[btn-1]));
+ }
+ }
+}
+
+//
+// beatjump - will get out of sync if called while deck is playing
+//
+
+HerculesMk2Hid.beatjump = function(group, jump) {
+ jump = jump * 120 / engine.getValue(group, "bpm") / engine.getValue(group, "track_samples") * engine.getValue(group, "track_samplerate");
+ engine.setValue(group, "playposition", engine.getValue(group, "playposition") + jump);
+}
+
+//
+// playlist scroll nex/previous with auto-repeat when held
+//
+
+HerculesMk2Hid.scroll_tracks = function(g, e, v) {
+ if (v > 0) {
+ engine.setValue("[Playlist]", e == "track_next_a" ? "SelectNextTrack" : "SelectPrevTrack", 1);
+ if (!HerculesMk2Hid.scroll_timer) {
+ HerculesMk2Hid.scroll_timer = engine.beginTimer(150, 'HerculesMk2Hid.scroll_tracks("[Playlist]","' + e + '",' + v + ')');
+ }
+ }
+ else {
+ if (HerculesMk2Hid.scroll_timer) {
+ engine.stopTimer(HerculesMk2Hid.scroll_timer);
+ HerculesMk2Hid.scroll_timer = null;
+ }
+ }
+}
+
+//
+// eq kill status
+//
+
+HerculesMk2Hid.kill_status = function(g, e, v) {
+ var deck = parseInt(g.substring(8,9));
+ HerculesMk2Hid.kills[deck-1][e] = v;
+
+ //
+ // update leds with kill status if we're on that layer
+ //
+
+ if (HerculesMk2Hid.layer[deck-1] == "kill") {
+ switch (e) {
+ case 'filterHighKill': HerculesMk2Hid.send(g, "fx", !v); break;
+ case 'filterMidKill': HerculesMk2Hid.send(g, "hotcue", !v); break;
+ case 'filterLowKill': HerculesMk2Hid.send(g, "loop", !v);
+ }
+ }
+}
+
+/*
+HerculesMk2Hid.scroll_tracks_joystick = function() {
+ engine.setValue("[Playlist]", HerculesMk2Hid.direction > 0 ? "SelectNextTrack" : "SelectPrevTrack", 1);
+}
+*/
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// define the hid packet to event mapping, could be defined via xml so can be used in multiple mappings
+// naming the controls as much as possible inline with the mixxx engine names makes most mappings trivial
+//
+
+HerculesMk2Hid.define_hid_format = function() {
+
+ var c = HerculesMk2Hid;
+ var pid = 0x1;
+
+ // deck 1
+
+ c.add_control(pid, "play", "[Channel1]", "button", 1, 0x80)
+ c.add_control(pid, "cue_default", "[Channel1]", "button", 2, 0x01)
+ c.add_control(pid, "track_previous_a", "[Channel1]", "button", 2, 0x04)
+ c.add_control(pid, "track_next_a", "[Channel1]", "button", 2, 0x08)
+ c.add_control(pid, "beatsync", "[Channel1]", "button", 2, 0x02)
+ c.add_control(pid, "pitchbend_down", "[Channel1]", "button", 3, 0x08)
+ c.add_control(pid, "pitchbend_up", "[Channel1]", "button", 3, 0x04)
+ c.add_control(pid, "load", "[Channel1]", "button", 4, 0x04)
+ c.add_control(pid, "beatlock", "[Channel1]", "button", 3, 0x20)
+ c.add_control(pid, "source", "[Channel1]", "button", 4, 0x10)
+ c.add_control(pid, "filterLow", "[Channel1]", "fader", 9, 0xff)
+ c.add_control(pid, "filterMid", "[Channel1]", "fader", 10, 0xff)
+ c.add_control(pid, "filterHigh", "[Channel1]", "fader", 11, 0xff)
+ c.add_control(pid, "volume", "[Channel1]", "fader", 13, 0xff)
+ c.add_control(pid, "rate", "[Channel1]", "encoder", 15, 0xff)
+ c.add_control(pid, "jog", "[Channel1]", "encoder", 17, 0xff)
+ c.add_control(pid, "layer_select", "[Channel1]", "button", 1, 0x40)
+ c.add_control(pid, "layer_btn1", "[Channel1]", "button", 2, 0x40)
+ c.add_control(pid, "layer_btn2", "[Channel1]", "button", 2, 0x20)
+ c.add_control(pid, "layer_btn3", "[Channel1]", "button", 2, 0x10)
+
+ // deck 2
+
+ c.add_control(pid, "play", "[Channel2]", "button", 1, 0x02)
+ c.add_control(pid, "cue_default", "[Channel2]", "button", 1, 0x04)
+ c.add_control(pid, "track_previous_b", "[Channel2]", "button", 1, 0x10)
+ c.add_control(pid, "track_next_b", "[Channel2]", "button", 1, 0x20)
+ c.add_control(pid, "beatsync", "[Channel2]", "button", 1, 0x08)
+ c.add_control(pid, "pitchbend_down", "[Channel2]", "button", 3, 0x80)
+ c.add_control(pid, "pitchbend_up", "[Channel2]", "button", 3, 0x40)
+ c.add_control(pid, "load", "[Channel2]", "button", 4, 0x08)
+ c.add_control(pid, "beatlock", "[Channel2]", "button", 4, 0x02)
+ c.add_control(pid, "source", "[Channel2]", "button", 4, 0x20)
+ c.add_control(pid, "filterLow", "[Channel2]", "fader", 6, 0xff)
+ c.add_control(pid, "filterMid", "[Channel2]", "fader", 7, 0xff)
+ c.add_control(pid, "filterHigh", "[Channel2]", "fader", 8, 0xff)
+ c.add_control(pid, "volume", "[Channel2]", "fader", 14, 0xff)
+ c.add_control(pid, "rate", "[Channel2]", "encoder", 16, 0xff)
+ c.add_control(pid, "jog", "[Channel2]", "encoder", 18, 0xff)
+ c.add_control(pid, "layer_select", "[Channel2]", "button", 1, 0x01)
+ c.add_control(pid, "layer_btn1", "[Channel2]", "button", 2, 0x80)
+ c.add_control(pid, "layer_btn2", "[Channel2]", "button", 3, 0x01)
+ c.add_control(pid, "layer_btn3", "[Channel2]", "button", 3, 0x02)
+
+ // master
+
+ c.add_control(pid, "crossfader", "[Master]", "fader", 12, 0xff)
+ c.add_control(pid, "joystick_x", "[Master]", "fader", 19, 0xff)
+ c.add_control(pid, "joystick_y", "[Master]", "fader", 20, 0xff)
+
+ // headphone cue
+
+ c.add_control(pid, "monitor_a", "[Master]", "button", 5, 0x1);
+ c.add_control(pid, "monitor_b", "[Master]", "button", 5, 0x2);
+ //c.add_control(pid, "monitor_both", "[Master]", "button", 5, 0x4);
+ c.add_control(pid, "monitor_both", "[Master]", "button", 5, 0x8);
+
+ // define led feedback
+
+ pid = 0;
+ c.cache_out[pid] = [ pid, 0x0, 0x0, 0x0 ];
+
+ c.add_control(pid, "play", "[Channel1]", "led", 2, 0x01); // blinking: 3, 0x2
+ c.add_control(pid, "cue_default", "[Channel1]", "led", 2, 0x08);
+ c.add_control(pid, "beatsync", "[Channel1]", "led", 2, 0x10);
+ c.add_control(pid, "beatlock", "[Channel1]", "led", 1, 0x01);
+
+ c.add_control(pid, "play", "[Channel2]", "led", 1, 0x40); // blinking: 3, 0x1
+ c.add_control(pid, "cue_default", "[Channel2]", "led", 1, 0x20);
+ c.add_control(pid, "beatsync", "[Channel2]", "led", 2, 0x20);
+ c.add_control(pid, "beatlock", "[Channel2]", "led", 1, 0x02);
+
+ c.add_control(pid, "fx", "[Channel1]", "led", 1, 0x04);
+ c.add_control(pid, "fx", "[Channel2]", "led", 1, 0x08);
+ c.add_control(pid, "hotcue", "[Channel2]", "led", 1, 0x10);
+ c.add_control(pid, "hotcue", "[Channel1]", "led", 1, 0x80);
+ c.add_control(pid, "loop", "[Channel1]", "led", 2, 0x40);
+ c.add_control(pid, "loop", "[Channel2]", "led", 2, 0x80);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// non-specific controller framework to allow hid packets to be defined and processed via
+// callback functions - could/should be in a shared file
+//
+
+HerculesMk2Hid.add_control = function(packetid, name, group, type, offset, mask) {
+ if (type == "led") {
+ HerculesMk2Hid.leds[group + name] = new HerculesMk2Hid.control(packetid, name, group, type, offset, mask);
+ }
+ else {
+ if (HerculesMk2Hid.controls[offset] == undefined) {
+ HerculesMk2Hid.controls[offset] = [];
+ }
+ HerculesMk2Hid.controls[offset].push(new HerculesMk2Hid.control(packetid, name, group, type, offset, mask));
+ }
+}
+
+//
+// bind a function to a modified controller value
+//
+
+HerculesMk2Hid.capture = function(name, values, func) {
+ if (HerculesMk2Hid.callbacks[name] == undefined) {
+ HerculesMk2Hid.callbacks[name] = [ [ values, func ] ];
+ }
+ else {
+ HerculesMk2Hid.callbacks[name].push([ values, func ]);
+ }
+}
+
+//
+// bind a function to feedback from mixxx, callbacks accept args in same order as from capture()
+//
+
+HerculesMk2Hid.feedback = function(g, e, f) {
+ engine.connectControl(g, e, "HerculesMk2Hid.feedbackData");
+ if (HerculesMk2Hid.feedbacks[g + e] == undefined) {
+ HerculesMk2Hid.feedbacks[g + e] = [];
+ }
+ HerculesMk2Hid.feedbacks[g + e].push(f);
+}
+
+//
+// controller feedback: send data to the controller by name and automatically send out the full hid packet needed
+//
+
+HerculesMk2Hid.send = function(g, e, v) {
+ if ((ctrl = this.leds[g + e]) != undefined) {
+
+ //
+ // for the byte in the hid packet that this led control affects, mask out it's old value
+ // and then add in it's new one
+ //
+
+ this.cache_out[ctrl.packetid][ctrl.offset] = this.cache_out[ctrl.packetid][ctrl.offset] & ctrl.maskinv | (v << ctrl.bitshift);
+
+ //
+ // send complete hid packet and update our cache
+ //
+
+ controller.send(this.cache_out[ctrl.packetid], this.cache_out[ctrl.packetid].length, 0);
+ this.cache_out[ctrl.packetid] = this.cache_out[ctrl.packetid];
+ }
+}
+
+//
+// process incoming data from mixxx and call any callbacks
+//
+
+HerculesMk2Hid.feedbackData = function(v, g, e) {
+ if (HerculesMk2Hid.feedbacks[g + e] != undefined) {
+ for (func in HerculesMk2Hid.feedbacks[g + e]) {
+ if (typeof(HerculesMk2Hid.feedbacks[g + e][func]) == "function") {
+ HerculesMk2Hid.feedbacks[g + e][func](g, e, v);
+ }
+ }
+ }
+}
+
+//
+// a single hid control, store last known value and offset/mask to work out the new value from incoming data
+//
+
+HerculesMk2Hid.control = function(packetid, name, group, type, offset, mask) {
+ this.packetid = packetid;
+ this.name = name;
+ this.group = group;
+ this.type = type;
+ this.value = 0;
+ this.relative = 0;
+ this.offset = offset;
+ this.mask = mask;
+ this.maskinv = ~mask;
+ this.bitshift = 0;
+ this.maxval = 255; // needed for encoder, could guess from the mask
+ this.changed = function(value) {
+ value = (value & this.mask) >> this.bitshift;
+ if (this.value == value) {
+ return false;
+ }
+ else {
+ // map to a relative value if it's an encoder, usually +1 or -1
+ if (this.type == 'encoder') {
+ this.relative = value - this.value;
+ if (this.relative > 100) {
+ this.relative -= this.maxval;
+ }
+ else if (this.relative < -100) {
+ this.relative += this.maxval;
+ }
+ }
+ this.value = value;
+ return true;
+ }
+ };
+ while (mask != 0 && (mask & 0x1) == 0) {
+ mask = mask >> 1;
+ this.bitshift++;
+ }
+}
+
+//
+// process incoming data and call any callbacks if their bound controls have changed
+//
+
+HerculesMk2Hid.incomingData = function (data, length) {
+
+ var c = HerculesMk2Hid;
+ var packetid = data[0];
+
+ //
+ // iterate thru each byte and only check controls for that byte if the byte has changed
+ //
+
+ for (i=1; i<length; i++) {
+ if ((c.cache_in[packetid] == undefined || data[i] != c.cache_in[packetid][i]) && c.controls[i] != undefined) {
+
+ //
+ // a byte has changed, check any controls defined in that byte, more efficient
+ // than checking old+new values for all controls
+ //
+
+ for (key in c.controls[i]) {
+ var control = c.controls[i][key];
+ if (typeof(control) == 'object' && control.packetid == data[0] && control.changed(data[i])) {
+
+ //
+ // we found a hid control that has changed value within that byte, check for callbacks
+ //
+
+ var callbacks = c.callbacks[control.name];
+ if (callbacks != undefined) {
+ for (var i=0; i<callbacks.length; i++) {
+ if (typeof(callbacks[i][1]) == 'function') {
+
+ //
+ // check we need to call for this value change: all, press, release
+ //
+
+ if (callbacks[i][0] == "all" ||
+ (callbacks[i][0] == "press" && control.value > 0) ||
+ (callbacks[i][0] == "release" && control.value == 0)) {
+
+ //
+ // call a callback function for this control
+ //
+
+ callbacks[i][1](control.group, control.name, control.value, control);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // store the new raw data
+ c.cache_in[data[0]] = data;
+}