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-SCS1m-scripts.js < prev    next >
Text File  |  2010-12-02  |  28KB  |  643 lines

  1. /****************************************************************/
  2. /*      Stanton SCS.1m MIDI controller script v1.1              */
  3. /*          Copyright (C) 2009, 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 StantonSCS1m() {}
  9.  
  10. // ----------   Customization variables ----------
  11. //      See http://mixxx.org/wiki/doku.php/stanton_SCS.1m_mixxx_user_guide  for details
  12.  
  13. // The below values vary with latency and are preset for 10ms. For 2ms, use 0.8, 0.8 and 1.5.
  14.  
  15. StantonSCS1m.scratchKnob = {    "slippage":0.2,             // Slipperiness of the virtual slipmat when scratching with the select knob (higher=slower response, 0<n<1)
  16.                                 "sensitivity":0.5,          // How much the audio moves for a given knob arc (higher=faster response, 0<n<1)
  17.                                 "stoppedMultiplier":2.2 };  // Correction for when the deck is stopped (set higher for higher latencies)
  18.  
  19. // ----------   Other global variables    ----------
  20. StantonSCS1m.debug = false; // Enable/disable debugging messages to the console
  21. StantonSCS1m.faderStart = true; // Allows decks to start when their channel or cross fader is opened (toggleable with the top button)
  22. StantonSCS1m.id = "";   // The ID for the particular device being controlled for use in debugging, set at init time
  23. StantonSCS1m.channel = 0;   // MIDI channel the device is on
  24. StantonSCS1m.swVersion = "1.9";   // Mixxx version for display
  25. StantonSCS1m.sysex = [0xF0, 0x00, 0x01, 0x02];  // Preamble for all SysEx messages for this device
  26. StantonSCS1m.modifier = { };    // Modifier buttons (allowing alternate controls) defined on-the-fly if needed
  27. StantonSCS1m.selectKnobMode = "browse"; // Current mode for the gray select knob
  28. StantonSCS1m.inSetup = false; // Flag for if the device is in setup mode
  29. StantonSCS1m.revtime = 1.8;   // Time in seconds for the virtual record to spin once. Used for calculating the position LEDs (1.8 for 33 1/3 RPM)
  30. StantonSCS1m.trackDuration = [0,0]; // Duration of the song on each deck (used for vinyl LEDs)
  31. StantonSCS1m.lastLight = [-1,-1];   // Last circle LED values
  32. StantonSCS1m.lastTime = ["-99:99","-99:99"];    // Last time remaining values
  33. StantonSCS1m.lastColor = [0,0]; // Last color of display flash
  34. StantonSCS1m.displayFlash = [-1,-1];  // Temp storage for display flash timeouts
  35. StantonSCS1m.lastCrossFader = 0;  // Last value of the cross fader
  36. StantonSCS1m.lastFader = [0,0];   // Last value of each channel fader
  37. StantonSCS1m.scratchDeck = 1;   // Current deck being scratched with the select knob
  38. StantonSCS1m.hotCueDeck = 1;    // Current hot cue page
  39. StantonSCS1m.cuePoints =  {     1:{ 35:-0.1, 36:-0.1, 37:-0.1, 38:-0.1 },
  40.                                 2:{ 35:-0.1, 36:-0.1, 37:-0.1, 38:-0.1 }    };
  41.  
  42. // ----------   Functions   ----------
  43.  
  44. StantonSCS1m.init = function (id) {    // called when the MIDI device is opened & set up
  45.     
  46.     StantonSCS1m.id = id;   // Store the ID of this device for later use
  47.     
  48.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 17, 0xF7]),7); // Extinguish all LEDs
  49.  
  50. //    var CC = 0xB0 + StantonSCS1m.channel;
  51.     var No = 0x90 + StantonSCS1m.channel;
  52.  
  53.     // Welcome message
  54.     var message = "Welcome";
  55.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 1],message.toInt(), 0xF7),7+message.length);   // Set LCD1
  56.     midi.sendShortMsg(No,49,127);   // to orange
  57.     message = "to";
  58.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 2],message.toInt(), 0xF7),7+message.length);   // Set LCD2
  59.     midi.sendShortMsg(No,49+1,127); // to orange
  60.     message = "Mixxx  v";
  61.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 3],message.toInt(), 0xF7),7+message.length);   // Set LCD3
  62.     midi.sendShortMsg(No,49+2,127); // to orange
  63.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 4],StantonSCS1m.swVersion.toInt(), 0xF7),7+StantonSCS1m.swVersion.length);   // Set LCD4
  64.     midi.sendShortMsg(No,49+3,32);  // to red
  65.     
  66. //    midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 16, 0xF7]),7); // Light all LEDs
  67.  
  68. //    for (i=0x48; i<=0x5c; i++) midi.sendShortMsg(No,i,0x40); // Set surface LEDs to black default
  69.  
  70.     // Connect signals
  71.         // Vu Meters
  72.     engine.connectControl("[Master]","VuMeterL","StantonSCS1m.MasterLVu");
  73.     engine.connectControl("[Master]","VuMeterR","StantonSCS1m.MasterRVu");
  74.     engine.connectControl("[Channel1]","VuMeter","StantonSCS1m.Channel1Vu");
  75.     engine.connectControl("[Channel2]","VuMeter","StantonSCS1m.Channel2Vu");
  76.     
  77.         // Pitch displays
  78.     engine.connectControl("[Channel1]","rate","StantonSCS1m.pitchDisplay1");
  79.     engine.connectControl("[Channel2]","rate","StantonSCS1m.pitchDisplay2");
  80.     
  81.         // Pitch display colors
  82.     engine.connectControl("[Channel1]","rateRange","StantonSCS1m.pitchColor1");
  83.     engine.connectControl("[Channel2]","rateRange","StantonSCS1m.pitchColor2");
  84.     
  85.         // Virtual platter LEDs & time displays
  86.     engine.connectControl("[Channel1]","visual_playposition","StantonSCS1m.positionUpdates1");
  87.     engine.connectControl("[Channel2]","visual_playposition","StantonSCS1m.positionUpdates2");
  88.     engine.connectControl("[Channel1]","duration","StantonSCS1m.durationChange1");
  89.     engine.connectControl("[Channel2]","duration","StantonSCS1m.durationChange2");
  90.     
  91.         // Faders
  92.     engine.connectControl("[Master]","crossfader","StantonSCS1m.crossFaderStart");
  93.     engine.connectControl("[Channel1]","volume","StantonSCS1m.ch1FaderStart");
  94.     engine.connectControl("[Channel2]","volume","StantonSCS1m.ch2FaderStart");
  95.     
  96.     //  Initialize the vinyl LEDs if the mapping is loaded after a song is
  97.     StantonSCS1m.durationChange1(engine.getValue("[Channel1]","duration"));
  98.     StantonSCS1m.durationChange2(engine.getValue("[Channel2]","duration"));
  99.     
  100.     // Set LCD text
  101.     StantonSCS1m.initLCDs();
  102.  
  103.     StantonSCS1m.browseButton(StantonSCS1m.channel, 0x20, 0x7F, 0x90+StantonSCS1m.channel); // Force into browse mode
  104.  
  105.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 34, 32, 0xF7]),8); // Get position of all pots
  106.     
  107.     // Button LEDs
  108.     if (StantonSCS1m.faderStart) midi.sendShortMsg(No,8,1);
  109.     
  110.     var LEDInit = [ ["Channels","rate_temp_up"],
  111.                     ["Channels","rate_temp_down"],
  112.                     ["Channels","pfl"],
  113.                     ["Channels","beatsync"],
  114.                     ["Channels","play"],
  115.                     ["Channels","cue_default"]     ];
  116.     
  117.     for (i=0; i<LEDInit.length; i++) {
  118.         var group = LEDInit[i][0];
  119.         var name = LEDInit[i][1];
  120.         if (group=="Channels") {
  121.             engine.trigger("[Channel1]",name);
  122.             engine.trigger("[Channel2]",name);
  123.             }
  124.         else engine.trigger(group,name);
  125.     }
  126.  
  127.     print ("StantonSCS1m: \""+StantonSCS1m.id+"\" on MIDI channel "+(StantonSCS1m.channel+1)+" initialized.");
  128. }
  129.  
  130. StantonSCS1m.shutdown = function () {   // called when the MIDI device is closed
  131.  
  132.     // Graffiti :)
  133.     var message = "Mixxx";
  134.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 1],message.toInt(), 0xF7),7+message.length);   // Set LCD1
  135.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 2],StantonSCS1m.swVersion.toInt(), 0xF7),7+StantonSCS1m.swVersion.length);   // Set LCD2
  136.     message = "was here";
  137.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 3],message.toInt(), 0xF7),7+message.length);   // Set LCD3
  138.     message = "";
  139.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 4],message.toInt(), 0xF7),7+message.length);   // Set LCD4
  140.     
  141.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 17, 0xF7]),7); // Extinguish all LEDs
  142.     print ("StantonSCS1m: \""+StantonSCS1m.id+"\" on MIDI channel "+(StantonSCS1m.channel+1)+" shut down.");
  143. }
  144.  
  145. StantonSCS1m.initLCDs = function () {
  146.     var No = 0x90 + StantonSCS1m.channel;
  147.     var message = "Pitch 1";
  148.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 1],message.toInt(), 0xF7),7+message.length);   // Set LCD1
  149.     StantonSCS1m.pitchColor1(engine.getValue("[Channel1]","rateRange"));
  150.     message = " Pitch 2";
  151.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 4],message.toInt(), 0xF7),7+message.length);   // Set LCD4
  152.     StantonSCS1m.pitchColor2(engine.getValue("[Channel2]","rateRange"));
  153.     message = " Deck 1";
  154.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 2],message.toInt(), 0xF7),7+message.length);   // Set LCD2
  155.     midi.sendShortMsg(No,49+1,32);   // to red
  156.     message = " Deck 2";
  157.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, 3],message.toInt(), 0xF7),7+message.length);   // Set LCD3
  158.     midi.sendShortMsg(No,49+2,32);   // to red
  159. }
  160.  
  161. StantonSCS1m.checkInSetup = function () {
  162.   if (StantonSCS1m.inSetup) print ("StantonSCS1m: In setup mode, ignoring command.");
  163.   return StantonSCS1m.inSetup;
  164. }
  165.  
  166. StantonSCS1m.playButton1 = function (channel, control, value, status) {
  167.     StantonSCS1m.playButton(channel, control, value, status, 1);
  168. }
  169.  
  170. StantonSCS1m.playButton2 = function (channel, control, value, status) {
  171.     StantonSCS1m.playButton(channel, control, value, status, 2);
  172. }
  173.  
  174. StantonSCS1m.playButton = function (channel, control, value, status, deck) {
  175.     if (StantonSCS1m.debug) print("Play button"+deck);
  176.     var byte1 = 0x90 + channel;
  177.     if ((status & 0xF0) == 0x90) {    // If button down
  178.         StantonSCS1m.modifier["play"+deck]=1;
  179.         if (StantonSCS1m.modifier["cue"+deck]==1) engine.setValue("[Channel"+deck+"]","play",1);
  180.         else {
  181.             var currentlyPlaying = engine.getValue("[Channel"+deck+"]","play");
  182.             if (currentlyPlaying && engine.getValue("[Channel"+deck+"]","cue_default")==1) engine.setValue("[Channel"+deck+"]","cue_default",0);
  183.             engine.setValue("[Channel"+deck+"]","play", !currentlyPlaying);
  184.         }
  185.         return;
  186.     }
  187.     StantonSCS1m.modifier["play"+deck]=0;
  188. }
  189.  
  190. StantonSCS1m.cueButton1 = function (channel, control, value, status) {
  191.     StantonSCS1m.cueButton(channel, control, value, status, 1);
  192. }
  193.  
  194. StantonSCS1m.cueButton2 = function (channel, control, value, status) {
  195.     StantonSCS1m.cueButton(channel, control, value, status, 2);
  196. }
  197.  
  198. StantonSCS1m.cueButton = function (channel, control, value, status, deck) {
  199.     if (StantonSCS1m.debug) print("Cue button"+deck);
  200.     var byte1 = 0x90 + channel;
  201.     if ((status & 0xF0) != 0x80) {    // If button down
  202.         engine.setValue("[Channel"+deck+"]","cue_default",1);
  203.         StantonSCS1m.modifier["cue"+deck]=1;   // Set button modifier flag
  204.         return;
  205.     }
  206.     if (StantonSCS1m.modifier["play"+deck]==0) engine.setValue("[Channel"+deck+"]","cue_default",0);
  207.     StantonSCS1m.modifier["cue"+deck]=0;   // Clear button modifier flag
  208. }
  209.  
  210. StantonSCS1m.setupButton = function (channel, control, value, status) {
  211.     if ((status & 0XF0) == 0x90) StantonSCS1m.inSetup = !StantonSCS1m.inSetup;
  212.     else if (StantonSCS1m.inSetup) {  // If entering setup, change the LCD back light colors to green
  213.         var No = 0x90 + channel;
  214.         midi.sendShortMsg(No,49,96);
  215.         midi.sendShortMsg(No,49+3,96);
  216.         midi.sendShortMsg(No,49+1,96);
  217.         midi.sendShortMsg(No,49+2,96);
  218.     }
  219.     else {
  220.         StantonSCS1m.initLCDs(); // If out of setup & the button was released, restore the displays 
  221.         StantonSCS1m.lastTime = ["-99:99","-99:99"];    // Force time displays to update
  222.         engine.trigger("[Channel1]","rate");    // Force pitch displays to update
  223.         engine.trigger("[Channel2]","rate");
  224.     }
  225. }
  226.  
  227. StantonSCS1m.controlButton = function (channel, control, value, status) {
  228.   if (StantonSCS1m.checkInSetup()) return;
  229.     var byte1 = 0x90 + channel;
  230.     if ((status & 0XF0) == 0x90) {    // If button down
  231.         midi.sendShortMsg(byte1,control,64);  // Light 'er up
  232.         StantonSCS1m.selectKnobMode = "control";
  233.         midi.sendShortMsg(0x80+channel,32,0);  // turn off the "browse" mode button
  234.         
  235.         if (StantonSCS1m.scratchDeck==1) {
  236.             midi.sendShortMsg(byte1,24,32); // Light left (cancel) button green
  237.             midi.sendShortMsg(0x80+channel,26,0);   // Exinguish right (enter) button
  238.         }
  239.         else {
  240.             midi.sendShortMsg(byte1,26,32); // Light right (enter) button green
  241.             midi.sendShortMsg(0x80+channel,24,0);   // Exinguish left (cancel) button
  242.         }
  243.         return;
  244.     }
  245. }
  246.  
  247. StantonSCS1m.browseButton = function (channel, control, value, status) {
  248.   if (StantonSCS1m.checkInSetup()) return;
  249.     var byte1 = 0x90 + channel;
  250.     if ((status & 0XF0) == 0x90) {    // If button down
  251.         midi.sendShortMsg(byte1,control,64);  // Light 'er up
  252.         StantonSCS1m.selectKnobMode = "browse";
  253.         midi.sendShortMsg(0x80+channel,30,0);  // turn off the "control" mode button
  254.         
  255.         midi.sendShortMsg(0x80+channel,24,0);   // Exinguish left (cancel) button
  256.         midi.sendShortMsg(0x80+channel,26,0);   // Exinguish right (enter) button
  257.         return;
  258.     }
  259. }
  260.  
  261. StantonSCS1m.selectKnob = function (channel, control, value, status) {
  262.   if (StantonSCS1m.checkInSetup()) return;
  263.   
  264.   jogValue = (value-64); // -64 to +63, - = CCW, + = CW
  265.   
  266.     switch (StantonSCS1m.selectKnobMode) {
  267.         case "control":
  268.             group = "[Channel"+StantonSCS1m.scratchDeck+"]";
  269.             if (engine.getValue(group,"play")==1 && engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
  270.             multiplier = StantonSCS1m.scratchKnob["sensitivity"] * (engine.getValue(group,"play") ? 1 : StantonSCS1m.scratchKnob["stoppedMultiplier"] );
  271. //            if (StantonSCS1m.debug) print("do scratching VALUE:" + value + " jogValue: " + jogValue );
  272.             engine.setValue(group,"scratch", (engine.getValue(group,"scratch") + (jogValue * multiplier)).toFixed(2));
  273.  
  274.             break;
  275.         case "browse":
  276.             engine.setValue("[Playlist]","SelectTrackKnob", jogValue);
  277.             break;
  278.     }
  279. }
  280.  
  281. StantonSCS1m.pressSelectKnob = function () {
  282.   if (StantonSCS1m.checkInSetup()) return;
  283.     switch (StantonSCS1m.selectKnobMode) {
  284.         case "control":
  285.             //engine.setValue("[Channel"+StantonSCS1m.scratchDeck+"]","scratch",0);
  286.             break;
  287.         case "browse":
  288.             engine.setValue("[Playlist]","LoadSelectedIntoFirstStopped",1);
  289.             break;
  290.     }
  291. }
  292.  
  293. StantonSCS1m.cancelButton = function (channel, control, value, status) {
  294.   if (StantonSCS1m.checkInSetup()) return;
  295.     switch (StantonSCS1m.selectKnobMode) {
  296.         case "control":
  297.             if (StantonSCS1m.scratchDeck!=1) {
  298.                 StantonSCS1m.scratchDeck=1; // Scratch deck 1
  299.                 midi.sendShortMsg(0x90+channel,24,32); // Light left (cancel) button green
  300.                 midi.sendShortMsg(0x80+channel,26,0);   // Exinguish right (enter) button
  301.             }
  302.             break;
  303.         case "browse":
  304.             break;
  305.     }
  306. }
  307.  
  308. StantonSCS1m.enterButton = function (channel, control, value, status) {
  309.   if (StantonSCS1m.checkInSetup()) return;
  310.     switch (StantonSCS1m.selectKnobMode) {
  311.         case "control":
  312.             if (StantonSCS1m.scratchDeck!=2) {
  313.                 StantonSCS1m.scratchDeck=2; // Scratch deck 1
  314.                 midi.sendShortMsg(0x90+channel,26,32); // Light right (enter) button green
  315.                 midi.sendShortMsg(0x80+channel,24,0);   // Exinguish left (cancel) button
  316.             }
  317.             break;
  318.         case "browse":
  319.             break;
  320.     }
  321. }
  322.  
  323. StantonSCS1m.encoderJog1 = function (channel, control, value, status) {
  324.     StantonSCS1m.encoderJog(value,1);
  325. }
  326.  
  327. StantonSCS1m.encoderJog2 = function (channel, control, value, status) {
  328.     StantonSCS1m.encoderJog(value,2);
  329. }
  330.  
  331. StantonSCS1m.encoderJog = function (value,deck) {
  332.     if (StantonSCS1m.checkInSetup()) return;
  333.     jogValue=(value-64);
  334.     if (engine.getValue("[Channel"+deck+"]","play")==1 && engine.getValue("[Channel"+deck+"]","reverse")==1) jogValue= -(jogValue);
  335.     engine.setValue("[Channel"+deck+"]","jog",jogValue*4);
  336. }
  337.  
  338. StantonSCS1m.pitchRangeKnob1 = function (channel, control, value, status) {
  339.     StantonSCS1m.pitchRangeKnob(value,1);
  340. }
  341.  
  342. StantonSCS1m.pitchRangeKnob2 = function (channel, control, value, status) {
  343.     StantonSCS1m.pitchRangeKnob(value,2);
  344. }
  345.  
  346. StantonSCS1m.pitchRangeKnob = function (value,deck) {
  347.     if (StantonSCS1m.checkInSetup()) return;
  348.     var currentValue = engine.getValue("[Channel"+deck+"]","rateRange");
  349.     var newValue = Math.round(currentValue*100+(value-64))*0.01;
  350.     if (newValue<=0.01) newValue=0.01;
  351.     if (newValue>1) newValue=1;
  352.     engine.setValue("[Channel"+deck+"]","rateRange",newValue);
  353.     engine.trigger("[Channel"+deck+"]","rate"); // Force GUI to update
  354.     StantonSCS1m.pitchDisplay(engine.getValue("[Channel"+deck+"]","rate"),deck); // Force LCDs to update
  355. }
  356.  
  357. StantonSCS1m.faderStartToggle = function (channel, control, value, status) {
  358.     StantonSCS1m.faderStart = !StantonSCS1m.faderStart;
  359.     var No = 0x90 + channel;
  360.     if (StantonSCS1m.faderStart) midi.sendShortMsg(No,8,1);
  361.     else midi.sendShortMsg(No,8,0);
  362. }
  363.  
  364. StantonSCS1m.hotCueDeckToggle = function (channel, control, value, status) {
  365.     if (StantonSCS1m.checkInSetup()) return;
  366.     if ((status & 0XF0) == 0x90) {    // If button down
  367.         StantonSCS1m.modifier["hotCueToggle"]=1;    // Set modifier flag (to allow cue deletion)
  368.         StantonSCS1m.modifier["hotCueToggleTime"] = new Date();  // Store the current time in milliseconds
  369.     }
  370.     else {    // If button up
  371.         StantonSCS1m.modifier["hotCueToggle"]=0;
  372.         // If the button was held down for over 1/3 of a second, stay on the current cue page
  373.         if (StantonSCS1m.modifier["hotCueToggleTime"] != 0.0 && ((new Date() - StantonSCS1m.modifier["hotCueToggleTime"])>300)) return;
  374.         
  375.         if (StantonSCS1m.hotCueDeck==2) {
  376.             StantonSCS1m.hotCueDeck--;
  377.             midi.sendShortMsg(0x80 + channel,34,0);
  378.             }
  379.         else {
  380.             StantonSCS1m.hotCueDeck++;
  381.             midi.sendShortMsg(0x90 + channel,34,64);
  382.         }
  383.         // Light the Preset buttons if any cues are set
  384.         for (i=35; i<=38; i++) {
  385.             if (StantonSCS1m.cuePoints[StantonSCS1m.hotCueDeck][i] != -0.1) 
  386.                 midi.sendShortMsg(0x90 + channel,i,64);
  387.             else midi.sendShortMsg(0x80 + channel,i,0);
  388.         }
  389.     }
  390. }
  391.  
  392. StantonSCS1m.presetButton = function (channel, control, value, status) {
  393.     if (StantonSCS1m.checkInSetup()) return;
  394.     if ((status & 0xF0) == 0x90) {    // If button down
  395.         midi.sendShortMsg(0x90 + channel,control,1); // Turn on button light
  396.         // Multiple cue points
  397.         if (StantonSCS1m.modifier["hotCueToggle"]==1) {
  398.             StantonSCS1m.cuePoints[StantonSCS1m.hotCueDeck][control] = -0.1;
  399.             midi.sendShortMsg(0x80 + channel,control,0);    // Turn off button light
  400.         }
  401.         else {
  402.             if (StantonSCS1m.cuePoints[StantonSCS1m.hotCueDeck][control] == -0.1)
  403.                 StantonSCS1m.cuePoints[StantonSCS1m.hotCueDeck][control] = engine.getValue("[Channel"+StantonSCS1m.hotCueDeck+"]","visual_playposition");
  404.             else engine.setValue("[Channel"+StantonSCS1m.hotCueDeck+"]","playposition",StantonSCS1m.cuePoints[StantonSCS1m.hotCueDeck][control]);
  405.         }
  406.     }
  407. }
  408.  
  409. // ----------   Slot functions  ----------
  410.  
  411. StantonSCS1m.crossFaderStart = function (value) {
  412.  
  413.   if (!StantonSCS1m.faderStart) return;
  414.   if (StantonSCS1m.lastCrossFader==value) return;
  415.  
  416.   if (value==-1.0 && engine.getValue("[Channel2]","play")==1) {
  417.     engine.setValue("[Channel2]","cue_default",1);
  418.     engine.setValue("[Channel2]","cue_default",0);
  419.     }
  420.   if (value==1.0 && engine.getValue("[Channel1]","play")==1) {
  421.     engine.setValue("[Channel1]","cue_default",1);
  422.     engine.setValue("[Channel1]","cue_default",0);
  423.     }
  424.   if (StantonSCS1m.lastCrossFader==-1.0) engine.setValue("[Channel2]","play",1);
  425.   if (StantonSCS1m.lastCrossFader==1.0) engine.setValue("[Channel1]","play",1);
  426.   
  427.   StantonSCS1m.lastCrossFader=value;
  428. }
  429.  
  430. StantonSCS1m.ch1FaderStart = function (value) {
  431.   StantonSCS1m.channelFaderStart(value,1);
  432. }
  433.  
  434. StantonSCS1m.ch2FaderStart = function (value) {
  435.   StantonSCS1m.channelFaderStart(value,2);
  436. }
  437.  
  438. StantonSCS1m.channelFaderStart = function (value,deck) {
  439.  
  440.   if (!StantonSCS1m.faderStart) return;
  441.   if (StantonSCS1m.lastFader[deck]==value) return;
  442.  
  443.   if (value==0 && engine.getValue("[Channel"+deck+"]","play")==1) {
  444.     engine.setValue("[Channel"+deck+"]","cue_default",1);
  445.     engine.setValue("[Channel"+deck+"]","cue_default",0);
  446.     }
  447.   if (StantonSCS1m.lastFader[deck]==0) engine.setValue("[Channel"+deck+"]","play",1);
  448.   
  449.   StantonSCS1m.lastFader[deck]=value;
  450. }
  451.  
  452. // ----------   LED slot functions  ----------
  453.  
  454. StantonSCS1m.buttonLED = function (value, note, on, off) {
  455.     var byte1 = 0x90 + StantonSCS1m.channel;
  456.     if (value>0) midi.sendShortMsg(byte1,note,on);
  457.     else midi.sendShortMsg(byte1,note,off);
  458. }
  459.  
  460.  
  461. // Vu Meters
  462.  
  463. StantonSCS1m.Channel1Vu = function (value) {
  464.     StantonSCS1m.VuMeter(value,93);
  465. }
  466.  
  467. StantonSCS1m.Channel2Vu = function (value) {
  468.     StantonSCS1m.VuMeter(value,94);
  469. }
  470.  
  471. StantonSCS1m.MasterLVu = function (value) {
  472.     StantonSCS1m.VuMeter(value,96);
  473. }
  474.  
  475. StantonSCS1m.MasterRVu = function (value) {
  476.     StantonSCS1m.VuMeter(value,97);
  477. }
  478.  
  479. StantonSCS1m.VuMeter = function (value,note) {
  480.     var on = 0x90 + StantonSCS1m.channel;
  481.     var off = 0x80 + StantonSCS1m.channel;
  482.     var range = 0.125;  // 1/8
  483.     if (value>0.001) midi.sendShortMsg(on,note,0);
  484.     else midi.sendShortMsg(off,note,0);
  485.     if (value>range) midi.sendShortMsg(on,note,1);
  486.     else midi.sendShortMsg(off,note,1);
  487.     if (value>range*2) midi.sendShortMsg(on,note,2);
  488.     else midi.sendShortMsg(off,note,2);
  489.     if (value>range*3) midi.sendShortMsg(on,note,3);
  490.     else midi.sendShortMsg(off,note,3);
  491.     if (value>range*4) midi.sendShortMsg(on,note,4);
  492.     else midi.sendShortMsg(off,note,4);
  493.     if (value>range*5) midi.sendShortMsg(on,note,5);
  494.     else midi.sendShortMsg(off,note,5);
  495.     if (value>range*6) midi.sendShortMsg(on,note,6);
  496.     else midi.sendShortMsg(off,note,6);
  497.     if (value>range*7) midi.sendShortMsg(on,note,7);
  498.     else midi.sendShortMsg(off,note,7);
  499.     if (value>=range*8) midi.sendShortMsg(on,note,8);
  500.     else midi.sendShortMsg(off,note,8);
  501. }
  502.  
  503. // LCD displays ("scribble strips")
  504.  
  505. StantonSCS1m.pitchDisplay1 = function (value) {
  506.     if (StantonSCS1m.inSetup) return;
  507.     StantonSCS1m.pitchDisplay(value,1);
  508. }
  509.  
  510. StantonSCS1m.pitchDisplay2 = function (value) {
  511.     if (StantonSCS1m.inSetup) return;
  512.     StantonSCS1m.pitchDisplay(value,2);
  513. }
  514.  
  515. StantonSCS1m.pitchDisplay = function (value,deck) {
  516.     var data = (value * engine.getValue("[Channel"+deck+"]","rateRange") * 100);
  517.     if (engine.getValue("[Channel"+deck+"]","rate_dir") == -1) data=-data;  // Show the correct sign depending on the preferences
  518.     data = data.toFixed(2); // Always two decimal places
  519.     if (data>0) data = "+"+data;
  520.     data = data + "%";
  521.     var message = "";
  522.     for (i=data.length; i<8; i++) message += " ";  // Pad the left side with spaces so the decimal point doesn't move around
  523.     message += data;
  524.     var LCD;
  525.     switch (deck) {
  526.         case 1: LCD=1; break;
  527.         case 2: LCD=4; break;
  528.     }
  529.     midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, LCD],message.toInt(), 0xF7),7+message.length);   // Set LCD with pitch value
  530. }
  531.  
  532. StantonSCS1m.pitchColor1 = function (value) {
  533.     StantonSCS1m.pitchColor(value,1);
  534. }
  535.  
  536. StantonSCS1m.pitchColor2 = function (value) {
  537.     StantonSCS1m.pitchColor(value,2);
  538. }
  539.  
  540. StantonSCS1m.pitchColor = function (value, deck) {
  541.     var No = 0x90 + StantonSCS1m.channel;
  542.     var offset=0;
  543.     if (deck==2) offset=3;
  544.  
  545.     if (value<=0.25) midi.sendShortMsg(No,49+offset,96);
  546.     else if (value<=0.5) midi.sendShortMsg(No,49+offset,127);
  547.     else if (value>0.5) midi.sendShortMsg(No,49+offset,32);
  548.     engine.trigger("[Channel"+deck+"]","rate");    // Force pitch display to update
  549. }
  550.  
  551. // Virtual platter rings & time displays
  552.  
  553. StantonSCS1m.durationChange1 = function (value) {
  554.     StantonSCS1m.trackDuration[1]=value;
  555.     StantonSCS1m.displayFlash[1]=-1;
  556. }
  557.  
  558. StantonSCS1m.durationChange2 = function (value) {
  559.     StantonSCS1m.trackDuration[2]=value;
  560.     StantonSCS1m.displayFlash[2]=-1;
  561. }
  562.  
  563. StantonSCS1m.positionUpdates1 = function (value) {
  564.     StantonSCS1m.positionUpdates(value,1);
  565. }
  566.  
  567. StantonSCS1m.positionUpdates2 = function (value) {
  568.     StantonSCS1m.positionUpdates(value,2);
  569. }
  570.  
  571. StantonSCS1m.positionUpdates = function (value,deck) {
  572.     StantonSCS1m.wheelDecay(value); // Take care of scratching
  573.     
  574.     // Revolution time of the imaginary record in seconds
  575.     var revtime = StantonSCS1m.revtime;
  576.     var currentTrackPos = value * StantonSCS1m.trackDuration[deck];
  577.     
  578.     var revolutions = currentTrackPos/revtime;
  579.     var light = ((revolutions-((revolutions)|0))*18) | 0; // OR with 0 replaces Math.floor and is faster
  580. //     print("----------Light="+light+", Revolutions="+revolutions+", Remainder="+(revolutions-Math.floor(revolutions)));
  581.  
  582.     if (StantonSCS1m.lastLight[deck]!=light) {  // Don't send light commands if there's no visible change
  583.         var byte1 = 0xB0 + StantonSCS1m.channel;
  584.         if (deck==1) midi.sendShortMsg(byte1,0x7E,light+1);
  585.         else midi.sendShortMsg(byte1,0x7D,light+1);
  586.         StantonSCS1m.lastLight[deck]=light;
  587.     }   // End platter lights
  588.  
  589.     
  590.     if (!StantonSCS1m.inSetup) {    // If not in setup mode
  591.         // Show track time remaining
  592.         var trackTimeRemaining = ((1-value) * StantonSCS1m.trackDuration[deck]) | 0;    // OR with 0 replaces Math.floor and is faster
  593.         var message = "-"+secondstominutes(trackTimeRemaining);
  594.         var No = 0x90 + StantonSCS1m.channel;
  595.         if (StantonSCS1m.lastTime[deck]!=message) { // Only send the message if its different
  596.             if (trackTimeRemaining>30) midi.sendShortMsg(No,49+deck,32);    // Set backlight to red
  597.             midi.sendSysexMsg(StantonSCS1m.sysex.concat([StantonSCS1m.channel, deck+1],message.toInt(), 0xF7),7+message.length);
  598.             StantonSCS1m.lastTime[deck]=message;
  599.         }
  600.         // Flash near the end of the track
  601.         // TODO: Use a timer for this
  602.         if (trackTimeRemaining<=30 && trackTimeRemaining>15) {   // If <30s left, flash the LCD slowly
  603.             if (StantonSCS1m.displayFlash[deck]==-1) StantonSCS1m.displayFlash[deck] = new Date();
  604.             if (new Date() - StantonSCS1m.displayFlash[deck]>500) {
  605.                 StantonSCS1m.displayFlash[deck] = new Date();
  606.                 if (StantonSCS1m.lastColor[deck]==32) StantonSCS1m.lastColor[deck]=96; // green
  607.                 else StantonSCS1m.lastColor[deck]=32;  // red
  608.                 midi.sendShortMsg(No,49+deck,StantonSCS1m.lastColor[deck]);
  609.             }
  610.         } else if (trackTimeRemaining<=15 && trackTimeRemaining>0) { // If <15s left, flash quickly
  611.             if (StantonSCS1m.displayFlash[deck]==-1) StantonSCS1m.displayFlash[deck] = new Date();
  612.             if (new Date() - StantonSCS1m.displayFlash[deck]>125) {
  613.                 StantonSCS1m.displayFlash[deck] = new Date();
  614.                 if (StantonSCS1m.lastColor[deck]==32) StantonSCS1m.lastColor[deck]=96; // green
  615.                 else StantonSCS1m.lastColor[deck]=32;  // red
  616.                 midi.sendShortMsg(No,49+deck,StantonSCS1m.lastColor[deck]);
  617.             }
  618.         }   // End flashing
  619.     }
  620. }
  621.  
  622. StantonSCS1m.wheelDecay = function (value) {
  623.  
  624.      if (StantonSCS1m.selectKnobMode=="control") {    // do some scratching
  625.         
  626.         scratch = engine.getValue("[Channel"+StantonSCS1m.scratchDeck+"]","scratch");
  627.         jogDecayRate = StantonSCS1m.scratchKnob["slippage"] * (engine.getValue("[Channel"+StantonSCS1m.scratchDeck+"]","play") ? 1 : 1.1 );
  628.         
  629.         if (StantonSCS1m.debug) print("Scratch deck"+StantonSCS1m.scratchDeck+": " + scratch + ", Jog decay rate="+jogDecayRate);
  630.          
  631.         if (scratch != 0) {
  632.             if (Math.abs(scratch) > jogDecayRate*0.001) {  
  633.                   engine.setValue("[Channel"+StantonSCS1m.scratchDeck+"]","scratch", (scratch * jogDecayRate).toFixed(4));
  634.                } else {
  635.                   engine.setValue("[Channel"+StantonSCS1m.scratchDeck+"]","scratch", 0);
  636.                }
  637.             }
  638.      }
  639. }
  640.  
  641. /* TODO:
  642. - Add cueplay fix?
  643. */