~mixxxdevelopers/mixxx/mixxx-buildserver

« back to all changes in this revision

Viewing changes to mixxx/res/midi/Stanton-SCS1d-scripts.js

  • Committer: Albert Santoni
  • Date: 2011-03-20 00:27:15 UTC
  • mfrom: (2607.1.162 mixxx-1.9)
  • Revision ID: alberts@mixxx.org-20110320002715-sa2d88zbuc5kkyya
MergedĀ fromĀ 1.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/****************************************************************/
2
 
/*      Stanton SCS.1d MIDI controller script vPre              */
3
 
/*          Copyright (C) 2009-2010, Sean M. Pappalardo         */
 
2
/*      Stanton SCS.1d MIDI controller script v1.01             */
 
3
/*          Copyright (C) 2009-2011, Sean M. Pappalardo         */
4
4
/*      but feel free to tweak this to your heart's content!    */
5
5
/*      For Mixxx version 1.9.x, controller firmware v1.25      */
6
6
/****************************************************************/
9
9
 
10
10
// ----------   Customization variables ----------
11
11
//      See http://mixxx.org/wiki/doku.php/stanton_scs.1d_mixxx_user_guide  for details
12
 
StantonSCS1d.pitchRanges = [ 0.08, 0.16, 0.25, 0.5 ];   // Pitch ranges (can add more, but the .rangeButton function would need to be extended.)
 
12
StantonSCS1d.pitchRanges = [ 0.08, 0.16, 0.25, 0.5 ];   // Available pitch ranges. You can add more (in ascending order.)
13
13
StantonSCS1d.fastDeckChange = false;    // Skip the flashy lights if true, for juggling
14
14
StantonSCS1d.globalMode = false;        // Stay in the current modes on deck changes if true
15
15
StantonSCS1d.platterSpeed = 0;          // Speed of the platter at 0% pitch: 0=33 RPM, 1=45 RPM
16
16
StantonSCS1d.deckChangeWait = 1000;     // Time in milliseconds to hold the Deck Change button down to avoid changing decks
17
17
StantonSCS1d.padVelocity = true;        // Use the velocity values when recalling cues on the trigger pads
18
18
StantonSCS1d.crossFader = true;         // Use the pitch slider to adjust cross-fader when Range is held down
19
 
StantonSCS1d.browseDamp = 2;                    // Number of platter ticks to move the highlight one item when browsing the library
20
 
 
21
 
// These values are heavily latency-dependent. They're preset for 10ms and will need tuning for other latencies. (For 2ms, try 0.885, 0.15, and 1.5.)
22
 
StantonSCS1d.scratching = {     "sensitivity":0.11,          // How much the audio moves for a given circle arc (higher=faster response, 0<n<1)
23
 
                                "stoppedMultiplier":1.0 };  // Correction for when the deck is stopped (set higher for higher latencies)
 
19
StantonSCS1d.browseDamp = 3;            // Number of platter ticks to move the highlight one item when browsing the library
 
20
StantonSCS1d.looseLoops = true;         // Re-define loop points while set (for loop rolls)
24
21
 
25
22
// ----------   Other global variables    ----------
26
23
StantonSCS1d.debug = false;  // Enable/disable debugging messages to the console
30
27
StantonSCS1d.buttons = { "control":27, "browse":28, "vinyl":29, "deckSelect":64 };
31
28
 
32
29
StantonSCS1d.platterMode = { "[Channel1]":"vinyl", "[Channel2]":"vinyl" };   // Set vinyl mode on both decks
 
30
StantonSCS1d.newPlatterMode;
33
31
StantonSCS1d.knobMode = { "[Channel1]":1, "[Channel2]":1 }; // 1=Low,Mid,High EQ,Vol; 2=Depth,Delay,LFO,Gain; 3=Cuemix,Headvol,Balance,MasterVol
34
32
StantonSCS1d.padBank = { "deck":1, "bank1":1, "bank2":1 };
35
33
StantonSCS1d.triggerBank = { 1:1, 2:1 };    // Trigger button bank for each deck
36
34
StantonSCS1d.deck = 1;  // Currently active virtual deck
37
35
StantonSCS1d.trackDuration = [0,0]; // Duration of the song on each deck (used for jog LCD and displays)
38
 
StantonSCS1d.lastLight = [-1,-1];       // Last circle LCD values
39
 
StantonSCS1d.modifier = { "cue":0, "play":0 };  // Modifier buttons (allowing alternate controls) defined on-the-fly if needed
 
36
StantonSCS1d.lastLight = [-1,-1];    // Last circle LCD values
 
37
StantonSCS1d.modifier = { "cue":0, "play":0, "trigger":-1 };  // Modifier buttons (allowing alternate controls) defined on-the-fly if needed
40
38
// Temporary state variables
41
 
StantonSCS1d.state = { "pitchAbs":0, "jog":0, "dontMove":0, "platterGrabbed":false, "browseTicks":0};
 
39
StantonSCS1d.state = { "pitchAbs":0, "dontMove":0, "browseTicks":0, "loopFlash":0, "control":false };
 
40
StantonSCS1d.timer = { "loop":-1, "deckChange":-1 };  // Temporary storage of timer IDs
 
41
StantonSCS1d.loopActive = [-1, -1, -1]; // Mark which loop is active on each deck, if any
42
42
StantonSCS1d.mutex = { };   // Temporary mutual exclusion variables
43
43
StantonSCS1d.prevValues = { };  // Temporary previous value storage
44
44
StantonSCS1d.inSetup = false;   // Flag for if the device is in setup mode
45
45
StantonSCS1d.sysex = [0xF0, 0x00, 0x01, 0x02];  // Preamble for all SysEx messages for this device
46
 
StantonSCS1d.rpm = [33+1/3,45]; // RPM values for StantonSCS1d.platterSpeed
 
46
StantonSCS1d.rpm = [33+1/3,45];    // RPM values for StantonSCS1d.platterSpeed - DO NOT CHANGE!
47
47
// Variables used in the scratching alpha-beta filter: (revtime = 1.8 to start)
48
 
StantonSCS1d.scratch = { "revtime":1.8, "resolution":4000, "alpha":1.0/8, "beta":(1.0/8)/32, "prevTimeStamp":0, "prevState":0 };
49
 
                                                // "alpha":0.1, "beta":1.0 for obsolete method
 
48
StantonSCS1d.scratch = { "revtime":(60/StantonSCS1d.rpm[StantonSCS1d.platterSpeed]), "resolution":4000, "alpha":1.0/8, "beta":(1.0/8)/32, "prevTimeStamp":0, "prevState":0 };
50
49
// Pitch values for key change mode
51
50
StantonSCS1d.pitchPoints = {    1:{ 8:-0.1998, 9:-0.1665, 10:-0.1332, 11:-0.0999, 12:-0.0666, 13:-0.0333,
52
51
                                    14:0.0333, 15:0.0666, 18:0.0999, 19:0.1332, 20:0.1665, 21:0.1998 }, // 3.33% increments
58
57
StantonSCS1d.hotCues = {    1:{ 0x20: 1, 0x21: 2, 0x22: 3, 0x23: 4 },
59
58
                            2:{ 0x20: 5, 0x21: 6, 0x22: 7, 0x23: 8 },
60
59
                            3:{ 0x20: 9, 0x21: 10, 0x22: 11, 0x23: 12 } };
61
 
/*
62
 
StantonSCS1d.padPoints =  {     1:{ // Deck
63
 
                                    1:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 },   // Bank
64
 
                                    2:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 },
65
 
                                    3:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 } },
66
 
                                2:{ // Deck
67
 
                                    1:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 },   // Bank
68
 
                                    2:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 },
69
 
                                    3:{ 0x20:-0.1, 0x21:-0.1, 0x22:-0.1, 0x23:-0.1 } }
70
 
                            };
71
 
*/
 
60
// Button-to-index mapping for trigger section
 
61
StantonSCS1d.trigButtons = {8:0,  9:1,  10:2,  11:3,
 
62
                            12:4, 13:5, 14:6,  15:7,
 
63
                            18:8, 19:9, 20:10, 21:11 };
 
64
// Button-to-reloop index mapping for trigger section
 
65
StantonSCS1d.trigButtonsLoopNr = {  8:1,  9:1,  10:2, 11:2,
 
66
                                    12:3, 13:3, 14:4, 15:4,
 
67
                                    18:5, 19:5, 20:6, 21:6 };
72
68
 
73
69
// Signals to (dis)connect by mode: Group, Key, Function name
74
70
StantonSCS1d.platterSignals = { "vinyl":[ ["CurrentChannel", "rate", "StantonSCS1d.platterSpeed"] ],
84
80
                                ["CurrentChannel", "beatsync", "StantonSCS1d.syncLED"],
85
81
                                ["CurrentChannel", "back", "StantonSCS1d.backLED"],
86
82
                                ["CurrentChannel", "fwd", "StantonSCS1d.fwdLED"],
87
 
                                ["CurrentChannel", "pfl", "StantonSCS1d.headphoneLED"]
 
83
                                ["CurrentChannel", "pfl", "StantonSCS1d.headphoneLED"],
 
84
                                ["CurrentChannel", "loop_enabled", "StantonSCS1d.loopEnabled"],
 
85
                                ["CurrentChannel", "reloop_exit", "StantonSCS1d.activateLoop"],
 
86
                                ["CurrentChannel", "bpm_tap", "StantonSCS1d.bpmLED"]
88
87
                            ];
 
88
// When Mixxx gets multiple loop capability, just change the key values here for the respective buttons
 
89
StantonSCS1d.trigSignals = [ [],    // Bank 0 (non-existent)
 
90
                             [  ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig1ILED"],
 
91
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig1OLED"],
 
92
                                ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig2ILED"],
 
93
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig2OLED"],
 
94
                                ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig3ILED"],
 
95
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig3OLED"],
 
96
                                ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig4ILED"],
 
97
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig4OLED"],
 
98
                                ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig5ILED"],
 
99
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig5OLED"],
 
100
                                ["CurrentChannel", "loop_start_position", "StantonSCS1d.Trig6ILED"],
 
101
                                ["CurrentChannel", "loop_end_position", "StantonSCS1d.Trig6OLED"]
 
102
                            ], [], [] ];    // Only one bank right now
89
103
StantonSCS1d.knobText =    [  ["Low EQ","Mid EQ","High EQ","Volume"],
90
104
                              ["Depth","Delay","Period","PF Gain"],
91
105
                              ["Pre/Main","Head Vol","Balance","M.Volume"]
103
117
                                ["[Master]", "balance", "StantonSCS1d.encoder3BalanceLEDs"],
104
118
                                ["[Master]", "volume", "StantonSCS1d.encoder4MVolumeLEDs"] ],
105
119
                            ];
106
 
StantonSCS1d.padSignals = [     [],     // Bank 0 (non-existent)
107
 
                                                        [       ["CurrentChannel", "hotcue_1_position", "StantonSCS1d.Pad1LCD"],
108
 
                                                                ["CurrentChannel", "hotcue_2_position", "StantonSCS1d.Pad2LCD"],
109
 
                                                                ["CurrentChannel", "hotcue_3_position", "StantonSCS1d.Pad3LCD"],
110
 
                                                                ["CurrentChannel", "hotcue_4_position", "StantonSCS1d.Pad4LCD"],
111
 
                                                                ["CurrentChannel", "hotcue_1_activate", "StantonSCS1d.Pad1aLED"],
112
 
                                                                ["CurrentChannel", "hotcue_2_activate", "StantonSCS1d.Pad2aLED"],
113
 
                                                                ["CurrentChannel", "hotcue_3_activate", "StantonSCS1d.Pad3aLED"],
114
 
                                                                ["CurrentChannel", "hotcue_4_activate", "StantonSCS1d.Pad4aLED"] ],
115
 
                                                        [       ["CurrentChannel", "hotcue_5_position", "StantonSCS1d.Pad1LCD"],
116
 
                                                                ["CurrentChannel", "hotcue_6_position", "StantonSCS1d.Pad2LCD"],
117
 
                                                                ["CurrentChannel", "hotcue_7_position", "StantonSCS1d.Pad3LCD"],
118
 
                                                                ["CurrentChannel", "hotcue_8_position", "StantonSCS1d.Pad4LCD"],
119
 
                                                                ["CurrentChannel", "hotcue_5_activate", "StantonSCS1d.Pad1aLED"],
120
 
                                                                ["CurrentChannel", "hotcue_6_activate", "StantonSCS1d.Pad2aLED"],
121
 
                                                                ["CurrentChannel", "hotcue_7_activate", "StantonSCS1d.Pad3aLED"],
122
 
                                                                ["CurrentChannel", "hotcue_8_activate", "StantonSCS1d.Pad4aLED"] ],
123
 
                                                        [       ["CurrentChannel", "hotcue_9_position", "StantonSCS1d.Pad1LCD"],
124
 
                                                                ["CurrentChannel", "hotcue_10_position", "StantonSCS1d.Pad2LCD"],
125
 
                                                                ["CurrentChannel", "hotcue_11_position", "StantonSCS1d.Pad3LCD"],
126
 
                                                                ["CurrentChannel", "hotcue_12_position", "StantonSCS1d.Pad4LCD"],
127
 
                                                                ["CurrentChannel", "hotcue_9_activate", "StantonSCS1d.Pad1aLED"],
128
 
                                                                ["CurrentChannel", "hotcue_10_activate", "StantonSCS1d.Pad2aLED"],
129
 
                                                                ["CurrentChannel", "hotcue_11_activate", "StantonSCS1d.Pad3aLED"],
130
 
                                                                ["CurrentChannel", "hotcue_12_activate", "StantonSCS1d.Pad4aLED"] ] ];
 
