Merge lp:~pwhelan/mixxx/mixxx-pitch_bend into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Phillip Whelan
Status: Merged
Approved by: RJ Skerry-Ryan
Approved revision: not available
Merged at revision: not available
Proposed branch: lp:~pwhelan/mixxx/mixxx-pitch_bend
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 1713 lines (+836/-422)
7 files modified
mixxx/src/dlgprefcontrols.cpp (+44/-0)
mixxx/src/dlgprefcontrols.h (+2/-0)
mixxx/src/dlgprefcontrolsdlg.ui (+435/-339)
mixxx/src/engine/enginebuffer.cpp (+3/-3)
mixxx/src/engine/enginebufferscalelinear.cpp (+43/-29)
mixxx/src/engine/ratecontrol.cpp (+228/-40)
mixxx/src/engine/ratecontrol.h (+81/-11)
To merge this branch: bzr merge lp:~pwhelan/mixxx/mixxx-pitch_bend
Reviewer Review Type Date Requested Status
RJ Skerry-Ryan Approve
Phillip Whelan Needs Resubmitting
Albert Santoni Abstain
Review via email: mp+13932@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Phillip Whelan (pwhelan) wrote :

Here is Pitchbend/Rateramp, ready for merging. It is only a revision or two behind trunk.

There is some optimizations in EngineBufferScaleLinear. These could be held off for now since they are not essential to this code.

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

ratecontrol.h:
- Please comment the enums that you have in there. Also, I'd change RATERAMP_OLD to something more descriptive (maybe RATERAMP_STEP instead).
- Please comment the constants you added at the top too. (RATE_TEMP_STEP, RATE_TEMP_STEP_SMALL)

