diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index d7f7347b3..46b44af3b 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -1590,30 +1590,27 @@ int AudioIO::StartStream(const WaveTrackArray &playbackTracks, mCaptureBuffers = NULL; mResample = NULL; + double playbackTime = 4.0; + #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT bool scrubbing = (options.pScrubbingOptions != nullptr); // Scrubbing is not compatible with looping or recording or a time track! - double maxScrubSpeed = options.maxScrubSpeed; - double minScrubStutter = options.minScrubStutter; - const double scrubDelay = scrubbing - ? lrint(options.scrubDelay * sampleRate) / sampleRate - : -1; if (scrubbing) { + const auto &scrubOptions = *options.pScrubbingOptions; + if (mCaptureTracks->size() > 0 || mPlayMode == PLAY_LOOPED || mTimeTrack != NULL || - options.maxScrubSpeed < - ScrubbingOptions::MinAllowedScrubSpeed()) - { + scrubOptions.maxSpeed < ScrubbingOptions::MinAllowedScrubSpeed()) { wxASSERT(false); scrubbing = false; } - } - if (scrubbing) - { - mPlayMode = PLAY_SCRUB; + else { + playbackTime = lrint(scrubOptions.delay * sampleRate) / sampleRate; + mPlayMode = PLAY_SCRUB; + } } #endif @@ -1654,11 +1651,6 @@ int AudioIO::StartStream(const WaveTrackArray &playbackTracks, // mouse input, so make fillings more and shorter. // What Audio thread produces for playback is then consumed by the PortAudio // thread, in many smaller pieces. - double playbackTime = 4.0; -#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT - if (scrubbing) - playbackTime = scrubDelay; -#endif mPlaybackSamplesToCopy = playbackTime * mRate; // Capacity of the playback buffer. @@ -1875,10 +1867,11 @@ int AudioIO::StartStream(const WaveTrackArray &playbackTracks, delete mScrubQueue; if (scrubbing) { + const auto &scrubOptions = *options.pScrubbingOptions; mScrubQueue = - new ScrubQueue(mT0, mT1, options.scrubStartClockTimeMillis, - 0.0, options.maxScrubTime, - sampleRate, maxScrubSpeed, minScrubStutter, + new ScrubQueue(mT0, mT1, scrubOptions.startClockTimeMillis, + 0.0, scrubOptions.maxTime, + sampleRate, scrubOptions.maxSpeed, scrubOptions.minStutter, *options.pScrubbingOptions); mScrubDuration = 0; mSilentScrub = false; diff --git a/src/AudioIO.h b/src/AudioIO.h index 2d20dc17b..a628b3384 100644 --- a/src/AudioIO.h +++ b/src/AudioIO.h @@ -99,13 +99,6 @@ struct AudioIOStartStreamOptions , cutPreviewGapStart(0.0) , cutPreviewGapLen(0.0) , pStartTime(NULL) -#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT - , scrubDelay(0.0) - , maxScrubSpeed(1.0) - , minScrubStutter(0.0) - , scrubStartClockTimeMillis(-1) - , maxScrubTime(0.0) -#endif {} TimeTrack *timeTrack; @@ -117,23 +110,6 @@ struct AudioIOStartStreamOptions double * pStartTime; #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT - double scrubDelay; - - // We need a limiting value for the speed of the first scrub - // interval: - double maxScrubSpeed; - - // When maximum speed scrubbing skips to follow the mouse, - // this is the minimum amount of playback at the maximum speed: - double minScrubStutter; - - // Scrubbing needs the time of start of the mouse movement that began - // the scrub: - wxLongLong scrubStartClockTimeMillis; - - // usually from TrackList::GetEndTime() - double maxScrubTime; - // Non-null value indicates that scrubbing will happen // (do not specify a time track, looping, or recording, which // are all incompatible with scrubbing): diff --git a/src/tracks/ui/Scrubbing.cpp b/src/tracks/ui/Scrubbing.cpp index eac5ab689..0fe3328cf 100644 --- a/src/tracks/ui/Scrubbing.cpp +++ b/src/tracks/ui/Scrubbing.cpp @@ -142,11 +142,9 @@ void Scrubber::ScrubPoller::Notify() Scrubber::Scrubber(AudacityProject *project) : mScrubToken(-1) - , mScrubStartClockTimeMillis(-1) , mPaused(true) , mScrubSpeedDisplayCountdown(0) , mScrubStartPosition(-1) - , mMaxScrubSpeed(-1.0) , mScrubSeekPress(false) #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL , mSmoothScrollingScrub(false) @@ -243,7 +241,7 @@ void Scrubber::MarkScrubStart( ctb->UpdateStatusBar(mProject); mScrubStartPosition = xx; - mScrubStartClockTimeMillis = ::wxGetLocalTimeMillis(); + mOptions.startClockTimeMillis = ::wxGetLocalTimeMillis(); CheckMenuItem(); } @@ -300,23 +298,22 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) AudioIOStartStreamOptions options(mProject->GetDefaultPlayOptions()); options.pScrubbingOptions = &mOptions; options.timeTrack = NULL; - options.scrubDelay = (ScrubPollInterval_ms / 1000.0); - options.scrubStartClockTimeMillis = mScrubStartClockTimeMillis; - options.minScrubStutter = 0.2; + mOptions.delay = (ScrubPollInterval_ms / 1000.0); + mOptions.minStutter = 0.2; #ifdef USE_TRANSCRIPTION_TOOLBAR if (!mAlwaysSeeking) { // Take the starting speed limit from the transcription toolbar, // but it may be varied during the scrub. - mMaxScrubSpeed = options.maxScrubSpeed = + mOptions.maxSpeed = mProject->GetTranscriptionToolBar()->GetPlaySpeed(); } #else // That idea seems unpopular... just make it one for move-scrub, // but big for drag-scrub - mMaxScrubSpeed = options.maxScrubSpeed = + mOptions.maxSpeed = mDragging ? ScrubbingOptions::MaxAllowedScrubSpeed() : 1.0; #endif - options.maxScrubTime = mProject->GetTracks()->GetEndTime(); + mOptions.maxTime = mProject->GetTracks()->GetEndTime(); ControlToolBar::PlayAppearance appearance = ControlToolBar::PlayAppearance::Scrub; const bool cutPreview = false; @@ -325,7 +322,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) static const double maxScrubSpeedBase = pow(2.0, 1.0 / ScrubSpeedStepsPerOctave); mLogMaxScrubSpeed = floor(0.5 + - log(mMaxScrubSpeed) / log(maxScrubSpeedBase) + log(mOptions.maxSpeed) / log(maxScrubSpeedBase) ); #endif mScrubSpeedDisplayCountdown = 0; @@ -336,7 +333,7 @@ bool Scrubber::MaybeStartScrubbing(wxCoord xx) } else // Wait to test again - mScrubStartClockTimeMillis = ::wxGetLocalTimeMillis(); + mOptions.startClockTimeMillis = ::wxGetLocalTimeMillis(); if (IsScrubbing()) { using Mode = AudacityProject::PlaybackScroller::Mode; @@ -392,7 +389,7 @@ void Scrubber::ContinueScrubbing() // When paused, enqueue silent scrubs. mOptions.adjustStart = false; mOptions.enqueueBySpeed = true; - result = gAudioIO->EnqueueScrub(0, mMaxScrubSpeed, mOptions); + result = gAudioIO->EnqueueScrub(0, mOptions.maxSpeed, mOptions); } else if (mDragging && mSmoothScrollingScrub) { const auto lastTime = gAudioIO->GetLastTimeInScrubQueue(); @@ -400,7 +397,7 @@ void Scrubber::ContinueScrubbing() const double time = viewInfo.OffsetTimeByPixels(lastTime, delta); mOptions.adjustStart = true; mOptions.enqueueBySpeed = false; - result = gAudioIO->EnqueueScrub(time, mMaxScrubSpeed, mOptions); + result = gAudioIO->EnqueueScrub(time, mOptions.maxSpeed, mOptions); mLastScrubPosition = position.x; } else { @@ -413,11 +410,11 @@ void Scrubber::ContinueScrubbing() if (mSmoothScrollingScrub) { const double speed = FindScrubSpeed(seek, time); mOptions.enqueueBySpeed = true; - result = gAudioIO->EnqueueScrub(speed, mMaxScrubSpeed, mOptions); + result = gAudioIO->EnqueueScrub(speed, mOptions.maxSpeed, mOptions); } else { mOptions.enqueueBySpeed = false; - result = gAudioIO->EnqueueScrub(time, seek ? 1.0 : mMaxScrubSpeed, mOptions); + result = gAudioIO->EnqueueScrub(time, seek ? 1.0 : mOptions.maxSpeed, mOptions); } } @@ -489,7 +486,7 @@ double Scrubber::FindScrubSpeed(bool seeking, double time) const ViewInfo &viewInfo = mProject->GetViewInfo(); const double screen = mProject->GetScreenEndTime() - viewInfo.h; return (seeking ? FindSeekSpeed : FindScrubbingSpeed) - (viewInfo, mMaxScrubSpeed, screen, time); + (viewInfo, mOptions.maxSpeed, screen, time); } void Scrubber::HandleScrollWheel(int steps) @@ -505,7 +502,7 @@ void Scrubber::HandleScrollWheel(int steps) if (newSpeed >= ScrubbingOptions::MinAllowedScrubSpeed() && newSpeed <= ScrubbingOptions::MaxAllowedScrubSpeed()) { mLogMaxScrubSpeed = newLogMaxScrubSpeed; - mMaxScrubSpeed = newSpeed; + mOptions.maxSpeed = newSpeed; if (!mSmoothScrollingScrub) // Show the speed for one second mScrubSpeedDisplayCountdown = kOneSecondCountdown + 1; diff --git a/src/tracks/ui/Scrubbing.h b/src/tracks/ui/Scrubbing.h index cd2e09926..8dcc9ec9c 100644 --- a/src/tracks/ui/Scrubbing.h +++ b/src/tracks/ui/Scrubbing.h @@ -29,6 +29,22 @@ struct ScrubbingOptions { bool enqueueBySpeed {}; + double delay {}; + + // A limiting value for the speed of a scrub interval: + double maxSpeed { 1.0 }; + + // When maximum speed scrubbing skips to follow the mouse, + // this is the minimum amount of playback allowed at the maximum speed: + double minStutter {}; + + // Scrubbing needs the time of start of the mouse movement that began + // the scrub: + wxLongLong startClockTimeMillis { -1 }; + + // usually from TrackList::GetEndTime() + double maxTime {}; + static double MaxAllowedScrubSpeed() { return 32.0; } // Is five octaves enough for your amusement? static double MinAllowedScrubSpeed() @@ -75,7 +91,7 @@ public: bool ShouldDrawScrubSpeed(); double FindScrubSpeed(bool seeking, double time) const; - double GetMaxScrubSpeed() const { return mMaxScrubSpeed; } + double GetMaxScrubSpeed() const { return mOptions.maxSpeed; } void HandleScrollWheel(int steps); @@ -123,12 +139,10 @@ private: private: int mScrubToken; - wxLongLong mScrubStartClockTimeMillis; bool mPaused; int mScrubSpeedDisplayCountdown; wxCoord mScrubStartPosition; wxCoord mLastScrubPosition {}; - double mMaxScrubSpeed; bool mScrubSeekPress; bool mSmoothScrollingScrub; bool mAlwaysSeeking {};