120
StantonSCS1d.padSignals = [    [],    // Bank 0 (non-existent)
 
121
                            [    ["CurrentChannel", "hotcue_1_position", "StantonSCS1d.Pad1LCD"],
 
122
                                ["CurrentChannel", "hotcue_2_position", "StantonSCS1d.Pad2LCD"],
 
123
                                ["CurrentChannel", "hotcue_3_position", "StantonSCS1d.Pad3LCD"],
 
124
                                ["CurrentChannel", "hotcue_4_position", "StantonSCS1d.Pad4LCD"],
 
125
                                ["CurrentChannel", "hotcue_1_activate", "StantonSCS1d.Pad1aLED"],
 
126
                                ["CurrentChannel", "hotcue_2_activate", "StantonSCS1d.Pad2aLED"],
 
127
                                ["CurrentChannel", "hotcue_3_activate", "StantonSCS1d.Pad3aLED"],
 
128
                                ["CurrentChannel", "hotcue_4_activate", "StantonSCS1d.Pad4aLED"] ],
 
129
                            [    ["CurrentChannel", "hotcue_5_position", "StantonSCS1d.Pad1LCD"],
 
130
                                ["CurrentChannel", "hotcue_6_position", "StantonSCS1d.Pad2LCD"],
 
131
                                ["CurrentChannel", "hotcue_7_position", "StantonSCS1d.Pad3LCD"],
 
132
                                ["CurrentChannel", "hotcue_8_position", "StantonSCS1d.Pad4LCD"],
 
133
                                ["CurrentChannel", "hotcue_5_activate", "StantonSCS1d.Pad1aLED"],
 
134
                                ["CurrentChannel", "hotcue_6_activate", "StantonSCS1d.Pad2aLED"],
 
135
                                ["CurrentChannel", "hotcue_7_activate", "StantonSCS1d.Pad3aLED"],
 
136
                                ["CurrentChannel", "hotcue_8_activate", "StantonSCS1d.Pad4aLED"] ],
 
137
                            [    ["CurrentChannel", "hotcue_9_position", "StantonSCS1d.Pad1LCD"],
 
138
                                ["CurrentChannel", "hotcue_10_position", "StantonSCS1d.Pad2LCD"],
 
139
                                ["CurrentChannel", "hotcue_11_position", "StantonSCS1d.Pad3LCD"],
 
140
                                ["CurrentChannel", "hotcue_12_position", "StantonSCS1d.Pad4LCD"],
 
141
                                ["CurrentChannel", "hotcue_9_activate", "StantonSCS1d.Pad1aLED"],
 
142
                                ["CurrentChannel", "hotcue_10_activate", "StantonSCS1d.Pad2aLED"],
 
143
                                ["CurrentChannel", "hotcue_11_activate", "StantonSCS1d.Pad3aLED"],
 
144
                                ["CurrentChannel", "hotcue_12_activate", "StantonSCS1d.Pad4aLED"] ] ];
131
145
 
132
146
// ----------   Functions   ----------
133
147
 
151
165
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 8],message.toInt(), 0xF7),7+message.length);
152
166
    //midi.sendShortMsg(No,49+2,127); // to orange
153
167
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 4],
154
 
                StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
 
168
        StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
155
169
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 9],
156
 
                StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
 
170
        StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
157
171
    //midi.sendShortMsg(No,49+3,32);  // to red
158
172
    
159
173
    StantonSCS1d.id = id;   // Store the ID of this device for later use
173
187
    
174
188
    // Force change to first deck, initializing the LEDs and connecting signals in the process
175
189
    StantonSCS1d.state["Oldknob"]=1;
176
 
    StantonSCS1d.deck = 2;  // Set active deck to right (#2) so the below will switch to #1.
177
 
    StantonSCS1d.DeckChange(StantonSCS1d.channel, StantonSCS1d.buttons["deckSelect"], "", 0x80+StantonSCS1d.channel);
 
190
    // Set active deck to last available so the below will switch to #1.
 
191
    StantonSCS1d.deck = engine.getValue("[Master]","num_decks");
 
192
    StantonSCS1d.DeckChange(StantonSCS1d.channel, StantonSCS1d.buttons["deckSelect"], 0x7F, 0x90+StantonSCS1d.channel);
 
193
    StantonSCS1d.DeckChange(StantonSCS1d.channel, StantonSCS1d.buttons["deckSelect"], 0x00, 0x80+StantonSCS1d.channel);
178
194
    
179
195
    // Connect the playposition functions permanently since they disrupt playback if connected on the fly
180
196
    engine.connectControl("[Channel1]","visual_playposition","StantonSCS1d.circleBars1");
187
203
    StantonSCS1d.durationChange2(engine.getValue("[Channel2]","duration"));
188
204
    
189
205
    //midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 16, 0xF7]),7); // Light all LEDs
190
 
 
 
206
    
191
207
    print ("StantonSCS1d: \""+StantonSCS1d.id+"\" on MIDI channel "+(StantonSCS1d.channel+1)+" initialized.");
192
208
}
193
209
 
194
210
StantonSCS1d.shutdown = function () {   // called when the MIDI device is closed
 
211
    
195
212
    var CC = 0xB0 + StantonSCS1d.channel;
196
213
    midi.sendShortMsg(CC,1,'x'.toInt());   // Stop the platter
197
214
 
201
218
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 6],message.toInt(), 0xF7),7+message.length);
202
219
    
203
220
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 2],
204
 
                StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
 
221
        StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
205
222
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 7],
206
 
                StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
 
223
        StantonSCS1d.swVersion.toInt(), 0xF7),7+StantonSCS1d.swVersion.length);
207
224
    
208
225
    message = "was here";
209
226
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 3],message.toInt(), 0xF7),7+message.length);
216
233
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 0, 0xF7]),8); // Jog backlight off
217
234
    // clear jog LCD character (set to space)
218
235
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 36, 0x20, 0xF7]),8);
219
 
        midi.sendShortMsg(CC,2,0x00);   // Clear jog circle
 
236
    midi.sendShortMsg(CC,2,0x00);    // Clear jog circle
220
237
    
221
238
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 17, 0xF7]),7); // Extinguish all LEDs
222
239
 
240
257
  if (StantonSCS1d.checkInSetup()) return;
241
258
    var byte1 = 0x90 + channel;
242
259
    if ((status & 0XF0) == 0x90) {    // If button down
243
 
                engine.scratchDisable(StantonSCS1d.deck);
 
260
        engine.scratchDisable(StantonSCS1d.deck);
244
261
        midi.sendShortMsg(0xB0 + channel,1,'x'.toInt());   // Stop platter
245
262
        midi.sendShortMsg(byte1,control,1);  // Light 'er up
246
263
        StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = "control";
247
264
        midi.sendShortMsg(0x80+channel,0x1C,0);  // turn off the "browse" mode button
248
265
        midi.sendShortMsg(0x80+channel,0x1D,0);  // turn off the "vinyl" mode button
249
 
        
 
266
 
250
267
        return;
251
268
    }
252
269
}
255
272
  if (StantonSCS1d.checkInSetup()) return;
256
273
    var byte1 = 0x90 + channel;
257
274
    if ((status & 0XF0) == 0x90) {    // If button down
258
 
                engine.scratchDisable(StantonSCS1d.deck);
259
 
        midi.sendShortMsg(0xB0 + channel,1,'x'.toInt());   // Stop platter
260
 
        midi.sendShortMsg(byte1,control,1);  // Light 'er up
261
 
        midi.sendShortMsg(0x80+channel,0x1B,0);  // turn off the "control" mode button
262
 
        midi.sendShortMsg(0x80+channel,0x1D,0);  // turn off the "vinyl" mode button
263
 
        
 
275
        if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "browse") {
 
276
            // If already in browse mode, change library view category
 
277
            engine.setValue("[Playlist]","SelectNextPlaylist",1);
 
278
        }
 
279
        else {
 
280
            engine.scratchDisable(StantonSCS1d.deck);
 
281
            StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = "";    // Avoid problems coming from vinyl mode
 
282
            midi.sendShortMsg(byte1,control,1);  // Light 'er up
 
283
            midi.sendShortMsg(0x80+channel,0x1B,0);  // turn off the "control" mode button
 
284
            midi.sendShortMsg(0x80+channel,0x1D,0);  // turn off the "vinyl" mode button
 
285
            midi.sendShortMsg(0xB0 + channel,1,'x'.toInt());   // Stop platter
 
286
            engine.setValue("[Playlist]","SelectPrevPlaylist",1);
 
287
        }
264
288
        return;
265
289
    }
266
 
    // Switch modes on button up to give the motor a chance to stop
267
 
        StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = "browse";
 
290
    
 
291
    // On button up
 
292
    if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "browse") {
 
293
        engine.setValue("[Playlist]","SelectNextPlaylist",0);
 
294
    }
 
295
    else {
 
296
        // Switch modes on button up to give the motor a chance to stop
 
297
        engine.setValue("[Playlist]","SelectPrevPlaylist",0);
 
298
        StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = "browse";
 
299
    }
268
300
}
269
301
 