=== modified file 'mixxx/src/mixxxkeyboard.cpp'
--- mixxx/src/mixxxkeyboard.cpp 2009-06-27 22:16:23 +0000
+++ mixxx/src/mixxxkeyboard.cpp 2009-10-26 01:10:25 +0000
@@ -103,7 +103,7 @@
         {
             if (release) {
                 //qDebug() << "Sending MIDI NOTE_OFF";
- ControlObject::getControl(*pConfigKey)->queueFromMidi(NOTE_OFF, 1);
+ ControlObject::getControl(*pConfigKey)->queueFromMidi(NOTE_OFF, 0);
             }
             else
             {
-----> What is this change?

Re: EngineBufferScaleLinear - I looked at your changes and I don't see anything immediately wrong. We're going to have to make sure we test the hell out of this though before our beta. :)

Re: The "Pitchbend sensitivity" label in the preferences. I think this label is misleading because higher sensitivity usually means faster response, but turning up the sensitivity slider seems to actually slow down the ramping. Can you flip your slider values around or something?

Awesome stuff Phil! I think ramping pitchbend is way easier to mix with and is more intuitive to use than the weirdo stepped stuff we had before.

See if you can fix these things up and then I think we're ready to merge.

Thanks!
Albert

review: Needs Fixing
lp:~pwhelan/mixxx/mixxx-pitch_bend updated
2499. By Phillip Whelan <madjester@voidwalker>

Merging about box changes from trunk.

2500. By Phillip Whelan <madjester@voidwalker>

Undoing a change that must have slipped in from a keyboard patch.

2501. By Phillip Whelan <madjester@voidwalker>

Commenting the enumerations and getting the sensitivity setting to work more intuitively, as per merge proposal change request from albert.

Revision history for this message
Phillip Whelan (pwhelan) wrote :

I have finally made the changes proposed in the merge review.

review: Needs Resubmitting
lp:~pwhelan/mixxx/mixxx-pitch_bend updated
2502. By Phillip Whelan <madjester@voidwalker>

Merging Debian package changes from trunk.

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

Code looks good. I'll approve once I get a chance to test it. Thanks for the fixes Phil!

review: Abstain
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :
Download full text (6.7 KiB)

I can check off on the EngineBufferScaleLinear changes -- they look fine to me. Also the dialog stuff looks fine too.

One note about the rateramp sensitivity -- is there a more usable way we can represent the sensitivity to the user? Given the ramping equations, can you characterize the sensitivity in some form of units? i.e. samples / second^2 ? It might be good to throw that in the label so you understand more what those numbers go into.

Here are my specific comments about ratecontrol.cpp -- in general it all looks great!

I did find one bug -- when you turn the rate down load (-30% or so) and then pitch bend down, the track can go backwards.

The rest of my comments are inline:

=== modified file 'mixxx/src/engine/ratecontrol.cpp'
--- mixxx/src/engine/ratecontrol.cpp 2009-09-28 02:12:07 +0000
+++ mixxx/src/engine/ratecontrol.cpp 2009-11-19 02:43:44 +0000

In this chunk -- can you add a safety check that the result of calculateRate is not NaN? (if it is NaN, just return 1*baserate or something) We need to make sure that NaN's don't end up in the engine, because they screw things up really fast -- they'll trigger an assert in our Butterworth filters.

@@ -318,15 +358,17 @@
     } else {
         // The buffer is playing, so calculate the buffer rate.

- // There are three rate effects we apply: wheel, scratch, and jog.
+ // There are four rate effects we apply: wheel, scratch, jog and temp.
         // Wheel: a linear additive effect
         // Scratch: a rate multiplier
- // Jog: a linear additive effect whose value is filtered
-
+ // Jog: a linear additive effect whose value is filtered
+ // Temp: pitch bend
+
         rate = (1. + getRawRate()) * baserate;
         rate += wheelFactor/10.;
         rate *= scratchFactor;
         rate += jogFactor;
+ rate += (getTempRate()) * baserate;

         // If we are reversing, flip the rate.
         if (m_pReverseButton->get()) {
@@ -340,6 +382,135 @@
 double RateControl::process(const double rate,
                             const double currentSample,
                             const double totalSamples,
- const int iBufferSize) {
- return 0;
+ const int bufferSamples)
+{
+ /*
+ * Code to handle temporary rate change buttons.
+ *
+ * We support two behaviours, the standard ramped pitch bending
+ * and pitch shift stepping, which is the old behaviour.
+ */
+
+ /*
+ * Initialize certain values necessary for pitchbending. Most of this
+ * code should be handled inside a slot, but we'd need to connect to
+ * the troublesome Latency ControlObject... Either the Master or Soundcard
+ * one.
+ */
+
+ double latrate = ((double)bufferSamples / (double)m_pSampleRate->get());
+
+
+ if ((m_ePbPressed) && (!m_bTempStarted))
+ {
+ m_bTempStarted = true;
+ m_dOldRate = m_pRateSlider->get();
+
+
+ if ( m_eRateRampMode == RATERAMP_STEP )
+ {

Here, could you consolidate the multiple get() calls on the same CO's? Remember, each get() call corresponds to a lock of the static CO loc...

Read more...

review: Needs Fixing
lp:~pwhelan/mixxx/mixxx-pitch_bend updated
2503. By Phillip Whelan <madjester@voidwalker>

Adding fixes requested by RJ Ryan.

2504. By Phillip Whelan <madjester@voidwalker>

Adding isnan code for multiplatform support.

Revision history for this message
Phillip Whelan (pwhelan) wrote :

I have added the fixes RJ has asked for. The few divisions I did not add isNaN checking to are unrelated to values that are setable via scripts.

review: Needs Resubmitting
lp:~pwhelan/mixxx/mixxx-pitch_bend updated
2505. By Phillip Whelan <madjester@voidwalker>

Merging from trunk and fixing some minor spelling and syntax mistakes in ratecontrol.

Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

Let's merge this! Phil do you want to do the honors?

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/src/dlgprefcontrols.cpp'
2--- mixxx/src/dlgprefcontrols.cpp 2009-07-04 07:51:40 +0000
3+++ mixxx/src/dlgprefcontrols.cpp 2009-12-29 01:10:25 +0000
4@@ -253,6 +253,23 @@
5 // Update combo box
6 ComboBoxTooltips->setCurrentIndex((m_pConfig->getValueString(ConfigKey("[Controls]","Tooltips")).toInt()+1)%2);
7
8+ //
9+ // Ramping Temporary Rate Change configuration
10+ //
11+
12+ // Set Ramp Rate On or Off
13+ connect(CheckBoxRateRamp, SIGNAL(stateChanged(int)), this, SLOT(slotSetRateRamp(int)));
14+ CheckBoxRateRamp->setChecked((bool)
15+ m_pConfig->getValueString(ConfigKey("[Controls]","RateRamp")).toInt()
16+ );
17+
18+ // Update Ramp Rate Sensitivity
19+ connect(SliderRateRampSensitivity, SIGNAL(valueChanged(int)), this, SLOT(slotSetRateRampSensitivity(int)));
20+ SliderRateRampSensitivity->setValue(
21+ m_pConfig->getValueString(ConfigKey("[Controls]","RateRampSensitivity")).toInt()
22+ );
23+
24+
25 connect(ComboBoxTooltips, SIGNAL(activated(int)), this, SLOT(slotSetTooltips(int)));
26
27 slotUpdateSchemes();
28@@ -461,6 +478,32 @@
29 RateControl::setPermSmall(v);
30 }
31
32+void DlgPrefControls::slotSetRateRampSensitivity(int sense)
33+{
34+ m_pConfig->set(ConfigKey("[Controls]","RateRampSensitivity"),
35+ ConfigValue(SliderRateRampSensitivity->value()));
36+ RateControl::setRateRampSensitivity(sense);
37+}
38+
39+void DlgPrefControls::slotSetRateRamp(int mode)
40+{
41+ m_pConfig->set(ConfigKey("[Controls]", "RateRamp"),
42+ ConfigValue(CheckBoxRateRamp->isChecked()));
43+ RateControl::setRateRamp(mode);
44+
45+
46+ if ( mode )
47+ {
48+ SliderRateRampSensitivity->setEnabled(TRUE);
49+ SpinBoxRateRampSensitivity->setEnabled(TRUE);
50+ }
51+ else
52+ {
53+ SliderRateRampSensitivity->setEnabled(FALSE);
54+ SpinBoxRateRampSensitivity->setEnabled(FALSE);
55+ }
56+}
57+
58 void DlgPrefControls::slotApply()
59 {
60 // Write rate range to config file
61@@ -475,5 +518,6 @@
62 m_pConfig->set(ConfigKey("[Controls]","RateDir"), ConfigValue(0));
63 else
64 m_pConfig->set(ConfigKey("[Controls]","RateDir"), ConfigValue(1));
65+
66 }
67
68
69=== modified file 'mixxx/src/dlgprefcontrols.h'
70--- mixxx/src/dlgprefcontrols.h 2008-10-21 19:03:51 +0000
71+++ mixxx/src/dlgprefcontrols.h 2009-12-29 01:10:25 +0000
72@@ -53,6 +53,8 @@
73 void slotSetPositionDisplay(int);
74 void slotSetCueDefault(int);
75 void slotSetCueRecall(int);
76+ void slotSetRateRamp(int);
77+ void slotSetRateRampSensitivity(int);
78 void slotApply();
79 private:
80 /** Pointer to ConfigObject */
81
82=== modified file 'mixxx/src/dlgprefcontrolsdlg.ui'
83--- mixxx/src/dlgprefcontrolsdlg.ui 2008-10-21 19:03:51 +0000
84+++ mixxx/src/dlgprefcontrolsdlg.ui 2009-12-29 01:10:25 +0000
85@@ -1,522 +1,618 @@
86-<ui version="4.0" >
87+<?xml version="1.0" encoding="UTF-8"?>
88+<ui version="4.0">
89 <class>DlgPrefControlsDlg</class>
90- <widget class="QWidget" name="DlgPrefControlsDlg" >
91- <property name="geometry" >
92+ <widget class="QWidget" name="DlgPrefControlsDlg">
93+ <property name="geometry">
94 <rect>
95 <x>0</x>
96 <y>0</y>
97- <width>427</width>
98- <height>505</height>
99+ <width>590</width>
100+ <height>534</height>
101 </rect>
102 </property>
103- <property name="windowTitle" >
104+ <property name="windowTitle">
105 <string>Form1</string>
106 </property>
107- <layout class="QGridLayout" >
108- <item row="0" column="0" >
109- <layout class="QGridLayout" >
110- <item row="0" column="0" >
111- <widget class="QLabel" name="TextLabel6_2_2" >
112- <property name="enabled" >
113- <bool>true</bool>
114- </property>
115- <property name="font" >
116- <font/>
117- </property>
118- <property name="text" >
119+ <layout class="QGridLayout">
120+ <item row="1" column="0">
121+ <layout class="QGridLayout">
122+ <item row="0" column="0">
123+ <widget class="QLabel" name="textLabel">
124+ <property name="maximumSize">
125+ <size>
126+ <width>16777215</width>
127+ <height>20</height>
128+ </size>
129+ </property>
130+ <property name="text">
131+ <string/>
132+ </property>
133+ <property name="wordWrap">
134+ <bool>true</bool>
135+ </property>
136+ </widget>
137+ </item>
138+ </layout>
139+ </item>
140+ <item row="3" column="0">
141+ <layout class="QGridLayout">
142+ <item row="0" column="0" colspan="2">
143+ <widget class="QLabel" name="TextLabel6_2_3">
144+ <property name="enabled">
145+ <bool>true</bool>
146+ </property>
147+ <property name="font">
148+ <font/>
149+ </property>
150+ <property name="text">
151+ <string>Temporary pitch/rate buttons</string>
152+ </property>
153+ <property name="wordWrap">
154+ <bool>false</bool>
155+ </property>
156+ </widget>
157+ </item>
158+ <item row="0" column="3" colspan="2">
159+ <widget class="QLabel" name="TextLabel6_2_3_3">
160+ <property name="enabled">
161+ <bool>true</bool>
162+ </property>
163+ <property name="font">
164+ <font/>
165+ </property>
166+ <property name="text">
167+ <string>Permanent pitch/rate buttons</string>
168+ </property>
169+ <property name="wordWrap">
170+ <bool>false</bool>
171+ </property>
172+ </widget>
173+ </item>
174+ <item row="1" column="0">
175+ <widget class="QLabel" name="TextLabel6_2_3_2">
176+ <property name="enabled">
177+ <bool>true</bool>
178+ </property>
179+ <property name="font">
180+ <font/>
181+ </property>
182+ <property name="text">
183+ <string>Left click</string>
184+ </property>
185+ <property name="wordWrap">
186+ <bool>false</bool>
187+ </property>
188+ </widget>
189+ </item>
190+ <item row="1" column="1">
191+ <widget class="QDoubleSpinBox" name="spinBoxTempRateLeft">
192+ <property name="toolTip">
193+ <string>Temporary rate change (between 1 and 8000) when left clicking</string>
194+ </property>
195+ <property name="accelerated">
196+ <bool>true</bool>
197+ </property>
198+ <property name="decimals">
199+ <number>1</number>
200+ </property>
201+ <property name="minimum">
202+ <double>0.100000000000000</double>
203+ </property>
204+ <property name="maximum">
205+ <double>10.000000000000000</double>
206+ </property>
207+ <property name="singleStep">
208+ <double>0.100000000000000</double>
209+ </property>
210+ </widget>
211+ </item>
212+ <item row="1" column="3">
213+ <widget class="QLabel" name="TextLabel6_2_3_2_3">
214+ <property name="enabled">
215+ <bool>true</bool>
216+ </property>
217+ <property name="font">
218+ <font/>
219+ </property>
220+ <property name="text">
221+ <string>Left click</string>
222+ </property>
223+ <property name="wordWrap">
224+ <bool>false</bool>
225+ </property>
226+ </widget>
227+ </item>
228+ <item row="1" column="4">
229+ <widget class="QDoubleSpinBox" name="spinBoxPermRateLeft">
230+ <property name="toolTip">
231+ <string>Permanent rate change (between 1 and 8000) when left clicking</string>
232+ </property>
233+ <property name="accelerated">
234+ <bool>true</bool>
235+ </property>
236+ <property name="decimals">
237+ <number>1</number>
238+ </property>
239+ <property name="minimum">
240+ <double>0.100000000000000</double>
241+ </property>
242+ <property name="maximum">
243+ <double>10.000000000000000</double>
244+ </property>
245+ <property name="singleStep">
246+ <double>0.100000000000000</double>
247+ </property>
248+ </widget>
249+ </item>
250+ <item row="2" column="0">
251+ <widget class="QLabel" name="TextLabel6_2_3_2_2">
252+ <property name="enabled">
253+ <bool>true</bool>
254+ </property>
255+ <property name="font">
256+ <font/>
257+ </property>
258+ <property name="text">
259+ <string>Right click</string>
260+ </property>
261+ <property name="wordWrap">
262+ <bool>false</bool>
263+ </property>
264+ </widget>
265+ </item>
266+ <item row="2" column="1">
267+ <widget class="QDoubleSpinBox" name="spinBoxTempRateRight">
268+ <property name="toolTip">
269+ <string>Temporary rate change (between 1 and 8000) when right clicking</string>
270+ </property>
271+ <property name="accelerated">
272+ <bool>true</bool>
273+ </property>
274+ <property name="decimals">
275+ <number>1</number>
276+ </property>
277+ <property name="minimum">
278+ <double>0.100000000000000</double>
279+ </property>
280+ <property name="maximum">
281+ <double>10.000000000000000</double>
282+ </property>
283+ <property name="singleStep">
284+ <double>0.100000000000000</double>
285+ </property>
286+ </widget>
287+ </item>
288+ <item row="2" column="3">
289+ <widget class="QLabel" name="TextLabel6_2_3_2_2_2">
290+ <property name="enabled">
291+ <bool>true</bool>
292+ </property>
293+ <property name="font">
294+ <font/>
295+ </property>
296+ <property name="text">
297+ <string>Right click</string>
298+ </property>
299+ <property name="wordWrap">
300+ <bool>false</bool>
301+ </property>
302+ </widget>
303+ </item>
304+ <item row="2" column="4">
305+ <widget class="QDoubleSpinBox" name="spinBoxPermRateRight">
306+ <property name="toolTip">
307+ <string>Permanent rate change (between 1 and 8000) when right clicking</string>
308+ </property>
309+ <property name="accelerated">
310+ <bool>true</bool>
311+ </property>
312+ <property name="decimals">
313+ <number>1</number>
314+ </property>
315+ <property name="minimum">
316+ <double>0.100000000000000</double>
317+ </property>
318+ <property name="maximum">
319+ <double>10.000000000000000</double>
320+ </property>
321+ <property name="singleStep">
322+ <double>0.100000000000000</double>
323+ </property>
324+ </widget>
325+ </item>
326+ <item row="3" column="0">
327+ <spacer>
328+ <property name="orientation">
329+ <enum>Qt::Vertical</enum>
330+ </property>
331+ <property name="sizeHint" stdset="0">
332+ <size>
333+ <width>20</width>
334+ <height>40</height>
335+ </size>
336+ </property>
337+ </spacer>
338+ </item>
339+ </layout>
340+ </item>
341+ <item row="0" column="0">
342+ <layout class="QGridLayout">
343+ <item row="0" column="0">
344+ <widget class="QLabel" name="TextLabel6_2_2">
345+ <property name="enabled">
346+ <bool>true</bool>
347+ </property>
348+ <property name="font">
349+ <font/>
350+ </property>
351+ <property name="text">
352 <string>Skin</string>
353 </property>
354- <property name="wordWrap" >
355+ <property name="wordWrap">
356 <bool>false</bool>
357 </property>
358 </widget>
359 </item>
360- <item row="0" column="1" colspan="2" >
361- <widget class="QComboBox" name="ComboBoxSkinconf" >
362- <property name="sizePolicy" >
363- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
364+ <item row="0" column="1" colspan="2">
365+ <widget class="QComboBox" name="ComboBoxSkinconf">
366+ <property name="sizePolicy">
367+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
368 <horstretch>0</horstretch>
369 <verstretch>0</verstretch>
370 </sizepolicy>
371 </property>
372- <property name="font" >
373+ <property name="font">
374 <font/>
375 </property>
376 </widget>
377 </item>
378- <item row="1" column="0" >
379- <widget class="QLabel" name="TextLabel6_2_2_4" >
380- <property name="enabled" >
381+ <item row="1" column="0">
382+ <widget class="QLabel" name="TextLabel6_2_2_4">
383+ <property name="enabled">
384 <bool>true</bool>
385 </property>
386- <property name="font" >
387+ <property name="font">
388 <font/>
389 </property>
390- <property name="text" >
391+ <property name="text">
392 <string>Scheme</string>
393 </property>
394- <property name="wordWrap" >
395+ <property name="wordWrap">
396 <bool>false</bool>
397 </property>
398 </widget>
399 </item>
400- <item row="1" column="1" colspan="2" >
401- <widget class="QComboBox" name="ComboBoxSchemeconf" >
402- <property name="sizePolicy" >
403- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
404+ <item row="1" column="1" colspan="2">
405+ <widget class="QComboBox" name="ComboBoxSchemeconf">
406+ <property name="sizePolicy">
407+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
408 <horstretch>0</horstretch>
409 <verstretch>0</verstretch>
410 </sizepolicy>
411 </property>
412- <property name="font" >
413+ <property name="font">
414 <font/>
415 </property>
416 </widget>
417 </item>
418- <item row="2" column="0" >
419- <widget class="QLabel" name="TextLabel6_2_2_2" >
420- <property name="enabled" >
421+ <item row="2" column="0">
422+ <widget class="QLabel" name="TextLabel6_2_2_2">
423+ <property name="enabled">
424 <bool>true</bool>
425 </property>
426- <property name="font" >
427+ <property name="font">
428 <font/>
429 </property>
430- <property name="text" >
431+ <property name="text">
432 <string>Waveform display</string>
433 </property>
434- <property name="wordWrap" >
435+ <property name="wordWrap">
436 <bool>false</bool>
437 </property>
438 </widget>
439 </item>
440- <item row="2" column="1" colspan="2" >
441- <widget class="QComboBox" name="ComboBoxVisuals" >
442- <property name="sizePolicy" >
443- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
444+ <item row="2" column="1" colspan="2">
445+ <widget class="QComboBox" name="ComboBoxVisuals">
446+ <property name="sizePolicy">
447+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
448 <horstretch>0</horstretch>
449 <verstretch>0</verstretch>
450 </sizepolicy>
451 </property>
452- <property name="font" >
453+ <property name="font">
454 <font/>
455 </property>
456 </widget>
457 </item>
458- <item row="3" column="0" >
459- <widget class="QLabel" name="TextLabel6_2_2_3" >
460- <property name="enabled" >
461+ <item row="3" column="0">
462+ <widget class="QLabel" name="TextLabel6_2_2_3">
463+ <property name="enabled">
464 <bool>true</bool>
465 </property>
466- <property name="font" >
467+ <property name="font">
468 <font/>
469 </property>
470- <property name="text" >
471+ <property name="text">
472 <string>Position display</string>
473 </property>
474- <property name="wordWrap" >
475+ <property name="wordWrap">
476 <bool>false</bool>
477 </property>
478 </widget>
479 </item>
480- <item row="3" column="1" colspan="2" >
481- <widget class="QComboBox" name="ComboBoxPosition" >
482- <property name="sizePolicy" >
483- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
484+ <item row="3" column="1" colspan="2">
485+ <widget class="QComboBox" name="ComboBoxPosition">
486+ <property name="sizePolicy">
487+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
488 <horstretch>0</horstretch>
489 <verstretch>0</verstretch>
490 </sizepolicy>
491 </property>
492- <property name="font" >
493+ <property name="font">
494 <font/>
495 </property>
496 </widget>
497 </item>
498- <item row="4" column="0" >
499- <widget class="QLabel" name="TextLabel6_2_2_3_3" >
500- <property name="enabled" >
501+ <item row="4" column="0">
502+ <widget class="QLabel" name="TextLabel6_2_2_3_3">
503+ <property name="enabled">
504 <bool>true</bool>
505 </property>
506- <property name="font" >
507+ <property name="font">
508 <font/>
509 </property>
510- <property name="text" >
511+ <property name="text">
512 <string>Scale BPM display</string>
513 </property>
514- <property name="wordWrap" >
515+ <property name="wordWrap">
516 <bool>false</bool>
517 </property>
518 </widget>
519 </item>
520- <item row="4" column="1" colspan="2" >
521- <widget class="QComboBox" name="ComboBoxScaleBpm" >
522- <property name="sizePolicy" >
523- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
524+ <item row="4" column="1" colspan="2">
525+ <widget class="QComboBox" name="ComboBoxScaleBpm">
526+ <property name="sizePolicy">
527+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
528 <horstretch>0</horstretch>
529 <verstretch>0</verstretch>
530 </sizepolicy>
531 </property>
532- <property name="font" >
533+ <property name="font">
534 <font/>
535 </property>
536- <property name="toolTip" >
537+ <property name="toolTip">
538 <string>Scale BPM display according to playback rate</string>
539 </property>
540 <item>
541- <property name="text" >
542+ <property name="text">
543 <string>Yes</string>
544 </property>
545 </item>
546 <item>
547- <property name="text" >
548+ <property name="text">
549 <string>No</string>
550 </property>
551 </item>
552 </widget>
553 </item>
554- <item row="5" column="0" >
555- <widget class="QLabel" name="TextLabel6_2_2_3_2" >
556- <property name="enabled" >
557+ <item row="5" column="0">
558+ <widget class="QLabel" name="TextLabel6_2_2_3_2">
559+ <property name="enabled">
560 <bool>true</bool>
561 </property>
562- <property name="font" >
563+ <property name="font">
564 <font/>
565 </property>
566- <property name="text" >
567+ <property name="text">
568 <string>Tool tips</string>
569 </property>
570- <property name="wordWrap" >
571+ <property name="wordWrap">
572 <bool>false</bool>
573 </property>
574 </widget>
575 </item>
576- <item row="5" column="1" colspan="2" >
577- <widget class="QComboBox" name="ComboBoxTooltips" >
578- <property name="sizePolicy" >
579- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
580+ <item row="5" column="1" colspan="2">
581+ <widget class="QComboBox" name="ComboBoxTooltips">
582+ <property name="sizePolicy">
583+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
584 <horstretch>0</horstretch>
585 <verstretch>0</verstretch>
586 </sizepolicy>
587 </property>
588- <property name="font" >
589+ <property name="font">
590 <font/>
591 </property>
592 <item>
593- <property name="text" >
594+ <property name="text">
595 <string>On</string>
596 </property>
597 </item>
598 <item>
599- <property name="text" >
600+ <property name="text">
601 <string>Off</string>
602 </property>
603 </item>
604 </widget>
605 </item>
606- <item row="6" column="0" >
607- <widget class="QLabel" name="TextLabel6" >
608- <property name="enabled" >
609+ <item row="6" column="0">
610+ <widget class="QLabel" name="TextLabel6">
611+ <property name="enabled">
612 <bool>true</bool>
613 </property>
614- <property name="font" >
615+ <property name="font">
616 <font/>
617 </property>
618- <property name="text" >
619+ <property name="text">
620 <string>Pitch/Rate slider range</string>
621 </property>
622- <property name="wordWrap" >
623+ <property name="wordWrap">
624 <bool>false</bool>
625 </property>
626 </widget>
627 </item>
628- <item row="6" column="1" colspan="2" >
629- <widget class="QComboBox" name="ComboBoxRateRange" >
630- <property name="sizePolicy" >
631- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
632+ <item row="6" column="1" colspan="2">
633+ <widget class="QComboBox" name="ComboBoxRateRange">
634+ <property name="sizePolicy">
635+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
636 <horstretch>0</horstretch>
637 <verstretch>0</verstretch>
638 </sizepolicy>
639 </property>
640- <property name="font" >
641+ <property name="font">
642 <font/>
643 </property>
644 </widget>
645 </item>
646- <item row="7" column="0" >
647- <widget class="QLabel" name="TextLabel6_2" >
648- <property name="enabled" >
649+ <item row="7" column="0">
650+ <widget class="QLabel" name="TextLabel6_2">
651+ <property name="enabled">
652 <bool>true</bool>
653 </property>
654- <property name="font" >
655+ <property name="font">
656 <font/>
657 </property>
658- <property name="text" >
659+ <property name="text">
660 <string>Pitch/Rate slider direction</string>
661 </property>
662- <property name="wordWrap" >
663+ <property name="wordWrap">
664 <bool>false</bool>
665 </property>
666 </widget>
667 </item>
668- <item row="7" column="1" colspan="2" >
669- <widget class="QComboBox" name="ComboBoxRateDir" >
670- <property name="sizePolicy" >
671- <sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
672+ <item row="7" column="1" colspan="2">
673+ <widget class="QComboBox" name="ComboBoxRateDir">
674+ <property name="sizePolicy">
675+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
676 <horstretch>0</horstretch>
677 <verstretch>0</verstretch>
678 </sizepolicy>
679 </property>
680- <property name="font" >
681+ <property name="font">
682 <font/>
683 </property>
684 </widget>
685 </item>
686- <item row="8" column="0" >
687- <widget class="QLabel" name="label" >
688- <property name="text" >
689+ <item row="10" column="0">
690+ <widget class="QLabel" name="label">
691+ <property name="text">
692 <string>Cue behaviour</string>
693 </property>
694 </widget>
695 </item>
696- <item row="8" column="1" colspan="2" >
697- <widget class="QComboBox" name="ComboBoxCueDefault" />
698+ <item row="10" column="1" colspan="2">
699+ <widget class="QComboBox" name="ComboBoxCueDefault"/>
700 </item>
701- <item row="9" column="0" >
702- <widget class="QLabel" name="textLabelCueRecall" >
703- <property name="text" >
704+ <item row="9" column="0">
705+ <widget class="QLabel" name="textLabelCueRecall">
706+ <property name="text">
707 <string>Auto Recall Cue</string>
708 </property>
709 </widget>
710 </item>
711- <item row="9" column="1" colspan="2" >
712- <widget class="QComboBox" name="ComboBoxCueRecall" />
713- </item>
714- </layout>
715- </item>
716- <item row="1" column="0" >
717- <layout class="QGridLayout" >
718- <item row="0" column="0" >
719- <widget class="QLabel" name="textLabel" >
720- <property name="maximumSize" >
721- <size>
722- <width>16777215</width>
723- <height>20</height>
724- </size>
725- </property>
726- <property name="text" >
727- <string/>
728- </property>
729- <property name="wordWrap" >
730- <bool>true</bool>
731- </property>
732- </widget>
733- </item>
734- </layout>
735- </item>
736- <item row="3" column="0" >
737- <layout class="QGridLayout" >
738- <item row="0" column="0" colspan="2" >
739- <widget class="QLabel" name="TextLabel6_2_3" >
740- <property name="enabled" >
741- <bool>true</bool>
742- </property>
743- <property name="font" >
744- <font/>
745- </property>
746- <property name="text" >
747- <string>Temporary pitch/rate buttons</string>
748- </property>
749- <property name="wordWrap" >
750- <bool>false</bool>
751- </property>
752- </widget>
753- </item>
754- <item row="0" column="3" colspan="2" >
755- <widget class="QLabel" name="TextLabel6_2_3_3" >
756- <property name="enabled" >
757- <bool>true</bool>
758- </property>
759- <property name="font" >
760- <font/>
761- </property>
762- <property name="text" >
763- <string>Permanent pitch/rate buttons</string>
764- </property>
765- <property name="wordWrap" >
766- <bool>false</bool>
767- </property>
768- </widget>
769- </item>
770- <item row="1" column="0" >
771- <widget class="QLabel" name="TextLabel6_2_3_2" >
772- <property name="enabled" >
773- <bool>true</bool>
774- </property>
775- <property name="font" >
776- <font/>
777- </property>
778- <property name="text" >
779- <string>Left click</string>
780- </property>
781- <property name="wordWrap" >
782- <bool>false</bool>
783- </property>
784- </widget>
785- </item>
786- <item row="1" column="1" >
787- <widget class="QDoubleSpinBox" name="spinBoxTempRateLeft" >
788- <property name="toolTip" >
789- <string>Temporary rate change (between 1 and 8000) when left clicking</string>
790- </property>
791- <property name="accelerated" >
792- <bool>true</bool>
793- </property>
794- <property name="decimals" >
795- <number>1</number>
796- </property>
797- <property name="minimum" >
798- <double>0.100000000000000</double>
799- </property>
800- <property name="maximum" >
801- <double>10.000000000000000</double>
802- </property>
803- <property name="singleStep" >
804- <double>0.100000000000000</double>
805- </property>
806- </widget>
807- </item>
808- <item row="1" column="3" >
809- <widget class="QLabel" name="TextLabel6_2_3_2_3" >
810- <property name="enabled" >
811- <bool>true</bool>
812- </property>
813- <property name="font" >
814- <font/>
815- </property>
816- <property name="text" >
817- <string>Left click</string>
818- </property>
819- <property name="wordWrap" >
820- <bool>false</bool>
821- </property>
822- </widget>
823- </item>
824- <item row="1" column="4" >
825- <widget class="QDoubleSpinBox" name="spinBoxPermRateLeft" >
826- <property name="toolTip" >
827- <string>Permanent rate change (between 1 and 8000) when left clicking</string>
828- </property>
829- <property name="accelerated" >
830- <bool>true</bool>
831- </property>
832- <property name="decimals" >
833- <number>1</number>
834- </property>
835- <property name="minimum" >
836- <double>0.100000000000000</double>
837- </property>
838- <property name="maximum" >
839- <double>10.000000000000000</double>
840- </property>
841- <property name="singleStep" >
842- <double>0.100000000000000</double>
843- </property>
844- </widget>
845- </item>
846- <item row="2" column="0" >
847- <widget class="QLabel" name="TextLabel6_2_3_2_2" >
848- <property name="enabled" >
849- <bool>true</bool>
850- </property>
851- <property name="font" >
852- <font/>
853- </property>
854- <property name="text" >
855- <string>Right click</string>
856- </property>
857- <property name="wordWrap" >
858- <bool>false</bool>
859- </property>
860- </widget>
861- </item>
862- <item row="2" column="1" >
863- <widget class="QDoubleSpinBox" name="spinBoxTempRateRight" >
864- <property name="toolTip" >
865- <string>Temporary rate change (between 1 and 8000) when right clicking</string>
866- </property>
867- <property name="accelerated" >
868- <bool>true</bool>
869- </property>
870- <property name="decimals" >
871- <number>1</number>
872- </property>
873- <property name="minimum" >
874- <double>0.100000000000000</double>
875- </property>
876- <property name="maximum" >
877- <double>10.000000000000000</double>
878- </property>
879- <property name="singleStep" >
880- <double>0.100000000000000</double>
881- </property>
882- </widget>
883- </item>
884- <item row="2" column="3" >
885- <widget class="QLabel" name="TextLabel6_2_3_2_2_2" >
886- <property name="enabled" >
887- <bool>true</bool>
888- </property>
889- <property name="font" >
890- <font/>
891- </property>
892- <property name="text" >
893- <string>Right click</string>
894- </property>
895- <property name="wordWrap" >
896- <bool>false</bool>
897- </property>
898- </widget>
899- </item>
900- <item row="2" column="4" >
901- <widget class="QDoubleSpinBox" name="spinBoxPermRateRight" >
902- <property name="toolTip" >
903- <string>Permanent rate change (between 1 and 8000) when right clicking</string>
904- </property>
905- <property name="accelerated" >
906- <bool>true</bool>
907- </property>
908- <property name="decimals" >
909- <number>1</number>
910- </property>
911- <property name="minimum" >
912- <double>0.100000000000000</double>
913- </property>
914- <property name="maximum" >
915- <double>10.000000000000000</double>
916- </property>
917- <property name="singleStep" >
918- <double>0.100000000000000</double>
919- </property>
920- </widget>
921- </item>
922- <item row="3" column="0" >
923- <spacer>
924- <property name="orientation" >
925- <enum>Qt::Vertical</enum>
926- </property>
927- <property name="sizeHint" >
928- <size>
929- <width>20</width>
930- <height>40</height>
931- </size>
932- </property>
933- </spacer>
934+ <item row="12" column="0">
935+ <widget class="QLabel" name="label_2">
936+ <property name="text">
937+ <string>Pitchbend sensitivity</string>
938+ </property>
939+ </widget>
940+ </item>
941+ <item row="9" column="1" colspan="2">
942+ <widget class="QComboBox" name="ComboBoxCueRecall"/>
943+ </item>
944+ <item row="12" column="1">
945+ <widget class="QSlider" name="SliderRateRampSensitivity">
946+ <property name="enabled">
947+ <bool>false</bool>
948+ </property>
949+ <property name="minimum">
950+ <number>100</number>
951+ </property>
952+ <property name="maximum">
953+ <number>2500</number>
954+ </property>
955+ <property name="singleStep">
956+ <number>50</number>
957+ </property>
958+ <property name="value">
959+ <number>250</number>
960+ </property>
961+ <property name="orientation">
962+ <enum>Qt::Horizontal</enum>
963+ </property>
964+ </widget>
965+ </item>
966+ <item row="11" column="0">
967+ <widget class="QLabel" name="label_3">
968+ <property name="text">
969+ <string>Ramping Pitchbend</string>
970+ </property>
971+ </widget>
972+ </item>
973+ <item row="11" column="1">
974+ <widget class="QCheckBox" name="CheckBoxRateRamp">
975+ <property name="text">
976+ <string>Enabled</string>
977+ </property>
978+ </widget>
979+ </item>
980+ <item row="12" column="2">
981+ <widget class="QSpinBox" name="SpinBoxRateRampSensitivity">
982+ <property name="enabled">
983+ <bool>false</bool>
984+ </property>
985+ <property name="minimum">
986+ <number>100</number>
987+ </property>
988+ <property name="maximum">
989+ <number>2500</number>
990+ </property>
991+ <property name="singleStep">
992+ <number>1</number>
993+ </property>
994+ <property name="value">
995+ <number>250</number>
996+ </property>
997+ </widget>
998 </item>
999 </layout>
1000 </item>
1001 </layout>
1002 </widget>
1003- <layoutdefault spacing="6" margin="11" />
1004+ <layoutdefault spacing="6" margin="11"/>
1005 <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
1006 <resources/>
1007- <connections/>
1008+ <connections>
1009+ <connection>
1010+ <sender>SliderRateRampSensitivity</sender>
1011+ <signal>valueChanged(int)</signal>
1012+ <receiver>SpinBoxRateRampSensitivity</receiver>
1013+ <slot>setValue(int)</slot>
1014+ <hints>
1015+ <hint type="sourcelabel">
1016+ <x>347</x>
1017+ <y>382</y>
1018+ </hint>
1019+ <hint type="destinationlabel">
1020+ <x>550</x>
1021+ <y>382</y>
1022+ </hint>
1023+ </hints>
1024+ </connection>
1025+ <connection>
1026+ <sender>SpinBoxRateRampSensitivity</sender>
1027+ <signal>valueChanged(int)</signal>
1028+ <receiver>SliderRateRampSensitivity</receiver>
1029+ <slot>setValue(int)</slot>
1030+ <hints>
1031+ <hint type="sourcelabel">
1032+ <x>552</x>
1033+ <y>382</y>
1034+ </hint>
1035+ <hint type="destinationlabel">
1036+ <x>347</x>
1037+ <y>382</y>
1038+ </hint>
1039+ </hints>
1040+ </connection>
1041+ </connections>
1042 </ui>
1043
1044=== modified file 'mixxx/src/engine/enginebuffer.cpp'
1045--- mixxx/src/engine/enginebuffer.cpp 2009-09-23 09:36:22 +0000
1046+++ mixxx/src/engine/enginebuffer.cpp 2009-12-29 01:10:25 +0000
1047@@ -507,9 +507,9 @@
1048 // Let RateControl do its logic. This is a temporary hack until this
1049 // step is just processing a list of EngineControls
1050 m_pRateControl->process(rate, filepos_play,
1051- file_length_old, iBufferSize);
1052-
1053-
1054+ file_length_old,
1055+ iBufferSize);
1056+
1057 // Give the Reader hints as to which chunks of the current song we
1058 // really care about. It will try very hard to keep these in memory
1059 hintReader(rate, iBufferSize);
1060
1061=== modified file 'mixxx/src/engine/enginebufferscalelinear.cpp'
1062--- mixxx/src/engine/enginebufferscalelinear.cpp 2009-10-18 21:14:48 +0000
1063+++ mixxx/src/engine/enginebufferscalelinear.cpp 2009-12-29 01:10:25 +0000
1064@@ -89,53 +89,58 @@
1065 CSAMPLE * EngineBufferScaleLinear::scale(double playpos, unsigned long buf_size,
1066 CSAMPLE* pBase, unsigned long iBaseLength)
1067 {
1068+ long unscaled_samples_needed;
1069 float rate_add_new = 2.*m_dBaseRate;
1070 float rate_add_old = 2.*m_fOldBaseRate; //Smoothly interpolate to new playback rate
1071 float rate_add = rate_add_new;
1072-
1073- m_fOldBaseRate = m_dBaseRate; //Update the old base rate because we only need to
1074- //interpolate/ramp up the pitch changes once.
1075+ float rate_add_diff = rate_add_new - rate_add_old;
1076+ double rate_add_abs;
1077+
1078+
1079+ //Update the old base rate because we only need to
1080+ //interpolate/ramp up the pitch changes once.
1081+ m_fOldBaseRate = m_dBaseRate;
1082
1083 // Determine position in read_buffer to start from
1084 new_playpos = playpos;
1085-
1086- long unscaled_samples_needed = buf_size + (long)(floor((float)buf_size * ((float)fabs(m_dBaseRate) - 1.0)));
1087- unscaled_samples_needed = long(ceil(fabs(buf_size * m_dBaseRate)));
1088-
1089- //unscaled_samples_needed = buf_size + floor(buf_size * (fabs(m_dBaseRate) - 1.0f));
1090-
1091+
1092+
1093 // Simulate the loop to estimate how many samples we need
1094 double samples = 0;
1095- for (int j = 0; j < buf_size; j+=2) {
1096- if (j < RATE_LERP_LENGTH) {
1097- rate_add = (rate_add_new-rate_add_old)/RATE_LERP_LENGTH*j + rate_add_old;
1098- }
1099- else {
1100- rate_add = rate_add_new;
1101- }
1102+ for (int j = 0; j < RATE_LERP_LENGTH; j+=2)
1103+ {
1104+ rate_add = (rate_add_diff) / RATE_LERP_LENGTH * j + rate_add_old;
1105 samples += fabs(rate_add);
1106 }
1107-
1108+
1109 rate_add = rate_add_new;
1110+ rate_add_abs = fabs(rate_add);
1111+
1112+ samples += (rate_add_abs * ((buf_size - RATE_LERP_LENGTH)/2));
1113+
1114+
1115 unscaled_samples_needed = ceil(samples);
1116 if (!even(unscaled_samples_needed))
1117 unscaled_samples_needed++;
1118+
1119 Q_ASSERT(unscaled_samples_needed >= 0);
1120 Q_ASSERT(unscaled_samples_needed != 0);
1121-
1122+
1123 int buffer_size = 0;
1124 double buffer_index = 0;
1125-
1126+
1127 long current_sample = 0;
1128 long prev_sample = 0;
1129 bool last_read_failed = false;
1130
1131- int i;
1132- for (i = 0; i < buf_size;) {
1133+ int i = 0;
1134+ while(i < buf_size)
1135+ {
1136 prev_sample = current_sample;
1137 current_sample = floor(buffer_index);
1138 if (!even(current_sample))
1139 current_sample++;
1140+
1141 Q_ASSERT(current_sample % 2 == 0);
1142 Q_ASSERT(current_sample >= 0);
1143
1144@@ -143,24 +148,28 @@
1145 m_fPreviousL = buffer_int[prev_sample];
1146 m_fPreviousR = buffer_int[prev_sample+1];
1147 }
1148-
1149+
1150 if (current_sample+1 >= buffer_size) {
1151 //Q_ASSERT(unscaled_samples_needed > 0);
1152 if (unscaled_samples_needed == 0) {
1153 unscaled_samples_needed = 2;
1154 }
1155+
1156 int samples_to_read = math_min(kiLinearScaleReadAheadLength,
1157 unscaled_samples_needed);
1158- buffer_size = m_pReadAheadManager->getNextSamples(m_dBaseRate,
1159- buffer_int,
1160+
1161+ buffer_size = m_pReadAheadManager
1162+ ->getNextSamples(m_dBaseRate,buffer_int,
1163 samples_to_read);
1164+
1165 if (buffer_size == 0 && last_read_failed) {
1166 break;
1167 }
1168 last_read_failed = buffer_size == 0;
1169-
1170+
1171 unscaled_samples_needed -= buffer_size;
1172 buffer_index = buffer_index - floor(buffer_index);
1173+
1174 continue;
1175 }
1176
1177@@ -168,7 +177,7 @@
1178 //prevvents the change from being discontinuous and helps improve sound
1179 //quality.
1180 if (i < RATE_LERP_LENGTH) {
1181- rate_add = (rate_add_new-rate_add_old)/RATE_LERP_LENGTH*i + rate_add_old;
1182+ rate_add = (rate_add_diff) / RATE_LERP_LENGTH * i + rate_add_old;
1183 }
1184 else {
1185 rate_add = rate_add_new;
1186@@ -179,11 +188,16 @@
1187 //Perform linear interpolation
1188 buffer[i] = m_fPreviousL + frac * (buffer_int[current_sample] - m_fPreviousL);
1189 buffer[i+1] = m_fPreviousR + frac * (buffer_int[current_sample+1] - m_fPreviousR);
1190- i += 2;
1191-
1192+
1193 new_playpos += rate_add;
1194- buffer_index += fabs(rate_add);
1195+ if (i < RATE_LERP_LENGTH)
1196+ buffer_index += fabs(rate_add);
1197+ else
1198+ buffer_index += rate_add_abs;
1199+
1200+ i+=2;
1201 }
1202+
1203 // If we broke out of the loop, zero the remaining samples
1204 for (; i < buf_size; i += 2) {
1205 buffer[i] = 0.0f;
1206
1207=== modified file 'mixxx/src/engine/ratecontrol.cpp'
1208--- mixxx/src/engine/ratecontrol.cpp 2009-09-28 02:12:07 +0000
1209+++ mixxx/src/engine/ratecontrol.cpp 2009-12-29 01:10:25 +0000
1210@@ -10,18 +10,35 @@
1211 #include "engine/enginecontrol.h"
1212 #include "engine/ratecontrol.h"
1213
1214+#ifdef _MSC_VER
1215+#include <float.h> // for _isnan() on VC++
1216+#define isnan(x) _isnan(x) // VC++ uses _isnan() instead of isnan()
1217+#else
1218+#include <math.h> // for isnan() everywhere else
1219+#endif
1220+
1221 // Static default values for rate buttons
1222 double RateControl::m_dTemp = 0.01;
1223 double RateControl::m_dTempSmall = 0.001;
1224 double RateControl::m_dPerm = 0.01;
1225 double RateControl::m_dPermSmall = 0.001;
1226
1227+int RateControl::m_iRateRampSensitivity = 250;
1228+enum RateControl::RATERAMP_MODE RateControl::m_eRateRampMode = RateControl::RATERAMP_STEP;
1229+
1230 RateControl::RateControl(const char* _group,
1231- const ConfigObject<ConfigValue>* _config) :
1232+ ConfigObject<ConfigValue>* _config) :
1233 EngineControl(_group, _config),
1234- m_bTempPress(false),
1235- m_dOldRate(0.0f) {
1236-
1237+ m_ePbCurrent(0),
1238+ m_ePbPressed(0),
1239+ m_bTempStarted(false),
1240+ m_dTempRateChange(0.0),
1241+ m_dRateTemp(0.0),
1242+ m_eRampBackMode(RATERAMP_RAMPBACK_NONE),
1243+ m_dRateTempRampbackChange(0.0),
1244+ m_dOldRate(0.0f),
1245+ m_pConfig(_config)
1246+{
1247 m_pRateDir = new ControlObject(ConfigKey(_group, "rate_dir"));
1248 m_pRateRange = new ControlObject(ConfigKey(_group, "rateRange"));
1249 m_pRateSlider = new ControlPotmeter(ConfigKey(_group, "rate"), -1.f, 1.f);
1250@@ -89,19 +106,32 @@
1251 connect(buttonRateTempUpSmall, SIGNAL(valueChanged(double)),
1252 this, SLOT(slotControlRateTempUpSmall(double)));
1253
1254+ // We need the sample rate so we can guesstimate something close
1255+ // what latency is.
1256+ m_pSampleRate = ControlObject::getControl(ConfigKey("[Master]","samplerate"));
1257+
1258 // Wheel to control playback position/speed
1259 m_pWheel = new ControlTTRotary(ConfigKey(_group, "wheel"));
1260
1261 // Scratch controller, this is an accumulator which is useful for
1262- // controllers that return individiual +1 or -1s, these get added up and
1263- // cleared when we read
1264+ // controllers that return individiual +1 or -1s, these get added up and
1265+ // cleared when we read
1266 m_pScratch = new ControlTTRotary(ConfigKey(_group, "scratch"));
1267
1268 m_pJog = new ControlObject(ConfigKey(_group, "jog"));
1269 m_pJogFilter = new Rotary();
1270 // FIXME: This should be dependent on sample rate/block size or something
1271 m_pJogFilter->setFilterLength(5);
1272-
1273+
1274+ // Update Internal Settings
1275+ // Set Pitchbend Mode
1276+ m_eRateRampMode = (RateControl::RATERAMP_MODE)
1277+ m_pConfig->getValueString(ConfigKey("[Controls]","RateRamp")).toInt();
1278+
1279+ // Set the Sensitivity
1280+ m_iRateRampSensitivity =
1281+ m_pConfig->getValueString(ConfigKey("[Controls]","RateRampSensitivity")).toInt();
1282+
1283 }
1284
1285 RateControl::~RateControl() {
1286@@ -130,6 +160,27 @@
1287 delete m_pJogFilter;
1288 }
1289
1290+void RateControl::setRateRamp(bool linearMode)
1291+{
1292+ if ( linearMode )
1293+ m_eRateRampMode = RateControl::RATERAMP_LINEAR;
1294+ else
1295+ m_eRateRampMode = RateControl::RATERAMP_STEP;
1296+}
1297+
1298+void RateControl::setRateRampSensitivity(int sense)
1299+{
1300+ // Reverse the actual sensitivity value passed.
1301+ // That way the gui works in an intuitive manner.
1302+ sense = RATE_SENSITIVITY_MAX - sense + RATE_SENSITIVITY_MIN;
1303+ if ( sense < RATE_SENSITIVITY_MIN )
1304+ m_iRateRampSensitivity = RATE_SENSITIVITY_MIN;
1305+ else if ( sense > RATE_SENSITIVITY_MAX )
1306+ m_iRateRampSensitivity = RATE_SENSITIVITY_MAX;
1307+ else
1308+ m_iRateRampSensitivity = sense;
1309+}
1310+
1311 void RateControl::setTemp(double v) {
1312 m_dTemp = v;
1313 }
1314@@ -194,65 +245,61 @@
1315
1316 void RateControl::slotControlRateTempDown(double)
1317 {
1318- // Adjusts temp rate down if button pressed, otherwise set to 0.
1319- if (buttonRateTempDown->get() && !m_bTempPress)
1320+ // Set the state of the Temporary button. Logic is handled in ::process()
1321+ if (buttonRateTempDown->get() && !(m_ePbPressed & RateControl::RATERAMP_DOWN))
1322 {
1323- m_bTempPress = true;
1324- m_dOldRate = m_pRateSlider->get();
1325- m_pRateSlider->sub(m_pRateDir->get() * m_dTemp / (100. * m_pRateRange->get()));
1326+ m_ePbPressed |= RateControl::RATERAMP_DOWN;
1327+ m_ePbCurrent = RateControl::RATERAMP_DOWN;
1328 }
1329 else if (!buttonRateTempDown->get())
1330 {
1331- m_bTempPress = false;
1332- m_pRateSlider->set(m_dOldRate);
1333+ m_ePbPressed &= ~RateControl::RATERAMP_DOWN;
1334+ m_ePbCurrent = m_ePbPressed;
1335 }
1336 }
1337
1338 void RateControl::slotControlRateTempDownSmall(double)
1339 {
1340- // Adjusts temp rate down if button pressed, otherwise set to 0.
1341- if (buttonRateTempDownSmall->get() && !m_bTempPress)
1342+ // Set the state of the Temporary button. Logic is handled in ::process()
1343+ if (buttonRateTempDownSmall->get() && !(m_ePbPressed & RateControl::RATERAMP_DOWN))
1344 {
1345- m_bTempPress = true;
1346- m_dOldRate = m_pRateSlider->get();
1347- m_pRateSlider->sub(m_pRateDir->get() * m_dTempSmall / (100. * m_pRateRange->get()));
1348+ m_ePbPressed |= RateControl::RATERAMP_DOWN;
1349+ m_ePbCurrent = RateControl::RATERAMP_DOWN;
1350 }
1351 else if (!buttonRateTempDownSmall->get())
1352 {
1353- m_bTempPress = false;
1354- m_pRateSlider->set(m_dOldRate);
1355+ m_ePbPressed &= ~RateControl::RATERAMP_DOWN;
1356+ m_ePbCurrent = m_ePbPressed;
1357 }
1358 }
1359
1360 void RateControl::slotControlRateTempUp(double)
1361 {
1362- // Adjusts temp rate up if button pressed, otherwise set to 0.
1363- if (buttonRateTempUp->get() && !m_bTempPress)
1364+ // Set the state of the Temporary button. Logic is handled in ::process()
1365+ if (buttonRateTempUp->get() && !(m_ePbPressed & RateControl::RATERAMP_UP))
1366 {
1367- m_bTempPress = true;
1368- m_dOldRate = m_pRateSlider->get();
1369- m_pRateSlider->add(m_pRateDir->get() * m_dTemp / (100. * m_pRateRange->get()));
1370+ m_ePbPressed |= RateControl::RATERAMP_UP;
1371+ m_ePbCurrent = RateControl::RATERAMP_UP;
1372 }
1373 else if (!buttonRateTempUp->get())
1374 {
1375- m_bTempPress = false;
1376- m_pRateSlider->set(m_dOldRate);
1377+ m_ePbPressed &= ~RateControl::RATERAMP_UP;
1378+ m_ePbCurrent = m_ePbPressed;
1379 }
1380 }
1381
1382 void RateControl::slotControlRateTempUpSmall(double)
1383 {
1384- // Adjusts temp rate up if button pressed, otherwise set to 0.
1385- if (buttonRateTempUpSmall->get() && !m_bTempPress)
1386+ // Set the state of the Temporary button. Logic is handled in ::process()
1387+ if (buttonRateTempUpSmall->get() && !(m_ePbPressed & RateControl::RATERAMP_UP))
1388 {
1389- m_bTempPress = true;
1390- m_dOldRate = m_pRateSlider->get();
1391- m_pRateSlider->add(m_pRateDir->get() * m_dTempSmall / (100. * m_pRateRange->get()));
1392+ m_ePbPressed |= RateControl::RATERAMP_UP;
1393+ m_ePbCurrent = RateControl::RATERAMP_UP;
1394 }
1395 else if (!buttonRateTempUpSmall->get())
1396 {
1397- m_bTempPress = false;
1398- m_pRateSlider->set(m_dOldRate);
1399+ m_ePbPressed &= ~RateControl::RATERAMP_UP;
1400+ m_ePbCurrent = m_ePbPressed;
1401 }
1402 }
1403
1404@@ -318,15 +365,17 @@
1405 } else {
1406 // The buffer is playing, so calculate the buffer rate.
1407
1408- // There are three rate effects we apply: wheel, scratch, and jog.
1409+ // There are four rate effects we apply: wheel, scratch, jog and temp.
1410 // Wheel: a linear additive effect
1411 // Scratch: a rate multiplier
1412- // Jog: a linear additive effect whose value is filtered
1413-
1414+ // Jog: a linear additive effect whose value is filtered
1415+ // Temp: pitch bend
1416+
1417 rate = (1. + getRawRate()) * baserate;
1418 rate += wheelFactor/10.;
1419 rate *= scratchFactor;
1420 rate += jogFactor;
1421+ rate += (getTempRate()) * baserate;
1422
1423 // If we are reversing, flip the rate.
1424 if (m_pReverseButton->get()) {
1425@@ -340,6 +389,145 @@
1426 double RateControl::process(const double rate,
1427 const double currentSample,
1428 const double totalSamples,
1429- const int iBufferSize) {
1430- return 0;
1431+ const int bufferSamples)
1432+{
1433+ /*
1434+ * Code to handle temporary rate change buttons.
1435+ *
1436+ * We support two behaviours, the standard ramped pitch bending
1437+ * and pitch shift stepping, which is the old behaviour.
1438+ */
1439+
1440+ /*
1441+ * Initialize certain values necessary for pitchbending. Most of this
1442+ * code should be handled inside a slot, but we'd need to connect to
1443+ * the troublesome Latency ControlObject... Either the Master or Soundcard
1444+ * one.
1445+ */
1446+
1447+ double latrate = ((double)bufferSamples / (double)m_pSampleRate->get());
1448+
1449+
1450+ if ((m_ePbPressed) && (!m_bTempStarted))
1451+ {
1452+ m_bTempStarted = true;
1453+ m_dOldRate = m_pRateSlider->get();
1454+
1455+
1456+ if ( m_eRateRampMode == RATERAMP_STEP )
1457+ {
1458+ // old temporary pitch shift behaviour
1459+ double range = m_pRateRange->get();
1460+
1461+ // Avoid Division by Zero
1462+ if (range == 0) {
1463+ qDebug() << "Avoiding a Division by Zero in RATERAMP_STEP code";
1464+ return m_dOldRate;
1465+ }
1466+
1467+ double change = m_pRateDir->get() * m_dTemp /
1468+ (100. * range);
1469+ double csmall = m_pRateDir->get() * m_dTempSmall /
1470+ (100. * range);
1471+
1472+
1473+ if (buttonRateTempUp->get())
1474+ addRateTemp(change);
1475+ else if (buttonRateTempDown->get())
1476+ subRateTemp(change);
1477+ else if (buttonRateTempUpSmall->get())
1478+ addRateTemp(csmall);
1479+ else if (buttonRateTempDownSmall->get())
1480+ subRateTemp(csmall);
1481+ }
1482+ else
1483+ {
1484+ m_dTempRateChange = ((double)latrate / ((double)m_iRateRampSensitivity / 100.));
1485+
1486+ if (m_eRampBackMode == RATERAMP_RAMPBACK_PERIOD)
1487+ m_dRateTempRampbackChange = 0.0;
1488+ }
1489+
1490+ }
1491+
1492+ if ((m_ePbCurrent) && (m_eRateRampMode == RATERAMP_LINEAR))
1493+ {
1494+ // apply ramped pitchbending
1495+ if ( m_ePbCurrent == RateControl::RATERAMP_UP )
1496+ addRateTemp(m_dTempRateChange);
1497+ else if ( m_ePbCurrent == RateControl::RATERAMP_DOWN )
1498+ subRateTemp(m_dTempRateChange);
1499+ }
1500+ else if ((!m_ePbCurrent) && (m_eRateRampMode == RATERAMP_STEP))
1501+ {
1502+ resetRateTemp();
1503+ }
1504+ else if ((m_bTempStarted) || ((m_eRampBackMode != RATERAMP_RAMPBACK_NONE) && (m_dRateTemp != 0.0)))
1505+ {
1506+ // No buttons pressed, so time to deinitialize
1507+ m_bTempStarted = false;
1508+
1509+
1510+ if ( m_eRateRampMode == RATERAMP_STEP )
1511+ m_pRateSlider->set(m_dOldRate);
1512+ else {
1513+
1514+ if ((m_eRampBackMode == RATERAMP_RAMPBACK_PERIOD) && (m_dRateTempRampbackChange == 0.0 ))
1515+ {
1516+ int period = 2;
1517+ if (period)
1518+ m_dRateTempRampbackChange = fabs(m_dRateTemp / (double)period);
1519+ else {
1520+ resetRateTemp();
1521+ return 1;
1522+ }
1523+
1524+ }
1525+
1526+ if ((m_eRampBackMode != RATERAMP_RAMPBACK_NONE))
1527+ {
1528+
1529+ if ( fabs(m_dRateTemp) < m_dRateTempRampbackChange)
1530+ resetRateTemp();
1531+ else if ( m_dRateTemp > 0 )
1532+ subRateTemp(m_dRateTempRampbackChange);
1533+ else
1534+ addRateTemp(m_dRateTempRampbackChange);
1535+ }
1536+ else
1537+ resetRateTemp();
1538+ }
1539+ }
1540+
1541+ return 1;
1542+}
1543+
1544+double RateControl::getTempRate() {
1545+ return (m_pRateDir->get() * (m_dRateTemp * m_pRateRange->get()));
1546+}
1547+
1548+void RateControl::setRateTemp(double v)
1549+{
1550+ m_dRateTemp = v;
1551+ if ( m_dRateTemp < -1.0 )
1552+ m_dRateTemp = -1.0;
1553+ else if ( m_dRateTemp > 1.0 )
1554+ m_dRateTemp = 1.0;
1555+ else if ( isnan(m_dRateTemp))
1556+ m_dRateTemp = 0;
1557+}
1558+
1559+void RateControl::addRateTemp(double v)
1560+{
1561+ setRateTemp(m_dRateTemp + v);
1562+}
1563+
1564+void RateControl::subRateTemp(double v)
1565+{
1566+ setRateTemp(m_dRateTemp - v);
1567+}
1568+
1569+void RateControl::resetRateTemp(void)
1570+{
1571+ setRateTemp(0.0);
1572 }
1573
1574=== modified file 'mixxx/src/engine/ratecontrol.h'
1575--- mixxx/src/engine/ratecontrol.h 2009-10-19 01:28:20 +0000
1576+++ mixxx/src/engine/ratecontrol.h 2009-12-29 01:10:25 +0000
1577@@ -9,6 +9,11 @@
1578 #include "configobject.h"
1579 #include "engine/enginecontrol.h"
1580
1581+const int RATE_TEMP_STEP = 500;
1582+const int RATE_TEMP_STEP_SMALL = RATE_TEMP_STEP * 10.;
1583+const int RATE_SENSITIVITY_MIN = 100;
1584+const int RATE_SENSITIVITY_MAX = 2500;
1585+
1586 class Rotary;
1587 class ControlTTRotary;
1588 class ControlObject;
1589@@ -21,7 +26,7 @@
1590 class RateControl : public EngineControl {
1591 Q_OBJECT
1592 public:
1593- RateControl(const char* _group, const ConfigObject<ConfigValue>* _config);
1594+ RateControl(const char* _group, ConfigObject<ConfigValue>* _config);
1595 ~RateControl();
1596
1597 // Must be called during each callback of the audio thread so that
1598@@ -29,7 +34,7 @@
1599 double process(const double dRate,
1600 const double currentSample,
1601 const double totalSamples,
1602- const int iBufferSize);
1603+ const int bufferSamples);
1604 // Returns the current engine rate.
1605 double calculateRate(double baserate, bool paused);
1606 double getRawRate();
1607@@ -42,7 +47,11 @@
1608 static void setPerm(double v);
1609 // Set rate change when perm rate small button is pressed
1610 static void setPermSmall(double v);
1611-
1612+ /** Set Rate Ramp Mode */
1613+ static void setRateRamp(bool);
1614+ /** Set Rate Ramp Sensitivity */
1615+ static void setRateRampSensitivity(int);
1616+
1617 public slots:
1618 void slotControlRatePermDown(double);
1619 void slotControlRatePermDownSmall(double);
1620@@ -58,8 +67,19 @@
1621 double getJogFactor();
1622 double getWheelFactor();
1623 double getScratchFactor();
1624-
1625- // Values used when temp and perm rate buttons are pressed
1626+
1627+ /** Set rate change of the temporary pitch rate */
1628+ void setRateTemp(double v);
1629+ /** Add a value to the temporary pitch rate */
1630+ void addRateTemp(double v);
1631+ /** Subtract a value from the temporary pitch rate */
1632+ void subRateTemp(double v);
1633+ /** Reset the temporary pitch rate */
1634+ void resetRateTemp(void);
1635+ /** Get the 'Raw' Temp Rate */
1636+ double getTempRate(void);
1637+
1638+ /** Values used when temp and perm rate buttons are pressed */
1639 static double m_dTemp, m_dTempSmall, m_dPerm, m_dPermSmall;
1640
1641 ControlPushButton *buttonRateTempDown, *buttonRateTempDownSmall,
1642@@ -78,15 +98,65 @@
1643 ControlObject* m_pJog;
1644 Rotary* m_pJogFilter;
1645
1646- // Is true if a rate temp button is pressed
1647- bool m_bTempPress;
1648+ ControlObject *m_pSampleRate;
1649
1650- // Old playback rate. Stored in this variable while a temp pitch change
1651- // buttons is in effect. It does not work to just decrease the pitch slider
1652- // by the value it has been increased with when the temp button was pressed,
1653- // because there is a fixed limit on the range of the pitch slider
1654+ // Enumerations which hold the state of the pitchbend buttons.
1655+ // These enumerations can be used like a bitmask.
1656+ enum RATERAMP_DIRECTION {
1657+ RATERAMP_NONE = 0, // No buttons are held down
1658+ RATERAMP_DOWN = 1, // Down button is being held
1659+ RATERAMP_UP = 2, // Up button is being held
1660+ RATERAMP_BOTH = 3 // Both buttons are being held down
1661+ };
1662+
1663+ // Rate ramping mode:
1664+ // RATERAMP_STEP: pitch takes a temporary step up/down a certain amount.
1665+ // RATERAMP_LINEAR: pitch moves up/down in a progresively linear fashion.
1666+ enum RATERAMP_MODE {
1667+ RATERAMP_STEP = 0,
1668+ RATERAMP_LINEAR = 1
1669+ };
1670+
1671+ // This defines how the rate returns to normal. Currently unused.
1672+ // Rate ramp back mode:
1673+ // RATERAMP_RAMPBACK_NONE: returns back to normal all at once.
1674+ // RATERAMP_RAMPBACK_SPEED: moves back in a linearly progresive manner.
1675+ // RATERAMP_RAMPBACK_PERIOD: returns to normal within a period of time.
1676+ enum RATERAMP_RAMPBACK_MODE {
1677+ RATERAMP_RAMPBACK_NONE,
1678+ RATERAMP_RAMPBACK_SPEED,
1679+ RATERAMP_RAMPBACK_PERIOD
1680+ };
1681+
1682+ // The current rate ramping direction. Only holds the last button pressed.
1683+ int m_ePbCurrent;
1684+ // The rate ramping buttons which are currently being pressed.
1685+ int m_ePbPressed;
1686+
1687+ /** This is true if we've already started to ramp the rate */
1688+ int m_bTempStarted;
1689+ /** Set to the rate change used for rate temp */
1690+ double m_dTempRateChange;
1691+ /** Set the Temporary Rate Change Mode */
1692+ static enum RATERAMP_MODE m_eRateRampMode;
1693+ /** The Rate Temp Sensitivity, the higher it is the slower it gets */
1694+ static int m_iRateRampSensitivity;
1695+ /** Temporary pitchrate, added to the permanent rate for calculateRate */
1696+ double m_dRateTemp;
1697+ /** */
1698+ enum RATERAMP_RAMPBACK_MODE m_eRampBackMode;
1699+ /** Return speed for temporary rate change */
1700+ double m_dRateTempRampbackChange;
1701+
1702+ /** Old playback rate. Stored in this variable while a temp pitch change
1703+ * buttons is in effect. It does not work to just decrease the pitch slider
1704+ * by the value it has been increased with when the temp button was
1705+ * pressed, because there is a fixed limit on the range of the pitch
1706+ * slider */
1707 double m_dOldRate;
1708
1709+ /** Handle for configuration */
1710+ ConfigObject<ConfigValue>* m_pConfig;
1711 };
1712
1713 #endif /* RATECONTROL_H */