1 #pragma once
2 
3 #include <QString>
4 
5 class EngineChannel;
6 
7 enum SyncMode {
8     SYNC_INVALID = -1,
9     SYNC_NONE = 0,
10     SYNC_FOLLOWER = 1,
11     // SYNC_MASTER_SOFT is a master that Mixxx has chosen automatically.
12     // depending on how decks stop and start, it may reassign soft master at will.
13     SYNC_MASTER_SOFT = 2,
14     // SYNC_MASTER_EXPLICIT represents an explicit request that the synacable be
15     // master. Mixxx will only remove a SYNC_MASTER_SOFT if the track is stopped or
16     // ejected.
17     SYNC_MASTER_EXPLICIT = 3,
18     SYNC_NUM_MODES
19 };
20 
syncModeFromDouble(double value)21 inline SyncMode syncModeFromDouble(double value) {
22     // msvs does not allow to cast from double to an enum
23     SyncMode mode = static_cast<SyncMode>(int(value));
24     if (mode >= SYNC_NUM_MODES || mode < 0) {
25         return SYNC_NONE;
26     }
27     return mode;
28 }
29 
toSynchronized(SyncMode mode)30 inline bool toSynchronized(SyncMode mode) {
31     return mode > SYNC_NONE;
32 }
33 
isMaster(SyncMode mode)34 inline bool isMaster(SyncMode mode) {
35     return (mode == SYNC_MASTER_SOFT || mode == SYNC_MASTER_EXPLICIT);
36 }
37 
38 /// Syncable is an abstract base class for any object that wants to participate
39 /// in Master Sync.
40 class Syncable {
41   public:
42     virtual ~Syncable() = default;
43     virtual const QString& getGroup() const = 0;
44     virtual EngineChannel* getChannel() const = 0;
45 
46     // Notify a Syncable that their mode has changed. The Syncable must record
47     // this mode and return the latest mode in response to getMode().
48     virtual void setSyncMode(SyncMode mode) = 0;
49 
50     // Notify a Syncable that it is now the only currently-playing syncable.
51     virtual void notifyOnlyPlayingSyncable() = 0;
52 
53     // Notify a Syncable that they should sync phase.
54     virtual void requestSync() = 0;
55 
56     // Must NEVER return a mode that was not set directly via
57     // notifySyncModeChanged.
58     virtual SyncMode getSyncMode() const = 0;
59 
isSynchronized()60     inline bool isSynchronized() const {
61         return toSynchronized(getSyncMode());
62     }
63 
64     // Only relevant for player Syncables.
65     virtual bool isPlaying() const = 0;
66     virtual bool isAudible() const = 0;
67 
68     // Gets the current speed of the syncable in bpm (bpm * rate slider), doesn't
69     // include scratch or FF/REW values.
70     virtual double getBpm() const = 0;
71 
72     // Gets the beat distance as a fraction from 0 to 1
73     virtual double getBeatDistance() const = 0;
74     // Gets the speed of the syncable if it was playing at 1.0 rate.
75     virtual double getBaseBpm() const = 0;
76 
77     // The following functions are used to tell syncables about the state of the
78     // current Sync Master.
79     // Must never result in a call to
80     // SyncableListener::notifyBeatDistanceChanged or signal loops could occur.
81     virtual void setMasterBeatDistance(double beatDistance) = 0;
82 
83     // Must never result in a call to SyncableListener::notifyBpmChanged or
84     // signal loops could occur.
85     virtual void setMasterBpm(double bpm) = 0;
86 
87     // Combines the above three calls into one, since they are often set
88     // simultaneously.  Avoids redundant recalculation that would occur by
89     // using the three calls separately.
90     virtual void setMasterParams(double beatDistance, double baseBpm, double bpm) = 0;
91 
92     // Must never result in a call to
93     // SyncableListener::notifyInstantaneousBpmChanged or signal loops could
94     // occur.
95     virtual void setInstantaneousBpm(double bpm) = 0;
96 };
97 
98 /// SyncableListener is an interface class used by EngineSync to receive
99 /// information about sync change requests.
100 class SyncableListener {
101   public:
102     virtual ~SyncableListener() = default;
103 
104     // Used by Syncables to tell EngineSync it wants to be enabled in a
105     // specific mode. If the state change is accepted, EngineSync calls
106     // Syncable::notifySyncModeChanged.
107     virtual void requestSyncMode(Syncable* pSyncable, SyncMode mode) = 0;
108 
109     // Used by Syncables to tell EngineSync it wants to be enabled in any mode
110     // (master/follower).
111     virtual void requestEnableSync(Syncable* pSyncable, bool enabled) = 0;
112 
113     // A Syncable must never call notifyBpmChanged in response to a setMasterBpm()
114     // call.
115     virtual void notifyBpmChanged(Syncable* pSyncable, double bpm) = 0;
116     virtual void requestBpmUpdate(Syncable* pSyncable, double bpm) = 0;
117 
118     // Syncables notify EngineSync directly about various events. EngineSync
119     // does not have a say in whether these succeed or not, they are simply
120     // notifications.
121     virtual void notifyInstantaneousBpmChanged(Syncable* pSyncable, double bpm) = 0;
122 
123     // Notify Syncable that the Syncable's scratching state changed.
124     virtual void notifyScratching(Syncable* pSyncable, bool scratching) = 0;
125 
126     // A Syncable must never call notifyBeatDistanceChanged in response to a
127     // setBeatDistance() call.
128     virtual void notifyBeatDistanceChanged(
129             Syncable* pSyncable, double beatDistance) = 0;
130 
131     virtual void notifyPlayingAudible(Syncable* pSyncable, bool playingAudible) = 0;
132 
133     virtual Syncable* getMasterSyncable() = 0;
134 };
135