1
#ifndef CALLBACKCONTROLMANAGER_H
2
#define CALLBACKCONTROLMANAGER_H
6
#include <QScopedPointer>
10
#include "configobject.h"
11
#include "controlobject.h"
13
class CallbackControlManager;
15
// Struct to describe a pending update between the callback controls and
16
// ControlObject system.
17
struct ControlUpdate {
22
ControlUpdate(double time, double value)
30
// A ControlUpdate and the ControlObject that it applies to.
31
struct CallbackControlMessage {
32
ControlObject* control;
36
// ControlWatcher is a class that listens to a ControlObject, receives its
37
// valueChanged() signals in an arbitrary thread, and emits a controlUpdated()
38
// signal that the CallbackControlManager receives.
39
class ControlWatcher : public QObject {
42
ControlWatcher(ControlObject* pControl);
43
virtual ~ControlWatcher();
45
void controlUpdated(ControlObject* pControl, double value);
47
void slotValueChanged(double v);
49
ControlObject* m_pControl;
52
// CallbackControl is a callback-safe wrapper around a ControlObject. Its
53
// valueChanged() signals are emitted from the callback thread at the start of
54
// the callback. Mutations of the CallbackControl are delivered to the wrapped
55
// ControlObject after the callback is complete via an EngineWorker.
56
class CallbackControl : public QObject {
59
// Create a CallbackControl wrapper around pControl. Takes ownership of
61
CallbackControl(CallbackControlManager* pControlManager,
62
ControlObject* pControl, int bufferLength);
63
virtual ~CallbackControl();
65
// Get access to the internal control. WARNING: Touching this control is NOT
67
ControlObject* getControl() const {
68
return m_control.data();
71
ConfigKey getKey() const {
72
return m_control->getKey();
75
inline double get() const {
78
void set(double value);
79
void add(double value);
80
void sub(double value);
82
// Receive update from CallbackControlManager
83
void receiveUpdate(ControlUpdate update);
86
// Callback-safe signal that a control value is changed. Always emitted from
87
// the callback thread. WARNING: always connect to this signal with
88
// Qt::DirectConnection or the slot WILL NOT be callback-safe.
89
void valueChanged(double value);
90
void valueChanged(double value, double time);
91
void valueChangedFromEngine(double value);
92
void valueChangedFromEngine(double value, double time);
93
void controlUpdatedFromCallback(CallbackControl* pControl, double value);
96
ControlUpdate m_value;
97
FIFO<ControlUpdate> m_updates;
98
QScopedPointer<ControlObject> m_control;
99
ControlWatcher m_controlWatcher;
102
class CallbackControlManager : public QObject {
105
explicit CallbackControlManager();
106
virtual ~CallbackControlManager();
108
// Add a control to be managed by CallbackControlManager. Returns a
109
// CallbackControl. MUST ONLY BE CALLED DURING MIXXX INITIALIZATION.
110
CallbackControl* addControl(ControlObject* pControl, int bufferLength);
112
// Get a CallbackControl for the given ControlObject
113
CallbackControl* getControl(ConfigKey key);
115
void callbackProcessIncomingUpdates();
116
void callbackProcessOutgoingUpdates();
117
void processOutgoingUpdates();
120
// Thread Safe but NOT callback-safe. Indicates that the control 'pControl'
121
// was just updated to value 'value'
122
void slotControlUpdated(ControlObject* pControl, double value);
125
void slotControlUpdatedFromCallback(CallbackControl* pControl, double value);
128
////////////////////////////////////////////////////////////////////////////
129
// The following may only be called/touched while m_incomingUpdateMutex is
131
////////////////////////////////////////////////////////////////////////////
134
// So stupid, but we can't trust QTime to give us accurate long-term
135
// times since if somebody changes the system clock while running Mixxx,
136
// the results is basically undefined. Restart it every time we get the
137
// time and keep a tally.
138
double elapsed = m_timer.restart();
139
m_lastTimeValue += elapsed;
140
return m_lastTimeValue;
142
QMutex m_incomingUpdateMutex;
143
FIFO<CallbackControlMessage> m_incomingUpdateFifo;
146
// TODO(XXX) Switch to QElapsedTimer once we require Qt >=4.7
148
double m_lastTimeValue;
150
////////////////////////////////////////////////////////////////////////////
151
// The following may only be touched from within the callback
152
////////////////////////////////////////////////////////////////////////////
154
QHash<ConfigKey, CallbackControl*> m_callbackControls;
155
QSet<ConfigKey> m_updatedControls;
156
FIFO<CallbackControlMessage> m_outgoingUpdateFifo;
159
#endif /* CALLBACKCONTROLMANAGER_H */