Merge lp:~mixxxdevelopers/mixxx/fixes_scratch into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Albert Santoni
Status: Merged
Merge reported by: Albert Santoni
Merged at revision: not available
Proposed branch: lp:~mixxxdevelopers/mixxx/fixes_scratch
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 533 lines (+130/-93)
5 files modified
mixxx/res/midi/Stanton-SCS3d-scripts.js (+56/-55)
mixxx/res/midi/midi-mappings-scripts.js (+38/-18)
mixxx/src/controlvaluedelegate.cpp (+1/-0)
mixxx/src/engine/ratecontrol.cpp (+33/-19)
mixxx/src/engine/ratecontrol.h (+2/-1)
To merge this branch: bzr merge lp:~mixxxdevelopers/mixxx/fixes_scratch
Reviewer Review Type Date Requested Status
Albert Santoni Approve
Review via email: mp+24234@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Albert Santoni (gamegod) wrote :

Needs testing with SCS.3d and vinyl control.

2363. By Sean M. Pappalardo

- Added new behavior flag to common scripts so old behavior can still work seamlessly, SCS.3d script uses new (This flag will be removed after the deprecation period)
- Fixed variable naming errors in common scripts!
- Added line breaks to long print lines

Revision history for this message
Albert Santoni (gamegod) wrote :