270
302
StantonSCS1d.vinylButton = function (channel, control, value, status) {
272
304
    var byte1 = 0x90 + channel;
273
305
    if ((status & 0XF0) == 0x90) {    // If button down
274
306
        midi.sendShortMsg(byte1,control,1);  // Light 'er up
275
 
        if (!StantonSCS1d.state["outsideMotor"])        // Enable direct platter control
276
 
                        engine.scratchEnable(StantonSCS1d.deck, StantonSCS1d.scratch["resolution"], StantonSCS1d.rpm[StantonSCS1d.platterSpeed],StantonSCS1d.scratch["alpha"], StantonSCS1d.scratch["beta"]);
 
307
        midi.sendShortMsg(0x80+channel,0x1B,0);  // turn off the "control" mode button
 
308
        midi.sendShortMsg(0x80+channel,0x1C,0);  // turn off the "browse" mode button
277
309
        StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = "vinyl";
278
 
        midi.sendShortMsg(0x80+channel,0x1B,0);  // turn off the "control" mode button
279
 
        midi.sendShortMsg(0x80+channel,0x1C,0);  // turn off the "browse" mode button
280
310
        
281
 
        StantonSCS1d.pitchChange(engine.getValue("[Channel"+StantonSCS1d.deck+"]","rate")); // So the platter speed is updated and it begins spinning if applicable
 
311
        // Update the platter speed and start it spinning if applicable
 
312
        StantonSCS1d.pitchChange(engine.getValue("[Channel"+StantonSCS1d.deck+"]","rate"),true);
282
313
        return;
283
314
    }
 
315
    // Enable direct platter control on button up to give the motor a chance to get to speed
 
316
    if (!StantonSCS1d.state["outsideMotor"] && StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl")    
 
317
        engine.scratchEnable(StantonSCS1d.deck, StantonSCS1d.scratch["resolution"],
 
318
            StantonSCS1d.rpm[StantonSCS1d.platterSpeed],StantonSCS1d.scratch["alpha"],
 
319
            StantonSCS1d.scratch["beta"]);
284
320
}
285
321
 
286
 
// (Dis)connects the appropriate Mixxx control signals to/from functions based on the currently controlled deck and what mode the encoder knobs are in
 
322
// (Dis)connects the appropriate Mixxx control signals to/from functions based on 
 
323
//      the currently controlled deck and what mode the encoder knobs are in
287
324
StantonSCS1d.connectKnobSignals = function (channel, disconnect) {
 
325
    if (StantonSCS1d.debug) print("     StantonSCS1d: "+(disconnect?"DISCONNECT":"connect")+"KnobSignals:");
288
326
 
289
327
    var signalList = StantonSCS1d.knobSignals[StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"]-1];
290
328
    for (var i=0; i<signalList.length; i++) {
325
363
 
326
364
// (Dis)connects the appropriate Mixxx control signals to/from functions based on the currently controlled deck
327
365
StantonSCS1d.connectPadSignals = function (channel, disconnect) {
328
 
        var deck = StantonSCS1d.padBank["deck"];
 
366
    if (StantonSCS1d.debug) print("     StantonSCS1d: "+(disconnect?"DISCONNECT":"connect")+"PadSignals:");
 
367
    var deck = StantonSCS1d.padBank["deck"];
329
368
    var bank = StantonSCS1d.padBank["bank"+deck];
330
369
    
331
370
    var signalList = StantonSCS1d.padSignals[bank];
361
400
    }
362
401
}
363
402
 
 
403
// (Dis)connects the appropriate Mixxx control signals to/from functions based on the currently controlled deck
 
404
StantonSCS1d.connectTrigSignals = function (channel, disconnect) {
 
405
    if (StantonSCS1d.debug) print("     StantonSCS1d: "+(disconnect?"DISCONNECT":"connect")+"TrigSignals:");
 
406
    var bank = StantonSCS1d.triggerBank[StantonSCS1d.deck];
 
407
    
 
408
    var signalList = StantonSCS1d.trigSignals[bank];
 
409
    for (var i=0; i<signalList.length; i++) {
 
410
        var group = signalList[i][0];
 
411
        if (group=="CurrentChannel") group = "[Channel"+StantonSCS1d.deck+"]";
 
412
        engine.connectControl(group,signalList[i][1],signalList[i][2],disconnect);
 
413
        
 
414
        // If connecting a signal, cause it to fire (by setting it to the same value) to update the LEDs
 
415
//         if (!disconnect) engine.trigger(group,signalList[i][1]);  // Commented because there's no sense in wasting queue length
 
416
        if (!disconnect) {
 
417
            // Alternate:
 
418
            var command = signalList[i][2]+"("+engine.getValue(group,signalList[i][1])+")";
 
419
            //print("StantonSCS1d: command="+command);
 
420
            eval(command);
 
421
        }
 
422
        if (StantonSCS1d.debug) {
 
423
            if (disconnect) print("StantonSCS1d: "+group+","+signalList[i][1]+" disconnected from "+signalList[i][2]);
 
424
            else print("StantonSCS1d: "+group+","+signalList[i][1]+" connected to "+signalList[i][2]);
 
425
        }
 
426
    }
 
427
    // If disconnecting signals, darken the button LEDs
 
428
    if (disconnect) {
 
429
        var byte1 = 0x80 + channel;
 
430
        for (var i=8; i<=15; i++)
 
431
            midi.sendShortMsg(byte1,i,0x00);
 
432
        for (var i=18; i<=21; i++)
 
433
            midi.sendShortMsg(byte1,i,0x00);
 
434
    }
 
435
}
 
436
 
364
437
// (Dis)connects the mode-independent Mixxx control signals to/from functions based on the currently controlled virtual deck
365
438
StantonSCS1d.connectDeckSignals = function (channel, disconnect) {
 
439
    if (StantonSCS1d.debug) print("     StantonSCS1d: "+(disconnect?"DISCONNECT":"connect")+"DeckSignals:");
366
440
    var signalList = StantonSCS1d.deckSignals;
367
441
    for (var i=0; i<signalList.length; i++) {
368
442
        var group = signalList[i][0];
369
443
        var name = signalList[i][1];
370
444
        if (group=="CurrentChannel") group = "[Channel"+StantonSCS1d.deck+"]";
371
445
        engine.connectControl(group,name,signalList[i][2],disconnect);
372
 
//         print("StantonSCS1d: (dis)connected "+group+","+name+" to/from "+signalList[i][2]);
373
446
        
374
447
        // If connecting a signal, update the LEDs
375
448
        if (!disconnect) {
376
449
            switch (name) {
377
450
                case "play":
378
 
                        var currentValue = engine.getValue(group,name);
379
 
//                         print("StantonSCS1d: current value="+currentValue);
380
 
                        StantonSCS1d.playLED(currentValue);
381
 
                        break;
 
451
                    var currentValue = engine.getValue(group,name);
 
452
//                    print("StantonSCS1d: current value="+currentValue);
 
453
                    StantonSCS1d.playLED(currentValue);
 
454
                    break;
382
455
                case "cue_default":
383
456
                case "beatsync": break;
384
457
                default:    // Cause the signal to fire to update LEDs
385
 
//                         engine.trigger(group,name);  // No sense in wasting queue length if we can do this another way
 
458
                    //engine.trigger(group,name);  // No sense in wasting queue length if we can do this another way
386
459
                    // Alternate:
387
 
                        var command = signalList[i][2]+"("+engine.getValue(group,name)+")";
388
 
//                         print("StantonSCS1d: command="+command);
389
 
                        eval(command);
390
 
                        break;
 
460
                    var command = signalList[i][2]+"("+engine.getValue(group,name)+")";
 
461
//                    print("StantonSCS1d: command="+command);
 
462
                    eval(command);
 
463
                    break;
391
464
            }
392
465
        }
393
466
        
411
484
StantonSCS1d.playButton = function (channel, control, value, status) {
412
485
    if ((status & 0xF0) != 0x80) {    // If button down
413
486
        StantonSCS1d.modifier["play"]=1;
414
 
        if (StantonSCS1d.modifier["cue"]==1) engine.setValue("[Channel"+StantonSCS1d.deck+"]","play",1);
415
 
        else {
416
 
            if (StantonSCS1d.modifier["pad"]==1) {
417
 
                // Continue playing (or stop playing) if play is pressed while a pad is held down
418
 
                midi.sendShortMsg(0x90+channel,control,127);    // Make it orange
419
 
                StantonSCS1d.state["padWasPlaying"]=!StantonSCS1d.state["padWasPlaying"];
420
 
                return;
421
 
            }
422
 
            
423
 
            var currentlyPlaying = engine.getValue("[Channel"+StantonSCS1d.deck+"]","play");
424
 
            if (currentlyPlaying && engine.getValue("[Channel"+StantonSCS1d.deck+"]","cue_default")==1) engine.setValue("[Channel"+StantonSCS1d.deck+"]","cue_default",0);
425
 
            engine.setValue("[Channel"+StantonSCS1d.deck+"]","play", !currentlyPlaying);
426
 
        }
 
487
        if (StantonSCS1d.modifier["pad"]==1 || StantonSCS1d.modifier["cue"]==1)
 
488
            midi.sendShortMsg(0x90+channel,control,127);    // Make it orange
 
489
        
 
490
        var currentlyPlaying = engine.getValue("[Channel"+StantonSCS1d.deck+"]","play");
 
491
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","play", !currentlyPlaying);
427
492
        return;
428
493
    }
429
494
    engine.trigger("[Channel"+StantonSCS1d.deck+"]","play");
437
502
        StantonSCS1d.modifier["cue"]=1;   // Set button modifier flag
438
503
        return;
439
504
    }
440
 
    if (StantonSCS1d.modifier["play"]==0) engine.setValue("[Channel"+StantonSCS1d.deck+"]","cue_default",0);
 
505
    engine.setValue("[Channel"+StantonSCS1d.deck+"]","cue_default",0);
441
506
    StantonSCS1d.modifier["cue"]=0;   // Clear button modifier flag
442
507
}
443
508
 
455
520
    StantonSCS1d.buttonLED(value,control,64,0);
456
521
    var byte1 = 0x90 + channel;
457
522
    if ((status & 0xF0) == 0x90) {    // If button down
458
 
//         print("StantonSCS1d: TAP");
459
 
        bpm.tapButton(StantonSCS1d.deck);
 
523
        //bpm.tapButton(StantonSCS1d.deck);
 
524
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","bpm_tap",1);
460
525
        return;
461
526
    }
 
527
    // Button up
 
528
    engine.setValue("[Channel"+StantonSCS1d.deck+"]","bpm_tap",0);
462
529
}
463
530
 
464
531
StantonSCS1d.pfl = function (channel, control, value, status) {
470
537
StantonSCS1d.rew = function (channel, control, value, status) {
471
538
    // If in vinyl mode and button down
472
539
    if ((status & 0xF0) == 0x90) {
473
 
                if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl") {
474
 
                        midi.sendShortMsg(0xB0+channel,1,'4'.toInt());   // 45 RPM backward
475
 
                        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, 1.5, 5, 0, 0, 0xF7]),11);  // Motor full speed
476
 
                        midi.sendShortMsg(0xB0+channel,1,'o'.toInt());   // Start platter
477
 
                }
 
540
        if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl") {
 
541
            midi.sendShortMsg(0xB0+channel,1,'4'.toInt());   // 45 RPM backward
 
542
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, 1.5, 5, 0, 0, 0xF7]),11);  // Motor full speed
 
543
            midi.sendShortMsg(0xB0+channel,1,'o'.toInt());   // Start platter
 
544
        }
478
545
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","back",1);
479
546
        return;
480
547
    }
487
554
StantonSCS1d.ffwd = function (channel, control, value, status) {
488
555
    // If in vinyl mode and button down
489
556
    if ((status & 0xF0) == 0x90) {
490
 
                if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl") {
491
 
                        midi.sendShortMsg(0xB0+channel,1,'2'.toInt());   // 45 RPM foreward
492
 
                        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, 1.5, 5, 0, 0, 0xF7]),11);  // Motor full speed
493
 
                        midi.sendShortMsg(0xB0+channel,1,'o'.toInt());   // Start platter
494
 
                }
 
557
        if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl") {
 
558
            midi.sendShortMsg(0xB0+channel,1,'2'.toInt());   // 45 RPM foreward
 
559
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, 1.5, 5, 0, 0, 0xF7]),11);  // Motor full speed
 
560
            midi.sendShortMsg(0xB0+channel,1,'o'.toInt());   // Start platter
 
561
        }
495
562
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","fwd",1);
496
563
        return;
497
564
    }
506
573
        midi.sendShortMsg(0x90+StantonSCS1d.channel,control,0x7F);  // Light button LED
507
574
        StantonSCS1d.modifier["pitchRange"]=1;   // Set button modifier flag
508
575
        if (StantonSCS1d.crossFader) {
509
 
                        // Move to cross-fader position
510
 
                        StantonSCS1d.pitchRangeLEDs(0); // darken range LEDs
511
 
                        var xfader = engine.getValue("[Master]","crossfader")*63+64;
512
 
                        if (StantonSCS1d.debug) print ("Moving slider to "+xfader);
513
 
                        midi.sendShortMsg(0xB0+StantonSCS1d.channel,0x00,xfader);
514
 
                        StantonSCS1d.state["crossfaderAdjusted"]=false;
515
 
                }
 
576
            // Move to cross-fader position
 
577
            StantonSCS1d.pitchRangeLEDs(0); // darken range LEDs
 
578
            var xfader = engine.getValue("[Master]","crossfader")*63+64;
 
579
            if (StantonSCS1d.debug) print ("Moving slider to "+xfader+" for cross-fader");
 
580
            midi.sendShortMsg(0xB0+StantonSCS1d.channel,0x00,xfader);
 
581
            StantonSCS1d.state["crossfaderAdjusted"]=false;
 
582
        }
516
583
    }
517
584
    else {
518
585
        midi.sendShortMsg(0x80+StantonSCS1d.channel,control,0); // Darken button LED
522
589
        if (!StantonSCS1d.state["crossfaderAdjusted"]) {
523
590
            // Change the range
524
591
            var currentRange = engine.getValue("[Channel"+StantonSCS1d.deck+"]","rateRange");
525
 
            // TODO: Extend this to work with arbitrary-length pitchRanges array
526
 
            switch (true) {
527
 
                case (currentRange<StantonSCS1d.pitchRanges[0]):
528
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[0]);
529
 
                    break;
530
 
                case (currentRange>=StantonSCS1d.pitchRanges[0] &&
531
 
                                          currentRange<StantonSCS1d.pitchRanges[1]):
532
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[1]);
533
 
                    break;
534
 
                case (currentRange>=StantonSCS1d.pitchRanges[1] &&
535
 
                                          currentRange<StantonSCS1d.pitchRanges[2]):
536
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[2]);
537
 
                    break;
538
 
                case (currentRange>=StantonSCS1d.pitchRanges[2] &&
539
 
                                          currentRange<StantonSCS1d.pitchRanges[3]):
540
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[3]);
541
 
                    break;
542
 
                case (currentRange>=StantonSCS1d.pitchRanges[3]):
543
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[0]);
544
 
                    break;
 
592
            var high = StantonSCS1d.pitchRanges.length;
 
593
            if (currentRange<StantonSCS1d.pitchRanges[0] || currentRange>=StantonSCS1d.pitchRanges[high-1])
 
594
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[0]);
 
595
            else {
 
596
                var i=1;
 
597
                while (i<high) {
 
598
                    if (currentRange>=StantonSCS1d.pitchRanges[i-1] &&
 
599
                        currentRange<StantonSCS1d.pitchRanges[i]) {
 
600
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",StantonSCS1d.pitchRanges[i]);
 
601
                        break;
 
602
                    }
 
603
                    i++;
 
604
                }
545
605
            }
546
606
            // Update the screen display
547
607
            engine.trigger("[Channel"+StantonSCS1d.deck+"]","rate");
563
623
}
564
624
 
565
625
StantonSCS1d.vinylMoved = function (data, length) {
566
 
        // Re-construct the 32-bit word
567
 
        var iInfo = (data.charCodeAt(0) << 24) | (data.charCodeAt(1) << 16) | 
568
 
                                (data.charCodeAt(2) << 8) | data.charCodeAt(3);
569
 
        
570
 
        //// Unpack the data - Firmware v1.24 and lower
571
 
        //var iTimeStamp = (iInfo >>> 5);
572
 
        //var iQuad = 3 & ((((iInfo >>> 1) & 1) | (iInfo << 1)) ^ (iInfo & 1)); 
573
 
        //var iDirection = ((iInfo >>> 2) & 1) ^ 1;
574
 
        //iDirection = 1 - (iDirection << 1);
575
 
        //
576
 
        //if (StantonSCS1d.debug) print("Timestamp="+iTimeStamp+" Quad="+iQuad+" Dir="+iDirection+" Info="+iInfo+" Delta="+(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]));
577
 
        //
578
 
        // // Timestamp range: 131071812 - 130547712 = 524,100
579
 
        
580
 
        // Unpack the data - Firmware 1.25 and higher
581
 
        var iTimeStamp = (iInfo >>> 8);
582
 
        var iState = data.charCodeAt(3);
583
 
        if (isNaN(iState)) return;
584
 
        var iMoved = (iState - StantonSCS1d.scratch["prevState"] + 384) % 256 - 128;
585
 
        var iSpeed = iMoved/(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]);
586
 
        
587
 
        if (StantonSCS1d.debug)
588
 
                print("Timestamp="+iTimeStamp+" State="+iState+" Moved="+iMoved+" Speed="+(iSpeed*60000|0));
589
 
        
590
 
        StantonSCS1d.scratch["prevTimeStamp"] = iTimeStamp;
591
 
        StantonSCS1d.scratch["prevState"] = iState;
592
 
        
593
 
        // Process the data
594
 
        
595
 
        var platterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
 
626
    // Re-construct the 32-bit word
 
627
    var iInfo = (data.charCodeAt(0) << 24) | (data.charCodeAt(1) << 16) | 
 
628
                (data.charCodeAt(2) << 8) | data.charCodeAt(3);
 
629
    
 
630
    //// Unpack the data - Firmware v1.24 and lower
 
631
    //var iTimeStamp = (iInfo >>> 5);
 
632
    //var iQuad = 3 & ((((iInfo >>> 1) & 1) | (iInfo << 1)) ^ (iInfo & 1)); 
 
633
    //var iDirection = ((iInfo >>> 2) & 1) ^ 1;
 
634
    //iDirection = 1 - (iDirection << 1);
 
635
    //
 
636
    //if (StantonSCS1d.debug) print("Timestamp="+iTimeStamp+" Quad="+iQuad+" Dir="+iDirection+" Info="+iInfo+" Delta="+(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]));
 
637
    //
 
638
    // // Timestamp range: 131071812 - 130547712 = 524,100
 
639
    
 
640
    // Unpack the data - Firmware 1.25 and higher
 
641
    var iTimeStamp = (iInfo >>> 8);
 
642
    var iState = data.charCodeAt(3);
 
643
    if (isNaN(iState)) return;
 
644
    var iMoved = (iState - StantonSCS1d.scratch["prevState"] + 384) % 256 - 128;
 
