From e0302257c5d956d86ce80e4cfb7518bbb6efe2e9 Mon Sep 17 00:00:00 2001 From: David Bailes Date: Tue, 11 Feb 2020 09:54:45 +0000 Subject: [PATCH] Keyboard scrubbing and Play-at-speed: remove initial silence Currently AudioIoCallback::ScrubState::Get(), inserts a period of silence the first time it's called because at this time Scrubber::ContinueScrubbingPoll() has not been called, and so message.end has not been set to an appropriate value. In the case of keyboard scrubbing and play-at-speed, the initial speed is already known, so message.end can be set to this value, removing the need for an initial silence. The start of keyboard scrubbing and play-at-speed are now faster (the latter very much faster). --- src/AudioIO.cpp | 34 ++++++++++++++++++++++------------ src/AudioIOBase.h | 3 ++- src/tracks/ui/Scrubbing.cpp | 6 +++--- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 883f27b0a..7e1164774 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -543,7 +543,7 @@ struct AudioIoCallback::ScrubState : mRate(rate) , mStartTime( t0 ) { - const double t1 = options.bySpeed ? 1.0 : t0; + const double t1 = options.bySpeed ? options.initSpeed : t0; Update( t1, options ); } @@ -558,25 +558,33 @@ struct AudioIoCallback::ScrubState { // Called by the thread that calls AudioIO::FillBuffers startSample = endSample = duration = -1LL; + sampleCount s0Init; Message message( mMessage.Read() ); if ( !mStarted ) { - // Make some initial silence - const sampleCount s0 { llrint( mRate * + s0Init = llrint( mRate * std::max( message.options.minTime, - std::min( message.options.maxTime, mStartTime ) ) ) }; - mData.mS0 = mData.mS1 = s0; - mData.mGoal = -1; - mData.mDuration = duration = inDuration; - mData.mSilence = 0; - mStarted = true; + std::min( message.options.maxTime, mStartTime ) ) ); + + // Make some initial silence. This is not needed in the case of + // keyboard scrubbing or play-at-speed, because the initial speed + // is known when this function is called the first time. + if ( !(message.options.isKeyboardScrubbing || + message.options.isPlayingAtSpeed) ) { + mData.mS0 = mData.mS1 = s0Init; + mData.mGoal = -1; + mData.mDuration = duration = inDuration; + mData.mSilence = 0; + } } - else { + + if (mStarted || message.options.isKeyboardScrubbing || + message.options.isPlayingAtSpeed) { Data newData; inDuration += mAccumulatedSeekDuration; - // Use the previous end as NEW start. - const auto s0 = mData.mS1; + // If already started, use the previous end as NEW start. + const auto s0 = mStarted ? mData.mS1 : s0Init; const sampleCount s1 ( message.options.bySpeed ? s0.as_double() + lrint(inDuration.as_double() * message.end) // end is a speed @@ -593,6 +601,8 @@ struct AudioIoCallback::ScrubState mData = newData; }; + mStarted = true; + Data &entry = mData; if ( mStopped.load( std::memory_order_relaxed ) ) { // We got the shut-down signal, or we discarded all the work. diff --git a/src/AudioIOBase.h b/src/AudioIOBase.h index 4b138fbce..2a53edda2 100644 --- a/src/AudioIOBase.h +++ b/src/AudioIOBase.h @@ -53,7 +53,8 @@ struct ScrubbingOptions { double delay {}; - // Limiting values for the speed of a scrub interval: + // Initial and limiting values for the speed of a scrub interval: + double initSpeed { 1.0 }; double minSpeed { 0.0 }; double maxSpeed { 1.0 }; diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index ac55f491f..4b8a5d61c 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -527,6 +527,7 @@ bool Scrubber::StartSpeedPlay(double speed, double time0, double time1) options.pScrubbingOptions = &mOptions; options.envelope = nullptr; mOptions.delay = (ScrubPollInterval_ms / 1000.0); + mOptions.initSpeed = speed; mOptions.minSpeed = speed -0.01; mOptions.maxSpeed = speed +0.01; @@ -602,12 +603,11 @@ bool Scrubber::StartKeyboardScrubbing(double time0, bool backwards) options.envelope = nullptr; // delay and minStutterTime are used in AudioIO::AllocateBuffers() for setting the - // values of mPlaybackQueueMinimum and mPlaybackSamplesToCopy respectively. minStutterTime - // is set lower here than in mouse scrubbing to ensure that there is not a long - // delay before the start of the playback of the audio. + // values of mPlaybackQueueMinimum and mPlaybackSamplesToCopy respectively. mOptions.delay = (ScrubPollInterval_ms / 1000.0); mOptions.minStutterTime = mOptions.delay; + mOptions.initSpeed = GetKeyboardScrubbingSpeed(); mOptions.minSpeed = ScrubbingOptions::MinAllowedScrubSpeed(); mOptions.maxSpeed = ScrubbingOptions::MaxAllowedScrubSpeed(); mOptions.minTime = 0;