38 using namespace std::chrono;
42 return { 0.05s, 0.05s, 0.25s };
54 return { 4.0s, 4.0s, 10.0s };
64 unsigned long outputFrames)
79 time = std::clamp(time, schedule.
mT0, schedule.
mT1);
86 using namespace std::chrono;
95 auto frames = available;
96 auto toProduce = frames;
97 double deltat = frames /
mRate;
99 if (deltat > realTimeRemaining)
104 auto extra =
std::min( extraRealTime, deltat - realTimeRemaining );
105 auto realTime = realTimeRemaining + extra;
106 frames = realTime *
mRate + 0.5;
107 toProduce = realTimeRemaining *
mRate + 0.5;
113 return { available, frames, toProduce };
116std::pair<double, double>
118 double trackTime,
size_t nSamples )
120 auto realDuration = nSamples /
mRate;
122 realDuration *= -1.0;
128 trackTime += realDuration;
130 if ( trackTime >= schedule.
mT1 )
131 return { schedule.
mT1, std::numeric_limits<double>::infinity() };
133 return { trackTime, trackTime };
159 static OldDefaultPlaybackPolicy defaultPolicy;
160 return defaultPolicy;
169 const double t0,
const double t1,
175 if ( pRecordingSchedule )
186 if (pRecordingSchedule)
190 if (pRecordingSchedule)
279 auto node = std::make_unique<Node>();
280 mProducerNode = mConsumerNode = node.get();
281 mProducerNode->active.test_and_set();
282 mProducerNode->records.resize(
size);
284 mNodePool.emplace_back( std::move(node) );
292 auto node = mProducerNode;
294 if ( node ==
nullptr )
299 auto written = node->written;
300 auto tail = node->tail.load(std::memory_order_acquire);
301 auto head = node->head.load(std::memory_order_relaxed);
302 auto time = mLastTime;
306 auto advanceTail = [&](
double time)
308 auto newTail = (tail + 1) %
static_cast<int>(node->records.size());
309 if((newTail > head &&
static_cast<size_t>(newTail - head) == node->records.size() - 1) ||
310 (newTail < head &&
static_cast<size_t>(head - newTail) == node->records.size() - 1))
314 Node* next =
nullptr;
315 for(
auto& p : mNodePool)
317 if(p.get() == node || p->active.test_and_set())
322 next->
next.store(
nullptr);
329 mNodePool.emplace_back(std::make_unique<Node>());
330 next = mNodePool.back().get();
334 next->
records.resize(node->records.size() * 2);
335 next->
records[0].timeValue = time;
337 node->next.store(next);
338 mProducerNode = node = next;
349 node->
records[newTail].timeValue = time;
356 while ( frames >= space )
358 const auto times = policy.AdvancedTrackTime( schedule, time, space);
360 if (!std::isfinite(time))
370 const auto times = policy.AdvancedTrackTime( schedule, time, frames );
372 if (!std::isfinite(time))
379 while (frames > 0 && frames >= space )
389 node->written = written + frames;
390 node->tail.store(tail, std::memory_order_release);
405 auto node = mConsumerNode;
407 if ( node ==
nullptr ) {
409 return ( mLastTime += nSamples / rate );
412 auto head = node->head.load(std::memory_order_acquire);
413 auto tail = node->tail.load(std::memory_order_relaxed);
415 auto offset = node->offset;
418 if(nSamples >= available)
423 nSamples -= available;
427 if(
const auto next = node->next.load())
430 node->active.clear();
432 mConsumerNode = node = next;
434 tail = node->tail.load(std::memory_order_relaxed);
440 return node->records[head].timeValue;
445 head = (head + 1) %
static_cast<int>(node->records.size());
448 }
while (nSamples >= available);
449 node->head.store(head, std::memory_order_release);
451 node->offset = offset + nSamples;
452 return node->records[head].timeValue;
459 if(mProducerNode !=
nullptr)
461 mConsumerNode = mProducerNode;
462 mConsumerNode->next.store(
nullptr);
463 mConsumerNode->head.store(0);
464 mConsumerNode->tail.store(0);
465 mConsumerNode->written = 0;
466 mConsumerNode->offset = 0;
467 mConsumerNode->records[0].timeValue = time;
constexpr size_t TimeQueueGrainSize
double SolveIntegralOfInverse(double t0, double area) const
double IntegralOfInverse(double t0, double t1) const
Directs which parts of tracks to fetch for playback.
virtual BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule)
Provide hints for construction of playback RingBuffer objects.
virtual std::pair< double, double > AdvancedTrackTime(PlaybackSchedule &schedule, double trackTime, size_t nSamples)
Compute a new point in a track's timeline from an old point and a real duration.
virtual double OffsetSequenceTime(PlaybackSchedule &schedule, double offset)
Called when the play head needs to jump a certain distance.
virtual bool AllowSeek(PlaybackSchedule &schedule)
Whether repositioning commands are allowed during playback.
std::vector< std::unique_ptr< Mixer > > Mixers
virtual void Finalize(PlaybackSchedule &schedule)
Called after stopping of an audio stream or an unsuccessful start.
virtual bool Looping(const PlaybackSchedule &schedule) const
virtual Mixer::WarpOptions MixerWarpOptions(PlaybackSchedule &schedule)
Options to use when constructing mixers for each playback track.
virtual void Initialize(PlaybackSchedule &schedule, double rate)
Called before starting an audio stream.
virtual bool RepositionPlayback(PlaybackSchedule &schedule, const Mixers &playbackMixers, size_t frames, size_t available)
AudioIO::FillPlayBuffers calls this to update its cursors into tracks for changes of position or spee...
virtual PlaybackSlice GetPlaybackSlice(PlaybackSchedule &schedule, size_t available)
Choose length of one fetch of samples from tracks in a call to AudioIO::FillPlayBuffers.
virtual bool Done(PlaybackSchedule &schedule, unsigned long outputFrames)
Returns true if schedule.GetSequenceTime() has reached the end of playback.
virtual ~PlaybackPolicy()=0
virtual std::chrono::milliseconds SleepInterval(PlaybackSchedule &schedule)
How long to wait between calls to AudioIO::SequenceBufferExchange.
std::vector< std::unique_ptr< Node > > mNodePool
void Producer(PlaybackSchedule &schedule, PlaybackSlice slice)
Enqueue track time value advanced by the slice according to schedule's PlaybackPolicy.
double GetLastTime() const
Return the last time saved by Producer.
double Consumer(size_t nSamples, double rate)
Find the track time value nSamples after the last consumed sample.
void Prime(double time)
Empty the queue and reassign the last produced time.
void SetLastTime(double time)
Positions or offsets within audio files need a wide type.
struct holding stream options, including a pointer to the time warp info and AudioIOListener and whet...
PolicyFactory policyFactory
const BoundedEnvelope * envelope
Immutable structure is an argument to Mixer's constructor.
std::atomic< Node * > next
Points to a node which should be used instead of current one when it becomes exhausted by a consumer ...
std::vector< Record > records
std::unique_ptr< PlaybackPolicy > mpPlaybackPolicy
double RealTimeRemaining() const
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...
double SolveWarpedLength(double t0, double length) const
Compute how much unwarped time must have elapsed if length seconds of warped time has elapsed,...
bool ReversedTime() const
True if the end time is before the start time.
double RealDurationSigned(double trackTime1) const
const BoundedEnvelope * mEnvelope
void Init(double t0, double t1, const AudioIOStartStreamOptions &options, const RecordingSchedule *pRecordingSchedule)
std::atomic< bool > mPolicyValid
double RealDuration(double trackTime1) const
void RealTimeInit(double trackTime)
void RealTimeAdvance(double increment)
void SetSequenceTime(double time)
Set current track time value, unadjusted.
double GetSequenceTime() const
Get current track time value, unadjusted.
double ComputeWarpedLength(double t0, double t1) const
Compute signed duration (in seconds at playback) of the specified region of the track.
PlaybackPolicy & GetPolicy()
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.
const size_t frames
Total number of frames to be buffered.
double TotalCorrection() const
double mLatencyCorrection
The old default playback policy plays once and consumes no messages.
~OldDefaultPlaybackPolicy() override=default