645
    var iSpeed = iMoved/(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]);
 
646
    
 
647
    //if (StantonSCS1d.debug)
 
648
    //    print("Timestamp="+iTimeStamp+" State="+iState+" Moved="+iMoved+" Speed="+(iSpeed*60000|0));
 
649
    
 
650
    StantonSCS1d.scratch["prevTimeStamp"] = iTimeStamp;
 
651
    StantonSCS1d.scratch["prevState"] = iState;
 
652
    
 
653
    // Process the data
 
654
    
 
655
    var platterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
596
656
 
597
657
    switch(platterMode) {
598
658
        case "control":
599
 
                        break;
 
659
            break;
600
660
        case "browse":
601
 
                        if (StantonSCS1d.state["browseTicks"]==StantonSCS1d.browseDamp) {
602
 
                                StantonSCS1d.state["browseTicks"]=0;
603
 
                                if (iMoved>0) engine.setValue("[Playlist]","SelectNextTrack",1);
604
 
                                else if (iMoved<0) engine.setValue("[Playlist]","SelectPrevTrack",1);
 
661
            if (StantonSCS1d.state["browseTicks"]==StantonSCS1d.browseDamp) {
 
662
                StantonSCS1d.state["browseTicks"]=0;
 
663
                if (iMoved>0) engine.setValue("[Playlist]","SelectNextTrack",1);
 
664
                else if (iMoved<0) engine.setValue("[Playlist]","SelectPrevTrack",1);
605
665
            }
606
666
            else StantonSCS1d.state["browseTicks"]++;
607
 
                        break;
608
 
        case "vinyl":   // Scratching
609
 
                        // Ignore if the music speed is outside the motor abilities and the platter is stopped
610
 
                        if (StantonSCS1d.state["outsideMotor"]) return;
611
 
 
612
 
                        // TODO: Remember to take into account default platter speed!
613
 
                        //              (StantonSCS1d.platterSpeed: 0=33 RPM, 1=45 RPM)
614
 
                        
615
 
                        engine.scratchTick(StantonSCS1d.deck,iMoved);
616
 
                        
617
 
                        /*
618
 
                        if (iDirection==1) engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",1);
619
 
                        else engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",-0.5);
620
 
 
621
 
                        // Skip if the track start position hasn't been set yet
622
 
                        if (scratch.variables["initialTrackPos"] == -1.0)
623
 
                                engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",0);
624
 
                        // If the slider start value hasn't been set yet, set it
625
 
                        if (scratch.variables["initialControlValue"] == 0) {
626
 
                                scratch.variables["initialControlValue"] = sliderValue;
627
 
                                 print("Initial slider="+scratch.variables["initialControlValue"]);
628
 
                                }
629
 
                        var temp=scratch.filter(StantonSCS1d.deck, iTimeStamp, StantonSCS1d.scratch["revtime"], StantonSCS1d.scratch["alpha"], StantonSCS1d.scratch["beta"], divisions);
630
 
                        engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",temp);
631
 
                        */
632
 
                        break;
633
 
    }
634
 
}
635
 
 
636
 
/*      Old DaRouter passthru stuff
637
 
StantonSCS1d.platterGrabbed = function (channel, control, value, status) {
638
 
        return;
639
 
    // Ignore if the music speed is outside the motor abilities and the platter is stopped
640
 
    if (StantonSCS1d.state["outsideMotor"]) return;
641
 
    
642
 
    if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] != "vinyl") return;  // Skip if not in vinyl mode
643
 
    if (value == 0x7f) {
644
 
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",0);
645
 
        StantonSCS1d.state["platterGrabbed"]=true;
646
 
        if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play")==1) {
647
 
            engine.setValue("[Channel"+StantonSCS1d.deck+"]","play",0);
648
 
            StantonSCS1d.scratch["wasPlaying"] = true;
649
 
        }
650
 
    }
651
 
    if (value == 0) {
652
 
        //engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",0);
653
 
        //engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",0);
654
 
        StantonSCS1d.state["platterGrabbed"]=false;
655
 
    }
656
 
}
657
 
 
658
 
StantonSCS1d.platterBend = function (channel, control, value, status) {
659
 
        return;
660
 
    // Ignore if the music speed is outside the motor abilities and the platter is stopped
661
 
    if (StantonSCS1d.state["outsideMotor"]) return;
662
 
    
663
 
    //if (!StantonSCS1d.state["platterGrabbed"])
664
 
        engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",(value-64)/63);
665
 
}
666
 
 
667
 
StantonSCS1d.platterScratch = function (channel, control, value, status) {
668
 
        return;
669
 
    // Ignore if the music speed is outside the motor abilities and the platter is stopped
670
 
    if (StantonSCS1d.state["outsideMotor"]) return;
671
 
    
672
 
    var currentMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
673
 
    switch (currentMode) {
674
 
        case "browse":
675
 
            if ((value-64)>0) {
676
 
                engine.setValue("[Playlist]","SelectNextTrack",1);
677
 
            }
678
 
            else {
679
 
                engine.setValue("[Playlist]","SelectPrevTrack",1);
680
 
            }
681
 
            break;
682
 
        case "vinyl":
683
 
            var group = "[Channel"+StantonSCS1d.deck+"]";
684
 
            var jogValue = (value-64)/3;
685
 
            if (engine.getValue(group,"play")==1 && engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
686
 
            
687
 
            var multiplier = StantonSCS1d.scratching["sensitivity"] * (engine.getValue(group,"play") ? 1 : StantonSCS1d.scratching["stoppedMultiplier"] );
688
 
//              if (StantonSCS1d.debug) print("do scratching VALUE:" + value + " jogValue: " + jogValue );
689
 
            engine.setValue(group,"scratch", (engine.getValue(group,"scratch") + (jogValue * multiplier)).toFixed(2));
690
 
            break;
691
 
    }
692
 
    return;
693
 
    //print("Play="+engine.getValue("[Channel"+StantonSCS1d.deck+"]","play")+ " Wheel="+engine.getValue("[Channel"+StantonSCS1d.deck+"]","wheel")+ " Jog="+engine.getValue("[Channel"+StantonSCS1d.deck+"]","jog")+ " Scratch="+engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch"));
694
 
    //engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",engine.getValue("[Channel"+StantonSCS1d.deck+"]","wheel")+(value-64)/63);
695
 
    
696
 
    // From SCS.1m
697
 
    //var jogValue = (value-64)/128; // -64 to +63, - = CCW, + = CW
698
 
 
699
 
    //var group = "[Channel"+StantonSCS1d.deck+"]";
700
 
    //if (engine.getValue(group,"play")==1 && engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
701
 
    //var multiplier = 0.18 * (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play") ? 1 : 2 );
702
 
    //if (StantonSCS1d.debug) print("do scratching VALUE:" + value + " jogValue: " + jogValue + " scratch="+ engine.getValue(group,"scratch"));
703
 
    //engine.setValue(group,"scratch", (engine.getValue(group,"scratch") + (jogValue * multiplier)).toFixed(2));
704
 
    
705
 
    // (33+1/3)/60 /1000
706
 
    
707
 
    var add = ((33+1/3)/60)/100;
708
 
    
709
 
    if (value==0x3d) add = -add;
710
 
 
711
 
    var newPosition = engine.getValue("[Channel"+StantonSCS1d.deck+"]","playposition") + add / engine.getValue("[Channel"+StantonSCS1d.deck+"]",    "duration");
712
 
    engine.setValue("[Channel"+StantonSCS1d.deck+"]","playposition",newPosition);
713
 
}
714
 
 
715
 
StantonSCS1d.scratchDecay = function (value) {
716
 
 
717
 
    // do some scratching
718
 
    //if (StantonSCS1d.debug) print("Scratch deck"+StantonSCS1d.deck+": " + engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch"));
719
 
    
720
 
    //scratch = engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch");
721
 
    //jogDecayRate = StantonSCS1d.slippage * (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play") ? 1 : 0.2 );
722
 
     
723
 
    //if (scratch != 0) {
724
 
    //    if (Math.abs(scratch) > jogDecayRate*0.01) {  
725
 
    //          engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", (scratch * jogDecayRate).toFixed(4));
726
 
    //       } else {
727
 
    //          engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", 0);
728
 
    //       }
729
 
    //    }
730
 
    
731
 
    var scratch = engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch");
732
 
    var jogDecayRate = (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play") ? 0.7 : 0.7 );
733
 
    //print ("Latency="+engine.getValue("[Soundcard]","latency"));
734
 
    
735
 
    //if (StantonSCS1d.debug) print("Scratch deck"+StantonSCS1d.deck+": " + scratch + ", Jog decay rate="+jogDecayRate);
736
 
    
737
 
    // If it was playing, ramp back to playback speed
738
 
    if (StantonSCS1d.scratch["wasPlaying"] && !StantonSCS1d.state["platterGrabbed"]) {
739
 
        var rate = engine.getValue("[Channel"+StantonSCS1d.deck+"]","rate") * engine.getValue("[Channel"+StantonSCS1d.deck+"]","rateRange");
740
 
        var convergeTo = 1+rate;
741
 
        //jogDecayRate = StantonSCS1d.scratching["slippage"] * 0.2;
742
 
        if (scratch != convergeTo) { // Thanks to jusics on IRC for help with this part
743
 
            if (Math.abs(scratch-convergeTo) > jogDecayRate*0.001) {  
744
 
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", (convergeTo + (scratch-convergeTo) * jogDecayRate).toFixed(5));
745
 
                //engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", (scratch + (convergeTo - scratch) / jogDecayRate).toFixed(5));
746
 
            } else {
747
 
                // Once "scratch" has gotten close enough to the play speed, just resume normal playback
748
 
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", 0);
749
 
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","play",1);
750
 
                StantonSCS1d.scratch["wasPlaying"] = false;
751
 
            }
752
 
        }
753
 
    } else
754
 
    if (scratch != 0) { // For regular scratching when stopped or if playing (and ramp down...grabbed functions set scratch=1 and play=0)
755
 
        if (Math.abs(scratch) > jogDecayRate*0.001) {  
756
 
              engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", (scratch * jogDecayRate).toFixed(4));
757
 
           } else {
758
 
              engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", 0);
759
 
           }
760
 
    }
761
 
}
762
 
*/
763
 
 
764
 
// FIXME: use a timer
765
 
StantonSCS1d.lightDelay = function () {
766
 
    var date = new Date();
767
 
    var curDate = null;
768
 
    
769
 
    do { curDate = new Date(); }
770
 
    while(curDate-date < 60);
 
667
            break;
 
668
        case "vinyl":    // Scratching
 
669
            // Ignore if the music speed is outside the motor abilities and the platter is stopped
 
670
            if (StantonSCS1d.state["outsideMotor"]) return;
 
671
            engine.scratchTick(StantonSCS1d.deck,iMoved);
 
672
            break;
 
673
    }
 
674
}
 
675
 
 
676
StantonSCS1d.deckChangeFlash = function (channel, value) {
 
677
    var byte1 = 0x90 + channel;
 
678
    var color=32;   // Green
 
679
    
 
680
    if (StantonSCS1d.deck % 2 == 0) color=64; // Deck select button red
 
681
    
 
682
    StantonSCS1d.state["flashes"]++;
 
683
    
 
684
    if (StantonSCS1d.state["flashes"] % 2 == 0) {
 
685
        midi.sendShortMsg(byte1,64,color); // Deck select button on
 
686
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
 
687
    }
 
688
    else {
 
689
        midi.sendShortMsg(0x80 + channel,64,0); // Deck select button off
 
690
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
 
691
    }
 
692
    
 
693
    if (StantonSCS1d.state["flashes"]>=7) {
 
694
        engine.stopTimer(StantonSCS1d.timer["deckChange"]);
 
695
        StantonSCS1d.timer["deckChange"] = -1;
 
696
        
 
697
        // Finish the deck change
 
698
        StantonSCS1d.DeckChangeFinish(channel);
 
699
        StantonSCS1d.DeckChangeP2(channel, value);  // Call part 2
 
700
    }
771
701
}
772
702
 
773
703
StantonSCS1d.DeckChange = function (channel, control, value, status) {
788
718
    StantonSCS1d.connectKnobSignals(channel,true);   // Disconnect old knob signals & turn off their LEDs
789
719
    StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"]=StantonSCS1d.state["Oldknob"];   // Restore previous mode
790
720
 
791
 
    var newPlatterMode;
792
721
    // If the button's been held down for over a second, stay on the current deck
793
722
    if (new Date() - StantonSCS1d.modifier["deckTime"]>StantonSCS1d.deckChangeWait) {
794
723
        //StantonSCS1d.connectKnobSignals(channel);   // Re-connect (restored) knob signals
795
724
        // Return to appropriate color
796
 
        if (StantonSCS1d.deck==2) midi.sendShortMsg(byte1,control,64); // Deck select button red
 
725
        if (StantonSCS1d.deck % 2 == 0) midi.sendShortMsg(byte1,control,64); // Deck select button red
797
726
        else midi.sendShortMsg(byte1,control,32); // Deck select button green
798
727
    }
799
728
    else {
800
 
                engine.scratchDisable(StantonSCS1d.deck);       // To avoid accidentally stopping the outgoing deck
 
729
        engine.scratchDisable(StantonSCS1d.deck);    // To avoid accidentally stopping the outgoing deck
 
730
        StantonSCS1d.loopEnabled(0);
801
731
        StantonSCS1d.connectDeckSignals(channel,true);    // Disconnect static signals
802
732
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 17, 0xF7]),7); // Extinguish all LEDs
803
 
        
804
 
        if (StantonSCS1d.globalMode) newPlatterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
