Audacity 3.2.0
PlaybackSchedule.h
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file PlaybackSchedule.h
6
7 Paul Licameli split from AudioIOBase.h
8
9 **********************************************************************/
10
11#ifndef __AUDACITY_PLAYBACK_SCHEDULE__
12#define __AUDACITY_PLAYBACK_SCHEDULE__
13
14#include "MemoryX.h"
15#include "MessageBuffer.h"
16#include "Mix.h"
17#include "Observer.h"
18#include <atomic>
19#include <chrono>
20#include <vector>
21
22class AudacityProject;
24class BoundedEnvelope;
25using PRCrossfadeData = std::vector< std::vector < float > >;
26
27constexpr size_t TimeQueueGrainSize = 2000;
28
30 double mPreRoll{};
31 double mLatencyCorrection{}; // negative value usually
32 double mDuration{};
34
35 // These are initialized by the main thread, then updated
36 // only by the thread calling SequenceBufferExchange:
37 double mPosition{};
39
40 double TotalCorrection() const { return mLatencyCorrection - mPreRoll; }
41 double ToConsume() const;
42 double Consumed() const;
43 double ToDiscard() const;
44};
45
46class Mixer;
47struct PlaybackSchedule;
48
51 const size_t frames;
52 const size_t toProduce;
53
55
58 size_t available, size_t frames_, size_t toProduce_)
59 : frames{ std::min(available, frames_) }
60 , toProduce{ std::min(toProduce_, frames) }
61 {}
62};
63
65
71class AUDIO_IO_API PlaybackPolicy {
72public:
73 using Duration = std::chrono::duration<double>;
74
76
77 virtual ~PlaybackPolicy() = 0;
78
80 virtual void Initialize( PlaybackSchedule &schedule, double rate );
81
83 virtual void Finalize( PlaybackSchedule &schedule );
84
86 virtual Mixer::WarpOptions MixerWarpOptions(PlaybackSchedule &schedule);
87
89 struct BufferTimes {
93 };
95 virtual BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule);
96
98
100 virtual bool AllowSeek( PlaybackSchedule &schedule );
101
103 virtual bool Done( PlaybackSchedule &schedule,
104 unsigned long outputFrames
105 );
106
108
111 virtual double OffsetSequenceTime( PlaybackSchedule &schedule, double offset );
112
114
116 virtual std::chrono::milliseconds
117 SleepInterval( PlaybackSchedule &schedule );
118
120 virtual PlaybackSlice GetPlaybackSlice( PlaybackSchedule &schedule,
121 size_t available
122 );
123
125
135 virtual std::pair<double, double>
136 AdvancedTrackTime( PlaybackSchedule &schedule,
137 double trackTime, size_t nSamples );
138
139 using Mixers = std::vector<std::unique_ptr<Mixer>>;
140
142
145 virtual bool RepositionPlayback(
146 PlaybackSchedule &schedule, const Mixers &playbackMixers,
147 size_t frames,
148 size_t available
149 );
150
152
153 virtual bool Looping( const PlaybackSchedule &schedule ) const;
154
155protected:
156 double mRate = 0;
157};
158
159
160struct AUDIO_IO_API PlaybackSchedule {
162 double mT0;
164 double mT1;
169 std::atomic<double> mTime;
170
175
180
181 // mWarpedTime and mWarpedLength are irrelevant when scrubbing,
182 // else they are used in updating mTime,
183 // and when not scrubbing or playing looped, mTime is also used
184 // in the test for termination of playback.
185
186 // with ComputeWarpedLength, it is now possible the calculate the warped length with 100% accuracy
187 // (ignoring accumulated rounding errors during playback) which fixes the 'missing sound at the end' bug
188
190
192 /*
193 Holds track time values corresponding to every nth sample in the
194 playback buffers, for the large n == TimeQueueGrainSize.
195
196 The "producer" is the Audio thread that fetches samples from tracks and
197 fills the playback RingBuffers. The "consumer" is the high-latency
198 PortAudio thread that drains the RingBuffers. The atomics in the
199 RingBuffer implement lock-free synchronization.
200
201 This other structure relies on the RingBuffer's synchronization, and adds
202 other information to the stream of samples: which track times they
203 correspond to.
204
205 The consumer thread uses that information, and also makes known to the main
206 thread, what the last consumed track time is. The main thread can use that
207 for other purposes such as refreshing the display of the play head position.
208 */
209 class AUDIO_IO_API TimeQueue {
210 public:
211
213
214 void Clear();
215 void Resize(size_t size);
216
218
220 void Producer( PlaybackSchedule &schedule, PlaybackSlice slice );
221
223 double GetLastTime() const;
224
225 void SetLastTime(double time);
226
228
230 double Consumer( size_t nSamples, double rate );
231
233
235
236 void Prime( double time );
237
238 private:
239 struct Record {
240 double timeValue;
241 // More fields to come
242 };
243 using Records = std::vector<Record>;
245 double mLastTime {};
246 struct Cursor {
247 size_t mIndex {};
248 size_t mRemainder {};
249 };
252 } mTimeQueue;
253
254 PlaybackPolicy &GetPolicy();
255 const PlaybackPolicy &GetPolicy() const;
256
257 void Init(
258 double t0, double t1,
259 const AudioIOStartStreamOptions &options,
260 const RecordingSchedule *pRecordingSchedule );
261
271 double ComputeWarpedLength(double t0, double t1) const;
272
280 double SolveWarpedLength(double t0, double length) const;
281
283 bool ReversedTime() const
284 {
285 return mT1 < mT0;
286 }
287
292 double GetSequenceTime() const
293 { return mTime.load(std::memory_order_relaxed); }
294
297 void SetSequenceTime( double time )
298 { mTime.store(time, std::memory_order_relaxed); }
299
300 void ResetMode() {
301 mPolicyValid.store(false, std::memory_order_release);
302 }
303
304 // Convert time between mT0 and argument to real duration, according to
305 // time track if one is given; result is always nonnegative
306 double RealDuration(double trackTime1) const;
307
308 // Convert time between mT0 and argument to real duration, according to
309 // time track if one is given; may be negative
310 double RealDurationSigned(double trackTime1) const;
311
312 // How much real time left?
313 double RealTimeRemaining() const;
314
315 // Advance the real time position
316 void RealTimeAdvance( double increment );
317
318 // Determine starting duration within the first pass -- sometimes not
319 // zero
320 void RealTimeInit( double trackTime );
321
322 void RealTimeRestart();
323
324private:
325 std::unique_ptr<PlaybackPolicy> mpPlaybackPolicy;
326 std::atomic<bool> mPolicyValid{ false };
327};
328#endif
std::vector< std::vector< float > > PRCrossfadeData
Definition: AudioIOBase.h:36
int min(int a, int b)
constexpr size_t TimeQueueGrainSize
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
Functions for doing the mixdown of the tracks.
Definition: Mix.h:27
Directs which parts of tracks to fetch for playback.
std::vector< std::unique_ptr< Mixer > > Mixers
virtual ~PlaybackPolicy()=0
std::chrono::duration< double > Duration
NonInterfering< Cursor > mHead
Aligned to avoid false sharing.
std::vector< Record > Records
STL namespace.
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
Definition: AudioIOBase.h:44
Immutable structure is an argument to Mixer's constructor.
Definition: MixerOptions.h:56
Times are in seconds.
Duration latency
Try not to let ring buffer contents fall below this.
Duration ringBufferDelay
Length of ring buffer.
Duration batchSize
Try to put at least this much into the ring buffer in each pass.
std::unique_ptr< PlaybackPolicy > mpPlaybackPolicy
double mT0
Playback starts at offset of mT0, which is measured in seconds.
double mT1
Playback ends at offset of mT1, which is measured in seconds. Note that mT1 may be less than mT0 duri...
bool ReversedTime() const
True if the end time is before the start time.
const BoundedEnvelope * mEnvelope
void SetSequenceTime(double time)
Set current track time value, unadjusted.
double GetSequenceTime() const
Get current track time value, unadjusted.
std::atomic< double > mTime
Describes an amount of contiguous (but maybe time-warped) data to be extracted from tracks to play.
const size_t toProduce
Not more than frames; the difference will be trailing silence.
PlaybackSlice(size_t available, size_t frames_, size_t toProduce_)
Constructor enforces some invariants.
const size_t frames
Total number of frames to be buffered.
double TotalCorrection() const
double ToDiscard() const
double ToConsume() const
double Consumed() const
PRCrossfadeData mCrossfadeData