Merge lp:~mixxxdevelopers/mixxx/features_spinny into lp:~mixxxdevelopers/mixxx/trunk
- features_spinny
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 2794 |
Proposed branch: | lp:~mixxxdevelopers/mixxx/features_spinny |
Merge into: | lp:~mixxxdevelopers/mixxx/trunk |
Diff against target: |
904 lines (+617/-26) 18 files modified
mixxx/build/depends.py (+2/-0) mixxx/src/dlgprefvinyl.cpp (+17/-2) mixxx/src/dlgprefvinyl.h (+4/-9) mixxx/src/engine/positionscratchcontroller.cpp (+1/-0) mixxx/src/engine/vinylcontrolcontrol.cpp (+13/-0) mixxx/src/engine/vinylcontrolcontrol.h (+1/-0) mixxx/src/mathstuff.h (+1/-1) mixxx/src/sharedglcontext.cpp (+23/-0) mixxx/src/sharedglcontext.h (+15/-0) mixxx/src/skin/legacyskinparser.cpp (+19/-0) mixxx/src/skin/legacyskinparser.h (+1/-0) mixxx/src/vinylcontrol/vinylcontrol.h (+3/-0) mixxx/src/waveformviewerfactory.cpp (+2/-11) mixxx/src/waveformviewerfactory.h (+0/-1) mixxx/src/widget/wglwaveformviewer.cpp (+13/-2) mixxx/src/widget/wglwaveformviewer.h (+1/-0) mixxx/src/widget/wspinny.cpp (+434/-0) mixxx/src/widget/wspinny.h (+67/-0) |
To merge this branch: | bzr merge lp:~mixxxdevelopers/mixxx/features_spinny |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
RJ Skerry-Ryan | Approve | ||
Owen Williams | Needs Fixing | ||
Review via email: mp+60327@code.launchpad.net |
Commit message
Description of the change
Spinning vinyl widget, and factors out GL context creation into its own class. Also makes the waveform grab used the _closed_ hand icon. :)
RJ Skerry-Ryan (rryan) wrote : | # |
RJ Skerry-Ryan (rryan) wrote : | # |
* Qt::MiddleButton isn't compatible with <Qt 4.7 either, use Qt::MidButton instead
- 2775. By Albert Santoni
-
* Addressing RJ's code review:
- Remove unnecessary SharedGLContext destructor (kept private constructor though).
- Handle WSpinny math when track_samples or other params are NaN.
- Protect all pixmap drawing in WSpinny against NULL pointers and pixmaps.
- Fixes for Qt < 4.7 compatibility
Albert Santoni (gamegod) wrote : | # |
k, fixed everything you pointed out in r2775 plus the ASSERTs Jus found when no tracks were loaded.
Thanks,
Albert
- 2776. By Albert Santoni
-
Squash WSpinny compiler warnings and my leftover qDebugs (oops)
- 2777. By Albert Santoni
-
* Merged from trunk
Owen Williams (ywwg) wrote : | # |
This widget will need to understand 33 vs 45 rpm record speeds and move the spinner at a higher speed if the record is set to 45RPM. Use [ChannelX]
Also, is the spinny thing guaranteed to show the same angle for the same sample index number? That's the important part :).
also, "roughly 0.5" is not acceptable. This value needs to be exact (5/9).
- 2778. By Albert Santoni
-
Use exact 33.3 RPM rotational speed in WSpinny
Albert Santoni (gamegod) wrote : | # |
Hey Owen,
I just jammed that fraction in there to make the rotation more precise.
The good news is that the spinny thing is guaranteed to show the same
angle for the same sample index.
The bad news is that I can't monitor for changes of that ConfigKey
because it's a ConfigKey and not a ControlObject. (ie. WSpinny can't
tell when the vinyl control speed preferences get changed.) In the
past, we've solved this problem by duplicating the ConfigKey's value
across to a ControlObject. For example, the [Master]
ControlObject just mirrors a ConfigKey that's hooked into the prefs. I
guess I'll have to fix this that way?
Thanks,
Albert
On Mon, May 9, 2011 at 7:18 AM, Owen Williams <email address hidden> wrote:
> Review: Needs Fixing
> This widget will need to understand 33 vs 45 rpm record speeds and move the spinner at a higher speed if the record is set to 45RPM. Use [ChannelX]
>
> Also, is the spinny thing guaranteed to show the same angle for the same sample index number? That's the important part :).
>
> also, "roughly 0.5" is not acceptable. This value needs to be exact (5/9).
> --
> https:/
> Your team Mixxx Development Team is subscribed to branch lp:mixxx.
>
--
Albert Santoni
Developer, Mixxx
http://
- 2779. By Albert Santoni
-
* WSpinny respects the vinyl control RPM setting now so it always matches your turntables' speed.
* Minor cleanup in DlgPrefVinyl.
Albert Santoni (gamegod) wrote : | # |
Ok that all up in r2779. Should be good to go now and matches your vinyl control speed.
Albert
Albert Santoni (gamegod) wrote : | # |
"Ok, *fixed* that all up in r2779.
> Ok that all up in r2779. Should be good to go now and matches your vinyl
> control speed.
>
> Albert
RJ Skerry-Ryan (rryan) wrote : | # |
LGTM! thanks albert
Owen Williams (ywwg) wrote : | # |
> The bad news is that I can't monitor for changes of that ConfigKey
> because it's a ConfigKey and not a ControlObject. (ie. WSpinny can't
> tell when the vinyl control speed preferences get changed.) In the
> past, we've solved this problem by duplicating the ConfigKey's value
> across to a ControlObject. For example, the [Master]
> ControlObject just mirrors a ConfigKey that's hooked into the prefs. I
> guess I'll have to fix this that way?
We can either do that, or I can add a function in vinylcontrolproxy like getSpeed() that returns 1.0 for 33rpm, and 1.35 for 45rpm
Owen Williams (ywwg) wrote : | # |
Is there a skin / example xml that shows this widget in action? It looks like it wants a couple pixmaps
RJ Skerry-Ryan (rryan) wrote : | # |
Jus is cooking up some examples -- my guess is they will show up in his 1.10
branch soon.
On Wed, May 11, 2011 at 2:09 PM, Owen Williams <email address hidden> wrote:
> Is there a skin / example xml that shows this widget in action? It looks
> like it wants a couple pixmaps
> --
>
> https:/
> You are reviewing the proposed merge of
> lp:~mixxxdevelopers/mixxx/features_spinny into lp:mixxx.
>
Preview Diff
1 | === modified file 'mixxx/build/depends.py' |
2 | --- mixxx/build/depends.py 2011-04-28 21:54:22 +0000 |
3 | +++ mixxx/build/depends.py 2011-05-11 04:41:18 +0000 |
4 | @@ -414,6 +414,7 @@ |
5 | |
6 | "soundsource.cpp", |
7 | |
8 | + "sharedglcontext.cpp", |
9 | "widget/wwidget.cpp", |
10 | "widget/wlabel.cpp", |
11 | "widget/wtracktext.cpp", |
12 | @@ -428,6 +429,7 @@ |
13 | "widget/wslider.cpp", |
14 | "widget/wstatuslight.cpp", |
15 | "widget/woverview.cpp", |
16 | + "widget/wspinny.cpp", |
17 | "widget/wskincolor.cpp", |
18 | "widget/wabstractcontrol.cpp", |
19 | "widget/wsearchlineedit.cpp", |
20 | |
21 | === modified file 'mixxx/src/dlgprefvinyl.cpp' |
22 | --- mixxx/src/dlgprefvinyl.cpp 2011-04-17 04:16:00 +0000 |
23 | +++ mixxx/src/dlgprefvinyl.cpp 2011-05-11 04:41:18 +0000 |
24 | @@ -30,7 +30,9 @@ |
25 | |
26 | DlgPrefVinyl::DlgPrefVinyl(QWidget * parent, VinylControlManager *pVCMan, |
27 | ConfigObject<ConfigValue> * _config) : QWidget(parent), Ui::DlgPrefVinylDlg(), |
28 | - m_COTMode(ControlObject::getControl(ConfigKey("[VinylControl]", "mode"))) |
29 | + m_COMode(ControlObject::getControl(ConfigKey("[VinylControl]", "mode"))), |
30 | + m_COSpeed1(ControlObject::getControl(ConfigKey("[Channel1]", "vinylcontrol_speed_type"))), |
31 | + m_COSpeed2(ControlObject::getControl(ConfigKey("[Channel2]", "vinylcontrol_speed_type"))) |
32 | { |
33 | m_pVCManager = pVCMan; |
34 | config = _config; |
35 | @@ -177,7 +179,7 @@ |
36 | |
37 | ControlObject::getControl(ConfigKey("[Channel1]", "vinylcontrol_mode"))->set(iMode); |
38 | ControlObject::getControl(ConfigKey("[Channel2]", "vinylcontrol_mode"))->set(iMode); |
39 | - m_COTMode.slotSet(iMode); |
40 | + m_COMode.slotSet(iMode); |
41 | config->set(ConfigKey("[VinylControl]","mode"), ConfigValue(iMode)); |
42 | config->set(ConfigKey("[VinylControl]","needle_skip_prevention" ), ConfigValue( (int)(NeedleSkipEnable->isChecked( )) ) ); |
43 | |
44 | @@ -196,6 +198,19 @@ |
45 | config->set(ConfigKey("[Channel2]","vinylcontrol_vinyl_type"), ConfigValue(ComboBoxVinylType2->currentText())); |
46 | config->set(ConfigKey("[Channel1]","vinylcontrol_speed_type"), ConfigValue(ComboBoxVinylSpeed1->currentText())); |
47 | config->set(ConfigKey("[Channel2]","vinylcontrol_speed_type"), ConfigValue(ComboBoxVinylSpeed2->currentText())); |
48 | + |
49 | + //Save the vinylcontrol_speed_type in ControlObjects as well so it can be retrieved quickly |
50 | + //on the fly. (eg. WSpinny needs to know how fast to spin) |
51 | + if (ComboBoxVinylSpeed1->currentText() == MIXXX_VINYL_SPEED_33) { |
52 | + m_COSpeed1.slotSet(MIXXX_VINYL_SPEED_33_NUM); |
53 | + } else if (ComboBoxVinylSpeed1->currentText() == MIXXX_VINYL_SPEED_45) { |
54 | + m_COSpeed1.slotSet(MIXXX_VINYL_SPEED_45_NUM); |
55 | + } |
56 | + if (ComboBoxVinylSpeed2->currentText() == MIXXX_VINYL_SPEED_33) { |
57 | + m_COSpeed2.slotSet(MIXXX_VINYL_SPEED_33_NUM); |
58 | + } else if (ComboBoxVinylSpeed2->currentText() == MIXXX_VINYL_SPEED_45) { |
59 | + m_COSpeed2.slotSet(MIXXX_VINYL_SPEED_45_NUM); |
60 | + } |
61 | } |
62 | |
63 | void DlgPrefVinyl::VinylGainSlotApply() |
64 | |
65 | === modified file 'mixxx/src/dlgprefvinyl.h' |
66 | --- mixxx/src/dlgprefvinyl.h 2011-04-17 04:16:00 +0000 |
67 | +++ mixxx/src/dlgprefvinyl.h 2011-05-11 04:41:18 +0000 |
68 | @@ -21,7 +21,7 @@ |
69 | #include "ui_dlgprefvinyldlg.h" |
70 | #include "configobject.h" |
71 | #include "vinylcontrol/vinylcontrolsignalwidget.h" |
72 | -#include "controlobjectthread.h" |
73 | +#include "controlobjectthreadmain.h" |
74 | |
75 | class QWidget; |
76 | class PlayerProxy; |
77 | @@ -61,14 +61,9 @@ |
78 | VinylControlManager* m_pVCManager; |
79 | /** Pointer to config object */ |
80 | ConfigObject<ConfigValue> *config; |
81 | - /** Indicates the strength of the timecode signal on each input */ |
82 | - ControlObjectThreadMain* m_timecodeQuality1; |
83 | - ControlObjectThreadMain* m_timecodeQuality2; |
84 | - ControlObjectThreadMain* m_vinylControlInput1L; |
85 | - ControlObjectThreadMain* m_vinylControlInput1R; |
86 | - ControlObjectThreadMain* m_vinylControlInput2L; |
87 | - ControlObjectThreadMain* m_vinylControlInput2R; |
88 | - ControlObjectThread m_COTMode; |
89 | + ControlObjectThreadMain m_COMode; |
90 | + ControlObjectThreadMain m_COSpeed1; |
91 | + ControlObjectThreadMain m_COSpeed2; |
92 | }; |
93 | |
94 | #endif |
95 | |
96 | === modified file 'mixxx/src/engine/positionscratchcontroller.cpp' |
97 | --- mixxx/src/engine/positionscratchcontroller.cpp 2011-04-26 23:57:28 +0000 |
98 | +++ mixxx/src/engine/positionscratchcontroller.cpp 2011-05-11 04:41:18 +0000 |
99 | @@ -113,6 +113,7 @@ |
100 | m_bScratching = false; |
101 | m_iScratchTime = 0; |
102 | m_bEnableInertia = false; |
103 | + m_dRate = 0.; |
104 | |
105 | //m_pVelocityController->setPID(0.2, 1.0, 5.0); |
106 | //m_pVelocityController->setPID(0.1, 0.0, 5.0); |
107 | |
108 | === modified file 'mixxx/src/engine/vinylcontrolcontrol.cpp' |
109 | --- mixxx/src/engine/vinylcontrolcontrol.cpp 2011-04-19 14:03:57 +0000 |
110 | +++ mixxx/src/engine/vinylcontrolcontrol.cpp 2011-05-11 04:41:18 +0000 |
111 | @@ -6,6 +6,19 @@ |
112 | VinylControlControl::VinylControlControl(const char* pGroup, ConfigObject<ConfigValue>* pConfig) |
113 | : EngineControl(pGroup, pConfig) { |
114 | m_pControlVinylStatus = new ControlObject(ConfigKey(pGroup, "vinylcontrol_status")); |
115 | + m_pControlVinylSpeedType = new ControlObject(ConfigKey(pGroup, "vinylcontrol_speed_type")); |
116 | + |
117 | + //Convert the ConfigKey's value into a double for the CO (for fast reads). |
118 | + QString strVinylSpeedType = pConfig->getValueString(ConfigKey(pGroup, |
119 | + "vinylcontrol_speed_type")); |
120 | + if (strVinylSpeedType == MIXXX_VINYL_SPEED_33) { |
121 | + m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_33_NUM); |
122 | + } else if (strVinylSpeedType == MIXXX_VINYL_SPEED_45) { |
123 | + m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_45_NUM); |
124 | + } else { |
125 | + m_pControlVinylSpeedType->set(MIXXX_VINYL_SPEED_33_NUM); |
126 | + } |
127 | + |
128 | m_pControlVinylSeek = new ControlObject(ConfigKey(pGroup, "vinylcontrol_seek")); |
129 | connect(m_pControlVinylSeek, SIGNAL(valueChanged(double)), |
130 | this, SLOT(slotControlVinylSeek(double)), |
131 | |
132 | === modified file 'mixxx/src/engine/vinylcontrolcontrol.h' |
133 | --- mixxx/src/engine/vinylcontrolcontrol.h 2011-04-17 02:42:45 +0000 |
134 | +++ mixxx/src/engine/vinylcontrolcontrol.h 2011-05-11 04:41:18 +0000 |
135 | @@ -21,6 +21,7 @@ |
136 | |
137 | private: |
138 | ControlObject* m_pControlVinylSeek; |
139 | + ControlObject* m_pControlVinylSpeedType; |
140 | ControlObject* m_pControlVinylStatus; |
141 | ControlPushButton* m_pControlVinylMode; |
142 | ControlPushButton* m_pControlVinylEnabled; |
143 | |
144 | === modified file 'mixxx/src/mathstuff.h' |
145 | --- mixxx/src/mathstuff.h 2010-11-27 03:10:36 +0000 |
146 | +++ mixxx/src/mathstuff.h 2011-05-11 04:41:18 +0000 |
147 | @@ -23,7 +23,6 @@ |
148 | #include <math.h> |
149 | #include <algorithm> |
150 | |
151 | -static CSAMPLE two_pi = (2.f*acos(-1.f)); |
152 | |
153 | CSAMPLE besseli(CSAMPLE); |
154 | int sign(CSAMPLE); |
155 | @@ -44,6 +43,7 @@ |
156 | float sigmoid_zero(double t, double max_t); |
157 | |
158 | static CSAMPLE pi = acos(-1.0f); |
159 | +static CSAMPLE two_pi = (2.f*acos(-1.f)); |
160 | |
161 | #ifdef _MSC_VER |
162 | #include <float.h> // for _isnan() on VC++ |
163 | |
164 | === added file 'mixxx/src/sharedglcontext.cpp' |
165 | --- mixxx/src/sharedglcontext.cpp 1970-01-01 00:00:00 +0000 |
166 | +++ mixxx/src/sharedglcontext.cpp 2011-05-11 04:41:18 +0000 |
167 | @@ -0,0 +1,23 @@ |
168 | +#include <QGLContext> |
169 | +#include <QGLFormat> |
170 | +#include "sharedglcontext.h" |
171 | + |
172 | +/** Singleton wrapper around QGLContext */ |
173 | + |
174 | +QGLContext* SharedGLContext::s_pSharedGLContext = (QGLContext*)NULL; |
175 | + |
176 | +QGLContext* SharedGLContext::getContext() |
177 | +{ |
178 | + QGLContext *ctxt; |
179 | + |
180 | + if (s_pSharedGLContext == (QGLContext*)NULL) { |
181 | + s_pSharedGLContext = new QGLContext(QGLFormat(QGL::SampleBuffers)); |
182 | + s_pSharedGLContext->create(); |
183 | + s_pSharedGLContext->makeCurrent(); |
184 | + } |
185 | + |
186 | + ctxt = new QGLContext(QGLFormat(QGL::SampleBuffers)); |
187 | + ctxt->create(s_pSharedGLContext); |
188 | + |
189 | + return ctxt; |
190 | +} |
191 | |
192 | === added file 'mixxx/src/sharedglcontext.h' |
193 | --- mixxx/src/sharedglcontext.h 1970-01-01 00:00:00 +0000 |
194 | +++ mixxx/src/sharedglcontext.h 2011-05-11 04:41:18 +0000 |
195 | @@ -0,0 +1,15 @@ |
196 | +#ifndef SHAREDGLCONTEXT_H_ |
197 | +#define SHAREDGLCONTEXT_H_ |
198 | + |
199 | +class QGLContext; |
200 | + |
201 | +class SharedGLContext |
202 | +{ |
203 | + public: |
204 | + static QGLContext* getContext(); |
205 | + private: |
206 | + SharedGLContext() { }; |
207 | + static QGLContext* s_pSharedGLContext; |
208 | +}; |
209 | + |
210 | +#endif //SHAREDGLCONTEXT_H_ |
211 | |
212 | === modified file 'mixxx/src/skin/legacyskinparser.cpp' |
213 | --- mixxx/src/skin/legacyskinparser.cpp 2011-04-24 06:00:11 +0000 |
214 | +++ mixxx/src/skin/legacyskinparser.cpp 2011-05-11 04:41:18 +0000 |
215 | @@ -39,6 +39,7 @@ |
216 | #include "widget/wnumberpos.h" |
217 | #include "widget/wnumberrate.h" |
218 | #include "widget/woverview.h" |
219 | +#include "widget/wspinny.h" |
220 | |
221 | #include "widget/wvisualsimple.h" |
222 | #include "widget/wglwaveformviewer.h" |
223 | @@ -264,6 +265,8 @@ |
224 | return parseWidgetGroup(node); |
225 | } else if (nodeName == "Style") { |
226 | return parseStyle(node); |
227 | + } else if (nodeName == "Spinny") { |
228 | + return parseSpinny(node); |
229 | } else { |
230 | qDebug() << "Invalid node name in skin:" << nodeName; |
231 | } |
232 | @@ -605,6 +608,22 @@ |
233 | return p; |
234 | } |
235 | |
236 | +QWidget* LegacySkinParser::parseSpinny(QDomElement node) { |
237 | + QString channelStr = lookupNodeGroup(node); |
238 | + const char* pSafeChannelStr = safeChannelString(channelStr); |
239 | + WSpinny* p = new WSpinny(m_pParent); |
240 | + setupWidget(node, p); |
241 | + |
242 | + connect(p, SIGNAL(trackDropped(QString, QString)), |
243 | + m_pPlayerManager, SLOT(slotLoadToPlayer(QString, QString))); |
244 | + |
245 | + p->setup(node, pSafeChannelStr); |
246 | + setupConnections(node, p); |
247 | + p->installEventFilter(m_pKeyboard); |
248 | + return p; |
249 | +} |
250 | + |
251 | + |
252 | QWidget* LegacySkinParser::parseTableView(QDomElement node) { |
253 | QStackedWidget* pTabWidget = new QStackedWidget(m_pParent); |
254 | |
255 | |
256 | === modified file 'mixxx/src/skin/legacyskinparser.h' |
257 | --- mixxx/src/skin/legacyskinparser.h 2011-03-26 02:04:46 +0000 |
258 | +++ mixxx/src/skin/legacyskinparser.h 2011-05-11 04:41:18 +0000 |
259 | @@ -59,6 +59,7 @@ |
260 | QWidget* parseKnob(QDomElement node); |
261 | QWidget* parseTableView(QDomElement node); |
262 | QWidget* parseStyle(QDomElement node); |
263 | + QWidget* parseSpinny(QDomElement node); |
264 | |
265 | void setupPosition(QDomNode node, QWidget* pWidget); |
266 | void setupSize(QDomNode node, QWidget* pWidget); |
267 | |
268 | === modified file 'mixxx/src/vinylcontrol/vinylcontrol.h' |
269 | --- mixxx/src/vinylcontrol/vinylcontrol.h 2011-04-17 04:16:00 +0000 |
270 | +++ mixxx/src/vinylcontrol/vinylcontrol.h 2011-05-11 04:41:18 +0000 |
271 | @@ -21,6 +21,9 @@ |
272 | #define MIXXX_VINYL_SPEED_33 "33.3 RPM" |
273 | #define MIXXX_VINYL_SPEED_45 "45 RPM" |
274 | |
275 | +#define MIXXX_VINYL_SPEED_33_NUM 33.3f |
276 | +#define MIXXX_VINYL_SPEED_45_NUM 45.0f |
277 | + |
278 | #define MIXXX_VCMODE_ABSOLUTE 0 |
279 | #define MIXXX_VCMODE_RELATIVE 1 |
280 | #define MIXXX_VCMODE_CONSTANT 2 |
281 | |
282 | === modified file 'mixxx/src/waveformviewerfactory.cpp' |
283 | --- mixxx/src/waveformviewerfactory.cpp 2011-01-14 09:50:57 +0000 |
284 | +++ mixxx/src/waveformviewerfactory.cpp 2011-05-11 04:41:18 +0000 |
285 | @@ -5,6 +5,7 @@ |
286 | |
287 | #include "configobject.h" |
288 | #include "waveformviewerfactory.h" |
289 | +#include "sharedglcontext.h" |
290 | |
291 | #include "waveform/waveformrenderer.h" |
292 | #include "widget/wvisualsimple.h" |
293 | @@ -17,21 +18,11 @@ |
294 | QList<WWaveformViewer*> WaveformViewerFactory::m_visualViewers = QList<WWaveformViewer*>(); |
295 | QList<WGLWaveformViewer*> WaveformViewerFactory::m_visualGLViewers = QList<WGLWaveformViewer*>(); |
296 | QTimer WaveformViewerFactory::s_waveformUpdateTimer;; |
297 | -QGLContext* WaveformViewerFactory::s_pSharedOGLCtxt = (QGLContext *)NULL; |
298 | |
299 | |
300 | WaveformViewerType WaveformViewerFactory::createWaveformViewer(const char *group, QWidget *parent, ConfigObject<ConfigValue> *pConfig, QWidget **target, WaveformRenderer* pWaveformRenderer) { |
301 | |
302 | - QGLContext *ctxt; |
303 | - |
304 | - if ( s_pSharedOGLCtxt == (QGLContext*)NULL ) { |
305 | - s_pSharedOGLCtxt = new QGLContext(QGLFormat(QGL::SampleBuffers)); |
306 | - s_pSharedOGLCtxt->create(); |
307 | - s_pSharedOGLCtxt->makeCurrent(); |
308 | - } |
309 | - |
310 | - ctxt = new QGLContext(QGLFormat(QGL::SampleBuffers)); |
311 | - ctxt->create(s_pSharedOGLCtxt); |
312 | + QGLContext* ctxt = SharedGLContext::getContext(); |
313 | |
314 | qDebug() << "createWaveformViewer()"; |
315 | |
316 | |
317 | === modified file 'mixxx/src/waveformviewerfactory.h' |
318 | --- mixxx/src/waveformviewerfactory.h 2011-01-14 09:32:49 +0000 |
319 | +++ mixxx/src/waveformviewerfactory.h 2011-05-11 04:41:18 +0000 |
320 | @@ -34,7 +34,6 @@ |
321 | static QList<WWaveformViewer*> m_visualViewers; |
322 | static QList<WGLWaveformViewer*> m_visualGLViewers; |
323 | static QTimer s_waveformUpdateTimer; |
324 | - static QGLContext *s_pSharedOGLCtxt; |
325 | |
326 | public: |
327 | static WaveformViewerType createWaveformViewer(const char* group, QWidget *pParent, ConfigObject<ConfigValue> *pConfig, QWidget **target, WaveformRenderer *pWaveformRenderer); |
328 | |
329 | === modified file 'mixxx/src/widget/wglwaveformviewer.cpp' |
330 | --- mixxx/src/widget/wglwaveformviewer.cpp 2011-04-26 02:43:58 +0000 |
331 | +++ mixxx/src/widget/wglwaveformviewer.cpp 2011-05-11 04:41:18 +0000 |
332 | @@ -13,6 +13,7 @@ |
333 | #include "wglwaveformviewer.h" |
334 | #include "waveform/waveformrenderer.h" |
335 | #include "controlobjectthreadmain.h" |
336 | +#include "sharedglcontext.h" |
337 | |
338 | WGLWaveformViewer::WGLWaveformViewer( |
339 | const char *group, |
340 | @@ -24,7 +25,6 @@ |
341 | ) : |
342 | QGLWidget(ctxt, pParent, pShareWidget) |
343 | { |
344 | - |
345 | m_pWaveformRenderer = pWaveformRenderer; |
346 | Q_ASSERT(m_pWaveformRenderer); |
347 | |
348 | @@ -46,6 +46,9 @@ |
349 | installEventFilter(this); |
350 | |
351 | m_painting = false; |
352 | + |
353 | + setSizePolicy(QSizePolicy::MinimumExpanding, |
354 | + QSizePolicy::MinimumExpanding); |
355 | } |
356 | |
357 | bool WGLWaveformViewer::directRendering() |
358 | @@ -63,6 +66,14 @@ |
359 | m_pWaveformRenderer->resize(w, h); |
360 | } |
361 | |
362 | +void WGLWaveformViewer::resizeEvent(QResizeEvent* e) |
363 | +{ |
364 | + const QSize newSize = e->size(); |
365 | + m_pWaveformRenderer->resize(newSize.width(), |
366 | + newSize.height()); |
367 | +} |
368 | + |
369 | + |
370 | void WGLWaveformViewer::paintEvent(QPaintEvent *event) { |
371 | QPainter painter; |
372 | painter.begin(this); |
373 | @@ -110,7 +121,7 @@ |
374 | //qDebug() << "m_dInitialPlaypos" << m_dInitialPlaypos; |
375 | |
376 | // Set the cursor to a hand while the mouse is down. |
377 | - setCursor(Qt::OpenHandCursor); |
378 | + setCursor(Qt::ClosedHandCursor); |
379 | } |
380 | } else if(e->type() == QEvent::MouseMove) { |
381 | // Only send signals for mouse moving if the left button is pressed |
382 | |
383 | === modified file 'mixxx/src/widget/wglwaveformviewer.h' |
384 | --- mixxx/src/widget/wglwaveformviewer.h 2011-04-26 02:30:22 +0000 |
385 | +++ mixxx/src/widget/wglwaveformviewer.h 2011-05-11 04:41:18 +0000 |
386 | @@ -47,6 +47,7 @@ |
387 | |
388 | protected: |
389 | void paintEvent(QPaintEvent* event); |
390 | + void resizeEvent(QResizeEvent* e); |
391 | |
392 | private: |
393 | /** Used in mouse event handler */ |
394 | |
395 | === added file 'mixxx/src/widget/wspinny.cpp' |
396 | --- mixxx/src/widget/wspinny.cpp 1970-01-01 00:00:00 +0000 |
397 | +++ mixxx/src/widget/wspinny.cpp 2011-05-11 04:41:18 +0000 |
398 | @@ -0,0 +1,434 @@ |
399 | +#include <math.h> |
400 | +#include "mathstuff.h" |
401 | +#include "wpixmapstore.h" |
402 | +#include "controlobject.h" |
403 | +#include "controlobjectthreadmain.h" |
404 | +#include "sharedglcontext.h" |
405 | +#include "wspinny.h" |
406 | + |
407 | +WSpinny::WSpinny(QWidget* parent) : QGLWidget(SharedGLContext::getContext(), parent), |
408 | + m_pBG(NULL), |
409 | + m_pFG(NULL), |
410 | + m_pGhost(NULL), |
411 | + m_pPlay(NULL), |
412 | + m_pPlayPos(NULL), |
413 | + m_pVisualPlayPos(NULL), |
414 | + m_pDuration(NULL), |
415 | + m_pTrackSamples(NULL), |
416 | + m_pBPM(NULL), |
417 | + m_pScratch(NULL), |
418 | + m_pScratchToggle(NULL), |
419 | + m_pScratchPos(NULL), |
420 | + m_pVinylControlSpeedType(NULL), |
421 | + m_fAngle(0.0f), |
422 | + m_fGhostAngle(0.0f), |
423 | + m_dPausedPosition(0.0f), |
424 | + m_bGhostPlayback(false), |
425 | + m_iStartMouseX(-1), |
426 | + m_iStartMouseY(-1), |
427 | + m_iFullRotations(0), |
428 | + m_dPrevTheta(0.) |
429 | +{ |
430 | + //Drag and drop |
431 | + setAcceptDrops(true); |
432 | +} |
433 | + |
434 | +WSpinny::~WSpinny() |
435 | +{ |
436 | + //Don't delete these because the pixmap store takes care of them. |
437 | + //delete m_pBG; |
438 | + //delete m_pFG; |
439 | + //delete m_pGhost; |
440 | + WPixmapStore::deletePixmap(m_pBG); |
441 | + WPixmapStore::deletePixmap(m_pFG); |
442 | + WPixmapStore::deletePixmap(m_pGhost); |
443 | + delete m_pPlay; |
444 | + delete m_pPlayPos; |
445 | + delete m_pVisualPlayPos; |
446 | + delete m_pDuration; |
447 | + delete m_pTrackSamples; |
448 | + delete m_pTrackSampleRate; |
449 | + delete m_pBPM; |
450 | + delete m_pScratch; |
451 | + delete m_pScratchToggle; |
452 | + delete m_pScratchPos; |
453 | + delete m_pVinylControlSpeedType; |
454 | +} |
455 | + |
456 | +void WSpinny::setup(QDomNode node, QString group) |
457 | +{ |
458 | + m_group = group; |
459 | + |
460 | + // Set pixmaps |
461 | + m_pBG = WPixmapStore::getPixmap(WWidget::getPath(WWidget::selectNodeQString(node, |
462 | + "PathBackground"))); |
463 | + m_pFG = WPixmapStore::getPixmap(WWidget::getPath(WWidget::selectNodeQString(node, |
464 | + "PathForeground"))); |
465 | + m_pGhost = WPixmapStore::getPixmap(WWidget::getPath(WWidget::selectNodeQString(node, |
466 | + "PathGhost"))); |
467 | + if (m_pBG && !m_pBG->isNull()) { |
468 | + setFixedSize(m_pBG->size()); |
469 | + } |
470 | + |
471 | + m_pPlay = new ControlObjectThreadMain(ControlObject::getControl( |
472 | + ConfigKey(group, "play"))); |
473 | + m_pPlayPos = new ControlObjectThreadMain(ControlObject::getControl( |
474 | + ConfigKey(group, "playposition"))); |
475 | + m_pVisualPlayPos = new ControlObjectThreadMain(ControlObject::getControl( |
476 | + ConfigKey(group, "visual_playposition"))); |
477 | + m_pDuration = new ControlObjectThreadMain(ControlObject::getControl( |
478 | + ConfigKey(group, "duration"))); |
479 | + m_pTrackSamples = new ControlObjectThreadMain(ControlObject::getControl( |
480 | + ConfigKey(group, "track_samples"))); |
481 | + m_pTrackSampleRate = new ControlObjectThreadMain( |
482 | + ControlObject::getControl( |
483 | + ConfigKey(group, "track_samplerate"))); |
484 | + m_pBPM = new ControlObjectThreadMain(ControlObject::getControl( |
485 | + ConfigKey(group, "bpm"))); |
486 | + |
487 | + m_pScratch = new ControlObjectThreadMain(ControlObject::getControl( |
488 | + ConfigKey(group, "scratch2"))); |
489 | + m_pScratchToggle = new ControlObjectThreadMain(ControlObject::getControl( |
490 | + ConfigKey(group, "scratch_position_enable"))); |
491 | + m_pScratchPos = new ControlObjectThreadMain(ControlObject::getControl( |
492 | + ConfigKey(group, "scratch_position"))); |
493 | + m_pVinylControlSpeedType = new ControlObjectThreadMain(ControlObject::getControl( |
494 | + ConfigKey(group, "vinylcontrol_speed_type"))); |
495 | + if (m_pVinylControlSpeedType) |
496 | + { |
497 | + //Initialize the rotational speed. |
498 | + this->updateVinylControlSpeed(m_pVinylControlSpeedType->get()); |
499 | + } |
500 | + Q_ASSERT(m_pPlayPos); |
501 | + Q_ASSERT(m_pDuration); |
502 | + |
503 | + //Repaint when visual_playposition changes. |
504 | + connect(m_pVisualPlayPos, SIGNAL(valueChanged(double)), |
505 | + this, SLOT(updateAngle(double))); |
506 | + |
507 | + //Match the vinyl control's set RPM so that the spinny widget rotates at the same |
508 | + //speed as your physical decks, if you're using vinyl control. |
509 | + connect(m_pVinylControlSpeedType, SIGNAL(valueChanged(double)), |
510 | + this, SLOT(updateVinylControlSpeed(double))); |
511 | +} |
512 | + |
513 | +void WSpinny::paintEvent(QPaintEvent *e) |
514 | +{ |
515 | + Q_UNUSED(e); //ditch unused param warning |
516 | + |
517 | + QPainter p(this); |
518 | + |
519 | + if (m_pBG) { |
520 | + p.drawPixmap(0, 0, *m_pBG); |
521 | + } |
522 | + |
523 | + //To rotate the foreground pixmap around the center of the image, |
524 | + //we use the classic trick of translating the coordinate system such that |
525 | + //the origin is at the center of the image. We then rotate the coordinate system, |
526 | + //and draw the pixmap at the corner. |
527 | + p.translate(width() / 2, height() / 2); |
528 | + |
529 | + if (m_bGhostPlayback) |
530 | + p.save(); |
531 | + |
532 | + if (m_pFG && !m_pFG->isNull()) { |
533 | + //Now rotate the pixmap and draw it on the screen. |
534 | + p.rotate(m_fAngle); |
535 | + p.drawPixmap(-(width() / 2), -(height() / 2), *m_pFG); |
536 | + } |
537 | + |
538 | + if (m_bGhostPlayback && m_pGhost && !m_pGhost->isNull()) |
539 | + { |
540 | + p.restore(); |
541 | + p.save(); |
542 | + p.rotate(m_fGhostAngle); |
543 | + p.drawPixmap(-(width() / 2), -(height() / 2), *m_pGhost); |
544 | + |
545 | + //Rotate back to the playback position (not the ghost positon), |
546 | + //and draw the beat marks from there. |
547 | + p.restore(); |
548 | + |
549 | + /* |
550 | + //Draw a line where the next 4 beats are |
551 | + double bpm = m_pBPM->get(); |
552 | + double duration = m_pDuration->get(); |
553 | + if (bpm <= 0. || duration <= 0.) { |
554 | + return; //Prevent div by zero |
555 | + } |
556 | + double beatLengthInSec = 60. / bpm; |
557 | + double beatLengthNormalized = beatLengthInSec / duration; //Noramlized to duration |
558 | + double beatAngle = calculateAngle(beatLengthNormalized); |
559 | + //qDebug() << "beatAngle:" << beatAngle; |
560 | + //qDebug() << "beatLenInSec:" << beatLengthInSec << "norm:" << beatLengthNormalized; |
561 | + p.rotate(m_fAngle); |
562 | + for (int i = 0; i < 4; i++) { |
563 | + QLineF beatLine(-(width()*0.6 / 2), -(height()*0.6 / 2), |
564 | + -(width()*0.8 / 2), -(height()*0.8 / 2)); |
565 | + //p.drawPoint(-(width()*0.5 / 2), -(height()*0.5 / 2)); |
566 | + p.drawLine(beatLine); |
567 | + p.rotate(beatAngle); |
568 | + } */ |
569 | + } |
570 | +} |
571 | + |
572 | +/* Convert between a normalized playback position (0.0 - 1.0) and an angle |
573 | + in our polar coordinate system. |
574 | + Returns an angle clamped between -180 and 180 degrees. */ |
575 | +double WSpinny::calculateAngle(double playpos) |
576 | +{ |
577 | + if (isnan(playpos)) |
578 | + return 0.0f; |
579 | + |
580 | + //Convert playpos to seconds. |
581 | + //double t = playpos * m_pDuration->get(); |
582 | + double t = playpos * (m_pTrackSamples->get()/2 / // Stereo audio! |
583 | + m_pTrackSampleRate->get()); |
584 | + |
585 | + if (isnan(t)) //Bad samplerate or number of track samples. |
586 | + return 0.0f; |
587 | + |
588 | + //33 RPM is approx. 0.5 rotations per second. |
589 | + double angle = 360*m_dRotationsPerSecond*t; |
590 | + //Clamp within -180 and 180 degrees |
591 | + //qDebug() << "pc:" << angle; |
592 | + //angle = ((angle + 180) % 360.) - 180; |
593 | + //modulo for doubles :) |
594 | + if (angle > 0) |
595 | + { |
596 | + int x = (angle+180)/360; |
597 | + angle = angle - (360*x); |
598 | + } else |
599 | + { |
600 | + int x = (angle-180)/360; |
601 | + angle = angle - (360*x); |
602 | + } |
603 | + |
604 | + Q_ASSERT(angle <= 180 && angle >= -180); |
605 | + return angle; |
606 | +} |
607 | + |
608 | +/** Given a normalized playpos, calculate the integer number of rotations |
609 | + that it would take to wind the vinyl to that position. */ |
610 | +int WSpinny::calculateFullRotations(double playpos) |
611 | +{ |
612 | + if (isnan(playpos)) |
613 | + return 0.0f; |
614 | + //Convert playpos to seconds. |
615 | + //double t = playpos * m_pDuration->get(); |
616 | + double t = playpos * (m_pTrackSamples->get()/2 / // Stereo audio! |
617 | + m_pTrackSampleRate->get()); |
618 | + |
619 | + //33 RPM is approx. 0.5 rotations per second. |
620 | + //qDebug() << t; |
621 | + double angle = 360*m_dRotationsPerSecond*t; |
622 | + |
623 | + return (((int)angle+180) / 360); |
624 | +} |
625 | + |
626 | +//Inverse of calculateAngle() |
627 | +double WSpinny::calculatePositionFromAngle(double angle) |
628 | +{ |
629 | + if (isnan(angle)) |
630 | + return 0.0f; |
631 | + |
632 | + //33 RPM is approx. 0.5 rotations per second. |
633 | + double t = angle/(360*m_dRotationsPerSecond); //time in seconds |
634 | + |
635 | + //Convert t from seconds into a normalized playposition value. |
636 | + //double playpos = t / m_pDuration->get(); |
637 | + double playpos = t / (m_pTrackSamples->get()/2 / // Stereo audio! |
638 | + m_pTrackSampleRate->get()); |
639 | + return playpos; |
640 | +} |
641 | + |
642 | +/** Update the playback angle saved in the widget and repaint. |
643 | + @param playpos A normalized (0.0-1.0) playback position. (Not an angle!) |
644 | +*/ |
645 | +void WSpinny::updateAngle(double playpos) |
646 | +{ |
647 | + m_fAngle = calculateAngle(playpos); |
648 | + update(); |
649 | +} |
650 | + |
651 | +//Update the angle using the ghost playback position. |
652 | +void WSpinny::updateAngleForGhost() |
653 | +{ |
654 | + qint64 elapsed = m_time.elapsed(); |
655 | + double duration = m_pDuration->get(); |
656 | + double newPlayPos = m_dPausedPosition + |
657 | + (((double)elapsed)/1000.)/duration; |
658 | + m_fGhostAngle = calculateAngle(newPlayPos); |
659 | + update(); |
660 | +} |
661 | + |
662 | +void WSpinny::updateVinylControlSpeed(double rpm) |
663 | +{ |
664 | + m_dRotationsPerSecond = rpm/60.; |
665 | +} |
666 | + |
667 | +void WSpinny::mouseMoveEvent(QMouseEvent * e) |
668 | +{ |
669 | + int y = e->y(); |
670 | + int x = e->x(); |
671 | + |
672 | + //Keeping these around in case we want to switch to control relative |
673 | + //to the original mouse position. |
674 | + //int dX = x-m_iStartMouseX; |
675 | + //int dY = y-m_iStartMouseY; |
676 | + |
677 | + //Coordinates from center of widget |
678 | + int c_x = x - width()/2; |
679 | + int c_y = y - height()/2; |
680 | + double theta = (180.0f/M_PI)*atan2(c_x, -c_y); |
681 | + |
682 | + //qDebug() << "c_x:" << c_x << "c_y:" << c_y << |
683 | + // "dX:" << dX << "dY:" << dY; |
684 | + |
685 | + //When we finish one full rotation (clockwise or anticlockwise), |
686 | + //we'll need to manually add/sub 360 degrees because atan2()'s range is |
687 | + //only within -180 to 180 degrees. We need a wider range so your position |
688 | + //in the song can be tracked. |
689 | + if (m_dPrevTheta > 100 && theta < 0) { |
690 | + m_iFullRotations++; |
691 | + } |
692 | + else if (m_dPrevTheta < -100 && theta > 0) { |
693 | + m_iFullRotations--; |
694 | + } |
695 | + |
696 | + m_dPrevTheta = theta; |
697 | + theta += m_iFullRotations*360; |
698 | + |
699 | + //qDebug() << "c t:" << theta << "pt:" << m_dPrevTheta << |
700 | + // "icr" << m_iFullRotations; |
701 | + |
702 | + if (e->buttons() & Qt::LeftButton) |
703 | + { |
704 | + //Convert deltaTheta into a percentage of song length. |
705 | + double absPos = calculatePositionFromAngle(theta); |
706 | + |
707 | + double absPosInSamples = absPos * m_pTrackSamples->get(); |
708 | + m_pScratchPos->slotSet(absPosInSamples); |
709 | + } |
710 | + else if (e->buttons() & Qt::MidButton) |
711 | + { |
712 | + } |
713 | + else if (e->buttons() & Qt::NoButton) |
714 | + { |
715 | + setCursor(QCursor(Qt::OpenHandCursor)); |
716 | + } |
717 | +} |
718 | + |
719 | +void WSpinny::mousePressEvent(QMouseEvent * e) |
720 | +{ |
721 | + int y = e->y(); |
722 | + int x = e->x(); |
723 | + |
724 | + m_iStartMouseX = x; |
725 | + m_iStartMouseY = y; |
726 | + |
727 | + if (e->button() == Qt::LeftButton) |
728 | + { |
729 | + QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor)); |
730 | + |
731 | + double initialPosInSamples = m_pPlayPos->get() * m_pTrackSamples->get(); |
732 | + m_pScratchPos->slotSet(initialPosInSamples); |
733 | + m_pScratchToggle->slotSet(1.0f); |
734 | + |
735 | + m_iFullRotations = calculateFullRotations(m_pPlayPos->get()); |
736 | + |
737 | + m_dPrevTheta = calculateAngle(m_pPlayPos->get()); |
738 | + |
739 | + //Trigger a mouse move to immediately line up the vinyl with the cursor |
740 | + mouseMoveEvent(e); |
741 | + } |
742 | + else if (e->button() == Qt::MidButton) |
743 | + { |
744 | + } |
745 | + else if (e->button() == Qt::RightButton) |
746 | + { |
747 | + //Stop playback and start the timer for ghost playback |
748 | + m_time.start(); |
749 | + m_dPausedPosition = m_pPlayPos->get(); |
750 | + updateAngleForGhost(); //Need to recalc the ghost angle right away |
751 | + m_bGhostPlayback = true; |
752 | + m_ghostPaintTimer.start(30); |
753 | + connect(&m_ghostPaintTimer, SIGNAL(timeout()), |
754 | + this, SLOT(updateAngleForGhost())); |
755 | + |
756 | + //TODO: Ramp down (brake) over a period of 1 beat |
757 | + // instead? Would be sweet. |
758 | + m_pPlay->slotSet(0.0f); |
759 | + } |
760 | +} |
761 | + |
762 | +void WSpinny::mouseReleaseEvent(QMouseEvent * e) |
763 | +{ |
764 | + if (e->button() == Qt::LeftButton) |
765 | + { |
766 | + QApplication::restoreOverrideCursor(); |
767 | + m_pScratchToggle->slotSet(0.0f); |
768 | + m_iFullRotations = 0; |
769 | + } |
770 | + else if (e->button() == Qt::RightButton) |
771 | + { |
772 | + //Start playback by jumping forwards in the song as if playback |
773 | + //was never paused. (useful for bleeping or adding silence breaks) |
774 | + qint64 elapsed = m_time.elapsed(); |
775 | + //qDebug() << "elapsed:" << elapsed; |
776 | + m_ghostPaintTimer.stop(); |
777 | + m_bGhostPlayback = false; |
778 | + |
779 | + //Convert elapsed to seconds, then normalize it to the duration so we can |
780 | + //move the playback position ahead by the elapsed amount. |
781 | + double duration = m_pDuration->get(); |
782 | + double newPlayPos = m_dPausedPosition + (((double)elapsed)/1000.)/duration; |
783 | + //qDebug() << m_dPausedPosition << newPlayPos; |
784 | + m_pPlay->slotSet(1.0f); |
785 | + m_pPlayPos->slotSet(newPlayPos); |
786 | + //m_bRightButtonPressed = true; |
787 | + } |
788 | +} |
789 | + |
790 | +void WSpinny::wheelEvent(QWheelEvent *e) |
791 | +{ |
792 | + Q_UNUSED(e); //ditch unused param warning |
793 | + |
794 | + /* |
795 | + double wheelDirection = ((QWheelEvent *)e)->delta() / 120.; |
796 | + double newValue = getValue() + (wheelDirection); |
797 | + this->updateValue(newValue); |
798 | + |
799 | + e->accept(); |
800 | + */ |
801 | +} |
802 | + |
803 | +/** DRAG AND DROP **/ |
804 | +void WSpinny::dragEnterEvent(QDragEnterEvent * event) |
805 | +{ |
806 | + // Accept the enter event if the thing is a filepath and nothing's playing |
807 | + // in this deck. |
808 | + if (event->mimeData()->hasUrls()) { |
809 | + if (m_pPlay && m_pPlay->get()) { |
810 | + event->ignore(); |
811 | + } else { |
812 | + event->acceptProposedAction(); |
813 | + } |
814 | + } |
815 | +} |
816 | + |
817 | +void WSpinny::dropEvent(QDropEvent * event) |
818 | +{ |
819 | + if (event->mimeData()->hasUrls()) { |
820 | + QList<QUrl> urls(event->mimeData()->urls()); |
821 | + QUrl url = urls.first(); |
822 | + QString name = url.toLocalFile(); |
823 | + //If the file is on a network share, try just converting the URL to a string... |
824 | + if (name == "") |
825 | + name = url.toString(); |
826 | + |
827 | + event->accept(); |
828 | + emit(trackDropped(name, m_group)); |
829 | + } else { |
830 | + event->ignore(); |
831 | + } |
832 | +} |
833 | |
834 | === added file 'mixxx/src/widget/wspinny.h' |
835 | --- mixxx/src/widget/wspinny.h 1970-01-01 00:00:00 +0000 |
836 | +++ mixxx/src/widget/wspinny.h 2011-05-11 04:41:18 +0000 |
837 | @@ -0,0 +1,67 @@ |
838 | + |
839 | +#ifndef _WSPINNY_H |
840 | +#define _WSPINNY_H |
841 | + |
842 | +#include <QGLWidget> |
843 | +#include "wwidget.h" |
844 | + |
845 | +class ControlObjectThreadMain; |
846 | + |
847 | +class WSpinny : public QGLWidget |
848 | +{ |
849 | + Q_OBJECT |
850 | + public: |
851 | + WSpinny(QWidget* parent); |
852 | + ~WSpinny(); |
853 | + void setup(QDomNode node, QString group); |
854 | + void dragEnterEvent(QDragEnterEvent *event); |
855 | + void dropEvent(QDropEvent *event); |
856 | + public slots: |
857 | + void updateAngle(double); |
858 | + void updateAngleForGhost(); |
859 | + void updateVinylControlSpeed(double rpm); |
860 | + signals: |
861 | + void trackDropped(QString filename, QString group); |
862 | + protected: |
863 | + //QWidget: |
864 | + void paintEvent(QPaintEvent*); |
865 | + void mouseMoveEvent(QMouseEvent * e); |
866 | + void mousePressEvent(QMouseEvent * e); |
867 | + void mouseReleaseEvent(QMouseEvent * e); |
868 | + void wheelEvent(QWheelEvent *e); |
869 | + |
870 | + double calculateAngle(double playpos); |
871 | + int calculateFullRotations(double playpos); |
872 | + double calculatePositionFromAngle(double angle); |
873 | + private: |
874 | + QPixmap* m_pBG; |
875 | + QPixmap* m_pFG; |
876 | + QPixmap* m_pGhost; |
877 | + ControlObjectThreadMain* m_pPlay; |
878 | + ControlObjectThreadMain* m_pPlayPos; |
879 | + ControlObjectThreadMain* m_pVisualPlayPos; |
880 | + ControlObjectThreadMain* m_pDuration; |
881 | + ControlObjectThreadMain* m_pTrackSamples; |
882 | + ControlObjectThreadMain* m_pTrackSampleRate; |
883 | + ControlObjectThreadMain* m_pBPM; |
884 | + ControlObjectThreadMain* m_pScratch; |
885 | + ControlObjectThreadMain* m_pScratchToggle; |
886 | + ControlObjectThreadMain* m_pScratchPos; |
887 | + ControlObjectThreadMain* m_pVinylControlSpeedType; |
888 | + QString m_group; |
889 | + float m_fAngle; //Degrees |
890 | + float m_fGhostAngle; |
891 | + QTime m_time; |
892 | + double m_dPausedPosition; |
893 | + bool m_bGhostPlayback; |
894 | + QTimer m_ghostPaintTimer; |
895 | + int m_iStartMouseX; |
896 | + int m_iStartMouseY; |
897 | + int m_iFullRotations; |
898 | + double m_dPrevTheta; |
899 | + double m_dTheta; |
900 | + /** Speed of the vinyl rotation. */ |
901 | + double m_dRotationsPerSecond; |
902 | +}; |
903 | + |
904 | +#endif //_WSPINNY_H |
* In SharedGLContext, are a constructor / destructor necessary? I don't think anything creates an instance, just uses the static methods.
* Check for PathBackground / PathForeground / PathGhost actually existing?
* WPixmapStore: :getPixmap can return NULL if the pixmap doesn't exist. All uses of the member-variable pixmaps should be checked for non-NULL first
* QElapsedTimer, while much better than QTime, means we are ditching any platform <Qt 4.7 (e.g. Ubuntu 10.04 and earlier). I think it's a bit early to do that -- maybe stick to QTime for now?