805
 
        if (StantonSCS1d.deck == 2) {
806
 
            if (StantonSCS1d.debug) print("StantonSCS1d: Switching to deck 1");
807
 
            StantonSCS1d.deck--;
808
 
            midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
809
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
810
 
            // Blank jog character
811
 
            //midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, 0x20, 0xF7]),8);
812
 
                        // Deck number jog character
813
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, '1'.toInt(), 0xF7]),8);
814
 
            if (!StantonSCS1d.fastDeckChange) { // Make flashy lights to signal a deck change
815
 
                                // TODO: Replace this with a timer
816
 
                StantonSCS1d.lightDelay();
817
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
818
 
                midi.sendShortMsg(byte1,control,32); // Deck select button green
819
 
                StantonSCS1d.lightDelay();
820
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
821
 
                midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
822
 
                StantonSCS1d.lightDelay();
823
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
824
 
                midi.sendShortMsg(byte1,control,32); // Deck select button green
825
 
                StantonSCS1d.lightDelay();
826
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
827
 
                midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
828
 
                StantonSCS1d.lightDelay();
829
 
            }
830
 
                        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
831
 
                        midi.sendShortMsg(byte1,control,32); // Deck select button green
832
 
        }
833
 
        else {
834
 
            if (StantonSCS1d.debug) print("StantonSCS1d: Switching to deck 2");
835
 
            StantonSCS1d.deck++;
836
 
            midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
837
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
838
 
            // Blank jog character
839
 
            //midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, 0x20, 0xF7]),8);
840
 
                        // Deck number jog character
841
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, '2'.toInt(), 0xF7]),8);
842
 
            if (!StantonSCS1d.fastDeckChange) { // Make flashy lights to signal a deck change
843
 
                StantonSCS1d.lightDelay();
844
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
845
 
                midi.sendShortMsg(byte1,control,64); // Deck select button red
846
 
                StantonSCS1d.lightDelay();
847
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
848
 
                midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
849
 
                StantonSCS1d.lightDelay();
850
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
851
 
                midi.sendShortMsg(byte1,control,64); // Deck select button red
852
 
                StantonSCS1d.lightDelay();
853
 
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
854
 
                midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
855
 
                StantonSCS1d.lightDelay();
856
 
            }
857
 
                        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
858
 
                        midi.sendShortMsg(byte1,control,64); // Deck select button red
859
 
        }
860
 
        StantonSCS1d.connectDeckSignals(channel);    // Connect static signals
861
 
        StantonSCS1d.padRefresh();  // Light pad section correctly
 
733
        StantonSCS1d.padRefresh();  // Re-light pad section. It's not affected by deck changes.
 
734
        midi.sendShortMsg(0xB0 + channel,2,0x00);    // Clear jog circle
 
735
        if (StantonSCS1d.globalMode)
 
736
            StantonSCS1d.newPlatterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
 
737
        
 
738
        // Supports n-decks
 
739
        if (StantonSCS1d.deck == engine.getValue("[Master]","num_decks")) StantonSCS1d.deck=1;
 
740
        else StantonSCS1d.deck++;
 
741
        
 
742
        if (StantonSCS1d.debug) print("StantonSCS1d: Switching to deck "+StantonSCS1d.deck);
 
743
        midi.sendShortMsg(0x80 + channel,control,0); // Deck select button off
 
744
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 0, 0xF7]),8); // Jog backlight off
 
745
        // Blank jog character
 
746
        //midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, 0x20, 0xF7]),8);
 
747
        // Deck number jog character
 
748
        var deckNr = StantonSCS1d.deck+"";
 
749
        deckNr = deckNr.toInt();
 
750
        if (StantonSCS1d.deck>9) deckNr = 64+(StantonSCS1d.deck-9);
 
751
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 36, deckNr, 0xF7]),8);
 
752
        
 
753
        if (StantonSCS1d.globalMode) StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"] = StantonSCS1d.state["Oldknob"];
 
754
        else StantonSCS1d.newPlatterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
 
755
        
 
756
        StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = ""; // Force mode change
 
757
        
 
758
        // 1st half
 
759
        switch(StantonSCS1d.newPlatterMode) {
 
760
            case "control": 
 
761
                StantonSCS1d.controlButton(channel, StantonSCS1d.buttons["control"], value, 0x90 + channel);
 
762
                break;
 
763
            case "browse": 
 
764
                StantonSCS1d.browseButton(channel, StantonSCS1d.buttons["browse"], value, 0x90 + channel);
 
765
                break;
 
766
            case "vinyl": 
 
767
                StantonSCS1d.vinylButton(channel, StantonSCS1d.buttons["vinyl"], value, 0x90 + channel);
 
768
                break;
 
769
        }
 
770
        
 
771
        // Make flashy lights to signal a deck change
 
772
        if (!StantonSCS1d.fastDeckChange) { 
 
773
            if (StantonSCS1d.timer["deckChange"] != -1) engine.stopTimer(StantonSCS1d.timer["deckChange"]);
 
774
            StantonSCS1d.state["flashes"] = 0;  // initialize number of flashes
 
775
            StantonSCS1d.timer["deckChange"] = engine.beginTimer(60,"StantonSCS1d.deckChangeFlash("+channel+","+value+")");
 
776
            return;
 
777
        }
 
778
        // No flashy lights
 
779
        StantonSCS1d.DeckChangeFinish(channel);
862
780
    }
863
 
    if (StantonSCS1d.globalMode) StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"] = StantonSCS1d.state["Oldknob"];
864
 
    else newPlatterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
 
781
    // Do this even if the deck has not changed
 
782
    StantonSCS1d.DeckChangeP2(channel, value); // Go to part 2.
 
783
}
 
784
 
 
785
StantonSCS1d.DeckChangeFinish = function(channel) {
 
786
    var byte1 = 0x90 + channel;
 
787
    // Finish the deck change
 
788
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
 
789
    if (StantonSCS1d.deck % 2 == 0) midi.sendShortMsg(byte1,64,64); // Deck select button red
 
790
    else midi.sendShortMsg(byte1,64,32); // Deck select button green
 
791
    StantonSCS1d.connectDeckSignals(channel);    // Connect static signals
 
792
    // Update jog circle
 
793
    StantonSCS1d.lastLight[StantonSCS1d.deck]=-1;
 
794
    StantonSCS1d.circleBars(engine.getValue("[Channel"+StantonSCS1d.deck+"]","visual_playposition"));
 
795
}
 
796
 
 
797
StantonSCS1d.DeckChangeP2 = function (channel, value) {
 
798
    
865
799
    
866
800
    StantonSCS1d.connectKnobSignals(channel);   // Connect new knob signals & light LEDs & displays
867
801
    StantonSCS1d.encoderBank(channel, 4, 0, 0x80);  // Light the bank button the correct color for the mode
868
802
    
869
 
    switch(newPlatterMode) {
870
 
        case "control": StantonSCS1d.controlButton(channel, StantonSCS1d.buttons["control"], value, 0x90 + channel); break;
871
 
        case "browse": StantonSCS1d.browseButton(channel, StantonSCS1d.buttons["browse"], value, 0x90 + channel); break;
872
 
        case "vinyl": StantonSCS1d.vinylButton(channel, StantonSCS1d.buttons["vinyl"], value, 0x90 + channel); break;
 
803
    // 2nd half
 
804
    switch(StantonSCS1d.newPlatterMode) {
 
805
        case "control": 
 
806
            StantonSCS1d.controlButton(channel, StantonSCS1d.buttons["control"], value, 0x80 + channel);
 
807
            break;
 
808
        case "browse": 
 
809
            StantonSCS1d.browseButton(channel, StantonSCS1d.buttons["browse"], value, 0x80 + channel);
 
810
            break;
 
811
        case "vinyl": 
 
812
            StantonSCS1d.vinylButton(channel, StantonSCS1d.buttons["vinyl"], value, 0x80 + channel);
 
813
            break;
873
814
    }
874
815
    
875
816
    switch (StantonSCS1d.triggerBank[StantonSCS1d.deck]) {
876
 
        case 1: StantonSCS1d.triggerBankSelect(channel, 22, 1, 0x90); break;
877
 
        case 2: StantonSCS1d.triggerBankSelect(channel, 23, 1, 0x90); break;
878
 
        case 3: StantonSCS1d.triggerBankSelect(channel, 5, 1, 0x90); break;
 
817
        case 1:
 
818
            StantonSCS1d.triggerBank[StantonSCS1d.deck]=-1; // Force LEDs to update
 
819
            StantonSCS1d.triggerBankSelect(channel, 22, 1, 0x90);
 
820
            StantonSCS1d.triggerBankSelect(channel, 22, 1, 0x80);
 
821
            break;
 
822
        case 2: 
 
823
            StantonSCS1d.triggerBankSelect(channel, 23, 1, 0x90);
 
824
            StantonSCS1d.triggerBankSelect(channel, 23, 1, 0x80);
 
825
            break;
 
826
        case 3: 
 
827
            StantonSCS1d.triggerBankSelect(channel, 5, 1, 0x90);
 
828
            StantonSCS1d.triggerBankSelect(channel, 5, 1, 0x80);
 
829
            break;
879
830
    }
880
831
    
881
832
}   // End Deck Change function
888
839
    var newMode = StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"];
889
840
    
890
841
    if ((status & 0xF0) == 0x80) {  // If button up
891
 
        print("Newmode="+newMode);
892
842
        switch (newMode) {
893
843
            case 1:
894
844
                midi.sendShortMsg(0x90+channel,control,32);    // Make button green
912
862
        StantonSCS1d.connectKnobSignals(channel);   // Connect new knob signals & light LEDs & displays
913
863
    }
914
864
    
915
 
    // Use button 1 to toggle the flanger effect if in mode 2 (which adjusts FX params)
916
865
    if (newMode==2) {
917
 
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","flanger","StantonSCS1d.FXLED");
 
866
        // Use button 1 to toggle the flanger effect if in mode 2 (which adjusts FX params)
 
867
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","flanger","StantonSCS1d.knobB1LED");
918
868
        engine.trigger("[Channel"+StantonSCS1d.deck+"]","flanger");
 
869
        // Use button 4 to toggle key lock if in mode 2 (which adjusts FX params)
 
870
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","keylock","StantonSCS1d.knobB4LED");
 
871
        engine.trigger("[Channel"+StantonSCS1d.deck+"]","keylock");
919
872
    }
920
873
    else {
921
 
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","flanger","StantonSCS1d.FXLED",true);
922
 
        midi.sendShortMsg(0x80+channel,0x19,0);    // Turn button off
 
874
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","flanger","StantonSCS1d.knobB1LED",true);
 
875
        midi.sendShortMsg(0x80+channel,25,0);    // Turn button off
 
876
        engine.connectControl("[Channel"+StantonSCS1d.deck+"]","keylock","StantonSCS1d.knobB4LED",true);
 
877
        midi.sendShortMsg(0x80+channel,17,0);    // Turn button off
923
878
    }
924
879
}
925
880
 
1215
1170
                    break;
1216
1171
            }
1217
1172
            break;
1218
 
        case 2: // Pre-fader gain
 
1173
        case 2: // Toggle key lock
 
1174
            switch (status & 0xF0) {
 
1175
                case 0x90:
 
1176
                    engine.setValue("[Channel"+StantonSCS1d.deck+"]","keylock",!engine.getValue("[Channel"+StantonSCS1d.deck+"]","keylock"));
 
1177
                    break;
 
1178
            }
1219
1179
            break;
1220
1180
        case 3: // Master volume momentary kill
1221
1181
            switch (status & 0xF0) {
1281
1241
        midi.sendShortMsg(byte1,23,0x00);
1282
1242
        midi.sendShortMsg(byte1,5,0x00);
1283
1243
        
 
1244
        var lastBank = StantonSCS1d.triggerBank[StantonSCS1d.deck];
1284
1245
        switch (control) {
1285
1246
            case 22: StantonSCS1d.triggerBank[StantonSCS1d.deck]=1; break;
1286
1247
            case 23: StantonSCS1d.triggerBank[StantonSCS1d.deck]=2; break;
1289
1250
        
1290
1251
        byte1 = 0x90 + channel;
1291
1252
        midi.sendShortMsg(byte1,control,0x01); // Turn on active bank button light
1292
 
        
1293
 
        // Light all the buttons since they're all pre-set
1294
 
        for (var i=8; i<=15; i++)
1295
 
            midi.sendShortMsg(byte1,i,0x01); // Turn on button light
1296
 
        for (var i=18; i<=21; i++)
1297
 
            midi.sendShortMsg(byte1,i,0x01); // Turn on button light
1298
 
        
1299
 
        ////  Print evrytinks
1300
 
        //for (var i=8; i<=15; i++) {
1301
 
        //    print ("                <control>\n\
1302
 
        //            <status>0x90</status>\n\
1303
 
        //            <midino>"+i+"</midino>\n\
1304
 
        //            <group>[Master]</group>\n\
1305
 
        //            <key>StantonSCS1d.triggerButton</key>\n\
1306
 
        //            <options>\n\
1307
 
        //                <Script-Binding/>\n\
1308
 
        //            </options>\n\
1309
 
        //        </control>");
1310
 
        //    print ("                <control>\n\
1311
 
        //            <status>0x80</status>\n\
1312
 
        //            <midino>"+i+"</midino>\n\
1313
 
        //            <group>[Master]</group>\n\
1314
 
        //            <key>StantonSCS1d.triggerButton</key>\n\
1315
 
        //            <options>\n\
1316
 
        //                <Script-Binding/>\n\
1317
 
        //            </options>\n\
1318
 
        //        </control>");
1319
 
        //}
1320
 
        //for (var i=18; i<=21; i++) {
1321
 
        //    print ("                <control>\n\
1322
 
        //            <status>0x90</status>\n\
1323
 
        //            <midino>"+i+"</midino>\n\
1324
 
        //            <group>[Master]</group>\n\
1325
 
        //            <key>StantonSCS1d.triggerButton</key>\n\
1326
 
        //            <options>\n\
1327
 
        //                <Script-Binding/>\n\
1328
 
        //            </options>\n\
1329
 
        //        </control>");
1330
 
        //    print ("                <control>\n\
1331
 
        //            <status>0x80</status>\n\
1332
 
        //            <midino>"+i+"</midino>\n\
1333
 
        //            <group>[Master]</group>\n\
1334
 
        //            <key>StantonSCS1d.triggerButton</key>\n\
1335
 
        //            <options>\n\
1336
 
        //                <Script-Binding/>\n\
1337
 
        //            </options>\n\
1338
 
        //        </control>");
1339
 
        //}
 
1253
        StantonSCS1d.modifier["trigger"] = StantonSCS1d.triggerBank[StantonSCS1d.deck];
 
1254
        
 
1255
        // If we've changed banks and the new one is #1, connect the loop signals
 
1256
        if (lastBank != StantonSCS1d.triggerBank[StantonSCS1d.deck] 
 
1257
            && StantonSCS1d.triggerBank[StantonSCS1d.deck]==1) {
 
1258
            StantonSCS1d.connectTrigSignals(channel,false);
 
1259
            StantonSCS1d.loopEnabled(1);
 
1260
        }
 
1261
        // If we've changed banks and the new one is other than #1,
 
1262
        //  disconnect the loop signals & set the LEDs
 
1263
        if (lastBank != StantonSCS1d.triggerBank[StantonSCS1d.deck] 
 
1264
            && StantonSCS1d.triggerBank[StantonSCS1d.deck]!=1) {  // Pitch points
 
1265
            StantonSCS1d.connectTrigSignals(channel,true);
 
1266
            StantonSCS1d.loopEnabled(0);
 
1267
            // Light all the buttons since they're all pre-set
 
1268
            for (var i=8; i<=15; i++)
 
1269
                midi.sendShortMsg(byte1,i,0x01); // Turn on button light
 
1270
            for (var i=18; i<=21; i++)
 
1271
                midi.sendShortMsg(byte1,i,0x01); // Turn on button light
 
1272
        }
 
1273
        
 
1274
        return;
1340
1275
    }
 
1276
    
 
1277
    // If button up
 
1278
    StantonSCS1d.modifier["trigger"] = -1;
1341
1279
}
1342
1280
 
