Merge lp:~zestoi/mixxx/spinback_brake into lp:~mixxxdevelopers/mixxx/trunk

Proposed by Zestoi
Status: Merged
Merged at revision: 3212
Proposed branch: lp:~zestoi/mixxx/spinback_brake
Merge into: lp:~mixxxdevelopers/mixxx/trunk
Diff against target: 188 lines (+104/-11)
2 files modified
mixxx/src/controllers/controllerengine.cpp (+99/-8)
mixxx/src/controllers/controllerengine.h (+5/-3)
To merge this branch: bzr merge lp:~zestoi/mixxx/spinback_brake
Reviewer Review Type Date Requested Status
RJ Skerry-Ryan Approve
Review via email: mp+107526@code.launchpad.net

Description of the change

implements a spinback/brake effect in the engine

new function: ControllerEngine::brake() to enable/disable the effect

modified function: ControllerEngine::scratchProcess()

* m_rampFactor[deck] variable instead of 0.0001 constant
* extra logic to work out when the scratch timer can be disabled
* m_brakeActive[deck] to store whether we are in this effect or normal scratching mode
* m_brakeKeylock[deck] to store the keylock status so we can disable for the effect and re-enable afterwards if we need to

To post a comment you must log in.
Revision history for this message
RJ Skerry-Ryan (rryan) wrote :

