1 #pragma once
2 
3 #include <gtest/gtest_prod.h>
4 
5 #include <QAtomicInt>
6 #include <QMutex>
7 #include <cfloat>
8 
9 #include "control/controlvalue.h"
10 #include "engine/cachingreader/cachingreader.h"
11 #include "engine/engineobject.h"
12 #include "engine/sync/syncable.h"
13 #include "preferences/usersettings.h"
14 #include "track/track_decl.h"
15 #include "util/rotary.h"
16 #include "util/types.h"
17 
18 //for the writer
19 #ifdef __SCALER_DEBUG__
20 #include <QFile>
21 #include <QTextStream>
22 #endif
23 
24 class EngineChannel;
25 class EngineControl;
26 class BpmControl;
27 class KeyControl;
28 class RateControl;
29 class SyncControl;
30 class VinylControlControl;
31 class LoopingControl;
32 class ClockControl;
33 class CueControl;
34 class ReadAheadManager;
35 class ControlObject;
36 class ControlProxy;
37 class ControlPushButton;
38 class ControlIndicator;
39 class ControlBeat;
40 class ControlTTRotary;
41 class ControlPotmeter;
42 class EngineBufferScale;
43 class EngineBufferScaleLinear;
44 class EngineBufferScaleST;
45 class EngineBufferScaleRubberBand;
46 class EngineSync;
47 class EngineWorkerScheduler;
48 class VisualPlayPosition;
49 class EngineMaster;
50 
51 class EngineBuffer : public EngineObject {
52      Q_OBJECT
53   private:
54     enum SyncRequestQueued {
55         SYNC_REQUEST_NONE,
56         SYNC_REQUEST_ENABLE,
57         SYNC_REQUEST_DISABLE,
58         SYNC_REQUEST_ENABLEDISABLE,
59     };
60   public:
61     enum SeekRequest {
62         SEEK_NONE = 0x00,
63         SEEK_PHASE = 0x01, // This is set to force an in-phase seek.
64         SEEK_EXACT = 0x02, // This is used to seek to position regardless of
65                            // if Quantize is enabled.
66         SEEK_EXACT_PHASE = SEEK_PHASE | SEEK_EXACT,
67 						   // This is an artificial state that happens if
68                            // an exact seek and a phase seek are scheduled
69                            // at the same time.
70         SEEK_STANDARD = 0x04, // This seeks to the exact position if Quantize is
71                               // disabled or performs an in-phase seek if it is enabled.
72         SEEK_STANDARD_PHASE = SEEK_STANDARD | SEEK_PHASE,
73                               // This is an artificial state that happens if
74                               // a standard seek and a phase seek are scheduled
75                               // at the same time.
76     };
77     Q_DECLARE_FLAGS(SeekRequests, SeekRequest);
78 
79     enum KeylockEngine {
80         SOUNDTOUCH,
81         RUBBERBAND,
82         KEYLOCK_ENGINE_COUNT,
83     };
84 
85     // This value is used to make sure the initial seek after loading a track is
86     // not omitted. Therefore this value must be different for 0.0 or any likely
87     // value for the main cue
88     static constexpr double kInitalSamplePosition = -DBL_MAX;
89 
90     EngineBuffer(const QString& group, UserSettingsPointer pConfig,
91                  EngineChannel* pChannel, EngineMaster* pMixingEngine);
92     virtual ~EngineBuffer();
93 
94     void bindWorkers(EngineWorkerScheduler* pWorkerScheduler);
95 
96     // Return the current rate (not thread-safe)
97     double getSpeed();
98     bool getScratching();
99     // Returns current bpm value (not thread-safe)
100     double getBpm();
101     // Returns the BPM of the loaded track around the current position (not thread-safe)
102     double getLocalBpm();
103     // Sets pointer to other engine buffer/channel
104     void setEngineMaster(EngineMaster*);
105 
106     // Queues a new seek position. Use SEEK_EXACT or SEEK_STANDARD as seekType
107     void queueNewPlaypos(double newpos, enum SeekRequest seekType);
108     void requestSyncPhase();
109     void requestEnableSync(bool enabled);
110     void requestSyncMode(SyncMode mode);
111     void requestClonePosition(EngineChannel* pChannel);
112 
113     // The process methods all run in the audio callback.
114     void process(CSAMPLE* pOut, const int iBufferSize);
115     void processSlip(int iBufferSize);
116     void postProcess(const int iBufferSize);
117 
118     QString getGroup();
119     bool isTrackLoaded();
120     // return true if a seek is currently cueued but not yet processed, false otherwise
121     // if no seek was queued, the seek position is set to -1
122     bool getQueuedSeekPosition(double* pSeekPosition);
123     TrackPointer getLoadedTrack() const;
124 
125     bool isReverse();
126 
127     double getExactPlayPos();
128     double getVisualPlayPos();
129     double getTrackSamples();
130 
131     void collectFeatures(GroupFeatureState* pGroupFeatures) const;
132 
133     double getRateRatio() const;
134 
135     // For dependency injection of readers.
136     //void setReader(CachingReader* pReader);
137 
138     // For dependency injection of scalers.
139     void setScalerForTest(EngineBufferScale* pScaleVinyl,
140                           EngineBufferScale* pScaleKeylock);
141 
142     // For injection of fake tracks.
143     void loadFakeTrack(TrackPointer pTrack, bool bPlay);
144 
getKeylockEngineName(KeylockEngine engine)145     static QString getKeylockEngineName(KeylockEngine engine) {
146         switch (engine) {
147         case SOUNDTOUCH:
148             return tr("Soundtouch (faster)");
149         case RUBBERBAND:
150             return tr("Rubberband (better)");
151         default:
152             return tr("Unknown (bad value)");
153         }
154     }
155 
156     // Request that the EngineBuffer load a track. Since the process is
157     // asynchronous, EngineBuffer will emit a trackLoaded signal when the load
158     // has completed.
159     void loadTrack(TrackPointer pTrack, bool play);
160 
setChannelIndex(int channelIndex)161     void setChannelIndex(int channelIndex) {
162         m_channelIndex = channelIndex;
163     }
164 
165   public slots:
166     void slotControlPlayRequest(double);
167     void slotControlPlayFromStart(double);
168     void slotControlJumpToStartAndStop(double);
169     void slotControlStop(double);
170     void slotControlStart(double);
171     void slotControlEnd(double);
172     void slotControlSeek(double);
173     void slotControlSeekAbs(double);
174     void slotControlSeekExact(double);
175     void slotKeylockEngineChanged(double);
176 
177     void slotEjectTrack(double);
178 
179   signals:
180     void trackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack);
181     void trackLoadFailed(TrackPointer pTrack, const QString& reason);
182 
183   private slots:
184     void slotTrackLoading();
185     void slotTrackLoaded(TrackPointer pTrack,
186                          int iSampleRate, int iNumSamples);
187     void slotTrackLoadFailed(TrackPointer pTrack,
188             const QString& reason);
189     // Fired when passthrough mode is enabled or disabled.
190     void slotPassthroughChanged(double v);
191     void slotUpdatedTrackBeats();
192 
193   private:
194     struct QueuedSeek {
195         double position;
196         enum SeekRequest seekType;
197     };
198 
199     // Add an engine control to the EngineBuffer
200     // must not be called outside the Constructor
201     void addControl(EngineControl* pControl);
202 
203     void enableIndependentPitchTempoScaling(bool bEnable,
204                                             const int iBufferSize);
205 
206     void updateIndicators(double rate, int iBufferSize);
207 
208     void hintReader(const double rate);
209 
210     void ejectTrack();
211 
212     double fractionalPlayposFromAbsolute(double absolutePlaypos);
213 
214     void doSeekFractional(double fractionalPos, enum SeekRequest seekType);
215     void doSeekPlayPos(double playpos, enum SeekRequest seekType);
216 
217     // Read one buffer from the current scaler into the crossfade buffer.  Used
218     // for transitioning from one scaler to another, or reseeking a scaler
219     // to prevent pops.
220     void readToCrossfadeBuffer(const int iBufferSize);
221 
222     // Copy the play position from the given buffer
223     void seekCloneBuffer(EngineBuffer* pOtherBuffer);
224 
225     // Reset buffer playpos and set file playpos.
226     void setNewPlaypos(double playpos);
227 
228     void processSyncRequests();
229     void processSeek(bool paused);
230 
231     bool updateIndicatorsAndModifyPlay(bool newPlay, bool oldPlay);
232     void verifyPlay();
233     void notifyTrackLoaded(TrackPointer pNewTrack, TrackPointer pOldTrack);
234     void processTrackLocked(CSAMPLE* pOutput, const int iBufferSize, int sample_rate);
235 
236     // Holds the name of the control group
237     const QString m_group;
238     int m_channelIndex;
239 
240     UserSettingsPointer m_pConfig;
241 
242     friend class CueControlTest;
243 
244     LoopingControl* m_pLoopingControl; // used for testes
245     FRIEND_TEST(LoopingControlTest, LoopScale_HalvesLoop);
246     FRIEND_TEST(LoopingControlTest, LoopMoveTest);
247     FRIEND_TEST(LoopingControlTest, LoopResizeSeek);
248     FRIEND_TEST(LoopingControlTest, ReloopToggleButton_DoesNotJumpAhead);
249     FRIEND_TEST(LoopingControlTest, ReloopAndStopButton);
250     FRIEND_TEST(LoopingControlTest, Beatjump_JumpsByBeats);
251     FRIEND_TEST(SyncControlTest, TestDetermineBpmMultiplier);
252     FRIEND_TEST(EngineSyncTest, HalfDoubleBpmTest);
253     FRIEND_TEST(EngineSyncTest, HalfDoubleThenPlay);
254     FRIEND_TEST(EngineSyncTest, UserTweakBeatDistance);
255     FRIEND_TEST(EngineSyncTest, UserTweakPreservedInSeek);
256     FRIEND_TEST(EngineSyncTest, BeatMapQantizePlay);
257     FRIEND_TEST(EngineBufferTest, ScalerNoTransport);
258     EngineSync* m_pEngineSync;
259     SyncControl* m_pSyncControl;
260     VinylControlControl* m_pVinylControlControl;
261     RateControl* m_pRateControl;
262     BpmControl* m_pBpmControl;
263     KeyControl* m_pKeyControl;
264     ClockControl* m_pClockControl;
265     CueControl* m_pCueControl;
266 
267     QList<EngineControl*> m_engineControls;
268 
269     // The read ahead manager for EngineBufferScale's that need to read ahead
270     ReadAheadManager* m_pReadAheadManager;
271 
272     // The reader used to read audio files
273     CachingReader* m_pReader;
274 
275     // List of hints to provide to the CachingReader
276     HintVector m_hintList;
277 
278     // The current sample to play in the file.
279     double m_filepos_play;
280 
281     // The previous callback's speed. Used to check if the scaler parameters
282     // need updating.
283     double m_speed_old;
284 
285     // The previous callback's tempo ratio.
286     double m_tempo_ratio_old;
287 
288     // True if the previous callback was scratching.
289     bool m_scratching_old;
290 
291     // True if the previous callback was reverse.
292     bool m_reverse_old;
293 
294     // The previous callback's pitch. Used to check if the scaler parameters
295     // need updating.
296     double m_pitch_old;
297 
298     // The previous callback's baserate. Used to check if the scaler parameters
299     // need updating.
300     double m_baserate_old;
301 
302     // Copy of rate_exchange, used to check if rate needs to be updated
303     double m_rate_old;
304 
305     // Copy of length of file
306     double m_trackSamplesOld;
307 
308     // Copy of file sample rate
309     double m_trackSampleRateOld;
310 
311     // Mutex controlling whether the process function is in pause mode. This happens
312     // during seek and loading of a new track
313     QMutex m_pause;
314     // Used in update of playpos slider
315     int m_iSamplesSinceLastIndicatorUpdate;
316 
317     // The location where the track would have been had slip not been engaged
318     double m_dSlipPosition;
319     // Saved value of rate for slip mode
320     double m_dSlipRate;
321     // m_bSlipEnabledProcessing is only used by the engine processing thread.
322     bool m_bSlipEnabledProcessing;
323 
324     ControlObject* m_pTrackSamples;
325     ControlObject* m_pTrackSampleRate;
326 
327     ControlPushButton* m_playButton;
328     ControlPushButton* m_playStartButton;
329     ControlPushButton* m_stopStartButton;
330     ControlPushButton* m_stopButton;
331 
332     ControlObject* m_fwdButton;
333     ControlObject* m_backButton;
334     ControlPushButton* m_pSlipButton;
335 
336     ControlObject* m_pQuantize;
337     ControlObject* m_pMasterRate;
338     ControlPotmeter* m_playposSlider;
339     ControlProxy* m_pSampleRate;
340     ControlProxy* m_pKeylockEngine;
341     ControlPushButton* m_pKeylock;
342 
343     // This ControlProxys is created as parent to this and deleted by
344     // the Qt object tree. This helps that they are deleted by the creating
345     // thread, which is required to avoid segfaults.
346     ControlProxy* m_pPassthroughEnabled;
347 
348     ControlPushButton* m_pEject;
349     ControlObject* m_pTrackLoaded;
350 
351     // Whether or not to repeat the track when at the end
352     ControlPushButton* m_pRepeat;
353 
354     // Fwd and back controls, start and end of track control
355     ControlPushButton* m_startButton;
356     ControlPushButton* m_endButton;
357 
358     // Object used to perform waveform scaling (sample rate conversion).  These
359     // three pointers may be reassigned depending on configuration and tests.
360     EngineBufferScale* m_pScale;
361     FRIEND_TEST(EngineBufferTest, SlowRubberBand);
362     FRIEND_TEST(EngineBufferTest, ResetPitchAdjustUsesLinear);
363     FRIEND_TEST(EngineBufferTest, VinylScalerRampZero);
364     FRIEND_TEST(EngineBufferTest, ReadFadeOut);
365     FRIEND_TEST(EngineBufferTest, RateTempTest);
366     FRIEND_TEST(EngineBufferTest, RatePermTest);
367     EngineBufferScale* m_pScaleVinyl;
368     // The keylock engine is configurable, so it could flip flop between
369     // ScaleST and ScaleRB during a single callback.
370     EngineBufferScale* volatile m_pScaleKeylock;
371 
372     // Object used for vinyl-style interpolation scaling of the audio
373     EngineBufferScaleLinear* m_pScaleLinear;
374     // Objects used for pitch-indep time stretch (key lock) scaling of the audio
375     EngineBufferScaleST* m_pScaleST;
376     EngineBufferScaleRubberBand* m_pScaleRB;
377 
378     // Indicates whether the scaler has changed since the last process()
379     bool m_bScalerChanged;
380     // Indicates that dependency injection has taken place.
381     bool m_bScalerOverride;
382 
383     QAtomicInt m_iSeekPhaseQueued;
384     QAtomicInt m_iEnableSyncQueued;
385     QAtomicInt m_iSyncModeQueued;
386     ControlValueAtomic<QueuedSeek> m_queuedSeek;
387     static constexpr QueuedSeek kNoQueuedSeek = {
388             -1.0, SEEK_NONE}; // value used if no seek is queued
389     QAtomicPointer<EngineChannel> m_pChannelToCloneFrom;
390 
391     // Is true if the previous buffer was silent due to pausing
392     QAtomicInt m_iTrackLoading;
393     bool m_bPlayAfterLoading;
394     // Records the sample rate so we can detect when it changes. Initialized to
395     // 0 to guarantee we see a change on the first callback.
396     int m_iSampleRate;
397 
398     TrackPointer m_pCurrentTrack;
399 #ifdef __SCALER_DEBUG__
400     QFile df;
401     QTextStream writer;
402 #endif
403 
404     // Certain operations like seeks and engine changes need to be crossfaded
405     // to eliminate clicks and pops.
406     CSAMPLE* m_pCrossfadeBuffer;
407     bool m_bCrossfadeReady;
408     int m_iLastBufferSize;
409 
410     QSharedPointer<VisualPlayPosition> m_visualPlayPos;
411 };
412 
413 Q_DECLARE_OPERATORS_FOR_FLAGS(EngineBuffer::SeekRequests)
414