1343
1281
StantonSCS1d.triggerButton = function (channel, control, value, status) {
1344
1282
    
1345
1283
    var byte1 = 0x90 + channel;
 
1284
    var deck = StantonSCS1d.deck;
1346
1285
    
1347
 
    var index = StantonSCS1d.triggerBank[StantonSCS1d.deck];
 
1286
    var index = StantonSCS1d.triggerBank[deck];
1348
1287
    
1349
1288
    if ((status & 0xF0) == 0x90) {    // If button down
1350
 
        midi.sendShortMsg(byte1,control,0x01); // Turn off activated button LED
 
1289
        
 
1290
        if (index == 1) { // bank 1 = Looping
 
1291
            var loopNumber = StantonSCS1d.trigButtonsLoopNr[control];   // For when we get multiple loops
 
1292
            loopNumber = 1; // REMOVE ME for multiple loops
 
1293
            var prevLoopNumber = StantonSCS1d.modifier["loop"+loopNumber];
 
1294
            StantonSCS1d.modifier["loop"+loopNumber] = 1;
 
1295
            // If the current bank select button is held down 
 
1296
            //  when this trigger button is pressed, erase the loop marker for this button
 
1297
            if (!StantonSCS1d.looseLoops && StantonSCS1d.modifier["trigger"]==index) {
 
1298
                if (control % 2 == 0) engine.setValue("[Channel"+deck+"]","loop_start_position",-1);
 
1299
                else engine.setValue("[Channel"+deck+"]","loop_end_position",-1);
 
1300
            }
 
1301
            else if ((!StantonSCS1d.looseLoops && prevLoopNumber == loopNumber)
 
1302
                        || (StantonSCS1d.looseLoops && StantonSCS1d.modifier["trigger"]==index)) {
 
1303
                // If another button is held down corresponding to the same loop as this one,
 
1304
                //  and the in and out points are set, toggle the loop
 
1305
                // Unless in looseLoops mode, where the bank button + a loop button will toggle theloop
 
1306
                if (engine.getValue("[Channel"+deck+"]","loop_start_position") != -1
 
1307
                    && engine.getValue("[Channel"+deck+"]","loop_end_position") != -1) {
 
1308
                    engine.setValue("[Channel"+deck+"]","reloop_exit",1);
 
1309
                    engine.setValue("[Channel"+deck+"]","reloop_exit",0);
 
1310
                }
 
1311
            }
 
1312
            else {
 
1313
                // Set loop marker
 
1314
                // If not in looseLoops mode, only set if it isn't currently
 
1315
                // If in looseLoops mode, set it regardless
 
1316
                if (control % 2 == 0) {
 
1317
                    if (!StantonSCS1d.looseLoops 
 
1318
                        && engine.getValue("[Channel"+deck+"]","loop_start_position") != -1)
 
1319
                        return;
 
1320
                    engine.setValue("[Channel"+deck+"]","loop_in",1);
 
1321
                }
 
1322
                if (control % 2 != 0) {
 
1323
                    if (!StantonSCS1d.looseLoops 
 
1324
                        && engine.getValue("[Channel"+deck+"]","loop_end_position") != -1)
 
1325
                        return;
 
1326
                    engine.setValue("[Channel"+deck+"]","loop_out",1);
 
1327
                }
 
1328
            }
 
1329
        }
 
1330
        else {
 
1331
            midi.sendShortMsg(byte1,control,0x01); // Turn off activated button LED
1351
1332
 
1352
1333
            // Multiple pitch points
1353
1334
            
1356
1337
            //    break;
1357
1338
            //}
1358
1339
            if (StantonSCS1d.pitchPoints[index][control] == -0.1)
1359
 
                StantonSCS1d.pitchPoints[index][control] = engine.getValue("[Channel"+StantonSCS1d.deck+"]","rate");
 
1340
                StantonSCS1d.pitchPoints[index][control] = engine.getValue("[Channel"+deck+"]","rate");
1360
1341
            else {
1361
1342
                // Need 100% range for values to be correct
1362
 
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","rateRange",1.0);
1363
 
                engine.setValue("[Channel"+StantonSCS1d.deck+"]","rate",StantonSCS1d.pitchPoints[index][control]); 
 
1343
                engine.setValue("[Channel"+deck+"]","rateRange",1.0);
 
1344
                engine.setValue("[Channel"+deck+"]","rate",StantonSCS1d.pitchPoints[index][control]); 
1364
1345
            }
 
1346
        }
1365
1347
        return;
1366
1348
    }
1367
 
    midi.sendShortMsg(byte1,control,0x01); // Turn on activated button LED
 
1349
    
 
1350
    // If button up
 
1351
    
 
1352
    if (index == 1) { // bank 1 = Looping
 
1353
        var loopNumber = StantonSCS1d.trigButtonsLoopNr[control];
 
1354
        loopNumber = 1; // REMOVE ME for multiple loops
 
1355
        StantonSCS1d.modifier["loop"+loopNumber] = -1;
 
1356
        if (StantonSCS1d.looseLoops || (!StantonSCS1d.looseLoops && StantonSCS1d.modifier["trigger"]!=index)) {
 
1357
            if (control % 2 == 0) engine.setValue("[Channel"+deck+"]","loop_in",0);
 
1358
            else engine.setValue("[Channel"+deck+"]","loop_out",0);
 
1359
        }
 
1360
    }
 
1361
    else {
 
1362
        midi.sendShortMsg(byte1,control,0x01); // Turn on activated button LED
 
1363
    }
1368
1364
}
1369
1365
 
1370
1366
// ----------   Other buttons  ----------
1392
1388
    StantonSCS1d.state["padCleared"]=true;
1393
1389
    StantonSCS1d.velocityButton(StantonSCS1d.channel,0x34,0,0x80);
1394
1390
    
1395
 
    // For each pad
1396
 
    /*
1397
 
    var deck = StantonSCS1d.padBank["deck"];
1398
 
    var bank = StantonSCS1d.padBank["bank"+deck];
1399
 
    for (i=0; i<=3; i++) {
1400
 
        StantonSCS1d.pad(StantonSCS1d.channel,0x20+i,0,0x80);
1401
 
        // Displays
1402
 
        var message = "Empty";
1403
 
        if (StantonSCS1d.padPoints[deck][bank][0x20+i] != -0.1) {
1404
 
            var trackTime = ((StantonSCS1d.padPoints[deck][bank][0x20+i] * StantonSCS1d.trackDuration[deck])*1000) | 0;  // OR with 0 replaces Math.floor and is faster
1405
 
            message = msecondstominutes(trackTime);
1406
 
        }
1407
 
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 6+i],message.toInt(), 0xF7),7+message.length);   // Set LCD
1408
 
    }
1409
 
    */
1410
 
    
 
1391
    // Darken both pad bank buttons
1411
1392
    StantonSCS1d.padBankButton(StantonSCS1d.channel, 0x35, 0, 0x80);
1412
1393
    StantonSCS1d.padBankButton(StantonSCS1d.channel, 0x36, 0, 0x80);
1413
1394
    
 
1395
    //StantonSCS1d.connectPadSignals(StantonSCS1d.channel,true);
1414
1396
    StantonSCS1d.connectPadSignals(StantonSCS1d.channel);
1415
1397
}
1416
1398
 
1423
1405
    if ((status & 0xF0) == 0x90) {    // If button down
1424
1406
        StantonSCS1d.modifier["pad"]=1;
1425
1407
 
1426
 
                // Multiple cue points
1427
 
                // Mixxx has 31 hot cues. Skip any above that.
1428
 
                
1429
 
                if (hotCue == -1) return;
1430
 
 
1431
 
                if (StantonSCS1d.modifier["velocityToggle"]==1) { // Delete a cue point
1432
 
                        engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_clear",1);
1433
 
                        engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_clear",0);
1434
 
                        StantonSCS1d.state["padCleared"]=true;
1435
 
                        return;
1436
 
                }
1437
 
                
1438
 
                if (StantonSCS1d.padVelocity && engine.getValue("[Channel"+deck+"]","hotcue_"+hotCue+"_enabled"))
1439
 
                        engine.setValue("[Channel"+deck+"]","volume",(value/0x7A));   // 0x7A seems the highest # the unit sends
1440
 
                        
1441
 
                // If hotcue X is set, seeks the player to hotcue X's position.
1442
 
                // If hotcue X is not set, sets hotcue X to the current play position.
1443
 
                engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_activate",1);
1444
 
                
1445
 
 
1446
 
        // Original code
1447
 
        /*
1448
 
        midi.sendShortMsg(byte1,control,127); // Light it orange
 
1408
        // Multiple cue points
 
1409
        // Mixxx has 31 hot cues. Skip any above that.
1449
1410
        
1450
 
        if (StantonSCS1d.modifier["velocityToggle"]==1) {
1451
 
            StantonSCS1d.padPoints[deck][bank][control] = -0.1;   // Erase
1452
 
            var message = "Empty";
1453
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, control-26],message.toInt(), 0xF7),7+message.length);   // Clear LCD
 
1411
        if (hotCue == -1) return;
 
1412
 
 
1413
        if (StantonSCS1d.modifier["velocityToggle"]==1) { // Delete a cue point
 
1414
            engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_clear",1);
 
1415
            engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_clear",0);
1454
1416
            StantonSCS1d.state["padCleared"]=true;
1455
1417
            return;
1456
1418
        }
1457
1419
        
1458
 
        if (StantonSCS1d.padPoints[deck][bank][control] == -0.1) { // Set if blank
1459
 
            StantonSCS1d.padPoints[deck][bank][control] = engine.getValue("[Channel"+deck+"]","playposition");
1460
 
            // Set display with cue point time
1461
 
            // Track time in milliseconds
1462
 
            var trackTime = ((StantonSCS1d.padPoints[deck][bank][control] * StantonSCS1d.trackDuration[deck])*1000) | 0;  // OR with 0 replaces Math.floor and is faster
1463
 
            var message = msecondstominutes(trackTime);
1464
 
            midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, control-26],message.toInt(), 0xF7),7+message.length);   // Set LCD
1465
 
        }
1466
 
        else {
1467
 
            engine.setValue("[Channel"+deck+"]","playposition",StantonSCS1d.padPoints[deck][bank][control]);  // Recall
1468
 
            if (StantonSCS1d.padVelocity) engine.setValue("[Channel"+deck+"]","volume",(value/0x7A));   // 0x7A seems the highest # the unit sends
1469
 
            if (engine.getValue("[Channel"+deck+"]","play") != 1) { // Start the deck playing if it isn't already
1470
 
                engine.setValue("[Channel"+deck+"]","play",1);
1471
 
                if (StantonSCS1d.state["padWasPlaying"]==null) StantonSCS1d.state["padWasPlaying"]=false;
1472
 
            }
1473
 
            else if (StantonSCS1d.state["padWasPlaying"]==null) StantonSCS1d.state["padWasPlaying"]=true;
1474
 
        }
1475
 
        */
 
1420
        if (StantonSCS1d.padVelocity && engine.getValue("[Channel"+deck+"]","hotcue_"+hotCue+"_enabled"))
 
1421
            engine.setValue("[Channel"+deck+"]","volume",(value/0x7A));   // 0x7A seems the highest # the unit sends
 
1422
            
 
1423
        // If hotcue X is set, seeks the player to hotcue X's position.
 
1424
        // If hotcue X is not set, sets hotcue X to the current play position.
 
1425
        engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_activate",1);
1476
1426
        return;
1477
1427
    }
1478
1428
    
1479
1429
    // If button up
1480
1430
    engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_activate",0);
1481
1431
    StantonSCS1d.modifier["pad"]=0;
1482
 
    
1483
 
    // Original code
1484
 
    /*
1485
 
    if (StantonSCS1d.state["padWasPlaying"]==false) engine.setValue("[Channel"+deck+"]","play",0);
1486
 
    StantonSCS1d.state["padWasPlaying"]=null;
1487
 
    StantonSCS1d.modifier["pad"]=0;
1488
 
    
1489
 
    // If a cue point is set, make the pad light red
1490
 
    if (StantonSCS1d.padPoints[deck][bank][control] != -0.1) midi.sendShortMsg(byte1,control,32);
1491
 
    else midi.sendShortMsg(byte1,control,0x00); // If not, darken the pad
1492
 
    */
