diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index 0e43e67ba..883f27b0a 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -2827,14 +2827,13 @@ void AudioIO::FillBuffers() if (!mSilentScrub) { for (i = 0; i < mPlaybackTracks.size(); i++) { - if (mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_AT_SPEED || - mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_KEYBOARD_SCRUB) { - mPlaybackMixers[i]->SetSpeed(mScrubSpeed); - } - else { + if (mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_AT_SPEED) + mPlaybackMixers[i]->SetSpeedForPlayAtSpeed(mScrubSpeed); + else if (mPlaybackSchedule.mPlayMode == PlaybackSchedule::PLAY_KEYBOARD_SCRUB) + mPlaybackMixers[i]->SetSpeedForKeyboardScrubbing(mScrubSpeed, startTime); + else mPlaybackMixers[i]->SetTimesAndSpeed( startTime, endTime, fabs( mScrubSpeed )); - } } } mTimeQueue.mLastTime = startTime; diff --git a/src/Mix.cpp b/src/Mix.cpp index 4c91a3411..1f9a90d37 100644 --- a/src/Mix.cpp +++ b/src/Mix.cpp @@ -762,12 +762,35 @@ void Mixer::SetTimesAndSpeed(double t0, double t1, double speed) Reposition(t0); } -void Mixer::SetSpeed(double speed) +void Mixer::SetSpeedForPlayAtSpeed(double speed) { wxASSERT(std::isfinite(speed)); mSpeed = fabs(speed); } +void Mixer::SetSpeedForKeyboardScrubbing(double speed, double startTime) +{ + wxASSERT(std::isfinite(speed)); + + // Check if the direction has changed + if ((speed > 0.0 && mT1 < mT0) || (speed < 0.0 && mT1 > mT0)) { + // It's safe to use 0 and DBL_MAX, because Mixer::MixVariableRates() + // doesn't sample past the start or end of the audio in a track. + if (speed > 0.0 && mT1 < mT0) { + mT0 = 0; + mT1 = DBL_MAX; + } + else { + mT0 = DBL_MAX; + mT1 = 0; + } + + Reposition(startTime, true); + } + + mSpeed = fabs(speed); +} + MixerSpec::MixerSpec( unsigned numTracks, unsigned maxNumChannels ) { mNumTracks = mNumChannels = numTracks; diff --git a/src/Mix.h b/src/Mix.h index 7a5753610..43fede468 100644 --- a/src/Mix.h +++ b/src/Mix.h @@ -134,7 +134,8 @@ class AUDACITY_DLL_API Mixer { // Used in scrubbing. void SetTimesAndSpeed(double t0, double t1, double speed); - void SetSpeed(double speed); + void SetSpeedForPlayAtSpeed(double speed); + void SetSpeedForKeyboardScrubbing(double speed, double startTime); /// Current time in seconds (unwarped, i.e. always between startTime and stopTime) /// This value is not accurate, it's useful for progress bars and indicators, but nothing else. diff --git a/src/menus/TransportMenus.cpp b/src/menus/TransportMenus.cpp index ac672154f..078da6d42 100644 --- a/src/menus/TransportMenus.cpp +++ b/src/menus/TransportMenus.cpp @@ -198,7 +198,7 @@ void DoKeyboardScrub(AudacityProject& project, bool backwards, bool keyUp) if (keyUp) { auto &scrubber = Scrubber::Get(project); - if (scrubber.IsKeyboardScrubbing()) { + if (scrubber.IsKeyboardScrubbing() && scrubber.IsBackwards() == backwards) { auto gAudioIO = AudioIOBase::Get(); auto time = gAudioIO->GetStreamTime(); auto &viewInfo = ViewInfo::Get(project); @@ -221,7 +221,11 @@ void DoKeyboardScrub(AudacityProject& project, bool backwards, bool keyUp) else { // KeyDown auto gAudioIO = AudioIOBase::Get(); auto &scrubber = Scrubber::Get(project); - if (!gAudioIO->IsBusy() && !scrubber.HasMark()) { + if (scrubber.IsKeyboardScrubbing() && scrubber.IsBackwards() != backwards) { + // change direction + scrubber.SetBackwards(backwards); + } + else if (!gAudioIO->IsBusy() && !scrubber.HasMark()) { auto &viewInfo = ViewInfo::Get(project); auto &selection = viewInfo.selectedRegion; double endTime = TrackList::Get(project).GetEndTime(); diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index 852bcf6ec..e5d2c7eaf 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -82,6 +82,10 @@ public: { return mKeyboardScrubbing; } bool IsKeyboardScrubbing() const { return IsScrubbing() && mKeyboardScrubbing; } + void SetBackwards(bool backwards) + { mBackwards = backwards;} + bool IsBackwards() const + { return mBackwards;} // True iff the user has clicked to start scrub and not yet stopped, // but IsScrubbing() may yet be false bool HasMark() const