1 #pragma once
2 
3 #include <QMutex>
4 #include <QTime>
5 #include <QMap>
6 #include <QAtomicPointer>
7 
8 #include "util/performancetimer.h"
9 #include "control/controlvalue.h"
10 
11 class ControlProxy;
12 class VSyncThread;
13 
14 // This class is for synchronizing the sound device DAC time with the waveforms, displayed on the
15 // graphic device, using the CPU time
16 //
17 // DAC: ------|--------------|-------|-------------------|-----------------------|-----
18 //            ^Audio Callback Entry  |                   |                       ^Last Sample to DAC
19 //            |              ^Buffer prepared            ^Waveform sample X
20 //            |                      ^First sample transferred to DAC
21 // CPU: ------|-------------------------------------------------------------------------
22 //            ^Start m_timeInfoTime                      |
23 //                                                       |
24 // GPU: ---------|----------------------------------- |--|-------------------------------
25 //               ^Render Waveform sample X            |  ^VSync (New waveform is displayed
26 //                by use usFromTimerToNextSync        ^swap Buffer
27 
28 class VisualPlayPositionData {
29   public:
30     PerformanceTimer m_referenceTime;
31     int m_callbackEntrytoDac; // Time from Audio Callback Entry to first sample of Buffer is transferred to DAC
32     double m_enginePlayPos; // Play position of fist Sample in Buffer
33     double m_rate;
34     double m_positionStep;
35     double m_slipPosition;
36     double m_tempoTrackSeconds; // total track time, taking the current tempo into account
37 };
38 
39 
40 class VisualPlayPosition : public QObject {
41     Q_OBJECT
42   public:
43     VisualPlayPosition(const QString& m_key);
44     virtual ~VisualPlayPosition();
45 
46     // WARNING: Not thread safe. This function must be called only from the
47     // engine thread.
48     void set(double playPos, double rate, double positionStep,
49             double slipPosition, double tempoTrackSeconds);
50     double getAtNextVSync(VSyncThread* vsyncThread);
51     void getPlaySlipAtNextVSync(VSyncThread* vSyncThread, double* playPosition, double* slipPosition);
52     double getEnginePlayPos();
53     void getTrackTime(double* pPlayPosition, double* pTempoTrackSeconds);
54 
55     // WARNING: Not thread safe. This function must only be called from the main
56     // thread.
57     static QSharedPointer<VisualPlayPosition> getVisualPlayPosition(const QString& group);
58 
59     // This is called by SoundDevicePortAudio just after the callback starts.
60     static void setCallbackEntryToDacSecs(double secs, const PerformanceTimer& time);
61 
setInvalid()62     void setInvalid() { m_valid = false; };
63 
64   private slots:
65     void slotAudioBufferSizeChanged(double sizeMs);
66 
67   private:
68     ControlValueAtomic<VisualPlayPositionData> m_data;
69     ControlProxy* m_audioBufferSize;
70     int m_audioBufferMicros; // Audio buffer size in µs
71     bool m_valid;
72     QString m_key;
73 
74     static QMap<QString, QWeakPointer<VisualPlayPosition> > m_listVisualPlayPosition;
75     // Time info from the Sound device, updated just after audio callback is called
76     static double m_dCallbackEntryToDacSecs;
77     // Time stamp for m_timeInfo in main CPU time
78     static PerformanceTimer m_timeInfoTime;
79 };
80