1493
 
    
 
1432
}
 
1433
 
 
1434
 
 
1435
StantonSCS1d.padTop1 = function (channel, control, value, status) {
 
1436
    // Future use
 
1437
}
 
1438
 
 
1439
StantonSCS1d.padTop2 = function (channel, control, value, status) {
 
1440
 
 
1441
}
 
1442
 
 
1443
StantonSCS1d.padTop3 = function (channel, control, value, status) {
 
1444
 
 
1445
}
 
1446
 
 
1447
StantonSCS1d.padTop4 = function (channel, control, value, status) {
 
1448
 
1494
1449
}
1495
1450
 
1496
1451
StantonSCS1d.velocityButton = function (channel, control, value, status) {
1518
1473
        midi.sendShortMsg(byte1,control,127); // Light it orange
1519
1474
        StantonSCS1d.modifier["padBank"+deck]=1;
1520
1475
        
1521
 
        StantonSCS1d.connectPadSignals(channel,true);   // Disconnect existing signals
 
1476
        StantonSCS1d.connectPadSignals(channel,true);    // Disconnect existing signals
1522
1477
    
1523
1478
        if (StantonSCS1d.padBank["deck"]!=deck) {
1524
1479
            StantonSCS1d.padBank["deck"]=deck;
1531
1486
            
1532
1487
            if (StantonSCS1d.debug) print("PadBank="+StantonSCS1d.padBank["bank"+deck]);
1533
1488
        }
1534
 
        StantonSCS1d.padRefresh();      // Signals connected here
 
1489
        StantonSCS1d.padRefresh();    // Signals connected here
1535
1490
        return;
1536
1491
    }
1537
1492
    else StantonSCS1d.modifier["padBank"+deck]=0;
1566
1521
    else midi.sendShortMsg(CC,1,'1'.toInt());   // 33 RPM foreward
1567
1522
}
1568
1523
 
1569
 
StantonSCS1d.pitchChange = function (value) {
 
1524
StantonSCS1d.pitchChange = function (value,noScratchEnable) {
1570
1525
    var CC = 0xB0 + StantonSCS1d.channel;
 
1526
    var group = "[Channel"+StantonSCS1d.deck+"]";
1571
1527
    
1572
1528
    if (StantonSCS1d.crossFader && StantonSCS1d.modifier["pitchRange"]==1) return; // Skip if adjusting the cross-fader
1573
1529
    if (value < -1 || value > 1) return;  // FIXME: This sometimes happens after using the BPM button to set the tempo and changing the pitch range. We should find out why.
1574
1530
    var now=new Date();
1575
1531
    // Move slider if applicable
1576
1532
    if (now - StantonSCS1d.state["dontMove"]>100) {
1577
 
        if (StantonSCS1d.debug) print ("Moving slider to "+(value*63+64));
 
1533
        if (StantonSCS1d.debug) print ("Moving slider to "+(value*63+64)+" for pitch");
1578
1534
        midi.sendShortMsg(0xB0+StantonSCS1d.channel,0x00,value*63+64);
1579
1535
        }
1580
1536
    
1581
1537
    // Skip motor speed change if fast-forwarding or rewinding
1582
 
    if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","fwd")>0 || engine.getValue("[Channel"+StantonSCS1d.deck+"]","back")>0) return;
 
1538
    if (engine.getValue(group,"fwd")>0 || engine.getValue(group,"back")>0) return;
1583
1539
    
1584
 
    if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","rate_dir") == -1) value = -value; // Take slider direction into account
1585
 
    var multiplier = value * engine.getValue("[Channel"+StantonSCS1d.deck+"]","rateRange");
 
1540
    if (engine.getValue(group,"rate_dir") == -1) value = -value; // Take slider direction into account
 
1541
    var multiplier = value * engine.getValue(group,"rateRange");
1586
1542
    var iMotorPitch = 1000+(1000*multiplier);
1587
1543
    if (iMotorPitch < 500 || iMotorPitch > 2000) {
1588
 
        if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play")>0 && !StantonSCS1d.state["outsideMotor"]) {
 
1544
        if (engine.getValue(group,"play")>0 && !StantonSCS1d.state["outsideMotor"]) {
1589
1545
            if (StantonSCS1d.debug) print ("Stopping platter motor: music speed is outside its abilities");
1590
 
            engine.scratchDisable(StantonSCS1d.deck);   // Disable direct platter control
1591
 
            midi.sendShortMsg(CC,1,'x'.toInt());        // Stop platter
 
1546
            engine.scratchDisable(StantonSCS1d.deck);    // Disable direct platter control
 
1547
            midi.sendShortMsg(CC,1,'x'.toInt());    // Stop platter
1592
1548
        }
1593
1549
        StantonSCS1d.state["outsideMotor"]=true;
1594
1550
        return;
1595
1551
    } else {    // Start the platter since the music speed is within the ability of the motor
1596
1552
        StantonSCS1d.state["outsideMotor"]=false;
1597
 
        if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl" && engine.getValue("[Channel"+StantonSCS1d.deck+"]","play")>0) {
1598
 
                        midi.sendShortMsg(CC,1,'o'.toInt());
1599
 
                        // Re-enable direct platter control
1600
 
                        engine.scratchEnable(StantonSCS1d.deck, StantonSCS1d.scratch["resolution"], StantonSCS1d.rpm[StantonSCS1d.platterSpeed],StantonSCS1d.scratch["alpha"], StantonSCS1d.scratch["beta"]);
1601
 
                }
 
1553
        if (StantonSCS1d.platterMode[group] == "vinyl" && engine.getValue(group,"play")>0) {
 
1554
                midi.sendShortMsg(CC,1,'o'.toInt());
 
1555
                // Re-enable direct platter control
 
1556
                if (noScratchEnable != true)
 
1557
                    engine.scratchEnable(StantonSCS1d.deck, StantonSCS1d.scratch["resolution"],
 
1558
                        StantonSCS1d.rpm[StantonSCS1d.platterSpeed],StantonSCS1d.scratch["alpha"],
 
1559
                        StantonSCS1d.scratch["beta"]);
 
1560
        }
1602
1561
    }
1603
 
    if (iMotorPitch < 500) iMotorPitch = 500;   // Or stop
1604
 
        if (iMotorPitch > 2000) iMotorPitch = 2000;     // Or stop
 
1562
    if (iMotorPitch < 500) iMotorPitch = 500;    // Or stop
 
1563
    if (iMotorPitch > 2000) iMotorPitch = 2000;    // Or stop
1605
1564
    //print("Motor pitch: "+iMotorPitch+" multiplier: "+multiplier);
1606
1565
    
1607
1566
    // Convert for AVR protocol
1608
1567
    iMotorPitch -= 500;
1609
 
        p1 = iMotorPitch  / 1000; 
1610
 
        p2 = (iMotorPitch / 100) % 10;
1611
 
        p3 = (iMotorPitch /  10) % 10;
1612
 
        p4 = (iMotorPitch      ) % 10;
 
1568
    p1 = iMotorPitch  / 1000; 
 
1569
    p2 = (iMotorPitch / 100) % 10;
 
1570
    p3 = (iMotorPitch /  10) % 10;
 
1571
    p4 = (iMotorPitch      ) % 10;
1613
1572
    
1614
1573
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, p1, p2, p3, p4, 0xF7]),11);  // Change motor speed
1615
1574
}
1625
1584
 
1626
1585
StantonSCS1d.playLED = function (value) {
1627
1586
    var CC = 0xB0 + StantonSCS1d.channel;
1628
 
    //if (StantonSCS1d.debug) print ("PlatterGrabbed="+StantonSCS1d.state["platterGrabbed"]);
1629
 
    //if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl" && !StantonSCS1d.state["platterGrabbed"]) {
1630
1587
    if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] == "vinyl") {
1631
1588
        if (value==0) midi.sendShortMsg(CC,1,'x'.toInt());   // Stop platter
1632
1589
        else if (!StantonSCS1d.state["outsideMotor"]) midi.sendShortMsg(CC,1,'o'.toInt());   // Start platter
1633
1590
    }
1634
 
    StantonSCS1d.buttonLED(value, 41, 32, 0x00);    //green
 
1591
    StantonSCS1d.buttonLED(value, 41, 32, 0);    //green
1635
1592
}
1636
1593
 
1637
1594
StantonSCS1d.cueLED = function (value) {
1638
 
    StantonSCS1d.buttonLED(value, 43, 127, 0x00);  //orange
 
1595
    StantonSCS1d.buttonLED(value, 43, 127, 0);  //orange
1639
1596
}
1640
1597
 
1641
1598
StantonSCS1d.syncLED = function (value) {
1642
 
    StantonSCS1d.buttonLED(value, 42, 64, 0x00);    //red
 
1599
    StantonSCS1d.buttonLED(value, 42, 64, 0);    //red
 
1600
}
 
1601
 
 
1602
StantonSCS1d.bpmLED = function (value) {
 
1603
    StantonSCS1d.buttonLED(value, 40, 64, 0);
1643
1604
}
1644
1605
 
1645
1606
StantonSCS1d.backLED = function (value) {
1646
 
    StantonSCS1d.buttonLED(value, 47, 0x7f, 0x00);
 
1607
    StantonSCS1d.buttonLED(value, 47, 0x7f, 0);
1647
1608
}
1648
1609
 
1649
1610
StantonSCS1d.fwdLED = function (value) {
1650
 
    StantonSCS1d.buttonLED(value, 46, 0x7f, 0x00);
 
1611
    StantonSCS1d.buttonLED(value, 46, 0x7f, 0);
1651
1612
}
1652
1613
 
1653
1614
StantonSCS1d.headphoneLED = function (value) {
1654
1615
    StantonSCS1d.buttonLED(value, 55, 0x7f, 32);
1655
1616
}
1656
1617
 
1657
 
StantonSCS1d.FXLED = function (value) {
1658
 
    StantonSCS1d.buttonLED(value, 0x19, 0x7f, 0);
1659
 
}
 
1618
StantonSCS1d.knobB1LED = function (value) {
 
1619
    StantonSCS1d.buttonLED(value, 25, 0x7f, 0);
 
1620
}
 
1621
 
 
1622
StantonSCS1d.knobB4LED = function (value) {
 
1623
    StantonSCS1d.buttonLED(value, 17, 0x7f, 0);
 
1624
}
 
1625
 
 
1626
// Triggers/Loops
 
1627
StantonSCS1d.activateLoop = function (value) {
 
1628
    // In the future for multiple loops, add a loopNum parameter and store that value below.
 
1629
    if (value>0) 
 
1630
        if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","loop_enabled"))
 
1631
            StantonSCS1d.loopActive[StantonSCS1d.deck]=1;
 
1632
        else StantonSCS1d.loopActive[StantonSCS1d.deck]=-1;
 
1633
}
 
1634
 
 
1635
StantonSCS1d.loopEnabled = function (value) {
 
1636
    if (value>0 && StantonSCS1d.timer["loop"]==-1) {
 
1637
        if (StantonSCS1d.loopActive[StantonSCS1d.deck]==-1) StantonSCS1d.activateLoop(1);
 
1638
        StantonSCS1d.timer["loop"] = engine.beginTimer(500,"StantonSCS1d.loopFlash()");
 
1639
    }
 
1640
    
 
1641
    if (value<=0 && StantonSCS1d.timer["loop"]!=-1) {
 
1642
        engine.stopTimer(StantonSCS1d.timer["loop"]);
 
1643
        StantonSCS1d.timer["loop"]=-1;
 
1644
        StantonSCS1d.connectTrigSignals(StantonSCS1d.channel);
 
1645
    }
 
1646
}
 
1647
 
 
1648
StantonSCS1d.loopFlash = function (end) {
 
1649
    var buttons = [0,8,10,12,14,18,20];
 
1650
    var target;
 
1651
    
 
1652
    var activeLoop = StantonSCS1d.loopActive[StantonSCS1d.deck];
 
1653
    if (activeLoop==-1) return;
 
1654
    target = buttons[activeLoop];
 
1655
    if (StantonSCS1d.state["loopFlash"] < 1) {
 
1656
        StantonSCS1d.state["loopFlash"]++;
 
1657
        for (var i=1; i<=6; i++) {  // REMOVE for multiple loops
 
1658
            target = buttons[i];     // REMOVE for multiple loops
 
1659
            StantonSCS1d.buttonLED(1, target, 0x7f, 0);
 
1660
            StantonSCS1d.buttonLED(1, target+1, 0x7f, 0);
 
1661
        }   // REMOVE for multiple loops
 
1662
    }
 
1663
    else {
 
1664
        StantonSCS1d.state["loopFlash"]=0;
 
1665
        for (var i=1; i<=6; i++) {  // REMOVE for multiple loops
 
1666
            target = buttons[i];     // REMOVE for multiple loops
 
1667
            StantonSCS1d.buttonLED(0, target, 0x7f, 0);
 
1668
            StantonSCS1d.buttonLED(0, target+1, 0x7f, 0);
 
1669
        }   // REMOVE for multiple loops
 
1670
    }
 
1671
    
 
1672
}
 
1673
 
 
1674
StantonSCS1d.trigLED = function (value,control) {
 
1675
    if (value == -1) StantonSCS1d.buttonLED(0, control, 0x7f, 0);
 
1676
    else StantonSCS1d.buttonLED(1, control, 0x7f, 0);
 
1677
}
 
1678
 
 
1679
StantonSCS1d.Trig1ILED = function (value) {    StantonSCS1d.trigLED(value, 8); }
 
1680
StantonSCS1d.Trig1OLED = function (value) {    StantonSCS1d.trigLED(value, 9); }
 
1681
StantonSCS1d.Trig2ILED = function (value) {    StantonSCS1d.trigLED(value, 10);}
 
1682
StantonSCS1d.Trig2OLED = function (value) {    StantonSCS1d.trigLED(value, 11);}
 
