home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Aplikacje_64-bitowe / Mixxx / mixxx-1.9.0-win64.exe / midi / Stanton-SCS3d-scripts.js < prev    next >
Text File  |  2011-02-04  |  95KB  |  1,878 lines

  1. /****************************************************************/
  2. /*      Stanton SCS.3d MIDI controller script v1.60             */
  3. /*          Copyright (C) 2009-2010, Sean M. Pappalardo         */
  4. /*      but feel free to tweak this to your heart's content!    */
  5. /*      For Mixxx version 1.9.x                                 */
  6. /****************************************************************/
  7.  
  8. function StantonSCS3d() {}
  9.  
  10. // ----------   Customization variables ----------
  11. //      See http://mixxx.org/wiki/doku.php/stanton_scs.3d_mixxx_user_guide  for details
  12. StantonSCS3d.pitchRanges = [ 0.08, 0.12, 0.5, 1.0 ];    // Pitch ranges for LED off, blue, purple, red
  13. StantonSCS3d.fastDeckChange = false;    // Skip the flashy lights if true, for juggling
  14. StantonSCS3d.spinningPlatter = true;    // Spinning platter LEDs
  15. StantonSCS3d.spinningPlatterOnlyVinyl = false;  // Only show the spinning platter LEDs in vinyl mode
  16. StantonSCS3d.spinningLights = 1;        // The number of spinning platter lights, 1 or 2
  17. StantonSCS3d.VUMeters = true;           // Pre-fader VU meter LEDs
  18. StantonSCS3d.markHotCues = "blue";      // Choose red or blue LEDs for marking the stored positions in TRIG mode
  19. StantonSCS3d.jogOnLoad = true;          // Automatically change to Vinyl1 (jog) mode after loading a track if true
  20. StantonSCS3d.globalMode = false;        // Stay in the current mode on deck changes if true.
  21. StantonSCS3d.singleDeck = false;        // When using more than one controller, set to true to avoid easy deck changes.
  22.                                         //  Toggle with DECK + SYNC.
  23. StantonSCS3d.deckChangeWait = 1000;     // Time in milliseconds to hold the DECK button down to avoid changing decks (multi deck mode)
  24.  
  25. // ----------   Other global variables    ----------
  26. StantonSCS3d.debug = false;  // Enable/disable debugging messages to the console
  27.  
  28. StantonSCS3d.id = "";   // The ID for the particular device being controlled for use in debugging, set at init time
  29. StantonSCS3d.channel = 0;   // MIDI channel to set the device to and use
  30. StantonSCS3d.revtime = 1.8; // Time in seconds for the virtual record to spin once.
  31.                             //  Used for calculating the position LEDs (1.8 for 33 1/3 RPM)
  32. StantonSCS3d.buttons = { "fx":0x20, "eq":0x26, "loop":0x22, "trig":0x28, "vinyl":0x24, "deck":0x2A };
  33. StantonSCS3d.buttonLEDs = { 0x48:0x62, 0x4A:0x61, 0x4C:0x60, 0x4e:0x5f, 0x4f:0x67, 0x51:0x68, 0x53:0x69, 0x55:0x6a,
  34.                             0x56:0x64, 0x58:0x65, 0x5A:0x6C, 0x5C:0x5D }; // Maps surface buttons to corresponding circle LEDs
  35. StantonSCS3d.mode_store = { "[Channel1]":"vinyl", "[Channel2]":"vinyl" };   // Set vinyl mode on both decks
  36. StantonSCS3d.scratchncue = [ false, false, false ];  // Scratch + cue mode for each deck (starts at zero)
  37. StantonSCS3d.deck = 1;  // Currently active virtual deck
  38. StantonSCS3d.modifier = { "cue":0, "play":0 };  // Modifier buttons (allowing alternate controls) defined on-the-fly if needed
  39. StantonSCS3d.state = { "pitchAbs":0, "jog":0, "changedDeck":false, "deckPrev":"vinyl"}; // Temporary state variables
  40. StantonSCS3d.timer = [-1];  // Temporary storage of timer IDs
  41. StantonSCS3d.modeSurface = { "deck":"S3+S5", "fx":"S3+S5", "eq":"S3+S5", 
  42.                              "loop":"S3+S5", "loop2":"Buttons", "loop3":"Buttons",
  43.                              "trig":"Buttons", "trig2":"Buttons", "trig3":"Buttons",
  44.                              "vinyl":"C1", "vinyl2":"C1", "vinyl3":"C1"};
  45. StantonSCS3d.surface = { "C1":0x00, "S5":0x01, "S3":0x02, "S3+S5":0x03, "Buttons":0x04 };
  46. StantonSCS3d.sysex = [0xF0, 0x00, 0x01, 0x60];  // Preamble for all SysEx messages for this device
  47. StantonSCS3d.trackDuration = [0,0]; // Duration of the song on each deck (used for vinyl LEDs)
  48. StantonSCS3d.lastLight = [-1,-1]; // Last circle LED values
  49. StantonSCS3d.lastLoop = 0;  // Last-used loop LED
  50. // Pitch values for key change mode
  51. StantonSCS3d.pitchPoints = {    1:{ 0x48:-0.1998, 0x4A:-0.1665, 0x4C:-0.1332, 0x4E:-0.0999, 0x56:-0.0666, 0x58:-0.0333,
  52.                                     0x5A:0.0333, 0x5C:0.0666, 0x4F:0.0999, 0x51:0.1332, 0x53:0.1665, 0x55:0.1998 }, // 3.33% increments
  53.                                 2:{ 0x48:-0.5, 0x4A:-0.4043, 0x4C:-0.2905, 0x4E:-0.1567, 0x56:-0.1058, 0x58:-0.0548, 
  54.                                     0x5A:0.06, 0x5C:0.12, 0x4F:0.181, 0x51:0.416, 0x53:0.688, 0x55:1.0 },  // Key changes
  55.                                 3:{ 0x48:-0.4370, 0x4A:-0.3677, 0x4C:-0.3320, 0x4E:-0.2495, 0x56:-0.1567, 0x58:-0.0548, 
  56.                                     0x5A:0.12, 0x5C:0.263, 0x4F:0.338, 0x51:0.506, 0x53:0.688, 0x55:0.895 } };  // Notes
  57. // Multiple banks of multiple cue points:
  58. StantonSCS3d.hotCues = {    1:{ 0x48: 1, 0x4A: 2, 0x4C: 3, 0x4E: 4, 0x4F: 5, 0x51: 6,
  59.                                 0x53: 7, 0x55: 8, 0x56: 9, 0x58:10, 0x5A:11, 0x5C:12 },
  60.                             2:{ 0x48:13, 0x4A:14, 0x4C:15, 0x4E:16, 0x4F:17, 0x51:18,
  61.                                 0x53:19, 0x55:20, 0x56:21, 0x58:22, 0x5A:23, 0x5C:24 },
  62.                             3:{ 0x48:25, 0x4A:26, 0x4C:27, 0x4E:28, 0x4F:29, 0x51:30,
  63.                                 0x53:31, 0x55:-1, 0x56:-1, 0x58:-1, 0x5A:-1, 0x5C:-1 } };
  64. StantonSCS3d.triggerS4 = 0xFF;
  65.  
  66. // Signals to (dis)connect by mode: Group, Key, Function name
  67. StantonSCS3d.modeSignals = {"fx":[    ["[Flanger]", "lfoDepth", "StantonSCS3d.FXDepthLEDs"],
  68.                                       ["[Flanger]", "lfoDelay", "StantonSCS3d.FXDelayLEDs"],
  69.                                       ["[Flanger]", "lfoPeriod", "StantonSCS3d.FXPeriodLEDs"],
  70.                                       ["CurrentChannel", "reverse", "StantonSCS3d.B11LED"],
  71.                                       ["CurrentChannel", "flanger", "StantonSCS3d.B12LED"] ],
  72.                             "eq":[    ["CurrentChannel", "filterLow", "StantonSCS3d.EQLowLEDs"],
  73.                                       ["CurrentChannel", "filterMid", "StantonSCS3d.EQMidLEDs"],
  74.                                       ["CurrentChannel", "filterHigh", "StantonSCS3d.EQHighLEDs"],
  75.                                       ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"] ],
  76.                             "loop":[  ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  77.                                       ["CurrentChannel", "loop_in", "StantonSCS3d.LoopInLEDs"],
  78.                                       ["CurrentChannel", "loop_out", "StantonSCS3d.LoopOutLEDs"],
  79.                                       ["CurrentChannel", "reloop_exit", "StantonSCS3d.ReloopLEDs"] ],
  80.                             "loop2":[ ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"] ],
  81.                             "loop3":[ ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"] ],
  82.                             "trig":[  ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  83.                                       ["CurrentChannel", "hotcue_1_enabled", "StantonSCS3d.BsALED"],
  84.                                       ["CurrentChannel", "hotcue_2_enabled", "StantonSCS3d.BsBLED"],
  85.                                       ["CurrentChannel", "hotcue_3_enabled", "StantonSCS3d.BsCLED"],
  86.                                       ["CurrentChannel", "hotcue_4_enabled", "StantonSCS3d.BsDLED"],
  87.                                       ["CurrentChannel", "hotcue_5_enabled", "StantonSCS3d.BsELED"],
  88.                                       ["CurrentChannel", "hotcue_6_enabled", "StantonSCS3d.BsFLED"],
  89.                                       ["CurrentChannel", "hotcue_7_enabled", "StantonSCS3d.BsGLED"],
  90.                                       ["CurrentChannel", "hotcue_8_enabled", "StantonSCS3d.BsHLED"],
  91.                                       ["CurrentChannel", "hotcue_9_enabled", "StantonSCS3d.BsILED"],
  92.                                       ["CurrentChannel", "hotcue_10_enabled", "StantonSCS3d.BsJLED"],
  93.                                       ["CurrentChannel", "hotcue_11_enabled", "StantonSCS3d.BsKLED"],
  94.                                       ["CurrentChannel", "hotcue_12_enabled", "StantonSCS3d.BsLLED"],
  95.                                       ["CurrentChannel", "hotcue_1_activate", "StantonSCS3d.BsAaLED"],
  96.                                       ["CurrentChannel", "hotcue_2_activate", "StantonSCS3d.BsBaLED"],
  97.                                       ["CurrentChannel", "hotcue_3_activate", "StantonSCS3d.BsCaLED"],
  98.                                       ["CurrentChannel", "hotcue_4_activate", "StantonSCS3d.BsDaLED"],
  99.                                       ["CurrentChannel", "hotcue_5_activate", "StantonSCS3d.BsEaLED"],
  100.                                       ["CurrentChannel", "hotcue_6_activate", "StantonSCS3d.BsFaLED"],
  101.                                       ["CurrentChannel", "hotcue_7_activate", "StantonSCS3d.BsGaLED"],
  102.                                       ["CurrentChannel", "hotcue_8_activate", "StantonSCS3d.BsHaLED"],
  103.                                       ["CurrentChannel", "hotcue_9_activate", "StantonSCS3d.BsIaLED"],
  104.                                       ["CurrentChannel", "hotcue_10_activate", "StantonSCS3d.BsJaLED"],
  105.                                       ["CurrentChannel", "hotcue_11_activate", "StantonSCS3d.BsKaLED"],
  106.                                       ["CurrentChannel", "hotcue_12_activate", "StantonSCS3d.BsLaLED"] ],
  107.                             "trig2":[ ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  108.                                       ["CurrentChannel", "hotcue_13_enabled", "StantonSCS3d.BsALED"],
  109.                                       ["CurrentChannel", "hotcue_14_enabled", "StantonSCS3d.BsBLED"],
  110.                                       ["CurrentChannel", "hotcue_15_enabled", "StantonSCS3d.BsCLED"],
  111.                                       ["CurrentChannel", "hotcue_16_enabled", "StantonSCS3d.BsDLED"],
  112.                                       ["CurrentChannel", "hotcue_17_enabled", "StantonSCS3d.BsELED"],
  113.                                       ["CurrentChannel", "hotcue_18_enabled", "StantonSCS3d.BsFLED"],
  114.                                       ["CurrentChannel", "hotcue_19_enabled", "StantonSCS3d.BsGLED"],
  115.                                       ["CurrentChannel", "hotcue_20_enabled", "StantonSCS3d.BsHLED"],
  116.                                       ["CurrentChannel", "hotcue_21_enabled", "StantonSCS3d.BsILED"],
  117.                                       ["CurrentChannel", "hotcue_22_enabled", "StantonSCS3d.BsJLED"],
  118.                                       ["CurrentChannel", "hotcue_23_enabled", "StantonSCS3d.BsKLED"],
  119.                                       ["CurrentChannel", "hotcue_24_enabled", "StantonSCS3d.BsLLED"],
  120.                                       ["CurrentChannel", "hotcue_13_activate", "StantonSCS3d.BsAaLED"],
  121.                                       ["CurrentChannel", "hotcue_14_activate", "StantonSCS3d.BsBaLED"],
  122.                                       ["CurrentChannel", "hotcue_15_activate", "StantonSCS3d.BsCaLED"],
  123.                                       ["CurrentChannel", "hotcue_16_activate", "StantonSCS3d.BsDaLED"],
  124.                                       ["CurrentChannel", "hotcue_17_activate", "StantonSCS3d.BsEaLED"],
  125.                                       ["CurrentChannel", "hotcue_18_activate", "StantonSCS3d.BsFaLED"],
  126.                                       ["CurrentChannel", "hotcue_19_activate", "StantonSCS3d.BsGaLED"],
  127.                                       ["CurrentChannel", "hotcue_20_activate", "StantonSCS3d.BsHaLED"],
  128.                                       ["CurrentChannel", "hotcue_21_activate", "StantonSCS3d.BsIaLED"],
  129.                                       ["CurrentChannel", "hotcue_22_activate", "StantonSCS3d.BsJaLED"],
  130.                                       ["CurrentChannel", "hotcue_23_activate", "StantonSCS3d.BsKaLED"],
  131.                                       ["CurrentChannel", "hotcue_24_activate", "StantonSCS3d.BsLaLED"] ],
  132.                             "trig3":[ ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  133.                                       ["CurrentChannel", "hotcue_25_enabled", "StantonSCS3d.BsALED"],
  134.                                       ["CurrentChannel", "hotcue_26_enabled", "StantonSCS3d.BsBLED"],
  135.                                       ["CurrentChannel", "hotcue_27_enabled", "StantonSCS3d.BsCLED"],
  136.                                       ["CurrentChannel", "hotcue_28_enabled", "StantonSCS3d.BsDLED"],
  137.                                       ["CurrentChannel", "hotcue_29_enabled", "StantonSCS3d.BsELED"],
  138.                                       ["CurrentChannel", "hotcue_30_enabled", "StantonSCS3d.BsFLED"],
  139.                                       ["CurrentChannel", "hotcue_31_enabled", "StantonSCS3d.BsGLED"],
  140.                                       ["CurrentChannel", "hotcue_25_activate", "StantonSCS3d.BsAaLED"],
  141.                                       ["CurrentChannel", "hotcue_26_activate", "StantonSCS3d.BsBaLED"],
  142.                                       ["CurrentChannel", "hotcue_27_activate", "StantonSCS3d.BsCaLED"],
  143.                                       ["CurrentChannel", "hotcue_28_activate", "StantonSCS3d.BsDaLED"],
  144.                                       ["CurrentChannel", "hotcue_29_activate", "StantonSCS3d.BsEaLED"],
  145.                                       ["CurrentChannel", "hotcue_30_activate", "StantonSCS3d.BsFaLED"],
  146.                                       ["CurrentChannel", "hotcue_31_activate", "StantonSCS3d.BsGaLED"] ],
  147.                             "vinyl":[ ["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  148.                                       ["CurrentChannel", "VuMeter", "StantonSCS3d.VUMeterLEDs"] ],
  149.                             "vinyl2":[["CurrentChannel", "pfl", "StantonSCS3d.B11LED"],
  150.                                       ["CurrentChannel", "VuMeter", "StantonSCS3d.VUMeterLEDs"] ],
  151.                             "vinyl3":[],
  152.                             "deck":[  ["[Master]","balance","StantonSCS3d.pitchLEDs"],
  153.                                       ["[Master]","volume","StantonSCS3d.MasterVolumeLEDs"],
  154.                                       ["[Master]","headMix","StantonSCS3d.headMixLEDs"],
  155.                                       ["[Master]","headVolume","StantonSCS3d.headVolLEDs"],
  156.                                       ["[Master]","crossfader","StantonSCS3d.crossFaderLEDs"] ],
  157.                             "none":[]  // To avoid an error on forced mode changes
  158.                             };
  159. StantonSCS3d.commonSignals = [  ["CurrentChannel", "rate", "StantonSCS3d.pitchLEDs"],
  160.                                 ["CurrentChannel", "rateRange", "StantonSCS3d.pitchSliderLED"]
  161.                              ];
  162.  
  163. StantonSCS3d.deckSignals = [    ["CurrentChannel", "volume", "StantonSCS3d.gainLEDs"],
  164.                                 ["CurrentChannel", "play", "StantonSCS3d.playLED"],
  165.                                 ["CurrentChannel", "cue_default", "StantonSCS3d.cueLED"],
  166.                                 ["CurrentChannel", "beatsync", "StantonSCS3d.syncLED"],
  167.                                 ["CurrentChannel", "back", "StantonSCS3d.B13LED"],
  168.                                 ["CurrentChannel", "fwd", "StantonSCS3d.B14LED"]
  169.                             ];
  170.  
  171. // ----------   Functions   ----------
  172.  
  173. StantonSCS3d.init = function (id) {    // called when the MIDI device is opened & set up
  174.     StantonSCS3d.id = id;   // Store the ID of this device for later use
  175.     
  176.     // Find out the firmware version
  177.     if (!StantonSCS3d.state["flat"]) midi.sendSysexMsg([0xF0, 0x7E, StantonSCS3d.channel, 0x06, 0x01, 0xF7],6);
  178.     
  179.     // TODO: Remove this once the deadlock issue is resolved
  180.     //  where you have to send something from the controller in order for the init2
  181.     //  function to run after the .statusResponse() calls it
  182.     StantonSCS3d.init2();
  183. }
  184.  
  185. StantonSCS3d.init2 = function () {    // called when the MIDI device is opened & set up
  186.     // Set the device's MIDI channel to a known value
  187. //     midi.sendSysexMsg(StantonSCS3d.sysex.concat([0x02, StantonSCS3d.channel, 0xF7]),7);
  188.  
  189.     var CC = 0xB0 + StantonSCS3d.channel;
  190.     var No = 0x90 + StantonSCS3d.channel;
  191.     midi.sendShortMsg(CC,0x7B,0x00);  // Extinguish all LEDs
  192.  
  193.     for (i=0x48; i<=0x5c; i++) midi.sendShortMsg(No,i,0x40); // Set surface LEDs to black default
  194.     
  195.     // Force change to first deck, initializing the control surface & LEDs and connecting signals in the process
  196.     StantonSCS3d.deck = 2;  // Set active deck to right (#2) so the below will switch to #1.
  197.     if (StantonSCS3d.singleDeck)    // Force timer to expire so the deck change happens
  198.         StantonSCS3d.modifier["deckTime"] = new Date() - StantonSCS3d.deckChangeWait;
  199.     StantonSCS3d.DeckChangeP1(StantonSCS3d.channel, StantonSCS3d.buttons["deck"], "null", 0x90+StantonSCS3d.channel);
  200.     StantonSCS3d.DeckChangeP1(StantonSCS3d.channel, StantonSCS3d.buttons["deck"], "null", 0x80+StantonSCS3d.channel);
  201.     
  202.     // Connect the playposition functions permanently since they disrupt playback if connected on the fly
  203.     if (StantonSCS3d.spinningPlatter) {
  204.         engine.connectControl("[Channel1]","visual_playposition","StantonSCS3d.circleLEDs1");
  205.         engine.connectControl("[Channel2]","visual_playposition","StantonSCS3d.circleLEDs2");
  206.         engine.connectControl("[Channel1]","duration","StantonSCS3d.durationChange1");
  207.         engine.connectControl("[Channel2]","duration","StantonSCS3d.durationChange2");
  208.     }
  209.     
  210.     //  Initialize the spinning platter LEDs if the mapping is loaded after a song is
  211.     StantonSCS3d.durationChange1(engine.getValue("[Channel1]","duration"));
  212.     StantonSCS3d.durationChange2(engine.getValue("[Channel2]","duration"));
  213.     
  214.     print ("StantonSCS3d: \""+StantonSCS3d.id+"\" on MIDI channel "+(StantonSCS3d.channel+1)+" initialized.");
  215. }
  216.  
  217. StantonSCS3d.statusResponse = function (data, length) {
  218.     var statusResponsePreamble=[0xF0,0x7E,0,6,2,0,1,0x60,0x2c,1,1,0];
  219.     // Check if this SysEx is the one we're looking for
  220.     var i=0;
  221.     var comp=true;
  222.     while (i<12 && comp) {
  223.         if (statusResponsePreamble[i]!=data.charCodeAt(i)) comp=false;
  224.         i++;
  225.     }
  226.     
  227.     if (comp) {
  228.         print ("Stanton SCS.3d v"+data.charCodeAt(12)+", "+(2008+data.charCodeAt(13))+"-"+data.charCodeAt(14)+"-"+data.charCodeAt(15));
  229.         
  230.         if ((2008+data.charCodeAt(13))==2009 && !StantonSCS3d.state["flat"]) {
  231.             // If the year is 2009, this is the test "smart" firmware
  232.             print ("WARNING: This SCS.3d is running test firmware and should be re-flashed with production firmware!\n\
  233.                     (Contact Stanton support.)  Changing unit to flat mode and re-initializing...");
  234.             //  Send the command to change the device to flat mode which is mostly compatible
  235.             midi.sendSysexMsg(StantonSCS3d.sysex.concat([0x10, StantonSCS3d.channel, 0xF7]),7);
  236.             StantonSCS3d.state["flat"]=true;
  237.             StantonSCS3d.init(StantonSCS3d.id); // TODO: Remove this once the deadlock issue is resolved
  238.         }
  239.     }
  240. //     StantonSCS3d.init2();
  241. }
  242.  
  243. StantonSCS3d.shutdown = function () {   // called when the MIDI device is closed
  244.  
  245.     StantonSCS3d.stopTimers();
  246.  
  247.     var CC = 0xB0 + StantonSCS3d.channel;
  248.     var No = 0x90 + StantonSCS3d.channel;
  249.  
  250.     for (i=0x48; i<=0x5c; i++) midi.sendShortMsg(No,i,0x40); // Set surface LEDs to black default
  251.     midi.sendShortMsg(CC,0x7B,0x00);  // Extinguish all LEDs
  252.     
  253.     print ("StantonSCS3d: \""+StantonSCS3d.id+"\" on MIDI channel "+(StantonSCS3d.channel+1)+" shut down.");
  254. }
  255.  
  256. StantonSCS3d.stopTimers = function () {
  257.     for (var i=0; i<StantonSCS3d.timer.length; i++) {
  258.         if (StantonSCS3d.timer[i] != -1) {
  259.             engine.stopTimer(StantonSCS3d.timer[i]);
  260.             StantonSCS3d.timer[i] = -1;
  261.         }
  262.     }
  263. }
  264.  
  265. // (Dis)connects the appropriate Mixxx control signals to/from functions based on the currently controlled deck and what mode the controller is in
  266. StantonSCS3d.connectSurfaceSignals = function (channel, disconnect) {
  267.  
  268.     var signalList = StantonSCS3d.modeSignals[StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]];
  269.     for (i=0; i<signalList.length; i++) {
  270.         var group = signalList[i][0];
  271.         if (group=="CurrentChannel") group = "[Channel"+StantonSCS3d.deck+"]";
  272.         engine.connectControl(group,signalList[i][1],signalList[i][2],disconnect);
  273.         
  274.         // If connecting a signal, cause it to fire (by setting it to the same value) to update the LEDs
  275. //         if (!disconnect) engine.trigger(group,signalList[i][1]);  // Commented because there's no sense in wasting queue length
  276.         if (!disconnect) {
  277.             // Alternate:
  278.             var command = signalList[i][2]+"("+engine.getValue(group,signalList[i][1])+")";
  279. //             print("StantonSCS3d: command="+command);
  280.             eval(command);
  281.         }
  282.         if (StantonSCS3d.debug) {
  283.             if (disconnect) print("StantonSCS3d: "+group+","+signalList[i][1]+" disconnected from "+signalList[i][2]);
  284.             else print("StantonSCS3d: "+group+","+signalList[i][1]+" connected to "+signalList[i][2]);
  285.         }
  286.     }
  287.     // If disconnecting signals, darken the LEDs on the control surface & soft buttons
  288.     if (disconnect) {
  289.         var CC = 0xB0 + channel;
  290.         midi.sendShortMsg(CC,0x62,0x00);  // C1 LEDs off
  291.         midi.sendShortMsg(CC,0x0C,0x00);  // S3 LEDs off
  292.         midi.sendShortMsg(CC,0x01,0x00);  // S4 LEDs off
  293.         midi.sendShortMsg(CC,0x0E,0x00);  // S5 LEDs off
  294.     }
  295. }
  296.  
  297. // (Dis)connects the mode-independent Mixxx control signals to/from functions based on the currently controlled virtual deck
  298. StantonSCS3d.connectDeckSignals = function (channel, disconnect, list) {
  299.     var signalList;
  300.     switch (list) {
  301.         case "common": signalList = StantonSCS3d.commonSignals; break;
  302.         case "deck":
  303.         default: signalList = StantonSCS3d.deckSignals; break;
  304.     }
  305.     for (i=0; i<signalList.length; i++) {
  306.         var group = signalList[i][0];
  307.         var name = signalList[i][1];
  308.         if (group=="CurrentChannel") group = "[Channel"+StantonSCS3d.deck+"]";
  309.         engine.connectControl(group,name,signalList[i][2],disconnect);
  310. //        if (StantonSCS3d.debug) print("StantonSCS3d: (dis)connected "+group+","+name+" to/from "+signalList[i][2]);
  311.         
  312.         // If connecting a signal, update the LEDs
  313.         if (!disconnect) {
  314.             switch (name) {
  315.                 case "play":
  316.                         var currentValue = engine.getValue(group,name);
  317. //                         print("StantonSCS3d: current value="+currentValue);
  318.                         StantonSCS3d.playLED(currentValue);
  319.                         break;
  320.                 case "cue_default":
  321.                 case "beatsync": break;
  322.                 default:    // Cause the signal to fire to update LEDs
  323. //                         engine.trigger(group,name);  // No sense in wasting queue length if we can do this another way
  324.                     // Alternate:
  325.                         var command = signalList[i][2]+"("+engine.getValue(group,name)+")";
  326. //                         print("StantonSCS3d: command="+command);
  327.                         eval(command);
  328.                         break;
  329.             }
  330.         }
  331.         if (StantonSCS3d.debug) {
  332.             if (disconnect) print("StantonSCS3d: "+group+","+signalList[i][1]+" disconnected from "+signalList[i][2]);
  333.             else print("StantonSCS3d: "+group+","+signalList[i][1]+" connected to "+signalList[i][2]);
  334.         }
  335.     }
  336.     // If disconnecting signals, darken the corresponding LEDs
  337.     if (disconnect) {
  338.         var CC = 0xB0 + channel;
  339.         var No = 0x90 + channel;
  340.         switch (list) {
  341.             case "common": 
  342.                 midi.sendShortMsg(CC,0x07,0x00);  // Gain LEDs off
  343.                 midi.sendShortMsg(CC,0x03,0x00);  // Pitch LEDs off
  344.                 break;
  345.             case "deck":
  346.                 midi.sendShortMsg(No,0x6D,0x00);  // PLAY button blue
  347.                 midi.sendShortMsg(No,0x6E,0x00);  // CUE button blue
  348.                 midi.sendShortMsg(No,0x6F,0x00);  // SYNC button blue
  349.                 midi.sendShortMsg(No,0x70,0x00);  // TAP button blue
  350.                 break;
  351.         }
  352.     }
  353. }
  354.  
  355. // Sets all mode buttons except Deck to the same color
  356. StantonSCS3d.modeButtonsColor = function (channel, color) {
  357.     var byte1 = 0x90 + channel;
  358.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["fx"],color); // Set FX button color
  359.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["eq"],color); // Set EQ button color
  360.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["loop"],color); // Set Loop button color
  361.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["trig"],color); // Set Trig button color
  362.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["vinyl"],color); // Set Vinyl button color
  363.     midi.sendShortMsg(byte1,StantonSCS3d.buttons["deck"],color); // Set Deck button color
  364. }
  365.  
  366. // Sets all four soft buttons to the same color
  367. StantonSCS3d.softButtonsColor = function (channel, color) {
  368.     var byte1 = 0x90 + channel;
  369.     midi.sendShortMsg(byte1,0x2c,color); // Set B11 button color
  370.     midi.sendShortMsg(byte1,0x2e,color); // Set B12 button color
  371.     midi.sendShortMsg(byte1,0x30,color); // Set B13 button color
  372.     midi.sendShortMsg(byte1,0x32,color); // Set B14 button color
  373. }
  374.  
  375. // Sets color of side circle LEDs (used for deck change effect)
  376. StantonSCS3d.circleLEDsColor = function (channel, color, side) {
  377.     var byte1 = 0x90 + channel;
  378.     var start;
  379.     var end;
  380.     if (side=="left") { start = 0x5e; end = 0x63; }
  381.     else { start = 0x66; end = 0x6b; }
  382.     for (i=start; i<=end; i++) midi.sendShortMsg(byte1,i,color);
  383. }
  384.  
  385. StantonSCS3d.pitch = function (channel, control, value) {   // Lower the sensitivity of the pitch slider
  386.     // If in DECK mode, ignore this.
  387.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") return;
  388.     
  389.     var currentValue = engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate");
  390.     var newValue;
  391.     if (StantonSCS3d.modifier[StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]]==1)
  392.         newValue = currentValue+(value-64)/1024;    // Fine pitch adjust
  393.     else newValue = currentValue+(value-64)/256;
  394.     if (newValue<-1) newValue=-1.0;
  395.     if (newValue>1) newValue=1.0;
  396.     engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate",newValue);
  397. }
  398.  
  399. StantonSCS3d.pitchAbsolute = function (channel, control, value) {
  400.     // Adjust the master balance if in DECK mode
  401.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") {
  402.         var newValue = (value-64)/64;
  403.         engine.setValue("[Master]","balance",newValue);
  404.         return;
  405.     }
  406.     
  407.     // Disable if doing fine adjustments (holding down the current mode button)
  408.     if (StantonSCS3d.modifier[StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]]==1) return;
  409.     
  410.     // --- Pitch bending at the edges of the slider ---
  411.     if (StantonSCS3d.state["pitchAbs"]==0) StantonSCS3d.state["pitchAbs"]=value;    // Log the initial value
  412.     
  413.     // Ignore if the slider was first touched in the middle
  414.     if (StantonSCS3d.state["pitchAbs"]>=10 && StantonSCS3d.state["pitchAbs"]<=117) return;
  415.     
  416.     if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate_dir") == -1) {   // Go in the appropriate direction
  417.         if (value<10) engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_up",1);
  418.         if (value>117) engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_down",1);
  419.     }
  420.     else {
  421.         if (value<10) engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_down",1);
  422.         if (value>117) engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_up",1);
  423.     }
  424. }
  425.  
  426. StantonSCS3d.pitchTouch = function (channel, control, value, status) {
  427.     if ((status & 0xF0) == 0x80) {   // If button up
  428.         StantonSCS3d.state["pitchAbs"]=0;   // Clear the initial value
  429.         if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_down") != 0)
  430.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_down",0);
  431.         if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_up") != 0)
  432.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate_temp_up",0);
  433.     }
  434. }
  435.  
  436. StantonSCS3d.gain = function (channel, control, value) {
  437.         var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  438.     // Ignore if in DECK mode
  439.     if (currentMode == "deck") return;
  440.     if (StantonSCS3d.modifier[currentMode]==1) return;
  441.     engine.setValue("[Channel"+StantonSCS3d.deck+"]","volume",value/127);
  442. }
  443.  
  444. StantonSCS3d.gainRelative = function (channel, control, value) {
  445.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  446.     if (StantonSCS3d.modifier[currentMode]==1)  {   // If mode button held, set pre-gain level
  447.         var newValue = engine.getValue("[Channel"+StantonSCS3d.deck+"]","pregain")+(value-64)/128;
  448.         if (newValue<0.0) newValue=0.0;
  449.         if (newValue>4.0) newValue=4.0;
  450.         engine.setValue("[Channel"+StantonSCS3d.deck+"]","pregain",newValue);
  451.         var add = StantonSCS3d.BoostCut(9,newValue, 0.0, 1.0, 4.0, 4, 4);
  452.         var byte1 = 0xB0 + channel;
  453.         midi.sendShortMsg(byte1,0x07,0x15+add);
  454.     }
  455.     else if (currentMode == "deck") { // If in DECK mode, adjust Master Volume
  456.         var newValue = engine.getValue("[Master]","volume")+(value-64)/256;
  457.         if (newValue<0.0) newValue=0.0;
  458.         if (newValue>5.0) newValue=5.0;
  459.         engine.setValue("[Master]","volume",newValue);
  460.         return;
  461.     }
  462. }
  463.  
  464. StantonSCS3d.playButton = function (channel, control, value, status) {
  465.     var byte1 = 0x90 + channel;
  466.     if ((status & 0xF0) == 0x90) {    // If button down
  467.         // If in single-deck mode and in DECK mode and Deck is held when this is pressed, change decks
  468.         var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  469.         if (StantonSCS3d.singleDeck && currentMode == "deck" && StantonSCS3d.modifier["deck"]==1) {
  470.             StantonSCS3d.DeckChangeP1(channel, StantonSCS3d.buttons["deck"], "null", 0x90+channel);
  471.             StantonSCS3d.DeckChangeP1(channel, StantonSCS3d.buttons["deck"], "null", 0x80+channel);
  472.             return
  473.         }
  474.         StantonSCS3d.modifier["play"]=1;
  475.         if (StantonSCS3d.modifier["cue"]==1) engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",1);
  476.         else {
  477.             var currentlyPlaying = engine.getValue("[Channel"+StantonSCS3d.deck+"]","play");
  478.             if (currentlyPlaying && engine.getValue("[Channel"+StantonSCS3d.deck+"]","cue_default")==1) engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_default",0);
  479.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","play", !currentlyPlaying);
  480.         }
  481.         return;
  482.     }
  483.     StantonSCS3d.modifier["play"]=0;
  484. }
  485.  
  486. StantonSCS3d.cueButton = function (channel, control, value, status) {
  487.     var byte1 = 0x90 + channel;
  488.     if ((status & 0xF0) != 0x80) {    // If button down
  489.         // If VINYL held down in a manipulation mode
  490.         if (StantonSCS3d.modifier["vinyl"] || StantonSCS3d.modifier["vinyl2"]) {
  491.             // Force the timer on the mode button to expire to avoid unintended mode changes
  492.             StantonSCS3d.modifier["time"] = new Date()-1000;
  493.             // Toggle scratch & cue mode
  494.             if (StantonSCS3d.scratchncue[StantonSCS3d.deck]) StantonSCS3d.scratchncue[StantonSCS3d.deck]=false;
  495.             else StantonSCS3d.scratchncue[StantonSCS3d.deck]=true;
  496.             // Flash the Stanton logo to acknowledge
  497.             midi.sendShortMsg(0x90,0x7A,0x00);
  498.             midi.sendShortMsg(0x90,0x7A,0x01);
  499.         }
  500.         else engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_default",1);
  501.         StantonSCS3d.modifier["cue"]=1;   // Set button modifier flag
  502.         return;
  503.     }
  504.     if (StantonSCS3d.modifier["play"]==0 && !StantonSCS3d.modifier["vinyl2"])
  505.         engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_default",0);
  506.     StantonSCS3d.modifier["cue"]=0;   // Clear button modifier flag
  507. }
  508.  
  509. StantonSCS3d.syncButton = function (channel, control, value, status) {
  510.     var byte1 = 0x90 + channel;
  511.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  512.     if ((status & 0xF0) == 0x90) {    // If button down
  513.         // If in DECK mode and Deck is held when this is pressed,
  514.         //  toggle between multi and single deck mode
  515.         if (currentMode == "deck" && (!StantonSCS3d.singleDeck || StantonSCS3d.modifier["deck"]==1)) {
  516.             // Flash the Stanton logo to acknowledge
  517.             midi.sendShortMsg(0x90,0x7A,0x00);
  518.             midi.sendShortMsg(0x90,0x7A,0x01);
  519.             if (StantonSCS3d.singleDeck) {
  520.                 if (StantonSCS3d.debug) print("StantonSCS3d: Switching to multiple-deck control mode");
  521.                 StantonSCS3d.singleDeck = false;
  522.                 // Prevent ending up in now-defunct "Deck" mode
  523.                 if (StantonSCS3d.mode_store["[Channel1]"]=="deck") StantonSCS3d.mode_store["[Channel1]"] = "vinyl";
  524.                 if (StantonSCS3d.mode_store["[Channel2]"]=="deck") StantonSCS3d.mode_store["[Channel2]"] = "vinyl";
  525.                 // Do deck change to acknowledge
  526.                 StantonSCS3d.DeckChangeP1(channel, StantonSCS3d.buttons["deck"], "null", 0x90+channel);
  527.             }
  528.             else {
  529.                 if (StantonSCS3d.debug) print("StantonSCS3d: Switching to single-deck control mode");
  530.                 StantonSCS3d.singleDeck = true;
  531.             }
  532.         }
  533.         else
  534.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","beatsync",1);
  535.         return;
  536.     }
  537.     // If button up
  538.     // Don't touch beatsync if we toggled modes
  539.     if (currentMode == "deck" && (!StantonSCS3d.singleDeck || StantonSCS3d.modifier["deck"]==1)) return;
  540. //     midi.sendShortMsg(byte1,control,0x00);  // SYNC button blue
  541.     engine.setValue("[Channel"+StantonSCS3d.deck+"]","beatsync",0);
  542. }
  543.  
  544. StantonSCS3d.tapButton = function (channel, control, value, status) {
  545.     var byte1 = 0x90 + channel;
  546.     // If in DECK mode, and not in single-deck mode
  547.     if (!StantonSCS3d.singleDeck && StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") {
  548.         engine.setValue("[Master]","crossfader",0.0);   // Reset cross-fader to center
  549.         return;
  550.     }
  551.     if ((status & 0xF0) == 0x90) {    // If button down
  552.         if (StantonSCS3d.debug) print("StantonSCS3d: TAP");
  553.         midi.sendShortMsg(byte1,control,0x01);  // TAP button red
  554.         bpm.tapButton(StantonSCS3d.deck);
  555.         return;
  556.     }
  557.     midi.sendShortMsg(byte1,control,0x00);  // TAP button blue
  558. }
  559.  
  560. StantonSCS3d.B11 = function (channel, control, value, status) {
  561.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  562.     var byte1 = 0x90 + channel;
  563.     if ((status & 0xF0) == 0x90) {    // If button down
  564.         StantonSCS3d.modifier["B11"]=1;   // Set button modifier flag
  565.         // If the current mode button is held down,
  566.         if (StantonSCS3d.modifier[currentMode]==1) { 
  567.             midi.sendShortMsg(byte1,control,0x01); // Make button red
  568.             // Reset channel pre-fader gain to center
  569.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","pregain",1.0);
  570.             // Update the LEDs
  571.             var add = StantonSCS3d.BoostCut(9,1.0, 0.0, 1.0, 4.0, 5, 4);
  572.             midi.sendShortMsg(0xB0 + channel,0x07,0x15+add);
  573.             return;
  574.         }
  575.  
  576.         switch (currentMode) {
  577.             case "vinyl3": midi.sendShortMsg(byte1,control,0x01); // Make button red
  578.                 break;
  579.             case "deck":
  580.                 midi.sendShortMsg(byte1,control,0x01); // Make button red
  581.                 engine.setValue("[Master]","volume",1.0);
  582.                 return; break;
  583.             default: break;
  584.         }
  585.     }
  586.     else {
  587.         StantonSCS3d.modifier["B11"]=0;   // Clear button modifier flag
  588.         if (currentMode=="deck" || StantonSCS3d.modifier[currentMode]==1) {
  589.             midi.sendShortMsg(byte1,control,0x02); // Make button blue if a mode button is held or in DECK mode
  590.             return;
  591.         }
  592.         switch (currentMode) {
  593.             case "vinyl3": midi.sendShortMsg(byte1,control,0x02); // Make button blue
  594.                 break;
  595.             default: break;
  596.         }
  597.     }
  598.     switch (currentMode) {
  599.         case "fx":
  600.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","reverse",!engine.getValue("[Channel"+StantonSCS3d.deck+"]","reverse"));
  601.                 break;
  602.         case "vinyl3":
  603.                 if ((status & 0xF0) != 0x80) {    // If button down
  604.                     engine.setValue("[Playlist]","SelectPrevPlaylist",1);
  605.                 }
  606.                 else engine.setValue("[Playlist]","SelectPrevPlaylist",0);
  607.                 break;
  608.         case "vinyl":
  609.         case "vinyl2":
  610.         default:
  611.                 if ((status & 0xF0) != 0x80) {    // If button down
  612.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","pfl",!engine.getValue("[Channel"+StantonSCS3d.deck+"]","pfl"));
  613.                 }
  614.                 break;
  615.     }
  616. }
  617.  
  618. StantonSCS3d.B12 = function (channel, control, value, status) {
  619.     var byte1 = 0x90 + channel;
  620.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  621.  
  622.     // Common & modifier actions
  623.     if ((status & 0xF0) == 0x90) {    // If button down
  624.         StantonSCS3d.modifier["B12"]=1;   // Set button modifier flag
  625.         if (currentMode != "fx")
  626.             midi.sendShortMsg(byte1,control,0x01); // Make button red
  627.         if (currentMode != "deck" && StantonSCS3d.modifier[currentMode]==1) {
  628.             // Reset pitch to 0 if mode button held down
  629.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate",0);
  630.             return;
  631.         }
  632.     }
  633.     else {  // If button up
  634.         StantonSCS3d.modifier["B12"]=0;   // Clear button modifier flag
  635.         if (currentMode != "fx")
  636.             midi.sendShortMsg(byte1,control,0x02); // Make button blue
  637.     }
  638.     switch (currentMode) {
  639.         case "deck":
  640.             if ((status & 0xF0) == 0x90)     // If button down
  641.                 engine.setValue("[Master]","balance",0.0); // Reset master balance to center
  642.             break;
  643.         case "loop2":
  644.         case "loop3":
  645.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate",0);
  646.                 break;
  647.         case "fx":
  648.                 if ((status & 0xF0) == 0x90)     // If button down
  649.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","flanger",!engine.getValue("[Channel"+StantonSCS3d.deck+"]","flanger"));
  650.                 break;
  651.         case "vinyl3":
  652.                 if ((status & 0xF0) == 0x90) {    // If button down
  653.                     engine.setValue("[Playlist]","SelectNextPlaylist",1);
  654.                 }
  655.                 else engine.setValue("[Playlist]","SelectNextPlaylist",0);
  656.                 break;
  657.         default:
  658.                 if ((status & 0xF0) == 0x90) {    // If button down
  659.                     var currentRange = engine.getValue("[Channel"+StantonSCS3d.deck+"]","rateRange");
  660.                     switch (true) {
  661.                         case (currentRange<=StantonSCS3d.pitchRanges[0]):
  662.                                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",StantonSCS3d.pitchRanges[1]);
  663.                             break;
  664.                         case (currentRange<=StantonSCS3d.pitchRanges[1]):
  665.                                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",StantonSCS3d.pitchRanges[2]);
  666.                             break;
  667.                         case (currentRange<=StantonSCS3d.pitchRanges[2]):
  668.                                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",StantonSCS3d.pitchRanges[3]);
  669.                             break;
  670.                         case (currentRange>=StantonSCS3d.pitchRanges[3]):
  671.                                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",StantonSCS3d.pitchRanges[0]);
  672.                             break;
  673.                     }
  674.                     // Update the screen display
  675.                     engine.trigger("[Channel"+StantonSCS3d.deck+"]","rate");
  676.                 }
  677.                 break;
  678.     }
  679. }
  680.  
  681. StantonSCS3d.B13 = function (channel, control, value, status) {
  682.     var byte1 = 0x90 + channel;
  683.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  684.     if ((status & 0xF0) == 0x90) {    // If button down
  685.         StantonSCS3d.modifier["B13"]=1;   // Set button modifier flag
  686.         if (currentMode == "vinyl3")
  687.             midi.sendShortMsg(byte1,control,0x01); // Make button red
  688.     }
  689.     else {
  690.         StantonSCS3d.modifier["B13"]=0;   // Clear button modifier flag
  691.         if (currentMode == "vinyl3")
  692.             midi.sendShortMsg(byte1,control,0x02); // Make button blue
  693.     }
  694.     switch (currentMode) {
  695.         case "vinyl3":
  696.                 if ((status & 0xF0) == 0x90) {    // If button down
  697.                     engine.setValue("[Playlist]","SelectPrevTrack",1);
  698.                 }
  699.                 else engine.setValue("[Playlist]","SelectPrevTrack",0);
  700.                 break;
  701.         default:
  702.             if ((status & 0xF0) == 0x90) {    // If button down
  703.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","back",1);
  704.                 return;
  705.             }
  706.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","back",0);
  707.             break;
  708.     }
  709. }
  710.  
  711. StantonSCS3d.B14 = function (channel, control, value, status) {
  712.     var byte1 = 0x90 + channel;
  713.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  714.     if ((status & 0xF0) == 0x90) {    // If button down
  715.         StantonSCS3d.modifier["B14"]=1;   // Set button modifier flag
  716.         if (currentMode == "vinyl3")
  717.             midi.sendShortMsg(byte1,control,0x01); // Make button red
  718.     }
  719.     else {
  720.         StantonSCS3d.modifier["B14"]=0;   // Clear button modifier flag
  721.         if (currentMode == "vinyl3")
  722.             midi.sendShortMsg(byte1,control,0x02); // Make button blue
  723.     }
  724.     switch (currentMode) {
  725.         case "vinyl3":
  726.                 if ((status & 0xF0) == 0x90) {    // If button down
  727.                     engine.setValue("[Playlist]","SelectNextTrack",1);
  728.                 }
  729.                 else engine.setValue("[Playlist]","SelectNextTrack",0);
  730.                 break;
  731.         default:
  732.             if ((status & 0xF0) == 0x90) {    // If button down
  733.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","fwd",1);
  734.                 return;
  735.             }
  736.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","fwd",0);
  737.             break;
  738.     }
  739. }
  740.  
  741. // ----------   Mode buttons  ----------
  742.  
  743. StantonSCS3d.modeButton = function (channel, control, status, modeName) {
  744.     var byte1 = 0x90 + channel;
  745.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  746.     if ((status & 0xF0) == 0x90) {    // If button down
  747.         midi.sendShortMsg(byte1,control,0x03); // Make button purple
  748.         StantonSCS3d.modifier[modeName]=1;   // Set mode modifier flag
  749.         if (currentMode == modeName) {
  750.             StantonSCS3d.modifier["time"] = new Date();  // Store the current time in milliseconds
  751.             StantonSCS3d.B11LED(0); // B11 blue
  752.             StantonSCS3d.B12LED(0); // B12 blue
  753.             // Set Gain LEDs to pregain value
  754.             var add = StantonSCS3d.BoostCut(9,engine.getValue("[Channel"+StantonSCS3d.deck+"]","pregain"), 0.0, 1.0, 4.0, 5, 4);
  755.             midi.sendShortMsg(0xB0+channel,0x07,0x15+add);
  756.         }
  757.         else StantonSCS3d.modifier["time"] = 0.0;
  758.         return;
  759.     }
  760.     StantonSCS3d.modifier[currentMode] = StantonSCS3d.modifier[modeName] = 0;   // Clear mode modifier flags
  761.     StantonSCS3d.gainLEDs(engine.getValue("[Channel"+StantonSCS3d.deck+"]","volume"));  // Restore Gain LEDs
  762.     StantonSCS3d.modeButtonsColor(channel,0x02);  // Make all mode buttons blue
  763.     // If trying to switch to the same mode, or the same button was held down for over 1/3 of a second, stay in the current mode
  764.     if (currentMode == modeName || (StantonSCS3d.modifier["time"] != 0.0 && ((new Date() - StantonSCS3d.modifier["time"])>300))) {
  765.         switch (currentMode.charAt(currentMode.length-1)) {   // Return the button to its original color
  766.             case "2": midi.sendShortMsg(byte1,control,0x03); break;   // Make button purple
  767.             case "3": midi.sendShortMsg(byte1,control,0x00); break;   // Make button black
  768.             default:  midi.sendShortMsg(byte1,control,0x01); break;  // Make button red
  769.         }
  770.         StantonSCS3d.connectSurfaceSignals(channel);  // Re-trigger signals
  771.         return;
  772.     }
  773.     // So if we've reached this point, modeName != currentMode, i.e. we're about to change modes
  774.     
  775.     if (StantonSCS3d.debug) print("StantonSCS3d: Switching to "+modeName.toUpperCase()+" mode on deck "+StantonSCS3d.deck);
  776.     switch (modeName.charAt(modeName.length-1)) {   // Set the button to its new color
  777.         case "2": midi.sendShortMsg(byte1,control,0x03); break;   // Make button purple
  778.         case "3": midi.sendShortMsg(byte1,control,0x00); break;   // Make button black
  779.         default:  midi.sendShortMsg(byte1,control,0x01); break;  // Make button red
  780.     }
  781.     StantonSCS3d.connectSurfaceSignals(channel,true);  // Disconnect previous ones
  782.     StantonSCS3d.softButtonsColor(channel,0x02);  // Make the soft buttons blue
  783.     switch (currentMode) {    // Special recovery from certain modes
  784.         case "vinyl":
  785.         case "vinyl2":
  786.             // So we don't get stuck at some strange speed when switching from a scratching mode
  787.             engine.scratchDisable(StantonSCS3d.deck);
  788.             break;
  789.         case "loop2":
  790.         case "loop3":
  791.         case "trig":
  792.         case "trig2":
  793.         case "trig3":
  794.                 // If switching to loop2-3 or trig from either, skip this
  795.                 if (modeName.substring(0,4)=="trig" || (modeName != "loop" && modeName.substring(0,4)=="loop")) break;
  796.                 var redButtonLEDs = [0x48, 0x4a, 0x4c, 0x4e, 0x4f, 0x51, 0x53, 0x55];
  797.                 for (i=0; i<redButtonLEDs.length; i++)
  798.                     midi.sendShortMsg(byte1,redButtonLEDs[i],0x40); // Set them to black
  799.                 for (i=0x56; i<=0x5c; i++)
  800.                     midi.sendShortMsg(byte1,i,0x40); // Set center slider to black
  801.             break;
  802.         case "deck":
  803.             StantonSCS3d.state["forceGain"]=true;
  804.             StantonSCS3d.gainLEDs(engine.getValue("[Channel"+StantonSCS3d.deck+"]","volume"));  // Restore Gain LEDs
  805.             StantonSCS3d.state["forceGain"]=false;
  806.             StantonSCS3d.connectDeckSignals(channel,false,"common");    // Connect static common signals
  807.             break;
  808.     }
  809. //     if (StantonSCS3d.modeSurface[modeName] != StantonSCS3d.modeSurface[currentMode])    // If different,
  810.         midi.sendSysexMsg(StantonSCS3d.sysex.concat([0x01,
  811.             StantonSCS3d.surface[StantonSCS3d.modeSurface[modeName]], 0xF7]),7);  // Configure surface
  812.     switch (modeName) {    // Prep for certain modes
  813.         case "loop2":
  814.         case "loop3":
  815.         case "trig":
  816.         case "trig2":
  817.         case "trig3":
  818.                 // If switching to loop2-3 or trig from any other mode, prep the surface background LEDs
  819.                 
  820.                 var index = modeName.charAt(modeName.length-1);
  821.                 if (index != "2" && index != "3") index = "1";
  822.                 
  823.                 var redButtonLEDs = [0x48, 0x4a, 0x4c, 0x4e, 0x4f, 0x51, 0x53, 0x55, 0x56, 0x58, 0x5A, 0x5C];
  824.                 if ( (currentMode.substring(0,4) != "trig"
  825.                       && (currentMode == "loop" || currentMode.substring(0,4) != "loop"))
  826.                       || StantonSCS3d.state["changedDeck"]) {
  827.                     StantonSCS3d.state["changedDeck"] = false;
  828.                     for (i=0; i<redButtonLEDs.length; i++)
  829.                         midi.sendShortMsg(byte1,redButtonLEDs[i],0x41); // Set them to red dim
  830.                 }
  831.             break;
  832.         case "deck":
  833.             StantonSCS3d.connectDeckSignals(channel,true,"common");    // Disconnect static common signals
  834.             midi.sendShortMsg(byte1,0x3D,0x00);  // Pitch LED black
  835.             midi.sendShortMsg(byte1,0x3E,0x00);
  836.             break;
  837.     }
  838.     StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = modeName;
  839.     StantonSCS3d.connectSurfaceSignals(channel);  // Connect new ones
  840.     // Force the circle LEDs to light if applicable
  841.     StantonSCS3d.lastLight[StantonSCS3d.deck]=-1;
  842.     StantonSCS3d.circleLEDs(engine.getValue("[Channel"+StantonSCS3d.deck+"]","visual_playposition"));
  843. }
  844.  
  845. StantonSCS3d.FX = function (channel, control, value, status) {
  846.     StantonSCS3d.modeButton(channel, control, status, "fx");
  847. }
  848.  
  849. StantonSCS3d.EQ = function (channel, control, value, status) {
  850.     StantonSCS3d.modeButton(channel, control, status, "eq");
  851. }
  852.  
  853. StantonSCS3d.Loop = function (channel, control, value, status) {
  854.     var mode;
  855.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  856.     
  857.     switch (currentMode) {
  858.         case "loop":
  859.             if ((status & 0xF0) == 0x80) mode = "loop2";
  860.             else mode = "loop";
  861.             break;
  862.         case "loop2":
  863.             if ((status & 0xF0) == 0x80) mode = "loop3";
  864.             else mode = "loop2";
  865.             break;
  866.         case "loop3":
  867.             if ((status & 0xF0) == 0x80) mode = "loop";
  868.             else mode = "loop3";
  869.             break;
  870.         default: mode = "loop";
  871.     }
  872.     StantonSCS3d.modeButton(channel, control, status, mode);
  873. }
  874.  
  875. StantonSCS3d.Trig = function (channel, control, value, status) {
  876.     StantonSCS3d.triggerS4 = 0xFF;
  877.     var mode;
  878.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  879.     
  880.     switch (currentMode) {
  881.         case "trig":
  882.             if ((status & 0xF0) == 0x80) mode = "trig2";
  883.             else mode = "trig";
  884.             break;
  885.         case "trig2":
  886.             if ((status & 0xF0) == 0x80) mode = "trig3";
  887.             else mode = "trig2";
  888.             break;
  889.         case "trig3":
  890.             if ((status & 0xF0) == 0x80) mode = "trig";
  891.             else mode = "trig3";
  892.             break;
  893.         default: mode = "trig";
  894.     }
  895.     StantonSCS3d.modeButton(channel, control, status, mode);
  896. }
  897.  
  898. StantonSCS3d.Vinyl = function (channel, control, value, status) {
  899.     var mode;
  900.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  901.     
  902.     switch (currentMode) {
  903.         case "vinyl":
  904.             if ((status & 0xF0) == 0x80) mode = "vinyl2";
  905.             else mode = "vinyl";
  906.             break;
  907.         case "vinyl2":
  908.             if ((status & 0xF0) == 0x80) mode = "vinyl3";
  909.             else mode = "vinyl2";
  910.             break;
  911.         case "vinyl3":
  912.             if ((status & 0xF0) == 0x80) mode = "vinyl";
  913.             else mode = "vinyl3";
  914.             break;
  915.         default: mode = "vinyl";
  916.     }
  917.     StantonSCS3d.modeButton(channel, control, status, mode);
  918. }
  919.  
  920. StantonSCS3d.DeckButton = function (channel, control, value, status) {
  921.     if (StantonSCS3d.singleDeck) StantonSCS3d.modeButton(channel, control, status, "deck");
  922.     else StantonSCS3d.DeckChangeP1(channel, control, value, status);
  923. }
  924.  
  925. StantonSCS3d.deckChangeFlash = function (channel, value, targetSide) {
  926.     var led = {"left":0x71,"right":0x72};
  927.     var byte1 = 0x90 + channel;
  928.     
  929.     StantonSCS3d.state["flashes"]++;
  930.     
  931.     if (StantonSCS3d.state["flashes"] % 2 == 0) {
  932.         midi.sendShortMsg(byte1,led[targetSide],0x01);  // Deck light on
  933.         StantonSCS3d.circleLEDsColor(channel,0x01,targetSide);  // Light half-circle
  934.     }
  935.     else {
  936.         midi.sendShortMsg(byte1,led[targetSide],0x00);  // Deck light off
  937.         StantonSCS3d.circleLEDsColor(channel,0x00,targetSide);  // Extinguish half-circle
  938.     }
  939.     
  940.     if (StantonSCS3d.state["flashes"]>=5) {
  941.         engine.stopTimer(StantonSCS3d.timer[0]);
  942.         StantonSCS3d.timer[0] = -1;
  943.         
  944.         // Finish the deck change
  945.         midi.sendShortMsg(byte1,led[targetSide],0x01);  // Deck light on
  946.         
  947.         StantonSCS3d.connectDeckSignals(channel);    // Connect static signals
  948.         StantonSCS3d.connectDeckSignals(channel,false,"common");    // Connect static common signals
  949.         StantonSCS3d.DeckChangeP2(channel, value);  // Call part 2
  950.     }
  951. }
  952.  
  953. StantonSCS3d.DeckChangeP1 = function (channel, control, value, status) {
  954.     var byte1 = 0x90 + channel;
  955.     if ((status & 0xF0) == 0x90) {  // If button down
  956.         StantonSCS3d.modeButtonsColor(channel,0x02);  // Make all mode buttons blue
  957.         midi.sendShortMsg(byte1,control,0x01); // Make button red
  958.         StantonSCS3d.modifier["deck"]=1;   // Set button modifier flag
  959.         StantonSCS3d.modifier["deckTime"] = new Date();  // Store the current time in milliseconds
  960.         StantonSCS3d.state["deckPrev"] = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  961.         StantonSCS3d.connectSurfaceSignals(channel,true);   // Disconnect surface signals & turn off surface LEDs
  962.         StantonSCS3d.connectDeckSignals(channel,true,"common"); // Disconnect common signals
  963.         StantonSCS3d.B11LED(0); // B11 blue
  964.         StantonSCS3d.B12LED(0); // B12 blue
  965.         midi.sendShortMsg(byte1,0x3D,0x00);  // Pitch LED black
  966.         midi.sendShortMsg(byte1,0x3E,0x00);
  967.         // Switch to three-slider mode
  968.         midi.sendSysexMsg(StantonSCS3d.sysex.concat([0x01, StantonSCS3d.surface["S3+S5"], 0xF7]),7);
  969.         StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "deck";
  970.         StantonSCS3d.connectSurfaceSignals(channel);  // Connect new ones
  971.         // Force the circle LEDs to light if applicable
  972.         StantonSCS3d.lastLight[StantonSCS3d.deck]=-1;
  973.         StantonSCS3d.circleLEDs(engine.getValue("[Channel"+StantonSCS3d.deck+"]","visual_playposition"));
  974.         return;
  975.     }
  976.     // If button up
  977.     StantonSCS3d.modifier["deck"]=0;   // Clear button modifier flag
  978.     StantonSCS3d.connectSurfaceSignals(channel,true);   // Disconnect surface signals & turn off surface LEDs
  979.     StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = StantonSCS3d.state["deckPrev"];
  980.     // To avoid getting stuck at a weird speed
  981.     engine.scratchDisable(StantonSCS3d.deck);
  982.     var newMode;
  983.     // In default multiple-deck mode, 
  984.     //      If the button's been held down for longer than the specified time, stay on the current deck.
  985.     //      If the button was just tapped, change control to another virtual deck.
  986.     if ((new Date() - StantonSCS3d.modifier["deckTime"])>=StantonSCS3d.deckChangeWait) {
  987.         midi.sendShortMsg(byte1,StantonSCS3d.buttons["deck"],0x01+StantonSCS3d.deck); // Return to appropriate color
  988.         StantonSCS3d.connectSurfaceSignals(channel);  // Connect new ones
  989.         StantonSCS3d.connectDeckSignals(channel,false,"common");    // Connect common signals again
  990.     }
  991.     else {
  992.         StantonSCS3d.stopTimers();  // Stop any flashing light timers
  993.         StantonSCS3d.connectDeckSignals(channel,true);    // Disconnect static signals
  994.         StantonSCS3d.connectDeckSignals(channel,true,"common");    // Disconnect common signals
  995.         StantonSCS3d.softButtonsColor(channel,0x00);  // Darken the soft buttons
  996.         if (StantonSCS3d.globalMode) newMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  997.         if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"].substring(0,4) == "trig" || 
  998.             StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"].substring(0,4) == "loop")
  999.                 for (i=0x48; i<=0x5c; i++) midi.sendShortMsg(byte1,i,0x40); // Set surface LEDs to black
  1000.         if (StantonSCS3d.deck == 1) {
  1001.             StantonSCS3d.deck++;
  1002.             if (StantonSCS3d.debug) print("StantonSCS3d: Switching to deck "+StantonSCS3d.deck);
  1003.             midi.sendShortMsg(byte1,StantonSCS3d.buttons["deck"],0x03); // Deck button purple
  1004.             midi.sendShortMsg(byte1,0x71,0x00); // Deck A light off
  1005.             // Make flashy lights to signal a deck change
  1006.             if (!StantonSCS3d.fastDeckChange) {
  1007.                 // If in the middle of flashing lights from a previous change, abort that one
  1008.                 if (StantonSCS3d.timer[0] != -1) engine.stopTimer(StantonSCS3d.timer[0]);
  1009.                 StantonSCS3d.state["flashes"] = 0;  // initialize number of flashes
  1010.                 StantonSCS3d.timer[0] = engine.beginTimer(60,"StantonSCS3d.deckChangeFlash("+channel+","+value+",\"right\")");
  1011.                 return;
  1012.             }
  1013.             // If fast deck change
  1014.             midi.sendShortMsg(byte1,0x72,0x01);  // Deck B light on
  1015.         }
  1016.         else {
  1017.             StantonSCS3d.deck--;
  1018.             if (StantonSCS3d.debug) print("StantonSCS3d: Switching to deck "+StantonSCS3d.deck);
  1019.             midi.sendShortMsg(byte1,StantonSCS3d.buttons["deck"],0x02); // Deck button blue
  1020.             midi.sendShortMsg(byte1,0x72,0x00);  // Deck B light off
  1021.             if (!StantonSCS3d.fastDeckChange) {
  1022.                 if (StantonSCS3d.timer[0] != -1) engine.stopTimer(StantonSCS3d.timer[0]);
  1023.                 StantonSCS3d.state["flashes"] = 0;  // initialize number of flashes
  1024.                 StantonSCS3d.timer[0] = engine.beginTimer(60,"StantonSCS3d.deckChangeFlash("+channel+","+value+",\"left\")");
  1025.                 return;
  1026.             }
  1027.             // If fast deck change
  1028.             midi.sendShortMsg(byte1,0x71,0x01);  // Deck A light on
  1029.         }
  1030.         // These are done in deckChangeFlash() when it's finished.
  1031.         //  They're here too if fastDeckChange is enabled
  1032.         StantonSCS3d.connectDeckSignals(channel);    // Connect static signals
  1033.         StantonSCS3d.connectDeckSignals(channel,false,"common");    // Connect static common signals
  1034.     }
  1035.     StantonSCS3d.DeckChangeP2(channel, value); // Go to part 2.
  1036. }
  1037.  
  1038. StantonSCS3d.DeckChangeP2 = function (channel, value) {
  1039.     if (!StantonSCS3d.globalMode) newMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1040.     StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "none"; // Forces a mode change when a function is called
  1041.     StantonSCS3d.modifier["time"] = 0.0;    // Reset the mode-modifier time
  1042.     StantonSCS3d.state["changedDeck"]= true;    // Mark that we just changed decks so the surface LEDs can update correctly for TRIG & LOOP
  1043.     switch (newMode) {    // Call the appropriate mode change function to set the control surface & connect signals on the now-current deck
  1044.         case "fx":      StantonSCS3d.FX(channel, StantonSCS3d.buttons["fx"], value, 0x80 + channel); break;
  1045.         case "eq":      StantonSCS3d.EQ(channel, StantonSCS3d.buttons["eq"], value, 0x80 + channel); break;
  1046.         case "loop2":   StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "loop"; // force correct change
  1047.         case "loop3":
  1048.             if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] == "none")
  1049.                 StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "loop2";    // force correct change
  1050.         case "loop":    StantonSCS3d.Loop(channel, StantonSCS3d.buttons["loop"], value, 0x80 + channel); break;
  1051.         case "trig2":   StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "trig"; // force correct change
  1052.         case "trig3":
  1053.             if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] == "none")
  1054.                 StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "trig2";    // force correct change
  1055.         case "trig":    StantonSCS3d.Trig(channel, StantonSCS3d.buttons["trig"], value, 0x80 + channel); break;
  1056.         case "vinyl2":  StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "vinyl";    // force correct change
  1057.         case "vinyl3":
  1058.             if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] == "none")
  1059.                 StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = "vinyl2";   // force correct change
  1060.         case "vinyl":   StantonSCS3d.Vinyl(channel, StantonSCS3d.buttons["vinyl"], value, 0x80 + channel); break;
  1061.     }
  1062. }   // End Deck Change function
  1063.  
  1064. // ----------   Sliders  ----------
  1065.  
  1066. StantonSCS3d.S4relative = function (channel, control, value) {
  1067.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1068.     if (currentMode=="deck") return;   // Skip if in DECK mode
  1069.     if (currentMode=="vinyl" || currentMode=="vinyl2") {
  1070.         var newValue = (value-64);
  1071.         engine.scratchTick(StantonSCS3d.deck,newValue);
  1072.     }
  1073. }
  1074.  
  1075. StantonSCS3d.S3absolute = function (channel, control, value) {
  1076.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1077.     switch (currentMode) {
  1078.         case "fx": script.absoluteSlider("[Flanger]","lfoDepth",value,0,1); break;
  1079.         case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterLow",script.absoluteNonLin(value,0,1,4)); break;
  1080.         case "deck": engine.setValue("[Master]","headMix",(value-64)/63); break;
  1081.     }
  1082. }
  1083.  
  1084. StantonSCS3d.S4absolute = function (channel, control, value) {
  1085.     // Adjust the cross-fader if in DECK mode
  1086.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] == "deck") {
  1087.         engine.setValue("[Master]","crossfader",(value-64)/63);
  1088.         return;
  1089.     }
  1090.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1091.     switch (currentMode) {
  1092.         case "fx": script.absoluteSlider("[Flanger]","lfoDelay",value,50,10000); break;
  1093.         case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterMid",script.absoluteNonLin(value,0,1,4)); break;
  1094.         case "vinyl":
  1095.         case "vinyl2":
  1096.             // Set slider lights
  1097.             var add = (value/15)|0;
  1098.             var byte1 = 0xB0 + channel;
  1099.             midi.sendShortMsg(byte1,0x01,add); //S4 LEDs
  1100.             if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=1) midi.sendShortMsg(byte1,0x0C,add); //S3 LEDs
  1101.             if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=2) midi.sendShortMsg(byte1,0x0E,add); //S5 LEDs
  1102.             break;
  1103.         case "loop2":
  1104.         case "loop3":
  1105.             var button = 0x5C-2*Math.floor(value/32);
  1106.             if (StantonSCS3d.triggerS4==button) return; // prevent retriggering before releasing the button
  1107.             StantonSCS3d.S4buttonLights(channel,false,StantonSCS3d.triggerS4);  // Clear the previous lights
  1108.             StantonSCS3d.triggerS4 = button;
  1109.             StantonSCS3d.S4buttonLights(channel,true,button);
  1110.             
  1111.             var index = currentMode.charAt(currentMode.length-1);
  1112.             if (index != "2" && index != "3") index = "1";
  1113.             
  1114. //             if (StantonSCS3d.modifier[currentMode]==1) {
  1115. //                 StantonSCS3d.pitchPoints[index][button] = -0.1;
  1116. //                 break;
  1117. //             }
  1118.             if (StantonSCS3d.pitchPoints[index][button] == -0.1)
  1119.                 StantonSCS3d.pitchPoints[index][button] = engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate");
  1120.             else {
  1121.                 // Need 100% range for values to be correct
  1122.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",1.0);
  1123.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate",StantonSCS3d.pitchPoints[index][button]);
  1124.             }
  1125.             break;
  1126.             
  1127.         case "trig":
  1128.         case "trig2":
  1129.         case "trig3":
  1130.             // Free Bonus! Four extra buttons!
  1131.             var button = 0x5C-2*Math.floor(value/32);
  1132.             if (StantonSCS3d.triggerS4==button) return; // prevent retriggering before releasing the button
  1133.             
  1134.             // Deactivate any previous hot cue in the same slider touch
  1135.             if (StantonSCS3d.state["S4hotcue"] != -1) {
  1136.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.state["S4hotcue"]+"_activate",0);
  1137.                 StantonSCS3d.state["S4hotcue"]=-1;
  1138.             }
  1139.             
  1140.             StantonSCS3d.triggerS4 = button;
  1141.             
  1142.             var index = currentMode.charAt(currentMode.length-1);
  1143.             if (index != "2" && index != "3") index = "1";
  1144.             
  1145.             // We support 36 hot cues but Mixxx only has 31 right now
  1146.             if (StantonSCS3d.hotCues[index][button] == -1) return;
  1147.             
  1148.             if (StantonSCS3d.modifier[currentMode]==1) {
  1149.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][button]+"_clear",1);
  1150.                 break;
  1151.             }
  1152.             // If hotcue X is set, seeks the player to hotcue X's position.
  1153.             // If hotcue X is not set, sets hotcue X to the current play position.            
  1154.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][button]+"_activate",1);
  1155.             StantonSCS3d.state["S4hotcue"]=StantonSCS3d.hotCues[index][button];    // so it can be deactivated later
  1156.             break;
  1157.     }
  1158. }
  1159.  
  1160. StantonSCS3d.S5absolute = function (channel, control, value) {
  1161.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") return;   // Ignore if in DECK mode
  1162.     switch (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]) {
  1163.         case "fx": script.absoluteSlider("[Flanger]","lfoPeriod",value,50000,2000000); break;
  1164.         case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterHigh",script.absoluteNonLin(value,0,1,4)); break;
  1165.     }
  1166. }
  1167.  
  1168. StantonSCS3d.S5relative = function (channel, control, value) {
  1169.     // Adjust the headphone volume if in DECK mode
  1170.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") {
  1171.         var newValue = engine.getValue("[Master]","headVolume")+(value-64)/128;
  1172.         if (newValue<0.0) newValue=0.0;
  1173.         if (newValue>5.0) newValue=5.0;
  1174.         engine.setValue("[Master]","headVolume",newValue);
  1175.         return;
  1176.     }
  1177. }
  1178.  
  1179. StantonSCS3d.C1touch = function (channel, control, value, status) {
  1180.     var byte1 = 0xB0 + channel;
  1181.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1182.     if ((status & 0xF0) == 0x90) {    // If button down
  1183.         switch (currentMode) {
  1184.             case "vinyl2":
  1185.                 engine.scratchEnable(StantonSCS3d.deck, 128, 45, 1.0/16, (1.0/16)/32);
  1186.                     // Recall the cue point if in "scratch & cue" mode only when playing
  1187.                     if (StantonSCS3d.scratchncue[StantonSCS3d.deck]
  1188.                         && engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1) {
  1189.                         engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_goto",1);
  1190.                         engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_goto",0);
  1191.                     }
  1192.                 break;
  1193.         }
  1194.     }
  1195.     else {  // If button up
  1196.         switch (currentMode) {
  1197.             case "vinyl": break;    // Leave C1 (platter) lights as they are
  1198.             case "vinyl2":
  1199.                 engine.scratchDisable(StantonSCS3d.deck);
  1200.                 break;
  1201.             default: midi.sendShortMsg(byte1,0x62,0x00); // Turn off C1 lights
  1202.                 break;
  1203.         }
  1204.     }
  1205. }
  1206.  
  1207. StantonSCS3d.S3touch = function (channel, control, value, status) {
  1208.     // Reset the value to center if the slider is touched while the mode button is held down
  1209.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1210.     if (StantonSCS3d.modifier[currentMode]==1){
  1211.         switch (currentMode) {
  1212.             case "fx": engine.setValue("[Flanger]","lfoDepth",0.5); break;
  1213.             case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterLow",1); break;
  1214.             case "deck": 
  1215.                 // Reset only if in single-deck mode
  1216.                 if (StantonSCS3d.singleDeck) engine.setValue("[Master]","headMix",-1);
  1217.                 break;
  1218.         }
  1219.     }
  1220.     if ((status & 0xF0) == 0x90) {    // If button down
  1221.         if (currentMode == "loop") engine.setValue("[Channel"+StantonSCS3d.deck+"]","loop_in",1);
  1222.         return;
  1223.     }
  1224.     // If button up
  1225.     if (currentMode == "loop") engine.setValue("[Channel"+StantonSCS3d.deck+"]","loop_in",0);
  1226. }
  1227.  
  1228. StantonSCS3d.S4touch = function (channel, control, value, status) {
  1229.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1230.     // If the current mode button is held down, reset the control to center
  1231.     if (StantonSCS3d.modifier[currentMode]==1) {
  1232.         switch (currentMode) {
  1233.             case "fx": engine.setValue("[Flanger]","lfoDelay",4950); break;
  1234.             case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterMid",1); break;
  1235.             case "deck":
  1236.                 // Reset cross-fader to center if in single-deck mode
  1237.                 if (StantonSCS3d.singleDeck) engine.setValue("[Master]","crossfader",0.0);
  1238.                 break;
  1239.         }
  1240.     }
  1241.     if ((status & 0xF0) == 0x90) {    // If button down
  1242.         switch (currentMode) {
  1243.             case "vinyl":  
  1244.             case "vinyl2":
  1245.                 engine.scratchEnable(StantonSCS3d.deck, 512, 33+1/3, 1.0/8, (1.0/8)/32);
  1246.                     // Recall the cue point if in "scratch & cue" mode only when playing
  1247.                     if (StantonSCS3d.scratchncue[StantonSCS3d.deck]
  1248.                         && engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1) {
  1249.                         engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_goto",1);
  1250.                         engine.setValue("[Channel"+StantonSCS3d.deck+"]","cue_goto",0);
  1251.                     }
  1252.                 break;
  1253.             case "vinyl3":  // Load the song
  1254.                 // If the deck is playing and the cross-fader is not completely toward the other deck...
  1255.                 if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1 &&
  1256.                 ((StantonSCS3d.deck==1 && engine.getValue("[Master]","crossfader")<1.0) || 
  1257.                 (StantonSCS3d.deck==2 && engine.getValue("[Master]","crossfader")>-1.0))) {
  1258.                     // ...light just the red button LEDs to show acknowledgement of the press but don't load
  1259.                     StantonSCS3d.sliderButtonLight(channel,"S4",true,true);
  1260.                     print ("StantonSCS3d: Not loading into deck "+StantonSCS3d.deck+" because it's playing to the Master output.");
  1261.                 }
  1262.                 else {
  1263.                     StantonSCS3d.sliderButtonLight(channel,"S4",true);
  1264. //                     engine.setValue("[Playlist]","LoadSelectedIntoFirstStopped",1);
  1265.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","LoadSelectedTrack",1);
  1266.                 }
  1267.                 break;
  1268.             case "loop":    // Reloop/Exit button
  1269.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","reloop_exit",1);
  1270.                 break;
  1271.         }
  1272.         return;
  1273.     }
  1274.     // If button up
  1275.     switch (currentMode) {
  1276.         case "vinyl":   
  1277.         case "vinyl2":
  1278.             engine.scratchDisable(StantonSCS3d.deck);
  1279.             var byte1a = 0xB0 + channel;
  1280.             midi.sendShortMsg(byte1a,0x01,0x00); //S4 LEDs off
  1281.             if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=1) midi.sendShortMsg(byte1a,0x0C,0x00); //S3 LEDs off
  1282.             if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=2) midi.sendShortMsg(byte1a,0x0E,0x00); //S5 LEDs off
  1283.             break;
  1284.         case "vinyl3":
  1285. //             engine.setValue("[Playlist]","LoadSelectedIntoFirstStopped",1);
  1286.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","LoadSelectedTrack",0);
  1287.             StantonSCS3d.sliderButtonLight(channel,"S4",false);
  1288.             if (StantonSCS3d.jogOnLoad) {   // Auto-change to vinyl jog mode on track load
  1289.                 // ...only if we actually loaded a track.
  1290.                 if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1 &&
  1291.                 ((StantonSCS3d.deck==1 && engine.getValue("[Master]","crossfader")<1.0) || 
  1292.                 (StantonSCS3d.deck==2 && engine.getValue("[Master]","crossfader")>-1.0))) return;
  1293.                 
  1294.                 StantonSCS3d.modifier["time"] = 0.0;
  1295.                 StantonSCS3d.Vinyl(channel, StantonSCS3d.buttons["vinyl"], value, 0x80 + channel);
  1296.             }
  1297.             break;
  1298.         case "loop":
  1299.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","reloop_exit",0);
  1300.             break;
  1301.         case "loop2":
  1302.         case "loop3":
  1303.             StantonSCS3d.S4buttonLights(channel,false,StantonSCS3d.triggerS4);
  1304.             StantonSCS3d.triggerS4 = 0xFF;
  1305.             break;
  1306.         case "trig":
  1307.         case "trig2":
  1308.         case "trig3":
  1309.             if (StantonSCS3d.state["S4hotcue"] != -1) {
  1310.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.state["S4hotcue"]+"_activate",0);
  1311.                 StantonSCS3d.state["S4hotcue"]=-1;
  1312.             }
  1313.             //StantonSCS3d.S4buttonLights(channel,false,StantonSCS3d.triggerS4);
  1314.             StantonSCS3d.triggerS4 = 0xFF;
  1315.             break;
  1316.     }
  1317. }
  1318.  
  1319. StantonSCS3d.S5touch = function (channel, control, value, status) {
  1320.     // Reset the value to center if the slider is touched while the mode button is held down
  1321.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1322.     if (StantonSCS3d.modifier[currentMode]==1){
  1323.         switch (currentMode) {
  1324.             case "fx": engine.setValue("[Flanger]","lfoPeriod",1025000); break;
  1325.             case "eq": engine.setValue("[Channel"+StantonSCS3d.deck+"]","filterHigh",1); break;
  1326.             case "deck":
  1327.                 // Reset to center only if in single-deck mode
  1328.                 if (StantonSCS3d.singleDeck) engine.setValue("[Master]","headVolume",1);
  1329.                 break;
  1330.         }
  1331.     }
  1332.     if ((status & 0xF0) == 0x90) {    // If button down
  1333.         if (currentMode == "loop") engine.setValue("[Channel"+StantonSCS3d.deck+"]","loop_out",1);
  1334.         return;
  1335.     }
  1336.     // If button up
  1337.     if (currentMode == "loop") engine.setValue("[Channel"+StantonSCS3d.deck+"]","loop_out",0);
  1338. }
  1339.  
  1340. StantonSCS3d.sliderButtonLight = function (channel, slider, light, noring) {     // Turn on/off button lights
  1341.     var byte1 = 0x90 + channel;
  1342.     var color=0x00; // Off
  1343.     if (light) color=0x01;  // On
  1344.     switch (slider) {
  1345.         case "S3":
  1346.             if (!noring) {
  1347.                 midi.sendShortMsg(byte1,0x62,color);
  1348.                 midi.sendShortMsg(byte1,0x63,color);
  1349.                 midi.sendShortMsg(byte1,0x5f,color);
  1350.                 midi.sendShortMsg(byte1,0x5e,color);
  1351.             }
  1352.                 midi.sendShortMsg(byte1,0x48,color);
  1353.                 midi.sendShortMsg(byte1,0x4e,color);
  1354.             break;
  1355.         case "S4":
  1356.             if (!noring) {
  1357.                 midi.sendShortMsg(byte1,0x64,color);
  1358.                 midi.sendShortMsg(byte1,0x65,color);
  1359.                 midi.sendShortMsg(byte1,0x5d,color);
  1360.                 midi.sendShortMsg(byte1,0x6c,color);
  1361.             }
  1362.                 midi.sendShortMsg(byte1,0x56,color);
  1363.                 midi.sendShortMsg(byte1,0x5c,color);
  1364.             break;
  1365.         case "S5":
  1366.             if (!noring) {
  1367.                 midi.sendShortMsg(byte1,0x66,color);
  1368.                 midi.sendShortMsg(byte1,0x67,color);
  1369.                 midi.sendShortMsg(byte1,0x6b,color);
  1370.                 midi.sendShortMsg(byte1,0x6a,color);
  1371.             }
  1372.             midi.sendShortMsg(byte1,0x4f,color);
  1373.             midi.sendShortMsg(byte1,0x55,color);
  1374.             break;
  1375.     }
  1376. }
  1377.  
  1378. StantonSCS3d.S4buttonLights = function (channel, light, button) {     // Turn on/off button lights for multiple buttons
  1379.     if (button == 0xFF) return;
  1380.     
  1381.     var buttonLight;
  1382.     var byte1 = 0x90 + channel;
  1383.     var color=0x00; // Off
  1384.     if (light) color=0x01;  // On
  1385.     
  1386.     // Turn on/off button LED
  1387.     if (StantonSCS3d.markHotCues == "red") buttonLight = StantonSCS3d.buttonLEDs[button];
  1388.     else buttonLight = button;
  1389.     midi.sendShortMsg(byte1,buttonLight,color);
  1390.     
  1391.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1392.     var index = currentMode.charAt(currentMode.length-1);
  1393.     if (index != "2" && index != "3") index = "1";
  1394. }
  1395.  
  1396. StantonSCS3d.C1relative = function (channel, control, value, status) {
  1397.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1398.     switch (currentMode) {
  1399.         case "vinyl":
  1400.             var newValue=(value-64);
  1401.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","jog",newValue);
  1402.             break;
  1403.         case "vinyl2":
  1404.             var newValue=(value-64);
  1405.             engine.scratchTick(StantonSCS3d.deck,newValue);
  1406.             break;
  1407.         case "vinyl3":
  1408.             if ((value-64)>0) {
  1409.                 engine.setValue("[Playlist]","SelectNextTrack",1);
  1410.             }
  1411.             else {
  1412.                 engine.setValue("[Playlist]","SelectPrevTrack",1);
  1413.             }
  1414.             break;
  1415.     }
  1416. }
  1417.  
  1418. StantonSCS3d.C1absolute = function (channel, control, value, status) {
  1419.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1420.     switch (currentMode) {
  1421.         case "vinyl":
  1422.         case "vinyl2":  // leave lights alone...circleLEDs handles them for vinyl modes
  1423.             break;
  1424.         default:
  1425.             // Light the LEDs
  1426.             var byte1 = 0xB0 + channel;
  1427.             var light = Math.floor(value/8)+1;
  1428.             midi.sendShortMsg(byte1,0x62,light);
  1429.             break;
  1430.     }
  1431. }
  1432.  
  1433. // ----------   Surface buttons  ----------
  1434.  
  1435. StantonSCS3d.SurfaceButton = function (channel, control, value, status) {
  1436.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1437.     var byte1 = 0x90 + channel;
  1438.     
  1439.     var index = currentMode.charAt(currentMode.length-1);
  1440.     if (index != "2" && index != "3") index = "1";
  1441.  
  1442.     //var marker;
  1443.     //if (StantonSCS3d.markHotCues == "red") marker = control;
  1444.     //else marker = StantonSCS3d.buttonLEDs[control];
  1445.     
  1446.     var buttonLight;
  1447.     if (StantonSCS3d.markHotCues == "red") buttonLight = StantonSCS3d.buttonLEDs[control];
  1448.     else buttonLight = control;
  1449.  
  1450.     if ((status & 0xF0) != 0x80) {    // If button down
  1451.         switch (currentMode) {
  1452.             case "loop2":
  1453.             case "loop3":
  1454.                 midi.sendShortMsg(byte1,buttonLight,0x01); // Turn on button light
  1455.                 // Multiple pitch points
  1456. //                 if (StantonSCS3d.modifier[currentMode]==1) {    // Delete a pitch point if the mode button is held
  1457. //                     StantonSCS3d.pitchPoints[index][button] = -0.1;
  1458. //                     break;
  1459. //                 }
  1460.                 if (StantonSCS3d.pitchPoints[index][control] == -0.1)
  1461.                     StantonSCS3d.pitchPoints[index][control] = engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate");
  1462.                 else {
  1463.                     // Need 100% range for values to be correct
  1464.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","rateRange",1.0);
  1465.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","rate",StantonSCS3d.pitchPoints[index][control]); 
  1466.                 }
  1467.                 break;
  1468.             case "trig":
  1469.             case "trig2":
  1470.             case "trig3":
  1471.                 // Multiple cue points
  1472.                 
  1473.                 // We support 36 hot cues but Mixxx only has 31 right now                
  1474.                 if (StantonSCS3d.hotCues[index][control] == -1) return;
  1475.                 
  1476.                 if (StantonSCS3d.modifier[currentMode]==1) { // Delete a cue point
  1477.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][control]+"_clear",1);
  1478.                     engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][control]+"_clear",0);
  1479.                     break;
  1480.                 }
  1481.                 // If hotcue X is set, seeks the player to hotcue X's position.
  1482.                 // If hotcue X is not set, sets hotcue X to the current play position.
  1483.                 engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][control]+"_activate",1);
  1484.                 break;
  1485.         }
  1486.         return;
  1487.     }
  1488.  
  1489.     switch (currentMode) {
  1490.         case "trig":
  1491.         case "trig2":
  1492.         case "trig3":
  1493.             engine.setValue("[Channel"+StantonSCS3d.deck+"]","hotcue_"+StantonSCS3d.hotCues[index][control]+"_activate",0);
  1494.             break;
  1495.         default:
  1496.             midi.sendShortMsg(byte1,buttonLight,0x00); // Turn off activated button LED
  1497.             break;
  1498.     }
  1499. }
  1500.  
  1501.  
  1502. // ----------   LED slot functions  ----------
  1503.  
  1504. StantonSCS3d.buttonLED = function (value, note, on, off) {
  1505.     var byte1 = 0x90 + StantonSCS3d.channel;
  1506.     if (value>0) midi.sendShortMsg(byte1,note,on);
  1507.     else midi.sendShortMsg(byte1,note,off);
  1508. }
  1509.  
  1510. // ---- Transport buttons ----
  1511.  
  1512. StantonSCS3d.playLED = function (value) {
  1513.     StantonSCS3d.buttonLED(value, 0x6D, 0x01, 0x00);
  1514. }
  1515.  
  1516. StantonSCS3d.cueLED = function (value) {
  1517.     StantonSCS3d.buttonLED(value, 0x6E, 0x01, 0x00);
  1518. }
  1519.  
  1520. StantonSCS3d.syncLED = function (value) {
  1521.     StantonSCS3d.buttonLED(value, 0x6F, 0x01, 0x00);
  1522. }
  1523.  
  1524. // ---- Soft buttons ----
  1525.  
  1526. StantonSCS3d.B11LED = function (value) {
  1527.     StantonSCS3d.buttonLED(value, 0x2C, 0x01, 0x02);
  1528. }
  1529.  
  1530. StantonSCS3d.B12LED = function (value) {
  1531.     StantonSCS3d.buttonLED(value, 0x2E, 0x01, 0x02);
  1532. }
  1533.  
  1534. StantonSCS3d.B13LED = function (value) {
  1535.     StantonSCS3d.buttonLED(value, 0x30, 0x01, 0x02);
  1536. }
  1537.  
  1538. StantonSCS3d.B14LED = function (value) {
  1539.     StantonSCS3d.buttonLED(value, 0x32, 0x01, 0x02);
  1540. }
  1541.  
  1542. // ---- Hot cues ----
  1543.  
  1544. StantonSCS3d.BsLED = function (value, button, activate) {
  1545.     var light = button;
  1546.     
  1547.     if (activate) {
  1548.         // Button-pressed (hot cue activated) LED
  1549.         if (StantonSCS3d.markHotCues == "red") light = StantonSCS3d.buttonLEDs[button];
  1550.     }
  1551.     else {
  1552.         // Hot cue set LED
  1553.         if (StantonSCS3d.markHotCues != "red") light = StantonSCS3d.buttonLEDs[button];
  1554.     }
  1555.  
  1556.     var byte1 = 0x90 + StantonSCS3d.channel;    
  1557.     if (value != 0) midi.sendShortMsg(byte1,light,0x01);
  1558.     else midi.sendShortMsg(byte1,light,0x00);
  1559. }
  1560.  
  1561. // Hotcue-set LEDs
  1562. StantonSCS3d.BsALED = function (value) { StantonSCS3d.BsLED(value,0x48,false); }
  1563. StantonSCS3d.BsBLED = function (value) { StantonSCS3d.BsLED(value,0x4A,false); }
  1564. StantonSCS3d.BsCLED = function (value) { StantonSCS3d.BsLED(value,0x4C,false); }
  1565. StantonSCS3d.BsDLED = function (value) { StantonSCS3d.BsLED(value,0x4E,false); }
  1566. StantonSCS3d.BsELED = function (value) { StantonSCS3d.BsLED(value,0x4F,false); }
  1567. StantonSCS3d.BsFLED = function (value) { StantonSCS3d.BsLED(value,0x51,false); }
  1568. StantonSCS3d.BsGLED = function (value) { StantonSCS3d.BsLED(value,0x53,false); }
  1569. StantonSCS3d.BsHLED = function (value) { StantonSCS3d.BsLED(value,0x55,false); }
  1570. StantonSCS3d.BsILED = function (value) { StantonSCS3d.BsLED(value,0x56,false); }
  1571. StantonSCS3d.BsJLED = function (value) { StantonSCS3d.BsLED(value,0x58,false); }
  1572. StantonSCS3d.BsKLED = function (value) { StantonSCS3d.BsLED(value,0x5A,false); }
  1573. StantonSCS3d.BsLLED = function (value) { StantonSCS3d.BsLED(value,0x5C,false); }
  1574.  
  1575. // Button-activated LEDs
  1576. StantonSCS3d.BsAaLED = function (value) { StantonSCS3d.BsLED(value,0x48,true); }
  1577. StantonSCS3d.BsBaLED = function (value) { StantonSCS3d.BsLED(value,0x4A,true); }
  1578. StantonSCS3d.BsCaLED = function (value) { StantonSCS3d.BsLED(value,0x4C,true); }
  1579. StantonSCS3d.BsDaLED = function (value) { StantonSCS3d.BsLED(value,0x4E,true); }
  1580. StantonSCS3d.BsEaLED = function (value) { StantonSCS3d.BsLED(value,0x4F,true); }
  1581. StantonSCS3d.BsFaLED = function (value) { StantonSCS3d.BsLED(value,0x51,true); }
  1582. StantonSCS3d.BsGaLED = function (value) { StantonSCS3d.BsLED(value,0x53,true); }
  1583. StantonSCS3d.BsHaLED = function (value) { StantonSCS3d.BsLED(value,0x55,true); }
  1584. StantonSCS3d.BsIaLED = function (value) { StantonSCS3d.BsLED(value,0x56,true); }
  1585. StantonSCS3d.BsJaLED = function (value) { StantonSCS3d.BsLED(value,0x58,true); }
  1586. StantonSCS3d.BsKaLED = function (value) { StantonSCS3d.BsLED(value,0x5A,true); }
  1587. StantonSCS3d.BsLaLED = function (value) { StantonSCS3d.BsLED(value,0x5C,true); }
  1588.  
  1589. // ---- Other slots ----
  1590.  
  1591. StantonSCS3d.LoopInLEDs = function (value) {
  1592.     if (value>0) StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S3",true,true);
  1593.     else StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S3",false,true);    
  1594. }
  1595.  
  1596. StantonSCS3d.LoopOutLEDs = function (value) {
  1597.     if (value>0) StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S5",true,true);
  1598.     else StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S5",false,true);
  1599. }
  1600.  
  1601. StantonSCS3d.ReloopLEDs = function (value) {
  1602.     if (value>0) StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S4",true,true);
  1603.     else StantonSCS3d.sliderButtonLight(StantonSCS3d.channel,"S4",false,true);
  1604. }
  1605.  
  1606. StantonSCS3d.BoostCut = function (numberLights, value, low, mid, high, lowMidSteps, midHighSteps) {
  1607.     var LEDs = 0;
  1608.     var lowMidInterval = (mid-low)/(lowMidSteps*2);     // Half the actual interval so the LEDs light in the middle of the interval
  1609.     var midHighInterval = (high-mid)/(midHighSteps*2);  // Half the actual interval so the LEDs light in the middle of the interval
  1610.     value=value.toFixed(4);
  1611.     if (value>low) LEDs++;
  1612.     if (value>low+lowMidInterval) LEDs++;
  1613.     if (value>low+lowMidInterval*3) LEDs++;
  1614.     if (numberLights==9 && value>low+lowMidInterval*5) LEDs++;
  1615.     if (value>mid+midHighInterval) LEDs++;
  1616.     if (value>mid+midHighInterval*3) LEDs++;
  1617.     if (numberLights==9 && value>mid+midHighInterval*5) LEDs++;
  1618.     if (value>=high) LEDs++;
  1619.     return LEDs;
  1620. }
  1621.  
  1622. StantonSCS3d.Peak7 = function (value, low, high) {
  1623.     var LEDs = 0;
  1624.     var halfInterval = ((high-low)/6)/2;
  1625.     value=value.toFixed(4);
  1626.     if (value>low) LEDs++;
  1627.     if (value>low+halfInterval) LEDs++;
  1628.     if (value>low+halfInterval*3) LEDs++;
  1629.     if (value>low+halfInterval*5) LEDs++;
  1630.     if (value>low+halfInterval*7) LEDs++;
  1631.     if (value>low+halfInterval*9) LEDs++;
  1632.     if (value>=high) LEDs++;
  1633.     return LEDs;
  1634. }
  1635.  
  1636. StantonSCS3d.headMixLEDs = function (value) {
  1637.     var add = StantonSCS3d.BoostCut(7, value, -1.0, 0.0, 1.0, 3, 3);
  1638.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1639.     midi.sendShortMsg(byte1,0x0C,0x15+add);
  1640. }
  1641.  
  1642. StantonSCS3d.headVolLEDs = function (value) {
  1643.     var add = StantonSCS3d.BoostCut(7, value, 0, 1, 5, 3, 3);
  1644.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1645.     midi.sendShortMsg(byte1,0x0E,0x15+add);
  1646. }
  1647.  
  1648. StantonSCS3d.crossFaderLEDs = function (value) {
  1649.     var add = StantonSCS3d.BoostCut(7, value, -1.0, 0.0, 1.0, 3, 3);
  1650.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1651.     midi.sendShortMsg(byte1,0x01,0x15+add);
  1652. }
  1653.  
  1654. StantonSCS3d.EQLowLEDs = function (value) {
  1655.     var add = StantonSCS3d.BoostCut(7,value, 0, 1, 4, 3, 3);
  1656.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1657.     midi.sendShortMsg(byte1,0x0C,0x15+add);
  1658. }
  1659.  
  1660. StantonSCS3d.EQMidLEDs = function (value) {
  1661.     var add = StantonSCS3d.BoostCut(7,value, 0, 1, 4, 3, 3);
  1662.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1663.     midi.sendShortMsg(byte1,0x01,0x15+add);
  1664. }
  1665.  
  1666. StantonSCS3d.EQHighLEDs = function (value) {
  1667.     var add = StantonSCS3d.BoostCut(7,value, 0, 1, 4, 3, 3);
  1668.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1669.     midi.sendShortMsg(byte1,0x0E,0x15+add);
  1670. }
  1671.  
  1672. StantonSCS3d.FXDepthLEDs = function (value) {
  1673.     var add = StantonSCS3d.Peak7(value,0,1);
  1674.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1675.     midi.sendShortMsg(byte1,0x0C,0x28+add);
  1676. }
  1677.  
  1678. StantonSCS3d.FXDelayLEDs = function (value) {
  1679.     var add = StantonSCS3d.Peak7(value,50,10000);
  1680.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1681.     midi.sendShortMsg(byte1,0x01,0x28+add);
  1682. }
  1683.  
  1684. StantonSCS3d.FXPeriodLEDs = function (value) {
  1685.     var add = StantonSCS3d.Peak7(value,50000,2000000);
  1686.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1687.     midi.sendShortMsg(byte1,0x0E,0x28+add);
  1688. }
  1689.  
  1690. StantonSCS3d.VUMeterLEDs = function (value) {
  1691.     if (!StantonSCS3d.VUMeters) return;
  1692.     // If in DECK mode, ignore this.
  1693.     if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="deck") return;
  1694.     
  1695.     var add = StantonSCS3d.Peak7(value,0,1);
  1696.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1697.     if (StantonSCS3d.deck==2) midi.sendShortMsg(byte1,0x0E,0x28+add);
  1698.     else midi.sendShortMsg(byte1,0x0C,0x28+add);
  1699. }
  1700.  
  1701. StantonSCS3d.pitchLEDs = function (value) {
  1702.     var LEDs = 0;
  1703.     if (value>=-1) LEDs++;
  1704.     if (value>-0.78) LEDs++;
  1705.     if (value>-0.56) LEDs++;
  1706.     if (value>-0.33) LEDs++;
  1707.     if (value>-0.11) LEDs++;
  1708.     if (value>0.11) LEDs++;
  1709.     if (value>0.33) LEDs++;
  1710.     if (value>0.56) LEDs++;
  1711.     if (value>0.78) LEDs++;
  1712.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1713.     midi.sendShortMsg(byte1,0x03,0x14+LEDs);
  1714. }
  1715.  
  1716. StantonSCS3d.gainLEDs = function (value) {
  1717.     // Skip if displaying something else
  1718.     var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
  1719.     if ((currentMode=="deck" && !StantonSCS3d.state["forceGain"]) || StantonSCS3d.modifier[currentMode]==1) return;
  1720.     
  1721.     var LEDs = 0;
  1722.     if (value>0.01) LEDs++;
  1723.     if (value>0.13) LEDs++;
  1724.     if (value>0.26) LEDs++;
  1725.     if (value>0.38) LEDs++;
  1726.     if (value>0.50) LEDs++;
  1727.     if (value>0.63) LEDs++;
  1728.     if (value>0.75) LEDs++;
  1729.     if (value>0.88) LEDs++;
  1730.     if (value>=1) LEDs++;
  1731.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1732.     midi.sendShortMsg(byte1,0x07,0x28+LEDs);
  1733. }
  1734.  
  1735. StantonSCS3d.MasterVolumeLEDs = function (value) {
  1736.     var LEDs = 0;
  1737.     var mid = 1.0;
  1738.     var lowMidInterval = 1/8;   // Half the actual interval so the LEDs light in the middle of the interval
  1739.     var midHighInterval = 4/8;  // Half the actual interval so the LEDs light in the middle of the interval
  1740.     if (value>0.0) LEDs++;
  1741.     if (value>lowMidInterval) LEDs++;
  1742.     if (value>lowMidInterval*3) LEDs++;
  1743.     if (value>lowMidInterval*5) LEDs++;
  1744.     if (value>lowMidInterval*7) LEDs++;
  1745.     if (value>mid+midHighInterval) LEDs++;
  1746.     if (value>mid+midHighInterval*3) LEDs++;
  1747.     if (value>mid+midHighInterval*5) LEDs++;
  1748.     if (value>mid+midHighInterval*7) LEDs++;
  1749.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1750.     midi.sendShortMsg(byte1,0x07,0x28+LEDs);
  1751. }
  1752.  
  1753. StantonSCS3d.pitchSliderLED = function (value) {
  1754.     var byte1 = 0x90 + StantonSCS3d.channel;
  1755.     switch (true) {
  1756.         case (value<=StantonSCS3d.pitchRanges[0]):
  1757.                 midi.sendShortMsg(byte1,0x3D,0x00);  // Pitch LED black
  1758.                 midi.sendShortMsg(byte1,0x3E,0x00);
  1759.             break;
  1760.         case (value<=StantonSCS3d.pitchRanges[1]):
  1761.                 midi.sendShortMsg(byte1,0x3D,0x00);  // Pitch LED blue
  1762.                 midi.sendShortMsg(byte1,0x3E,0x01);
  1763.             break;
  1764.         case (value<=StantonSCS3d.pitchRanges[2]):
  1765.                 midi.sendShortMsg(byte1,0x3D,0x01);  // Pitch LED purple
  1766.                 midi.sendShortMsg(byte1,0x3E,0x01);
  1767.             break;
  1768.         case (value>=StantonSCS3d.pitchRanges[3]):
  1769.                 midi.sendShortMsg(byte1,0x3D,0x01);  // Pitch LED red
  1770.                 midi.sendShortMsg(byte1,0x3E,0x00);
  1771.             break;
  1772.     }
  1773. }
  1774.  
  1775. StantonSCS3d.circleLEDs1 = function (value) {
  1776.     if (StantonSCS3d.deck!=1) return;
  1777.     StantonSCS3d.circleLEDs(value);
  1778. }
  1779.  
  1780. StantonSCS3d.circleLEDs2 = function (value) {
  1781.     if (StantonSCS3d.deck!=2) return;
  1782.     StantonSCS3d.circleLEDs(value);
  1783. }
  1784.  
  1785. StantonSCS3d.durationChange1 = function (value) {
  1786.     StantonSCS3d.trackDuration[1]=value;
  1787. }
  1788.  
  1789. StantonSCS3d.durationChange2 = function (value) {
  1790.     StantonSCS3d.trackDuration[2]=value;
  1791. }
  1792.  
  1793. StantonSCS3d.circleFlash = function (deck) {
  1794.     if (StantonSCS3d.deck != deck) return;  // Only do this for the current deck
  1795.     if (!StantonSCS3d.state["circleInvert"]) StantonSCS3d.state["circleInvert"]=true;
  1796.     else StantonSCS3d.state["circleInvert"]=false;
  1797.     // Force the circle LEDs to light
  1798.     StantonSCS3d.lastLight[deck]=-1;
  1799.     StantonSCS3d.circleLEDs(engine.getValue("[Channel"+deck+"]","visual_playposition"));
  1800. }
  1801.  
  1802. StantonSCS3d.circleLEDs = function (value) {
  1803.     
  1804.     var deck = StantonSCS3d.deck;
  1805.  
  1806.     var currentMode = StantonSCS3d.mode_store["[Channel"+deck+"]"];
  1807.     if (StantonSCS3d.spinningPlatterOnlyVinyl) {    // Skip if not in vinyl mode
  1808.         if (currentMode != "vinyl" && currentMode != "vinyl2") return;
  1809.     } else {
  1810.         // Skip if in LOOP2-3, TRIG, or VINYL3 modes since they use the circle LEDs
  1811.         //  for other things
  1812.         if (currentMode == "vinyl3" || (currentMode != "loop" && currentMode.substring(0,4) == "loop") ||
  1813.         currentMode.substring(0,4) == "trig") return;
  1814.     }
  1815.     
  1816.     // Flash the circle near the end of the track if the track is longer than 30s
  1817.     if (StantonSCS3d.trackDuration[deck]>30) {
  1818.         var trackTimeRemaining = ((1-value) * StantonSCS3d.trackDuration[deck]) | 0;
  1819.         if (trackTimeRemaining<=30 && trackTimeRemaining>15) {   // If <30s left, flash slowly
  1820.             if (StantonSCS3d.timer["30s-d"+deck] == -1) {
  1821.                 // Start timer
  1822.                 StantonSCS3d.timer["30s-d"+deck] = engine.beginTimer(500,"StantonSCS3d.circleFlash("+deck+")");
  1823.                 if (StantonSCS3d.timer["15s-d"+deck] != -1) {
  1824.                     // Stop the 15s timer if it was running
  1825.                     engine.stopTimer(StantonSCS3d.timer["15s-d"+deck]);
  1826.                     StantonSCS3d.timer["15s-d"+deck] = -1;
  1827.                 }
  1828.             }
  1829.         } else if (trackTimeRemaining<=15 && trackTimeRemaining>0) { // If <15s left, flash quickly
  1830.             if (StantonSCS3d.timer["15s-d"+deck] == -1) {
  1831.                 // Start timer
  1832.                 StantonSCS3d.timer["15s-d"+deck] = engine.beginTimer(125,"StantonSCS3d.circleFlash("+deck+")");
  1833.                 if (StantonSCS3d.timer["30s-d"+deck] != -1) {
  1834.                     // Stop the 30s timer if it was running
  1835.                     engine.stopTimer(StantonSCS3d.timer["30s-d"+deck]);
  1836.                     StantonSCS3d.timer["30s-d"+deck] = -1;
  1837.                 }
  1838.             }
  1839.         } else {    // Stop flashing
  1840.             if (StantonSCS3d.timer["15s-d"+deck] != -1) {
  1841.                 engine.stopTimer(StantonSCS3d.timer["15s-d"+deck]);
  1842.                 StantonSCS3d.timer["15s-d"+deck] = -1;
  1843.             }
  1844.             if (StantonSCS3d.timer["30s-d"+deck] != -1) {
  1845.                 engine.stopTimer(StantonSCS3d.timer["30s-d"+deck]);
  1846.                 StantonSCS3d.timer["30s-d"+deck] = -1;
  1847.             }
  1848.             StantonSCS3d.state["circleInvert"]=false;
  1849.         }
  1850.     } else StantonSCS3d.state["circleInvert"]=false;
  1851.     
  1852.     // Revolution time of the imaginary record in seconds
  1853.     var revtime = StantonSCS3d.revtime;
  1854.     
  1855.     if (StantonSCS3d.spinningLights==2) revtime = revtime/2;    // Use this for two lights
  1856.     var currentTrackPos = value * StantonSCS3d.trackDuration[deck];
  1857.     
  1858.     var revolutions = currentTrackPos/revtime;
  1859.     
  1860.     var light = ((revolutions-(revolutions|0))*16)|0;   // OR with 0 replaces Math.floor and is faster
  1861.     if (StantonSCS3d.spinningLights==2) light = ((revolutions-(revolutions|0))*8)|0;    // Use this for two lights
  1862.  
  1863.     // Don't send light commands if there's no visible change
  1864.     if (StantonSCS3d.lastLight[deck]==light) return;
  1865.     
  1866.     // Clear circle lights
  1867.     var byte1 = 0xB0 + StantonSCS3d.channel;
  1868.     var byte2 = 0x62;   // normal
  1869.     if (StantonSCS3d.state["circleInvert"]) byte2 = 0x72;   // inverted
  1870.     midi.sendShortMsg(byte1,byte2,0x00);
  1871.     
  1872.     var byte1 = 0x90 + StantonSCS3d.channel;
  1873.     var byte3 = 0x01;
  1874.     StantonSCS3d.lastLight[deck]=light;
  1875.     if (StantonSCS3d.state["circleInvert"]) byte3 = 0x00;
  1876.     midi.sendShortMsg(byte1,0x5d+light,byte3);
  1877.     if (StantonSCS3d.spinningLights==2) midi.sendShortMsg(byte1,0x65+light,byte3);   // Add this for two lights
  1878. }