LGTM -- thanks zestoi!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mixxx/src/controllers/controllerengine.cpp'
2--- mixxx/src/controllers/controllerengine.cpp 2012-05-01 21:42:24 +0000
3+++ mixxx/src/controllers/controllerengine.cpp 2012-05-26 16:40:25 +0000
4@@ -41,6 +41,9 @@
5 m_rampTo.resize(kDecks);
6 m_ramp.resize(kDecks);
7 m_pitchFilter.resize(kDecks);
8+ m_rampFactor.resize(kDecks);
9+ m_brakeActive.resize(kDecks);
10+ m_brakeKeylock.resize(kDecks);
11
12 // Initialize arrays used for testing and pointers
13 for (int i=0; i < kDecks; i++) {
14@@ -945,6 +948,8 @@
15 m_dx[deck] = 1/intervalsPerSecond;
16 m_intervalAccumulator[deck] = 0;
17 m_ramp[deck] = false;
18+ m_rampFactor[deck] = 0.001;
19+ m_brakeActive[deck] = false;
20
21 QString group = QString("[Channel%1]").arg(deck);
22
23@@ -1030,8 +1035,9 @@
24 -------- ------------------------------------------------------ */
25 void ControllerEngine::scratchProcess(int timerId) {
26 int deck = m_scratchTimers[timerId];
27+ QString group = QString("[Channel%1]").arg(deck);
28 PitchFilter* filter = m_pitchFilter[deck];
29- QString group = QString("[Channel%1]").arg(deck);
30+ float pitch = filter->currentPitch();
31
32 if (!filter) {
33 qWarning() << "Scratch filter pointer is null on deck" << deck;
34@@ -1042,7 +1048,7 @@
35
36 // If we're ramping to end scratching, feed fixed data
37 if (m_ramp[deck]) {
38- filter->observation(m_rampTo[deck]*0.001);
39+ filter->observation(m_rampTo[deck]*m_rampFactor[deck]);
40 } else {
41 // This will (and should) be 0 if no net ticks have been accumulated
42 // (i.e. the wheel is stopped)
43@@ -1059,17 +1065,26 @@
44 m_intervalAccumulator[deck] = 0;
45
46 // If we're ramping and the current pitch is really close to the rampTo
47- // value, end scratching
48+ // value or we're in brake mode and have crossed over the zero value, end scratching
49
50 //if (m_ramp[deck]) qDebug() << "Ramping to" << m_rampTo[deck] << " Currently at:" << filter->currentPitch();
51- if (m_ramp[deck] && fabs(m_rampTo[deck]-filter->currentPitch()) <= 0.00001) {
52+ if ((m_ramp[deck] && fabs(m_rampTo[deck]-filter->currentPitch()) <= 0.00001)
53+ || (m_brakeActive[deck] && ((pitch > 0.0 && filter->currentPitch() < 0.0) || (pitch < 0.0 && filter->currentPitch() > 0.0)))) {
54+
55 // Not ramping no mo'
56 m_ramp[deck] = false;
57
58- // Clear scratch2_enable
59- cot = getControlObjectThread(group, "scratch2_enable");
60- if(cot != NULL) {
61- cot->slotSet(0);
62+ // Clear scratch2_enable unless brake mode where we just set scratch2 to 0.0
63+ if (m_brakeActive[deck]) {
64+ if (cot != NULL) {
65+ cot->slotSet(0.0);
66+ }
67+ }
68+ else {
69+ cot = getControlObjectThread(group, "scratch2_enable");
70+ if(cot != NULL) {
71+ cot->slotSet(0);
72+ }
73 }
74
75 // Remove timer
76@@ -1077,6 +1092,7 @@
77 m_scratchTimers.remove(timerId);
78
79 m_dx[deck] = 0.0;
80+ m_brakeActive[deck] = false;
81 }
82 }
83
84@@ -1154,3 +1170,78 @@
85 m_st.disable(pControl);
86 }
87 }
88+
89+/* -------- ------------------------------------------------------
90+ Purpose: [En/dis]ables spinback effect for the channel
91+ Input: deck, activate/deactivate, factor (optional),
92+ delay (optional), rate (optional)
93+ Output: -
94+ -------- ------------------------------------------------------ */
95+void ControllerEngine::spinback(int deck, bool activate, float factor, float rate) {
96+ // defaults for args set in header file
97+ brake(deck, activate, factor, rate);
98+}
99+
100+/* -------- ------------------------------------------------------
101+ Purpose: [En/dis]ables brake/spinback effect for the channel
102+ Input: deck, activate/deactivate, factor (optional),
103+ delay (optional), rate (optional)
104+ Output: -
105+ -------- ------------------------------------------------------ */
106+void ControllerEngine::brake(int deck, bool activate, float factor, float rate) {
107+ QString group = QString("[Channel%1]").arg(deck);
108+
109+ // kill timer when both enabling or disabling
110+ int timerId = m_scratchTimers.key(deck);
111+ killTimer(timerId);
112+ m_scratchTimers.remove(timerId);
113+
114+ // enable/disable scratch2 mode
115+ ControlObjectThread *cot = getControlObjectThread(group, "scratch2_enable");
116+ if (cot != NULL) {
117+ cot->slotSet(activate ? 1 : 0);
118+ }
119+
120+ // used in scratchProcess for the different timer behaviour we need
121+ m_brakeActive[deck] = activate;
122+
123+ if (activate) {
124+ // store the new values for this spinback/brake effect
125+ m_rampFactor[deck] = rate * factor / 100000; // approx 1 second for a factor of 1
126+ m_rampTo[deck] = -1.0;
127+
128+ // save current keylock status and disable
129+ cot = getControlObjectThread(group, "keylock");
130+ if (cot != NULL) {
131+ m_brakeKeylock[deck] = cot->get();
132+ cot->slotSet(0);
133+ }
134+
135+ // setup timer and send first scratch2 'tick'
136+ int timerId = startTimer(1);
137+ m_scratchTimers[timerId] = deck;
138+
139+ cot = getControlObjectThread(group, "scratch2");
140+ if (cot != NULL) {
141+ cot->slotSet(rate);
142+ }
143+
144+ // setup the filter
145+ PitchFilter* filter = m_pitchFilter[deck];
146+ if (filter != NULL) {
147+ m_pitchFilter[deck]->init(0.001, rate);
148+ }
149+
150+ // activate the ramping in scratchProcess()
151+ m_ramp[deck] = true;
152+ }
153+ else {
154+ // re-enable keylock if needed
155+ if (m_brakeKeylock[deck]) {
156+ cot = getControlObjectThread(group, "keylock");
157+ if (cot != NULL) {
158+ cot->slotSet(1);
159+ }
160+ }
161+ }
162+}
163
164=== modified file 'mixxx/src/controllers/controllerengine.h'
165--- mixxx/src/controllers/controllerengine.h 2012-04-27 04:04:33 +0000
166+++ mixxx/src/controllers/controllerengine.h 2012-05-26 16:40:25 +0000
167@@ -59,6 +59,8 @@
168 Q_INVOKABLE void scratchTick(int deck, int interval);
169 Q_INVOKABLE void scratchDisable(int deck, bool ramp = true);
170 Q_INVOKABLE void softTakeover(QString group, QString name, bool set);
171+ Q_INVOKABLE void brake(int deck, bool activate, float factor=0.9, float rate=1.0);
172+ Q_INVOKABLE void spinback(int deck, bool activate, float factor=1.8, float rate=-10.0);
173
174 // Handler for timers that scripts set.
175 virtual void timerEvent(QTimerEvent *event);
176@@ -117,9 +119,9 @@
177 ByteArrayClass *m_pBaClass;
178 // 256 (default) available virtual decks is enough I would think.
179 // If more are needed at run-time, these will move to the heap automatically
180- QVarLengthArray<int> m_intervalAccumulator;
181- QVarLengthArray<float> m_dx, m_rampTo;
182- QVarLengthArray<bool> m_ramp;
183+ QVarLengthArray<int> m_intervalAccumulator, m_brakeKeylock;
184+ QVarLengthArray<float> m_dx, m_rampTo, m_rampFactor;
185+ QVarLengthArray<bool> m_ramp, m_brakeActive;
186 QVarLengthArray<PitchFilter*> m_pitchFilter;
187 QHash<int, int> m_scratchTimers;
188 };

Subscribers

People subscribed via source and target branches