1683
StantonSCS1d.Trig3ILED = function (value) {    StantonSCS1d.trigLED(value, 12);}
 
1684
StantonSCS1d.Trig3OLED = function (value) {    StantonSCS1d.trigLED(value, 13);}
 
1685
StantonSCS1d.Trig4ILED = function (value) {    StantonSCS1d.trigLED(value, 14);}
 
1686
StantonSCS1d.Trig4OLED = function (value) {    StantonSCS1d.trigLED(value, 15);}
 
1687
StantonSCS1d.Trig5ILED = function (value) {    StantonSCS1d.trigLED(value, 18);}
 
1688
StantonSCS1d.Trig5OLED = function (value) {    StantonSCS1d.trigLED(value, 19);}
 
1689
StantonSCS1d.Trig6ILED = function (value) {    StantonSCS1d.trigLED(value, 20);}
 
1690
StantonSCS1d.Trig6OLED = function (value) {    StantonSCS1d.trigLED(value, 21);}
1660
1691
 
1661
1692
// ---- Hot cues ----
1662
1693
 
1663
1694
// Pad LCDs
1664
1695
 
1665
1696
StantonSCS1d.PadDisplay = function (value, pad) {
1666
 
        // value = hotcue position
1667
 
        var deck = StantonSCS1d.padBank["deck"];
1668
 
        var bank = StantonSCS1d.padBank["bank"+deck];
1669
 
        var hotCue = StantonSCS1d.hotCues[bank][pad];
1670
 
        
1671
 
        var message= "Hotcue"+hotCue;   // If empty, just display hot cue #
1672
 
        
1673
 
        if (value!=-1) {
1674
 
                // Set display with cue point time
1675
 
                var samplerate = engine.getValue("[Channel"+deck+"]","track_samplerate");
1676
 
                var msecs = (value/2/samplerate)*1000 | 0;      // OR with 0 replaces Math.floor and is faster
1677
 
                
1678
 
                // Track time in milliseconds
1679
 
                //var trackTime = ((StantonSCS1d.padPoints[deck][bank][control] * StantonSCS1d.trackDuration[deck])*1000) | 0;  // OR with 0 replaces Math.floor and is faster
1680
 
                //var message = msecondstominutes(trackTime);
1681
 
                message = msecondstominutes(msecs);
1682
 
        }
1683
 
        else {
1684
 
                // Light pad LED on hot cue erase
1685
 
                midi.sendShortMsg(0x90 + StantonSCS1d.channel,pad,127);
1686
 
        }
1687
 
        
1688
 
        // Display value
1689
 
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, pad-26],message.toInt(), 0xF7),7+message.length);
 
1697
    // value = hotcue position
 
1698
    var deck = StantonSCS1d.padBank["deck"];
 
1699
    var bank = StantonSCS1d.padBank["bank"+deck];
 
1700
    var hotCue = StantonSCS1d.hotCues[bank][pad];
 
1701
    
 
1702
    var message= "Hotcue"+(hotCue < 10 ? " " + hotCue : hotCue);    // If empty, just display hot cue #
 
1703
    
 
1704
    if (value!=-1) {
 
1705
        // Set display with cue point time
 
1706
        var samplerate = engine.getValue("[Channel"+deck+"]","track_samplerate");
 
1707
        var msecs = ((value/2/samplerate)*1000) | 0;    // OR with 0 replaces Math.floor and is faster
 
1708
        
 
1709
        // Track time in milliseconds
 
1710
        message = msecondstominutes(msecs);
 
1711
    }
 
1712
    else {
 
1713
        // Light pad LED on hot cue erase
 
1714
        midi.sendShortMsg(0x90 + StantonSCS1d.channel,pad,127);
 
1715
    }
 
1716
    
 
1717
    // Display value
 
1718
    midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, pad-26],message.toInt(), 0xF7),7+message.length);
1690
1719
}
1691
1720
 
1692
1721
StantonSCS1d.Pad1LCD = function (value) { StantonSCS1d.PadDisplay(value,0x20); }
1697
1726
// Pad LEDs
1698
1727
 
1699
1728
StantonSCS1d.PadLED = function (value, pad) {
1700
 
        var deck = StantonSCS1d.padBank["deck"];
1701
 
        var bank = StantonSCS1d.padBank["bank"+deck];
1702
 
        var hotCue = StantonSCS1d.hotCues[bank][pad];
1703
 
        
1704
 
        //print ("Hot cue #"+hotCue+": value="+value+", activated="+activate);
1705
 
 
1706
 
        var color = 0;
1707
 
        
1708
 
        if (value != 0) {       // Activated
1709
 
                color = 127;
1710
 
        }
1711
 
        else {  // Deactivated
1712
 
                if (engine.getValue("[Channel"+deck+"]","hotcue_"+hotCue+"_enabled")==1) color = 32;    // Hot cue set (green)
1713
 
        }
1714
 
        
 
1729
    var deck = StantonSCS1d.padBank["deck"];
 
1730
    var bank = StantonSCS1d.padBank["bank"+deck];
 
1731
    var hotCue = StantonSCS1d.hotCues[bank][pad];
 
1732
    
 
1733
    var color = 0;
 
1734
    
 
1735
    if (value != 0) {    // Activated
 
1736
        color = 127;
 
1737
    }
 
1738
    else {    // Deactivated
 
1739
        if (engine.getValue("[Channel"+deck+"]","hotcue_"+hotCue+"_enabled")==1) color = 32;    // Hot cue set (green)
 
1740
    }
 
1741
    
1715
1742
    midi.sendShortMsg(0x90 + StantonSCS1d.channel,pad,color);
1716
1743
}
1717
1744
 
1920
1947
}
1921
1948
 
1922
1949
StantonSCS1d.durationChange1 = function (value) {
 
1950
    // Stop any leftover end-of-track-flash timers
 
1951
    var deck = 1;
 
1952
    if (StantonSCS1d.timer["15s-d"+deck] != -1) {
 
1953
        engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
 
1954
        StantonSCS1d.timer["15s-d"+deck] = -1;
 
1955
    }
 
1956
    if (StantonSCS1d.timer["30s-d"+deck] != -1) {
 
1957
        engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
 
1958
        StantonSCS1d.timer["30s-d"+deck] = -1;
 
1959
    }
 
1960
    // Make sure jog is lit
 
1961
    if (StantonSCS1d.state["jogFlash"]!=false) {
 
1962
        StantonSCS1d.state["jogFlash"]=false;
 
1963
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 1, 0xF7]),8); // Jog backlight on
 
1964
    }
 
1965
    
1923
1966
    StantonSCS1d.trackDuration[1]=value;
1924
 
    StantonSCS1d.padRefresh();  // Update hot cues
 
1967
    StantonSCS1d.padRefresh();    // Update hot cues
1925
1968
}
1926
1969
 
1927
1970
StantonSCS1d.durationChange2 = function (value) {
 
1971
    // Stop any leftover end-of-track-flash timers
 
1972
    var deck = 2;
 
1973
    if (StantonSCS1d.timer["15s-d"+deck] != -1) {
 
1974
        engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
 
1975
        StantonSCS1d.timer["15s-d"+deck] = -1;
 
1976
    }
 
1977
    if (StantonSCS1d.timer["30s-d"+deck] != -1) {
 
1978
        engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
 
1979
        StantonSCS1d.timer["30s-d"+deck] = -1;
 
1980
    }
 
1981
    // Make sure jog is lit
 
1982
    if (StantonSCS1d.state["jogFlash"]!=false) {
 
1983
        StantonSCS1d.state["jogFlash"]=false;
 
1984
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 1, 0xF7]),8); // Jog backlight on
 
1985
    }
 
1986
    
1928
1987
    StantonSCS1d.trackDuration[2]=value;
1929
 
    StantonSCS1d.padRefresh();  // Update hot cues
 
1988
    StantonSCS1d.padRefresh();    // Update hot cues
 
1989
}
 
1990
 
 
1991
StantonSCS1d.circleFlash = function (deck) {
 
1992
    if (StantonSCS1d.deck != deck) return;  // Only do this for the current deck
 
1993
    if (!StantonSCS1d.state["jogFlash"]) {
 
1994
        StantonSCS1d.state["jogFlash"]=true;
 
1995
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 0, 0xF7]),8); // Jog backlight off
 
1996
    }
 
1997
    else {
 
1998
        StantonSCS1d.state["jogFlash"]=false;
 
1999
        midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 1, 0xF7]),8); // Jog backlight on
 
2000
    }
1930
2001
}
1931
2002
 
1932
2003
StantonSCS1d.circleBars = function (value) {
 
2004
    var deck = StantonSCS1d.deck;
 
2005
 
 
2006
    // Flash the jog back light near the end of the track if the track is longer than 30s
 
2007
    if (StantonSCS1d.trackDuration[deck]>30) {
 
2008
        var trackTimeRemaining = ((1-value) * StantonSCS1d.trackDuration[deck]) | 0;
 
2009
        if (trackTimeRemaining<=30 && trackTimeRemaining>15) {   // If <30s left, flash slowly
 
2010
            if (StantonSCS1d.timer["30s-d"+deck] == -1) {
 
2011
                // Start timer
 
2012
                StantonSCS1d.timer["30s-d"+deck] = engine.beginTimer(500,"StantonSCS1d.circleFlash("+deck+")");
 
2013
                if (StantonSCS1d.timer["15s-d"+deck] != -1) {
 
2014
                    // Stop the 15s timer if it was running
 
2015
                    engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
 
2016
                    StantonSCS1d.timer["15s-d"+deck] = -1;
 
2017
                }
 
2018
            }
 
2019
        } else if (trackTimeRemaining<=15 && trackTimeRemaining>0) { // If <15s left, flash quickly
 
2020
            if (StantonSCS1d.timer["15s-d"+deck] == -1) {
 
2021
                // Start timer
 
2022
                StantonSCS1d.timer["15s-d"+deck] = engine.beginTimer(125,"StantonSCS1d.circleFlash("+deck+")");
 
2023
                if (StantonSCS1d.timer["30s-d"+deck] != -1) {
 
2024
                    // Stop the 30s timer if it was running
 
2025
                    engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
 
2026
                    StantonSCS1d.timer["30s-d"+deck] = -1;
 
2027
                }
 
2028
            }
 
2029
        } else {    // Stop flashing
 
2030
            if (StantonSCS1d.timer["15s-d"+deck] != -1) {
 
2031
                engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
 
2032
                StantonSCS1d.timer["15s-d"+deck] = -1;
 
2033
            }
 
2034
            if (StantonSCS1d.timer["30s-d"+deck] != -1) {
 
2035
                engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
 
2036
                StantonSCS1d.timer["30s-d"+deck] = -1;
 
2037
            }
 
2038
            // Make sure jog is lit
 
2039
            if (StantonSCS1d.state["jogFlash"]!=false) {
 
2040
                StantonSCS1d.state["jogFlash"]=false;
 
2041
                midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 1, 0xF7]),8); // Jog backlight on
 
2042
            }
 
2043
        }
 
2044
    }
 
2045
    
1933
2046
    // Revolution time of the imaginary record in seconds
1934
2047
//     var revtime = StantonSCS1d.scratch["revtime"]/2;    // Use this for two bars
1935
2048
    var revtime = StantonSCS1d.scratch["revtime"];
1936
 
    var currentTrackPos = value * StantonSCS1d.trackDuration[StantonSCS1d.deck];
 
2049
    var currentTrackPos = value * StantonSCS1d.trackDuration[deck];
1937
2050
    
1938
2051
    var revolutions = currentTrackPos/revtime;
1939
2052
//     var light = ((revolutions-(revolutions|0))*18)|0;    // Use this for two bars
1940
2053
    var light = ((revolutions-(revolutions|0))*36)|0;   // OR with 0 replaces Math.floor and is faster
1941
2054
 
1942
 
    if (StantonSCS1d.lastLight[StantonSCS1d.deck]==light) return;   // Don't send light commands if there's no visible change
 
2055
    if (StantonSCS1d.lastLight[deck]==light) return;   // Don't send light commands if there's no visible change
1943
2056
    
1944
2057
    var byte1 = 0xB0 + StantonSCS1d.channel;
1945
2058
    //midi.sendShortMsg(byte1,2,0);     // Clear circle markers
1946
 
    StantonSCS1d.lastLight[StantonSCS1d.deck]=light;
 
2059
    StantonSCS1d.lastLight[deck]=light;
1947
2060
    midi.sendShortMsg(byte1,2,light+1);
1948
2061
//     midi.sendShortMsg(byte1,2,18+light);   // Add this for two bars
1949
2062
}
1950
2063
 
1951
2064
/*
1952
2065
TODO:
1953
 
- Add looping controls
1954
 
- If in Browse mode, press Browse again to change category (Playlists, Crates, etc.)
1955
 
 
1956
2066
- Motor calibration option (would be really nice to have GUI interaction for this)
1957
2067
- Wait for motor to stop in-between mode/deck changes
1958
 
- Wait for motor to get to speed before changing to vinyl mode
 
2068
- Wait for motor to get to speed before latching on when pressing CUE or PLAY (soft-takeover! :) )
1959
2069
- Stop motor on FF/REW? If not, FF/REW only at motor speed?
1960
 
 
1961
 
- Use timers for flashy deck change lights
1962
 
- End-of-track warning flash
1963
 
 
1964
 
- Extend .rangeButton*() to work with arbitrary-length pitchRanges array
 
2070
- Connect cross-fader signal?
1965
2071
 
1966
2072
BUGS:
1967
 
- Window dragging screws up speed - use timestamps
 
2073
- Dragging the window/tooltips screw up speed - use timestamps
1968
2074
- Sticker drift - timestamps?
1969
 
- Changing pitch makes speed jiggly - timestamps??
 
2075
- Manipulating other controls in vinyl mode makes speed jiggly - timestamps??
 
2076
 
 
2077
- Pads get stuck in playback mode when you rapid-fire hammer them
1970
2078
*/
 
 
b'\\ No newline at end of file'