Changes to the engine are minimal. Approving...

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/res/midi/Stanton-SCS3d-scripts.js'
2--- mixxx/res/midi/Stanton-SCS3d-scripts.js 2010-03-06 21:46:14 +0000
3+++ mixxx/res/midi/Stanton-SCS3d-scripts.js 2010-04-29 07:06:29 +0000
4@@ -23,9 +23,8 @@
5 StantonSCS3d.deckChangeWait = 1000; // Time in milliseconds to hold the DECK button down to avoid changing decks (multi deck mode)
6
7 // 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.)
8-StantonSCS3d.scratching = { "slippage":0.8, // Slipperiness of the virtual slipmat when scratching with the circle (higher=slower response, 0<n<1)
9- "sensitivity":0.2, // How much the audio moves for a given circle arc (higher=faster response, 0<n<1)
10- "stoppedMultiplier":1.7 }; // Correction for when the deck is stopped (set higher for higher latencies)
11+StantonSCS3d.scratching = { "slippage":0.7, // Slipperiness of the virtual slipmat when scratching with the circle (higher=slower response, 0<n<1)
12+ "sensitivity":0.2 }; // How much the audio moves for a given circle arc (higher=faster response, 0<n<1)
13
14 // ---------- Other global variables ----------
15 StantonSCS3d.debug = false; // Enable/disable debugging messages to the console
16@@ -47,7 +46,7 @@
17 StantonSCS3d.surface = { "C1":0x00, "S5":0x01, "S3":0x02, "S3+S5":0x03, "Buttons":0x04 };
18 StantonSCS3d.sysex = [0xF0, 0x00, 0x01, 0x60]; // Preamble for all SysEx messages for this device
19 // Variables used in the scratching alpha-beta filter: (revtime = 1.8 to start)
20-StantonSCS3d.scratch = { "revtime":1.8, "alpha":0.1, "beta":1.0, "touching":false };
21+StantonSCS3d.scratch = { "revtime":4.0, "alpha":0.1, "beta":1.0, "touching":false };
22 StantonSCS3d.trackDuration = [0,0]; // Duration of the song on each deck (used for vinyl LEDs)
23 StantonSCS3d.lastLight = [-1,-1]; // Last circle LED values
24 StantonSCS3d.lastLoop = 0; // Last-used loop LED
25@@ -667,11 +666,8 @@
26 case "vinyl":
27 case "vinyl2":
28 // So we don't get stuck at some strange speed when switching from a scratching mode
29- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", 0);
30- if (StantonSCS3d.scratch["wasPlaying"]) { // to avoid getting stuck stopped
31- engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",1);
32- StantonSCS3d.scratch["wasPlaying"] = false;
33- }
34+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 0);
35+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", 0);
36 break;
37 case "loop2":
38 case "loop3":
39@@ -855,11 +851,9 @@
40 StantonSCS3d.modifier["deck"]=0; // Clear button modifier flag
41 StantonSCS3d.connectSurfaceSignals(channel,true); // Disconnect surface signals & turn off surface LEDs
42 StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"] = StantonSCS3d.state["deckPrev"];
43- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", 0); // To avoid getting stuck at a weird speed
44- if (StantonSCS3d.scratch["wasPlaying"]) { // to avoid the deck stopping
45- engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",1);
46- StantonSCS3d.scratch["wasPlaying"] = false;
47- }
48+ // To avoid getting stuck at a weird speed
49+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 0);
50+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", 0);
51 var newMode;
52 // In default multiple-deck mode,
53 // If the button's been held down for longer than the specified time, stay on the current deck.
54@@ -960,12 +954,12 @@
55 if (currentMode=="vinyl2" && StantonSCS3d.vinyl2ScratchMethod=="pp") {
56 var group = "[Channel"+StantonSCS3d.deck+"]";
57 var jogValue = (value-64);
58- if (engine.getValue(group,"play")==1 && engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
59+ if (engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
60
61- var multiplier = StantonSCS3d.scratching["sensitivity"] * (engine.getValue(group,"play") ? 1 : StantonSCS3d.scratching["stoppedMultiplier"] );
62+ var multiplier = StantonSCS3d.scratching["sensitivity"]/2;
63 // if (StantonSCS3d.debug) print("do scratching VALUE:" + value + " jogValue: " + jogValue );
64 multiplier = multiplier * 0.5; // Reduce sensitivity of the slider since it's lower res
65- engine.setValue(group,"scratch", (engine.getValue(group,"scratch") + (jogValue * multiplier)).toFixed(2));
66+ engine.setValue(group,"scratch2", (engine.getValue(group,"scratch2") + (jogValue * multiplier)).toFixed(2));
67 }
68 }
69
70@@ -996,12 +990,12 @@
71 var byte1 = 0xB0 + channel;
72 midi.sendShortMsg(byte1,0x01,add); //S4 LEDs
73 if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=1) midi.sendShortMsg(byte1,0x0C,add); //S3 LEDs
74- if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=2)midi.sendShortMsg(byte1,0x0E,add); //S5 LEDs
75+ if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=2) midi.sendShortMsg(byte1,0x0E,add); //S5 LEDs
76
77 if (currentMode=="vinyl" || StantonSCS3d.vinyl2ScratchMethod == "a-b") { // this is only for the alpha-beta filter implementation
78 // Call global scratch slider function
79 var newScratchValue = scratch.slider(StantonSCS3d.deck, value, StantonSCS3d.scratch["revtime"], StantonSCS3d.scratch["alpha"], StantonSCS3d.scratch["beta"]);
80- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch",newScratchValue);
81+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",newScratchValue);
82 }
83 break;
84 case "loop2":
85@@ -1081,13 +1075,12 @@
86 switch (currentMode) {
87 // case "vinyl":
88 case "vinyl2":
89- if (StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.enable(StantonSCS3d.deck);
90+ if (StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.enable(StantonSCS3d.deck, true);
91 else {
92 StantonSCS3d.scratch["touching"] = true;
93+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 1);
94 if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1) {
95- engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",0);
96- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch",(1+engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch"))); // So it ramps down when you touch
97- StantonSCS3d.scratch["wasPlaying"] = true;
98+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",(1+engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch2"))); // So it ramps down when you touch
99 }
100 }
101 break;
102@@ -1098,7 +1091,9 @@
103 case "vinyl": break;
104 case "vinyl2":
105 if (StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.disable(StantonSCS3d.deck);
106- else StantonSCS3d.scratch["touching"] = false;
107+ else {
108+ StantonSCS3d.scratch["touching"] = false;
109+ }
110 break;
111 default: midi.sendShortMsg(byte1,0x62,0x00); // Turn off C1 lights
112 break;
113@@ -1143,13 +1138,14 @@
114 switch (currentMode) {
115 case "vinyl": // Store scratch info the point it was touched
116 case "vinyl2":
117- if (currentMode=="vinyl" || StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.enable(StantonSCS3d.deck);
118+ if (currentMode=="vinyl" || StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.enable(StantonSCS3d.deck, true);
119 else {
120 StantonSCS3d.scratch["touching"] = true;
121+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 1);
122 if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1) {
123- engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",0);
124- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch",(1+engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch"))); // So it ramps down when you touch
125- StantonSCS3d.scratch["wasPlaying"] = true;
126+ // So it ramps down when you touch
127+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",
128+ (1+engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch2")));
129 }
130 }
131 break;
132@@ -1179,7 +1175,9 @@
133 case "vinyl": // Reset the triggers
134 case "vinyl2":
135 if (currentMode=="vinyl" || StantonSCS3d.vinyl2ScratchMethod == "a-b") scratch.disable(StantonSCS3d.deck);
136- else StantonSCS3d.scratch["touching"] = false;
137+ else {
138+ StantonSCS3d.scratch["touching"] = false;
139+ }
140 var byte1a = 0xB0 + channel;
141 midi.sendShortMsg(byte1a,0x01,0x00); //S4 LEDs off
142 if (!StantonSCS3d.VUMeters || StantonSCS3d.deck!=1) midi.sendShortMsg(byte1a,0x0C,0x00); //S3 LEDs off
143@@ -1305,7 +1303,6 @@
144 var currentMode = StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"];
145 switch (currentMode) {
146 case "vinyl":
147-// if (currentMode=="deck") return; // ignore if the cross-fader is being adjusted
148 var newValue=(value-64);
149 // print("C1="+value+", jog="+newValue);
150 engine.setValue("[Channel"+StantonSCS3d.deck+"]","jog",newValue);
151@@ -1316,12 +1313,11 @@
152 var jogValue = (value-64);
153 if (engine.getValue(group,"play")==1 && engine.getValue(group,"reverse")==1) jogValue= -(jogValue);
154
155- var multiplier = StantonSCS3d.scratching["sensitivity"] * (engine.getValue(group,"play") ? 1 : StantonSCS3d.scratching["stoppedMultiplier"] );
156+ var multiplier = StantonSCS3d.scratching["sensitivity"];
157 // if (StantonSCS3d.debug) print("do scratching VALUE:" + value + " jogValue: " + jogValue );
158- engine.setValue(group,"scratch", (engine.getValue(group,"scratch") + (jogValue * multiplier)).toFixed(2));
159+ engine.setValue(group,"scratch2", (engine.getValue(group,"scratch2") + (jogValue * multiplier)).toFixed(2));
160 break;
161 case "vinyl3":
162-// if (currentMode=="deck") return; // ignore if the cross-fader is being adjusted
163 if ((value-64)>0) {
164 engine.setValue("[Playlist]","SelectNextTrack",1);
165 }
166@@ -1339,7 +1335,7 @@
167 // // Slower response for jog wheel
168 // var newValue = scratch.wheel(StantonSCS3d.deck, value, 1.8, StantonSCS3d.scratch["alpha"], 1.0);
169 // print("StantonSCS3d: newValue="+newValue);
170-// engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch",newValue);
171+// engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",newValue);
172 break;
173 case "vinyl2":
174 if (StantonSCS3d.vinyl2ScratchMethod != "a-b") break; // this is only for the alpha-beta filter implementation
175@@ -1349,7 +1345,7 @@
176 // Call global scratch wheel function
177 var newScratchValue = scratch.wheel(StantonSCS3d.deck, value, StantonSCS3d.scratch["revtime"], StantonSCS3d.scratch["alpha"], StantonSCS3d.scratch["beta"]);
178
179- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch",newScratchValue);
180+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",newScratchValue);
181 break;
182 default:
183 // Light the LEDs
184@@ -1688,7 +1684,8 @@
185 }
186
187 // Revolution time of the imaginary record in seconds
188- var revtime = StantonSCS3d.scratch["revtime"];
189+ var revtime = 1.8; // 1.8s at 33 1/3 RPM
190+// var revtime = StantonSCS3d.scratch["revtime"];
191 if (StantonSCS3d.spinningLights==2) revtime = StantonSCS3d.scratch["revtime"]/2; // Use this for two lights
192 var currentTrackPos = value * StantonSCS3d.trackDuration[StantonSCS3d.deck];
193
194@@ -1710,34 +1707,38 @@
195 StantonSCS3d.wheelDecay = function (value) {
196
197 if (StantonSCS3d.mode_store["[Channel"+StantonSCS3d.deck+"]"]=="vinyl2") { // Only in Vinyl2 mode
198- var scratch = engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch");
199- var jogDecayRate = StantonSCS3d.scratching["slippage"] * (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play") ? 1 : 1.1 );
200+ var scratch = engine.getValue("[Channel"+StantonSCS3d.deck+"]","scratch2");
201+ var jogDecayRate = StantonSCS3d.scratching["slippage"] * 1.1; // 0.2
202
203- if (StantonSCS3d.debug) print("Scratch deck"+StantonSCS3d.deck+": " + scratch + ", Jog decay rate="+jogDecayRate);
204+// if (StantonSCS3d.debug) print("Scratch deck"+StantonSCS3d.deck+": " + scratch + ", Jog decay rate="+jogDecayRate);
205
206 // If it was playing, ramp back to playback speed
207- if (StantonSCS3d.scratch["wasPlaying"] && !StantonSCS3d.scratch["touching"]) {
208+ if (engine.getValue("[Channel"+StantonSCS3d.deck+"]","play")==1 && !StantonSCS3d.scratch["touching"]) {
209 var rate = engine.getValue("[Channel"+StantonSCS3d.deck+"]","rate") * engine.getValue("[Channel"+StantonSCS3d.deck+"]","rateRange");
210 var convergeTo = 1+rate;
211- //jogDecayRate = StantonSCS3d.scratching["slippage"] * 0.2;
212 if (scratch != convergeTo) { // Thanks to jusics on IRC for help with this part
213- if (Math.abs(scratch-convergeTo) > jogDecayRate*0.001) {
214- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", (convergeTo + (scratch-convergeTo) * jogDecayRate).toFixed(5));
215- //engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", (scratch + (convergeTo - scratch) / jogDecayRate).toFixed(5));
216+ if (Math.abs(scratch-convergeTo) > jogDecayRate*0.001) {
217+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2",
218+ (convergeTo + (scratch-convergeTo) * jogDecayRate).toFixed(5));
219+ //engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", (scratch + (convergeTo - scratch) / jogDecayRate).toFixed(5));
220 } else {
221- // Once "scratch" has gotten close enough to the play speed, just resume normal playback
222- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", 0);
223- engine.setValue("[Channel"+StantonSCS3d.deck+"]","play",1);
224- StantonSCS3d.scratch["wasPlaying"] = false;
225+ // Once "scratch2" has gotten close enough to the play speed, just resume normal playback
226+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", 0);
227+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 0);
228 }
229 }
230- } else
231- if (scratch != 0) { // For regular scratching when stopped or if playing (and ramp down...touch functions set scratch=1 and play=0)
232- if (Math.abs(scratch) > jogDecayRate*0.001) {
233- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", (scratch * jogDecayRate).toFixed(4));
234- } else {
235- engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch", 0);
236- }
237+ }
238+ else if (scratch != 0) {
239+ // For regular scratching when stopped or if playing and ramp down
240+ if (Math.abs(scratch) > jogDecayRate*0.001) {
241+ var value=(scratch * jogDecayRate).toFixed(5);
242+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", value);
243+ if (StantonSCS3d.debug) print("Scratch deck"+StantonSCS3d.deck+": " + value + ", Jog decay rate="+jogDecayRate);
244+ } else {
245+ engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2", 0);
246+ if (!StantonSCS3d.scratch["touching"]) engine.setValue("[Channel"+StantonSCS3d.deck+"]","scratch2_enable", 0);
247+ if (StantonSCS3d.debug) print("Scratch deck"+StantonSCS3d.deck+": 0, Jog decay rate="+jogDecayRate);
248+ }
249 }
250 }
251 }
252
253=== modified file 'mixxx/res/midi/midi-mappings-scripts.js'
254--- mixxx/res/midi/midi-mappings-scripts.js 2010-03-20 02:33:20 +0000
255+++ mixxx/res/midi/midi-mappings-scripts.js 2010-04-29 07:06:29 +0000
256@@ -33,7 +33,7 @@
257 msecs = Math.round(msecs * 100 / 1000);
258 if (msecs==100) msecs=99;
259
260- print("secs="+secs+", msecs="+msecs);
261+// print("secs="+secs+", msecs="+msecs);
262
263 return (m < 10 ? "0" + m : m)
264 + ":"
265@@ -43,8 +43,10 @@
266 }
267
268 function script() {}
269-script.debug = function (channel, control, value, status) {
270- print("Script.Debug --- channel: " + channel.toString(16) + " control: " + control.toString(16) + " value: " + value.toString(16) + " status: " + status.toString(16));
271+script.debug = function (channel, control, value, status, group) {
272+ print("Script.Debug --- channel: " + channel.toString(16) +
273+ " control: " + control.toString(16) + " value: " + value.toString(16) +
274+ " status: " + status.toString(16) + " group: " + group);
275 }
276
277 // Used to control a generic Mixxx control setting (low..high) from an absolute control (0..127)
278@@ -64,7 +66,9 @@
279 script.absoluteEQ = function (group, key, value) {
280 if (value<=64) engine.setValue(group, key, value/64);
281 else engine.setValue(group, key, 1+(value-63)/(21+1/3));
282- print ("MIDI Script: script.absoluteEQ is deprecated. Use script.absoluteNonLin(value,0,1,4) instead and set the MixxxControl to its return value.");
283+ print ("MIDI Script: script.absoluteEQ is deprecated. " +
284+ "Use script.absoluteNonLin(value,0,1,4) instead and set the " +
285+ "MixxxControl to its return value.");
286 }
287
288 /* -------- ------------------------------------------------------
289@@ -134,7 +138,9 @@
290 // See full details here: http://mixxx.org/wiki/doku.php/midi_scripting#available_common_functions
291
292 // ---------- Variables ----------
293-scratch.variables = { "time":0.0, "trackPos":0.0, "initialTrackPos":-1.0, "initialControlValue":0, "scratch":0.0, "prevControlValue":0, "wrapCount":0 };
294+scratch.variables = { "time":0.0, "trackPos":0.0, "initialTrackPos":-1.0,
295+ "initialControlValue":0, "scratch":0.0,
296+ "prevControlValue":0, "wrapCount":0 };
297
298 // ---------- Functions ----------
299
300@@ -146,19 +152,18 @@
301 Input: Currently-controlled Mixxx deck
302 Output: -
303 -------- ------------------------------------------------------ */
304-scratch.enable = function (currentDeck) {
305+scratch.enable = function (currentDeck,newBehavior) {
306 // Store scratch info at the point it was touched
307 // Current position in seconds:
308- scratch.variables["initialTrackPos"] = scratch.variables["trackPos"] = engine.getValue("[Channel"+currentDeck+"]","playposition") * engine.getValue("[Channel"+currentDeck+"]","duration");
309+ scratch.variables["initialTrackPos"] = scratch.variables["trackPos"] = engine.getValue("[Channel"+currentDeck+"]","visual_playposition") * engine.getValue("[Channel"+currentDeck+"]","duration");
310
311 scratch.variables["time"] = new Date()/1000; // Current time in seconds
312+ if (newBehavior) engine.setValue("[Channel"+currentDeck+"]","scratch2_enable", 1);
313
314- // Stop the deck motion. This means we have to pause it if playing
315+ // If the deck is playing, slow it to a stop
316 if (engine.getValue("[Channel"+currentDeck+"]","play") > 0) {
317- scratch.variables["play"]=true;
318-// engine.setValue("[Channel"+currentDeck+"]","play",0); // pause playback
319+ // TODO: ramp down
320 }
321- else scratch.variables["play"]=false;
322
323 // print("MIDI Script: Scratch initial: time=" + scratch.variables["time"] + "s, track=" + scratch.variables["trackPos"] + "s");
324 return;
325@@ -172,6 +177,10 @@
326 Output: -
327 -------- ------------------------------------------------------ */
328 scratch.disable = function (currentDeck) {
329+ // If the deck is playing, ramp it up to the play speed
330+ if (engine.getValue("[Channel"+currentDeck+"]","play") > 0) {
331+ //TODO: ramp up
332+ }
333 // Reset the triggers
334 scratch.variables["trackPos"] = 0.0;
335 scratch.variables["initialTrackPos"] = -1.0;
336@@ -181,8 +190,9 @@
337 scratch.variables["time"] = 0.0;
338 scratch.variables["scratch"] = 0.0;
339 // print("MIDI Script: Scratch values CLEARED");
340- engine.setValue("[Channel"+currentDeck+"]","scratch",0.0); // disable scratching
341- if (scratch.variables["play"]) engine.setValue("[Channel"+currentDeck+"]","play",1); // resume playback
342+ engine.setValue("[Channel"+currentDeck+"]","scratch2_enable", 0); // disable scratching
343+ engine.setValue("[Channel"+currentDeck+"]","scratch2",0);
344+ engine.setValue("[Channel"+currentDeck+"]","scratch",0); // Deprecated
345 }
346
347 /* -------- ------------------------------------------------------
348@@ -201,8 +211,13 @@
349 // If the slider start value hasn't been set yet, set it
350 if (scratch.variables["initialControlValue"] == 0) {
351 scratch.variables["initialControlValue"] = sliderValue;
352+ if (engine.getValue("[Channel"+currentDeck+"]","play") > 0) {
353+ scratch.variables["scratch"] = 1;
354+ engine.setValue("[Channel"+currentDeck+"]","scratch2", 1);
355+ }
356+// engine.setValue("[Channel"+currentDeck+"]","scratch2_enable", 1);
357 // print("Initial slider="+scratch.variables["initialControlValue"]);
358- }
359+ }
360 return scratch.filter(currentDeck, sliderValue, revtime, alpha, beta);
361 }
362
363@@ -222,8 +237,13 @@
364 // If the wheel start value hasn't been set yet, set it
365 if (scratch.variables["initialControlValue"] == 0) {
366 scratch.variables["initialControlValue"] = scratch.variables["prevControlValue"] = wheelValue;
367+ if (engine.getValue("[Channel"+currentDeck+"]","play") > 0) {
368+ scratch.variables["scratch"] = 1;
369+ engine.setValue("[Channel"+currentDeck+"]","scratch2", 1);
370+ }
371+// engine.setValue("[Channel"+currentDeck+"]","scratch2_enable", 1);
372 // print("Initial wheel="+scratch.variables["initialControlValue"]);
373- }
374+ }
375
376 // Take wrap around into account
377 if (wheelValue>=0 && wheelValue<10 && scratch.variables["prevControlValue"]>117 && scratch.variables["prevControlValue"]<=127) scratch.variables["wrapCount"]+=1;
378@@ -244,7 +264,7 @@
379 // ideal position = (initial_p + (y - x) / 128 * 1.8)
380 var ideal_p = scratch.variables["initialTrackPos"] + (controlValue - scratch.variables["initialControlValue"]) / 128 * revtime;
381
382- var currentTrackPos = engine.getValue("[Channel"+currentDeck+"]","playposition") * engine.getValue("[Channel"+currentDeck+"]","duration");
383+ var currentTrackPos = engine.getValue("[Channel"+currentDeck+"]","visual_playposition") * engine.getValue("[Channel"+currentDeck+"]","duration");
384 var newTime = new Date()/1000;
385 var dt = newTime - scratch.variables["time"];
386 scratch.variables["time"] = newTime;
387@@ -259,13 +279,13 @@
388 // scratch.variables["trackPos"] += rx * alpha; // Don't need this result so why waste the CPU time?
389
390 // v += rx * BETA / dt;
391- // scratch.variables["scratch"] += rx * (beta / dt); // This doesn't work
392+// scratch.variables["scratch"] += rx * beta / dt; // This doesn't work
393 scratch.variables["scratch"] = rx * beta;
394
395 // print("MIDI Script: Ideal position="+ideal_p+", Predicted position="+predicted_p + ", New scratch val=" + scratch.variables["scratch"]);
396
397 // var newPos = scratch.variables["trackPos"]/engine.getValue("[Channel"+currentDeck+"]","duration");
398-// engine.setValue("[Channel"+currentDeck+"]","playposition",newPos);
399+// engine.setValue("[Channel"+currentDeck+"]","visual_playposition",newPos);
400 // engine.setValue("[Channel"+currentDeck+"]","scratch",scratch.variables["scratch"]);
401
402 return scratch.variables["scratch"];
403
404=== modified file 'mixxx/src/controlvaluedelegate.cpp'
405--- mixxx/src/controlvaluedelegate.cpp 2009-09-01 15:33:21 +0000
406+++ mixxx/src/controlvaluedelegate.cpp 2010-04-29 07:06:29 +0000
407@@ -47,6 +47,7 @@
408 m_channelControlValues.append("rate_perm_up_small");
409 m_channelControlValues.append("rateRange");
410 m_channelControlValues.append("scratch");
411+ m_channelControlValues.append("scratch_enable");
412 m_channelControlValues.append("transform");
413 m_channelControlValues.append("volume");
414 m_channelControlValues.append("wheel");
415
416=== modified file 'mixxx/src/engine/ratecontrol.cpp'
417--- mixxx/src/engine/ratecontrol.cpp 2010-03-20 21:14:06 +0000
418+++ mixxx/src/engine/ratecontrol.cpp 2010-04-29 07:06:29 +0000
419@@ -116,7 +116,13 @@
420 // Scratch controller, this is an accumulator which is useful for
421 // controllers that return individiual +1 or -1s, these get added up and
422 // cleared when we read
423- m_pScratch = new ControlTTRotary(ConfigKey(_group, "scratch"));
424+ m_pScratch = new ControlTTRotary(ConfigKey(_group, "scratch2"));
425+ m_pOldScratch = new ControlTTRotary(ConfigKey(_group, "scratch")); // Deprecated
426+
427+ // Scratch enable toggle
428+ m_pScratchToggle = new ControlPushButton(ConfigKey(_group, "scratch2_enable"));
429+ m_pScratchToggle->set(0);
430+ m_pScratchToggle->setToggleButton(true);
431
432 m_pJog = new ControlObject(ConfigKey(_group, "jog"));
433 m_pJogFilter = new Rotary();
434@@ -156,6 +162,7 @@
435
436 delete m_pWheel;
437 delete m_pScratch;
438+ delete m_pOldScratch;
439 delete m_pJog;
440 delete m_pJogFilter;
441 }
442@@ -309,20 +316,6 @@
443 m_pRateDir->get();
444 }
445
446-double RateControl::getScratchFactor() {
447- double scratchFactor = m_pScratch->get();
448- if(!isnan(scratchFactor) && scratchFactor != 0.0f) {
449- if (scratchFactor < 0.) {
450- scratchFactor = scratchFactor - 1.0f;
451- } else if (scratchFactor > 0.) {
452- scratchFactor = scratchFactor + 1.0f;
453- }
454- } else {
455- scratchFactor = 1.0f;
456- }
457- return scratchFactor;
458-}
459-
460 double RateControl::getWheelFactor() {
461 // Calculate wheel (experimental formula)
462 return 40 * m_pWheel->get();
463@@ -350,17 +343,27 @@
464 double RateControl::calculateRate(double baserate, bool paused) {
465 double rate = 0.0;
466 double wheelFactor = getWheelFactor();
467- double scratchFactor = getScratchFactor();
468 double jogFactor = getJogFactor();
469 bool searching = m_pRateSearch->get() != 0.;
470+ bool scratchEnable = m_pScratchToggle->get() != 0;
471+ double scratchFactor = m_pScratch->get();
472+ double oldScratchFactor = m_pOldScratch->get(); // Deprecated
473+ // Don't trust values from m_pScratch
474+ if(isnan(scratchFactor)) {
475+ scratchFactor = 0.0;
476+ }
477+ if(isnan(oldScratchFactor)) {
478+ oldScratchFactor = 0.0;
479+ }
480
481 if (searching) {
482 // If searching is in progress, it overrides the playback rate.
483 rate = m_pRateSearch->get();
484 } else if (paused) {
485 // Stopped. Wheel, jog and scratch controller all scrub through audio.
486- // Scratch is centered around 1.0, so subtract 1.0
487- rate = scratchFactor - 1.0f + jogFactor + wheelFactor/10.;
488+ // New scratch behavior overrides old
489+ if (scratchEnable) rate = scratchFactor + jogFactor + wheelFactor/10.;
490+ else rate = oldScratchFactor + jogFactor + wheelFactor/10.; // Just remove oldScratchFactor in future
491 } else {
492 // The buffer is playing, so calculate the buffer rate.
493
494@@ -372,7 +375,18 @@
495
496 rate = 1. + getRawRate() + getTempRate();
497 rate += wheelFactor/10.;
498- rate *= scratchFactor;
499+
500+ // New scratch behavior - overrides playback speed (and old behavior)
501+ if (scratchEnable) rate *= scratchFactor;
502+ // Deprecated old scratch behavior
503+ else {
504+ if (oldScratchFactor < 0.) {
505+ rate *= (oldScratchFactor-1.);
506+ } else if (oldScratchFactor > 0.) {
507+ rate *= (oldScratchFactor+1.);
508+ }
509+ }
510+
511 rate += jogFactor;
512
513 // If we are reversing, flip the rate.
514
515=== modified file 'mixxx/src/engine/ratecontrol.h'
516--- mixxx/src/engine/ratecontrol.h 2010-01-05 03:57:34 +0000
517+++ mixxx/src/engine/ratecontrol.h 2010-04-29 07:06:29 +0000
518@@ -66,7 +66,6 @@
519 private:
520 double getJogFactor();
521 double getWheelFactor();
522- double getScratchFactor();
523
524 /** Set rate change of the temporary pitch rate */
525 void setRateTemp(double v);
526@@ -95,6 +94,8 @@
527
528 ControlTTRotary* m_pWheel;
529 ControlTTRotary* m_pScratch;
530+ ControlTTRotary* m_pOldScratch;
531+ ControlPushButton* m_pScratchToggle;
532 ControlObject* m_pJog;
533 Rotary* m_pJogFilter;
534