30
27
StantonSCS1d.buttons = { "control":27, "browse":28, "vinyl":29, "deckSelect":64 };
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
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
// 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"] ],
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"] ] ];
132
146
// ---------- Functions ----------
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];
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);
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
418
var command = signalList[i][2]+"("+engine.getValue(group,signalList[i][1])+")";
419
//print("StantonSCS1d: command="+command);
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]);
427
// If disconnecting signals, darken the button LEDs
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);
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]);
374
447
// If connecting a signal, update the LEDs
375
448
if (!disconnect) {
378
var currentValue = engine.getValue(group,name);
379
// print("StantonSCS1d: current value="+currentValue);
380
StantonSCS1d.playLED(currentValue);
451
var currentValue = engine.getValue(group,name);
452
// print("StantonSCS1d: current value="+currentValue);
453
StantonSCS1d.playLED(currentValue);
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
387
var command = signalList[i][2]+"("+engine.getValue(group,name)+")";
388
// print("StantonSCS1d: command="+command);
460
var command = signalList[i][2]+"("+engine.getValue(group,name)+")";
461
// print("StantonSCS1d: command="+command);
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);
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);
576
//if (StantonSCS1d.debug) print("Timestamp="+iTimeStamp+" Quad="+iQuad+" Dir="+iDirection+" Info="+iInfo+" Delta="+(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]));
578
// // Timestamp range: 131071812 - 130547712 = 524,100
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"]);
587
if (StantonSCS1d.debug)
588
print("Timestamp="+iTimeStamp+" State="+iState+" Moved="+iMoved+" Speed="+(iSpeed*60000|0));
590
StantonSCS1d.scratch["prevTimeStamp"] = iTimeStamp;
591
StantonSCS1d.scratch["prevState"] = iState;
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);
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);
636
//if (StantonSCS1d.debug) print("Timestamp="+iTimeStamp+" Quad="+iQuad+" Dir="+iDirection+" Info="+iInfo+" Delta="+(iTimeStamp - StantonSCS1d.scratch["prevTimeStamp"]));
638
// // Timestamp range: 131071812 - 130547712 = 524,100
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"]);
647
//if (StantonSCS1d.debug)
648
// print("Timestamp="+iTimeStamp+" State="+iState+" Moved="+iMoved+" Speed="+(iSpeed*60000|0));
650
StantonSCS1d.scratch["prevTimeStamp"] = iTimeStamp;
651
StantonSCS1d.scratch["prevState"] = iState;
655
var platterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
597
657
switch(platterMode) {
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);
606
666
else StantonSCS1d.state["browseTicks"]++;
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;
612
// TODO: Remember to take into account default platter speed!
613
// (StantonSCS1d.platterSpeed: 0=33 RPM, 1=45 RPM)
615
engine.scratchTick(StantonSCS1d.deck,iMoved);
618
if (iDirection==1) engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",1);
619
else engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",-0.5);
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"]);
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);
636
/* Old DaRouter passthru stuff
637
StantonSCS1d.platterGrabbed = function (channel, control, value, status) {
639
// Ignore if the music speed is outside the motor abilities and the platter is stopped
640
if (StantonSCS1d.state["outsideMotor"]) return;
642
if (StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] != "vinyl") return; // Skip if not in vinyl mode
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;
652
//engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",0);
653
//engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch",0);
654
StantonSCS1d.state["platterGrabbed"]=false;
658
StantonSCS1d.platterBend = function (channel, control, value, status) {
660
// Ignore if the music speed is outside the motor abilities and the platter is stopped
661
if (StantonSCS1d.state["outsideMotor"]) return;
663
//if (!StantonSCS1d.state["platterGrabbed"])
664
engine.setValue("[Channel"+StantonSCS1d.deck+"]","wheel",(value-64)/63);
667
StantonSCS1d.platterScratch = function (channel, control, value, status) {
669
// Ignore if the music speed is outside the motor abilities and the platter is stopped
670
if (StantonSCS1d.state["outsideMotor"]) return;
672
var currentMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
673
switch (currentMode) {
676
engine.setValue("[Playlist]","SelectNextTrack",1);
679
engine.setValue("[Playlist]","SelectPrevTrack",1);
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);
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));
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);
697
//var jogValue = (value-64)/128; // -64 to +63, - = CCW, + = CW
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));
707
var add = ((33+1/3)/60)/100;
709
if (value==0x3d) add = -add;
711
var newPosition = engine.getValue("[Channel"+StantonSCS1d.deck+"]","playposition") + add / engine.getValue("[Channel"+StantonSCS1d.deck+"]", "duration");
712
engine.setValue("[Channel"+StantonSCS1d.deck+"]","playposition",newPosition);
715
StantonSCS1d.scratchDecay = function (value) {
717
// do some scratching
718
//if (StantonSCS1d.debug) print("Scratch deck"+StantonSCS1d.deck+": " + engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch"));
720
//scratch = engine.getValue("[Channel"+StantonSCS1d.deck+"]","scratch");
721
//jogDecayRate = StantonSCS1d.slippage * (engine.getValue("[Channel"+StantonSCS1d.deck+"]","play") ? 1 : 0.2 );
723
//if (scratch != 0) {
724
// if (Math.abs(scratch) > jogDecayRate*0.01) {
725
// engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", (scratch * jogDecayRate).toFixed(4));
727
// engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", 0);
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"));
735
//if (StantonSCS1d.debug) print("Scratch deck"+StantonSCS1d.deck+": " + scratch + ", Jog decay rate="+jogDecayRate);
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));
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;
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));
758
engine.setValue("[Channel"+StantonSCS1d.deck+"]","scratch", 0);
764
// FIXME: use a timer
765
StantonSCS1d.lightDelay = function () {
766
var date = new Date();
769
do { curDate = new Date(); }
770
while(curDate-date < 60);
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);
676
StantonSCS1d.deckChangeFlash = function (channel, value) {
677
var byte1 = 0x90 + channel;
678
var color=32; // Green
680
if (StantonSCS1d.deck % 2 == 0) color=64; // Deck select button red
682
StantonSCS1d.state["flashes"]++;
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
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
693
if (StantonSCS1d.state["flashes"]>=7) {
694
engine.stopTimer(StantonSCS1d.timer["deckChange"]);
695
StantonSCS1d.timer["deckChange"] = -1;
697
// Finish the deck change
698
StantonSCS1d.DeckChangeFinish(channel);
699
StantonSCS1d.DeckChangeP2(channel, value); // Call part 2
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
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
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
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");
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();
830
midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
831
midi.sendShortMsg(byte1,control,32); // Deck select button green
834
if (StantonSCS1d.debug) print("StantonSCS1d: Switching to deck 2");
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();
857
midi.sendSysexMsg(StantonSCS1d.sysex.concat([channel, 13, 1, 0xF7]),8); // Jog backlight on
858
midi.sendShortMsg(byte1,control,64); // Deck select button red
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+"]"];
739
if (StantonSCS1d.deck == engine.getValue("[Master]","num_decks")) StantonSCS1d.deck=1;
740
else StantonSCS1d.deck++;
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);
753
if (StantonSCS1d.globalMode) StantonSCS1d.knobMode["[Channel"+StantonSCS1d.deck+"]"] = StantonSCS1d.state["Oldknob"];
754
else StantonSCS1d.newPlatterMode = StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"];
756
StantonSCS1d.platterMode["[Channel"+StantonSCS1d.deck+"]"] = ""; // Force mode change
759
switch(StantonSCS1d.newPlatterMode) {
761
StantonSCS1d.controlButton(channel, StantonSCS1d.buttons["control"], value, 0x90 + channel);
764
StantonSCS1d.browseButton(channel, StantonSCS1d.buttons["browse"], value, 0x90 + channel);
767
StantonSCS1d.vinylButton(channel, StantonSCS1d.buttons["vinyl"], value, 0x90 + channel);
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+")");
779
StantonSCS1d.DeckChangeFinish(channel);
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.
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
793
StantonSCS1d.lastLight[StantonSCS1d.deck]=-1;
794
StantonSCS1d.circleBars(engine.getValue("[Channel"+StantonSCS1d.deck+"]","visual_playposition"));
797
StantonSCS1d.DeckChangeP2 = function (channel, value) {
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
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;
804
switch(StantonSCS1d.newPlatterMode) {
806
StantonSCS1d.controlButton(channel, StantonSCS1d.buttons["control"], value, 0x80 + channel);
809
StantonSCS1d.browseButton(channel, StantonSCS1d.buttons["browse"], value, 0x80 + channel);
812
StantonSCS1d.vinylButton(channel, StantonSCS1d.buttons["vinyl"], value, 0x80 + channel);
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;
818
StantonSCS1d.triggerBank[StantonSCS1d.deck]=-1; // Force LEDs to update
819
StantonSCS1d.triggerBankSelect(channel, 22, 1, 0x90);
820
StantonSCS1d.triggerBankSelect(channel, 22, 1, 0x80);
823
StantonSCS1d.triggerBankSelect(channel, 23, 1, 0x90);
824
StantonSCS1d.triggerBankSelect(channel, 23, 1, 0x80);
827
StantonSCS1d.triggerBankSelect(channel, 5, 1, 0x90);
828
StantonSCS1d.triggerBankSelect(channel, 5, 1, 0x80);
881
832
} // End Deck Change function
1290
1251
byte1 = 0x90 + channel;
1291
1252
midi.sendShortMsg(byte1,control,0x01); // Turn on active bank button light
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
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\
1307
// <Script-Binding/>\n\
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\
1316
// <Script-Binding/>\n\
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\
1327
// <Script-Binding/>\n\
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\
1336
// <Script-Binding/>\n\
1253
StantonSCS1d.modifier["trigger"] = StantonSCS1d.triggerBank[StantonSCS1d.deck];
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);
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
1278
StantonSCS1d.modifier["trigger"] = -1;
1343
1281
StantonSCS1d.triggerButton = function (channel, control, value, status) {
1345
1283
var byte1 = 0x90 + channel;
1284
var deck = StantonSCS1d.deck;
1347
var index = StantonSCS1d.triggerBank[StantonSCS1d.deck];
1286
var index = StantonSCS1d.triggerBank[deck];
1349
1288
if ((status & 0xF0) == 0x90) { // If button down
1350
midi.sendShortMsg(byte1,control,0x01); // Turn off activated button LED
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);
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);
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)
1320
engine.setValue("[Channel"+deck+"]","loop_in",1);
1322
if (control % 2 != 0) {
1323
if (!StantonSCS1d.looseLoops
1324
&& engine.getValue("[Channel"+deck+"]","loop_end_position") != -1)
1326
engine.setValue("[Channel"+deck+"]","loop_out",1);
1331
midi.sendShortMsg(byte1,control,0x01); // Turn off activated button LED
1352
1333
// Multiple pitch points
1423
1405
if ((status & 0xF0) == 0x90) { // If button down
1424
1406
StantonSCS1d.modifier["pad"]=1;
1426
// Multiple cue points
1427
// Mixxx has 31 hot cues. Skip any above that.
1429
if (hotCue == -1) return;
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;
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
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);
1448
midi.sendShortMsg(byte1,control,127); // Light it orange
1408
// Multiple cue points
1409
// Mixxx has 31 hot cues. Skip any above that.
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;
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;
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
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;
1473
else if (StantonSCS1d.state["padWasPlaying"]==null) StantonSCS1d.state["padWasPlaying"]=true;
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
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);
1479
1429
// If button up
1480
1430
engine.setValue("[Channel"+deck+"]","hotcue_"+hotCue+"_activate",0);
1481
1431
StantonSCS1d.modifier["pad"]=0;
1485
if (StantonSCS1d.state["padWasPlaying"]==false) engine.setValue("[Channel"+deck+"]","play",0);
1486
StantonSCS1d.state["padWasPlaying"]=null;
1487
StantonSCS1d.modifier["pad"]=0;
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
1435
StantonSCS1d.padTop1 = function (channel, control, value, status) {
1439
StantonSCS1d.padTop2 = function (channel, control, value, status) {
1443
StantonSCS1d.padTop3 = function (channel, control, value, status) {
1447
StantonSCS1d.padTop4 = function (channel, control, value, status) {
1496
1451
StantonSCS1d.velocityButton = function (channel, control, value, status) {
1566
1521
else midi.sendShortMsg(CC,1,'1'.toInt()); // 33 RPM foreward
1569
StantonSCS1d.pitchChange = function (value) {
1524
StantonSCS1d.pitchChange = function (value,noScratchEnable) {
1570
1525
var CC = 0xB0 + StantonSCS1d.channel;
1526
var group = "[Channel"+StantonSCS1d.deck+"]";
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);
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;
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
1593
1549
StantonSCS1d.state["outsideMotor"]=true;
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"]);
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"]);
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);
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;
1614
1573
midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 35, p1, p2, p3, p4, 0xF7]),11); // Change motor speed
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
1634
StantonSCS1d.buttonLED(value, 41, 32, 0x00); //green
1591
StantonSCS1d.buttonLED(value, 41, 32, 0); //green
1637
1594
StantonSCS1d.cueLED = function (value) {
1638
StantonSCS1d.buttonLED(value, 43, 127, 0x00); //orange
1595
StantonSCS1d.buttonLED(value, 43, 127, 0); //orange
1641
1598
StantonSCS1d.syncLED = function (value) {
1642
StantonSCS1d.buttonLED(value, 42, 64, 0x00); //red
1599
StantonSCS1d.buttonLED(value, 42, 64, 0); //red
1602
StantonSCS1d.bpmLED = function (value) {
1603
StantonSCS1d.buttonLED(value, 40, 64, 0);
1645
1606
StantonSCS1d.backLED = function (value) {
1646
StantonSCS1d.buttonLED(value, 47, 0x7f, 0x00);
1607
StantonSCS1d.buttonLED(value, 47, 0x7f, 0);
1649
1610
StantonSCS1d.fwdLED = function (value) {
1650
StantonSCS1d.buttonLED(value, 46, 0x7f, 0x00);
1611
StantonSCS1d.buttonLED(value, 46, 0x7f, 0);
1653
1614
StantonSCS1d.headphoneLED = function (value) {
1654
1615
StantonSCS1d.buttonLED(value, 55, 0x7f, 32);
1657
StantonSCS1d.FXLED = function (value) {
1658
StantonSCS1d.buttonLED(value, 0x19, 0x7f, 0);
1618
StantonSCS1d.knobB1LED = function (value) {
1619
StantonSCS1d.buttonLED(value, 25, 0x7f, 0);
1622
StantonSCS1d.knobB4LED = function (value) {
1623
StantonSCS1d.buttonLED(value, 17, 0x7f, 0);
1627
StantonSCS1d.activateLoop = function (value) {
1628
// In the future for multiple loops, add a loopNum parameter and store that value below.
1630
if (engine.getValue("[Channel"+StantonSCS1d.deck+"]","loop_enabled"))
1631
StantonSCS1d.loopActive[StantonSCS1d.deck]=1;
1632
else StantonSCS1d.loopActive[StantonSCS1d.deck]=-1;
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()");
1641
if (value<=0 && StantonSCS1d.timer["loop"]!=-1) {
1642
engine.stopTimer(StantonSCS1d.timer["loop"]);
1643
StantonSCS1d.timer["loop"]=-1;
1644
StantonSCS1d.connectTrigSignals(StantonSCS1d.channel);
1648
StantonSCS1d.loopFlash = function (end) {
1649
var buttons = [0,8,10,12,14,18,20];
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
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
1674
StantonSCS1d.trigLED = function (value,control) {
1675
if (value == -1) StantonSCS1d.buttonLED(0, control, 0x7f, 0);
1676
else StantonSCS1d.buttonLED(1, control, 0x7f, 0);
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);}
1661
1692
// ---- Hot cues ----
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];
1671
var message= "Hotcue"+hotCue; // If empty, just display hot cue #
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
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);
1684
// Light pad LED on hot cue erase
1685
midi.sendShortMsg(0x90 + StantonSCS1d.channel,pad,127);
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];
1702
var message= "Hotcue"+(hotCue < 10 ? " " + hotCue : hotCue); // If empty, just display hot cue #
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
1709
// Track time in milliseconds
1710
message = msecondstominutes(msecs);
1713
// Light pad LED on hot cue erase
1714
midi.sendShortMsg(0x90 + StantonSCS1d.channel,pad,127);
1718
midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, pad-26],message.toInt(), 0xF7),7+message.length);
1692
1721
StantonSCS1d.Pad1LCD = function (value) { StantonSCS1d.PadDisplay(value,0x20); }
1922
1949
StantonSCS1d.durationChange1 = function (value) {
1950
// Stop any leftover end-of-track-flash timers
1952
if (StantonSCS1d.timer["15s-d"+deck] != -1) {
1953
engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
1954
StantonSCS1d.timer["15s-d"+deck] = -1;
1956
if (StantonSCS1d.timer["30s-d"+deck] != -1) {
1957
engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
1958
StantonSCS1d.timer["30s-d"+deck] = -1;
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
1923
1966
StantonSCS1d.trackDuration[1]=value;
1924
StantonSCS1d.padRefresh(); // Update hot cues
1967
StantonSCS1d.padRefresh(); // Update hot cues
1927
1970
StantonSCS1d.durationChange2 = function (value) {
1971
// Stop any leftover end-of-track-flash timers
1973
if (StantonSCS1d.timer["15s-d"+deck] != -1) {
1974
engine.stopTimer(StantonSCS1d.timer["15s-d"+deck]);
1975
StantonSCS1d.timer["15s-d"+deck] = -1;
1977
if (StantonSCS1d.timer["30s-d"+deck] != -1) {
1978
engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
1979
StantonSCS1d.timer["30s-d"+deck] = -1;
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
1928
1987
StantonSCS1d.trackDuration[2]=value;
1929
StantonSCS1d.padRefresh(); // Update hot cues
1988
StantonSCS1d.padRefresh(); // Update hot cues
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
1998
StantonSCS1d.state["jogFlash"]=false;
1999
midi.sendSysexMsg(StantonSCS1d.sysex.concat([StantonSCS1d.channel, 13, 1, 0xF7]),8); // Jog backlight on
1932
2003
StantonSCS1d.circleBars = function (value) {
2004
var deck = StantonSCS1d.deck;
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) {
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;
2019
} else if (trackTimeRemaining<=15 && trackTimeRemaining>0) { // If <15s left, flash quickly
2020
if (StantonSCS1d.timer["15s-d"+deck] == -1) {
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;
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;
2034
if (StantonSCS1d.timer["30s-d"+deck] != -1) {
2035
engine.stopTimer(StantonSCS1d.timer["30s-d"+deck]);
2036
StantonSCS1d.timer["30s-d"+deck] = -1;
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
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];
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
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
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
1953
- Add looping controls
1954
- If in Browse mode, press Browse again to change category (Playlists, Crates, etc.)
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?
1961
- Use timers for flashy deck change lights
1962
- End-of-track warning flash
1964
- Extend .rangeButton*() to work with arbitrary-length pitchRanges array
2070
- Connect cross-fader signal?
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??
2077
- Pads get stuck in playback mode when you rapid-fire hammer them
b'\\ No newline at end of file'