29 Update( t1, options );
33 mAccumulatedSeekDuration = 0;
39 mMessage.Write({
end, options });
46 startSample = endSample = duration = -1LL;
49 Message message( mMessage.Read() );
51 s0Init = llrint( mRate *
59 mData.mS0 = mData.mS1 = s0Init;
61 mData.mDuration = duration = inDuration;
68 inDuration += mAccumulatedSeekDuration;
71 const auto s0 = mStarted ? mData.mS1 : s0Init;
78 newData.
Init(mData, s0, s1, inDuration, message.
options, mRate);
80 mAccumulatedSeekDuration = 0;
82 mAccumulatedSeekDuration += inDuration;
91 if ( mStopped.load( std::memory_order_relaxed ) ) {
95 else if (
entry.mDuration > 0) {
97 startSample =
entry.mS0;
98 endSample =
entry.mS1;
99 duration =
entry.mDuration;
102 else if (
entry.mSilence > 0) {
104 startSample = endSample =
entry.mS1;
105 duration =
entry.mSilence;
112 mStopped.store(
true, std::memory_order_relaxed );
120 return mData.mS1.as_double() / mRate;
142 auto previous = &rPrevious;
143 auto origDuration = duration;
148 wxASSERT(duration > 0);
150 (std::abs((s1 - s0).as_long_long())) / duration.
as_double();
151 bool adjustedSpeed =
false;
154 wxASSERT(minSpeed == options.
minSpeed);
157 if (!adjustStart && speed > options.
maxSpeed)
162 adjustedSpeed =
true;
164 else if (!adjustStart &&
165 previous->mGoal >= 0 &&
166 previous->mGoal == s1)
175 adjustedSpeed =
true;
180 if (speed < minSpeed) {
181 if (s0 != s1 && adjustStart)
190 adjustedSpeed =
true;
196 adjustedSpeed =
true;
202 if (adjustedSpeed && !adjustStart)
227 auto newDuration = duration;
228 const auto newS1 = std::max(minSample,
std::min(maxSample, s1));
232 duration.
as_double() * (newS1 - s0).as_double() /
233 (s1 - s0).as_double()
236 if (newDuration == 0) {
241 else if (s1 != newS1) {
243 duration = newDuration;
248 if (adjustStart && !silent)
261 mDuration = duration;
262 if (duration < origDuration)
263 mSilence = origDuration - duration;
276 bool mStarted{
false };
277 std::atomic<bool> mStopped {
false };
290ScrubQueue ScrubQueue::Instance;
295 : mOptions{ options }
309 ScrubQueue::Instance.Init( schedule.
mT0, rate,
mOptions );
314 ScrubQueue::Instance.Stop();
327 using namespace std::chrono;
358std::chrono::milliseconds
368 return { available, 0, 0 };
373 auto frames = available;
374 auto toProduce = frames;
392 ScrubQueue::Instance.Get(
399 return { available, frames, toProduce };
405 auto realDuration = nSamples /
mRate;
406 auto result = trackTime + realDuration *
mScrubSpeed;
407 bool discontinuity = nSamples > 0 &&
413 return { result, result };
418 size_t frames,
size_t available)
437 double startTime, endTime;
448 for (
auto &pMixer : playbackMixers) {
450 pMixer->SetSpeedForKeyboardScrubbing(
mScrubSpeed, startTime);
452 pMixer->SetTimesAndSpeed(
465 auto &queue = ScrubQueue::Instance;
466 queue.Update(endTimeOrSpeed, options);
471 auto &queue = ScrubQueue::Instance;
478 auto &queue = ScrubQueue::Instance;
479 return queue.LastTrackTime();
485 auto &queue = ScrubQueue::Instance;
486 return gAudioIO->IsBusy() && queue.Started();
static ProjectFileIORegistry::AttributeWriterEntry entry
size_t limitSampleBufferSize(size_t bufferSize, sampleCount limit)
static constexpr auto ScrubPollInterval
static AudioIOBase * Get()
Communicate data atomically from one writer thread to one reader.
std::vector< std::unique_ptr< Mixer > > Mixers
virtual void Initialize(PlaybackSchedule &schedule, double rate)
Called before starting an audio stream.
const ScrubbingOptions mOptions
std::chrono::milliseconds SleepInterval(PlaybackSchedule &) override
How long to wait between calls to AudioIO::SequenceBufferExchange.
BufferTimes SuggestedBufferTimes(PlaybackSchedule &schedule) override
Provide hints for construction of playback RingBuffer objects.
void Finalize(PlaybackSchedule &schedule) override
Called after stopping of an audio stream or an unsuccessful start.
bool Done(PlaybackSchedule &schedule, unsigned long) override
Returns true if schedule.GetSequenceTime() has reached the end of playback.
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...
~ScrubbingPlaybackPolicy() override
sampleCount mScrubDuration
PlaybackSlice GetPlaybackSlice(PlaybackSchedule &schedule, size_t available) override
Choose length of one fetch of samples from tracks in a call to AudioIO::FillPlayBuffers.
size_t mUntilDiscontinuity
ScrubbingPlaybackPolicy(const ScrubbingOptions &)
Mixer::WarpOptions MixerWarpOptions(PlaybackSchedule &schedule) override
Options to use when constructing mixers for each playback track.
bool AllowSeek(PlaybackSchedule &) override
Whether repositioning commands are allowed during playback.
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.
void Initialize(PlaybackSchedule &schedule, double rate) override
Called before starting an audio stream.
Positions or offsets within audio files need a wide type.
long long as_long_long() const
const char * end(const char *str) noexcept
Immutable structure is an argument to Mixer's constructor.
double mT0
Playback starts at offset of mT0, which is measured in seconds.
Describes an amount of contiguous (but maybe time-warped) data to be extracted from tracks to play.
static bool IsScrubbing()
static double GetLastScrubTime()
return the ending time of the last scrub interval.
static void UpdateScrub(double endTimeOrSpeed, const ScrubbingOptions &options)
Notify scrubbing engine of desired position or speed. If options.adjustStart is true,...
PlaybackPolicy::Duration minStutterTime
PlaybackPolicy::Duration delay
static double MinAllowedScrubSpeed()
static double MaxAllowedScrubSpeed()
bool Init(Data &rPrevious, sampleCount s0, sampleCount s1, sampleCount duration, const ScrubbingOptions &options, double rate)
Message(const Message &)=default
double LastTrackTime() const
static ScrubQueue Instance
MessageBuffer< Message > mMessage
void Init(double t0, double rate, const ScrubbingOptions &options)
void Get(sampleCount &startSample, sampleCount &endSample, sampleCount inDuration, sampleCount &duration)
void Update(double end, const ScrubbingOptions &options)