40 using namespace std::chrono;
44 return { 0.05s, 0.05s, 0.25s };
56 return { 4.0s, 4.0s, 10.0s };
66 unsigned long outputFrames)
87 using namespace std::chrono;
96 auto frames = available;
97 auto toProduce = frames;
98 double deltat = frames /
mRate;
100 if (deltat > realTimeRemaining)
105 auto extra =
std::min( extraRealTime, deltat - realTimeRemaining );
106 auto realTime = realTimeRemaining + extra;
107 frames = realTime *
mRate;
108 toProduce = realTimeRemaining *
mRate;
114 return { available, frames, toProduce };
117std::pair<double, double>
119 double trackTime,
size_t nSamples )
121 auto realDuration = nSamples /
mRate;
123 realDuration *= -1.0;
129 trackTime += realDuration;
131 if ( trackTime >= schedule.
mT1 )
132 return { schedule.
mT1, std::numeric_limits<double>::infinity() };
134 return { trackTime, trackTime };
160 static OldDefaultPlaybackPolicy defaultPolicy;
161 return defaultPolicy;
170 double trackEndTime,
double loopEndTime,
171 bool loopEnabled,
bool variableSpeed )
172 : mProject{ project }
173 , mTrackEndTime{ trackEndTime }
174 , mLoopEndTime{ loopEndTime }
175 , mLoopEnabled{ loopEnabled }
176 , mVariableSpeed{ variableSpeed }
192 mProject.Bind( EVT_PLAY_SPEED_CHANGE,
211 using namespace std::chrono;
212 return { 0.05s, 0.05s, 0.25s };
242 auto frames = available;
243 auto toProduce = frames;
246 if (deltat > realTimeRemaining) {
248 auto realTime = realTimeRemaining;
253 const double extraRealTime =
255 extra =
std::min( extraRealTime, deltat - realTimeRemaining );
269 frames = available, toProduce = 0;
271 return { available, frames, toProduce };
284 return { schedule.
mT1, schedule.
mT0 };
287 if ( fabs(schedule.
mT0 - schedule.
mT1) < 1e-9 )
288 return {schedule.
mT0, schedule.
mT0};
292 realDuration *= -1.0;
298 trackTime += realDuration;
300 return { trackTime, trackTime };
305 size_t frames,
size_t available )
310 bool speedChange =
false;
316 bool empty = (data.mT0 >= data.mT1);
321 constexpr auto allowance = 0.5;
337 auto theirs = std::tie(data.mT0, data.mT1);
338 if (
mLoopEnabled ? (mine != theirs) : loopWasEnabled ) {
342 schedule.
mT1 = data.mT1;
353 newTime = std::clamp(newTime, schedule.
mT0, schedule.
mT1);
357 newTime = schedule.
mT0;
366 else if (speedChange)
382 for (
auto &pMixer : playbackMixers)
383 pMixer->SetTimesAndSpeed(
391 for (
auto &pMixer : playbackMixers) {
394 pMixer->Reposition(time,
true);
421 region.GetStart(), region.GetEnd(), region.Active()
433 const double t0,
const double t1,
439 if ( pRecordingSchedule )
450 if (pRecordingSchedule)
454 if (pRecordingSchedule)
555 auto index = mTail.mIndex;
556 auto time = mLastTime;
557 auto remainder = mTail.mRemainder;
559 const auto size = mData.size();
563 while ( frames >= space ) {
564 auto times = policy.AdvancedTrackTime( schedule, time, space );
566 if (!std::isfinite(time))
568 index = (index + 1) %
size;
569 mData[ index ].timeValue = time;
576 auto times = policy.AdvancedTrackTime( schedule, time, frames );
578 if (!std::isfinite(time))
586 while ( frames > 0 && frames >= space ) {
587 index = (index + 1) %
size;
588 mData[ index ].timeValue = time;
595 mTail.mRemainder = remainder + frames;
596 mTail.mIndex = index;
611 if ( mData.empty() ) {
613 return ( mLastTime += nSamples / rate );
618 auto remainder = mHead.mRemainder;
620 const auto size = mData.size();
621 if ( nSamples >= space ) {
623 mHead.mIndex = (mHead.mIndex + 1) %
size,
630 mHead.mRemainder = remainder + nSamples;
631 return mData[ mHead.mIndex ].timeValue;
638 if ( !mData.empty() )
639 mData[0].timeValue = time;
constexpr size_t TimeQueueGrainSize
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
double SolveIntegralOfInverse(double t0, double area) const
double IntegralOfInverse(double t0, double t1) const
MixerOptions::Warp WarpOptions
const double mTrackEndTime
bool Done(PlaybackSchedule &schedule, unsigned long) override
Returns true if schedule.GetTrackTime() has reached the end of playback.
void Initialize(PlaybackSchedule &schedule, double rate) override
Called before starting an audio stream.
MessageBuffer< SlotData > mMessageChannel
~NewDefaultPlaybackPolicy() override
Mixer::WarpOptions MixerWarpOptions(PlaybackSchedule &schedule) override
Options to use when constructing mixers for each playback track.
AudacityProject & mProject
bool Looping(const PlaybackSchedule &) const override
PlaybackSlice GetPlaybackSlice(PlaybackSchedule &schedule, size_t available) override
Choose length of one fetch of samples from tracks in a call to AudioIO::FillPlayBuffers.
std::pair< double, double > AdvancedTrackTime(PlaybackSchedule &schedule, double trackTime, size_t nSamples) override
Compute a new point in a track's timeline from an old point and a real duration.
Observer::Subscription mSubscription
bool RevertToOldDefault(const PlaybackSchedule &schedule) const
bool RepositionPlayback(PlaybackSchedule &schedule, const Mixers &playbackMixers, size_t frames, size_t available) override
AudioIO::FillPlayBuffers calls this to update its cursors into tracks for changes of position or spee...
NewDefaultPlaybackPolicy(AudacityProject &project, double trackEndTime, double loopEndTime, bool loopEnabled, bool variableSpeed)
void OnPlayRegionChange(Observer::Message)
BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule) override
Provide hints for construction of playback RingBuffer objects.
void OnPlaySpeedChange(wxCommandEvent &evt)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
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 OffsetTrackTime(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.GetTrackTime() has reached the end of playback.
virtual ~PlaybackPolicy()=0
virtual std::chrono::milliseconds SleepInterval(PlaybackSchedule &schedule)
How long to wait between calls to AudioIO::TrackBufferExchange.
NonInterfering< Cursor > mHead
Aligned to avoid false sharing.
void Producer(PlaybackSchedule &schedule, PlaybackSlice slice)
Enqueue track time value advanced by the slice according to schedule's PlaybackPolicy.
std::vector< Record > Records
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.
NonInterfering< Cursor > mTail
void SetLastTime(double time)
double GetPlaySpeed() const
static ProjectAudioIO & Get(AudacityProject &project)
static ViewInfo & Get(AudacityProject &project)
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.
Default message type for Publisher.
std::unique_ptr< PlaybackPolicy > mpPlaybackPolicy
double RealTimeRemaining() const
double GetTrackTime() const
Get current track time value, unadjusted.
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
class PlaybackSchedule::TimeQueue mTimeQueue
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 SetTrackTime(double time)
Set 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