Bug1967: scrub shouldn't be clicky...
... And this further simplifies the use of the clock. Rely on the regularity
of spacing between calls to FillBuffers at commit a62cf53
This commit is contained in:
parent
e724ef0793
commit
03def8dbaf
|
@ -541,49 +541,40 @@ struct AudioIO::ScrubState
|
|||
}
|
||||
|
||||
void Get(sampleCount &startSample, sampleCount &endSample,
|
||||
sampleCount &duration)
|
||||
sampleCount inDuration, sampleCount &duration)
|
||||
{
|
||||
// Called by the thread that calls AudioIO::FillBuffers
|
||||
startSample = endSample = duration = -1LL;
|
||||
Duration dd { *this };
|
||||
if (dd.duration <= 0)
|
||||
return;
|
||||
|
||||
Message message( mMessage.Read() );
|
||||
if ( !mStarted ) {
|
||||
// Make some initial silence
|
||||
const sampleCount s0 { llrint( mRate *
|
||||
std::max( message.options.minTime,
|
||||
std::min( message.options.maxTime, mStartTime ) ) ) };
|
||||
const sampleCount s1 ( message.options.bySpeed
|
||||
? s0.as_double() +
|
||||
llrint(dd.duration.as_double() * message.end) // end is a speed
|
||||
: llrint(message.end * mRate) // end is a time
|
||||
);
|
||||
auto actualDuration = std::max(sampleCount{1}, dd.duration);
|
||||
auto success = mData.Init(nullptr,
|
||||
s0, s1, actualDuration, message.options, mRate);
|
||||
if ( !success ) {
|
||||
// If not, we can wait to enqueue again later
|
||||
dd.Cancel();
|
||||
return;
|
||||
}
|
||||
mData.mS0 = mData.mS1 = s0;
|
||||
mData.mGoal = -1;
|
||||
mData.mDuration = duration = inDuration;
|
||||
mData.mSilence = 0;
|
||||
mStarted = true;
|
||||
}
|
||||
else {
|
||||
Data newData;
|
||||
auto previous = &mData;
|
||||
inDuration += mAccumulatedSeekDuration;
|
||||
|
||||
// Use the previous end as NEW start.
|
||||
const auto s0 = previous->mS1;
|
||||
const auto s0 = mData.mS1;
|
||||
const sampleCount s1 ( message.options.bySpeed
|
||||
? s0.as_double() +
|
||||
lrint(dd.duration.as_double() * message.end) // end is a speed
|
||||
lrint(inDuration.as_double() * message.end) // end is a speed
|
||||
: lrint(message.end * mRate) // end is a time
|
||||
);
|
||||
auto success =
|
||||
newData.Init(previous, s0, s1, dd.duration, message.options, mRate);
|
||||
if ( !success ) {
|
||||
dd.Cancel();
|
||||
newData.Init(mData, s0, s1, inDuration, message.options, mRate);
|
||||
if (success)
|
||||
mAccumulatedSeekDuration = 0;
|
||||
else {
|
||||
mAccumulatedSeekDuration += inDuration;
|
||||
return;
|
||||
}
|
||||
mData = newData;
|
||||
|
@ -639,10 +630,11 @@ private:
|
|||
, mSilence(0)
|
||||
{}
|
||||
|
||||
bool Init(Data *previous, sampleCount s0, sampleCount s1,
|
||||
bool Init(Data &rPrevious, sampleCount s0, sampleCount s1,
|
||||
sampleCount duration,
|
||||
const ScrubbingOptions &options, double rate)
|
||||
{
|
||||
auto previous = &rPrevious;
|
||||
auto origDuration = duration;
|
||||
mSilence = 0;
|
||||
|
||||
|
@ -665,7 +657,6 @@ private:
|
|||
adjustedSpeed = true;
|
||||
}
|
||||
else if (!adjustStart &&
|
||||
previous &&
|
||||
previous->mGoal >= 0 &&
|
||||
previous->mGoal == s1)
|
||||
{
|
||||
|
@ -776,39 +767,11 @@ private:
|
|||
sampleCount mSilence;
|
||||
};
|
||||
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
struct Duration {
|
||||
Duration (ScrubState &queue_) : queue(queue_)
|
||||
{
|
||||
do {
|
||||
clockTime = Clock::now();
|
||||
using Seconds = std::chrono::duration<double>;
|
||||
const auto elapsed = std::chrono::duration_cast<Seconds>(
|
||||
clockTime - queue.mLastScrubTime);
|
||||
duration = static_cast<long long>( queue.mRate * elapsed.count() );
|
||||
} while( duration <= 0 && (::wxMilliSleep(1), true) );
|
||||
}
|
||||
~Duration ()
|
||||
{
|
||||
if(!cancelled)
|
||||
queue.mLastScrubTime = clockTime;
|
||||
}
|
||||
|
||||
void Cancel() { cancelled = true; }
|
||||
|
||||
ScrubState &queue;
|
||||
Clock::time_point clockTime;
|
||||
sampleCount duration;
|
||||
bool cancelled { false };
|
||||
};
|
||||
|
||||
double mStartTime;
|
||||
bool mStarted{ false };
|
||||
std::atomic<bool> mStopped { false };
|
||||
Data mData;
|
||||
const double mRate;
|
||||
Clock::time_point mLastScrubTime { Clock::now() };
|
||||
struct Message {
|
||||
Message() = default;
|
||||
Message(const Message&) = default;
|
||||
|
@ -816,6 +779,7 @@ private:
|
|||
ScrubbingOptions options;
|
||||
};
|
||||
MessageBuffer<Message> mMessage;
|
||||
sampleCount mAccumulatedSeekDuration{};
|
||||
};
|
||||
#endif
|
||||
|
||||
|
@ -3927,7 +3891,7 @@ void AudioIO::FillBuffers()
|
|||
{
|
||||
sampleCount startSample, endSample;
|
||||
mScrubState->Get(
|
||||
startSample, endSample, mScrubDuration);
|
||||
startSample, endSample, available, mScrubDuration);
|
||||
if (mScrubDuration < 0)
|
||||
{
|
||||
// Can't play anything
|
||||
|
|
|
@ -364,7 +364,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx)
|
|||
AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions());
|
||||
options.pScrubbingOptions = &mOptions;
|
||||
options.timeTrack = NULL;
|
||||
mOptions.delay = (ScrubPollInterval_ms * 0.9 / 1000.0);
|
||||
mOptions.delay = (ScrubPollInterval_ms / 1000.0);
|
||||
mOptions.isPlayingAtSpeed = false;
|
||||
mOptions.minSpeed = 0.0;
|
||||
#ifdef USE_TRANSCRIPTION_TOOLBAR
|
||||
|
@ -470,7 +470,7 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1)
|
|||
AudioIOStartStreamOptions options(mProject->GetSpeedPlayOptions());
|
||||
options.pScrubbingOptions = &mOptions;
|
||||
options.timeTrack = NULL;
|
||||
mOptions.delay = (ScrubPollInterval_ms * 0.9 / 1000.0);
|
||||
mOptions.delay = (ScrubPollInterval_ms / 1000.0);
|
||||
mOptions.minSpeed = speed -0.01;
|
||||
mOptions.maxSpeed = speed +0.01;
|
||||
|
||||
|
|
Loading…
Reference in New Issue