From 3c88f8ce4dd114ba5c979aa9da0f537ac24756dc Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 24 May 2015 17:31:00 -0400 Subject: [PATCH] Bugs 925, 926, 928 fixed again, better, for double click and shift too --- src/AudioIO.cpp | 78 ++++++++++++++++++++++++++++++++++++---------- src/AudioIO.h | 4 +++ src/TrackPanel.cpp | 7 ++--- 3 files changed, 67 insertions(+), 22 deletions(-) diff --git a/src/AudioIO.cpp b/src/AudioIO.cpp index c3d472603..5f62cb6af 100644 --- a/src/AudioIO.cpp +++ b/src/AudioIO.cpp @@ -370,10 +370,13 @@ So a small, fixed queue size should be adequate. struct AudioIO::ScrubQueue { ScrubQueue(double t0, double t1, wxLongLong startClockMillis, + double minTime, double maxTime, double rate, double maxSpeed, double minStutter) : mTrailingIdx(0) , mMiddleIdx(1) , mLeadingIdx(2) + , mMinSample(minTime * rate) + , mMaxSample(maxTime * rate) , mRate(rate) , mMinStutter(lrint(std::max(0.0, minStutter) * mRate)) , mLastScrubTimeMillis(startClockMillis) @@ -505,7 +508,8 @@ private: {} bool Init(long s0, long s1, long duration, Entry *previous, - double maxSpeed, long minStutter, bool adjustStart) + double maxSpeed, long minStutter, long minSample, long maxSample, + bool adjustStart) { if (duration <= 0) return false; @@ -539,39 +543,76 @@ private: maxed = true; } - if (maxed) - { - // When playback follows a fast mouse movement by "stuttering" - // at maximum playback, don't make stutters too short to be useful. - if (adjustStart && duration < minStutter) - return false; - } - else if (speed < GetMinScrubSpeed()) + if (speed < GetMinScrubSpeed()) // Mixers were set up to go only so slowly, not slower. // This will put a request for some silence in the work queue. speed = 0.0; - // No more rejections. - // Before we change s1: mGoal = maxed ? s1 : -1; // May change s1 or s0 to match speed change: - long diff = lrint(speed * duration); if (adjustStart) { - if (s0 < s1) - s0 = s1 - diff; - else - s0 = s1 + diff; + bool silent = false; + + // Adjust s1 first, and duration, if s1 is out of bounds. + // (Assume s0 is in bounds, because it is the last scrub's s1 which was checked.) + if (s1 != s0) + { + const long newS1 = std::max(minSample, std::min(maxSample, s1)); + if (s1 != newS1) + { + long newDuration = long(duration * double(newS1 - s0) / (s1 - s0)); + s1 = newS1; + if (newDuration == 0) + // Enqueue a silent scrub with s0 == s1 + silent = true; + else + // Shorten + duration = newDuration; + } + } + + if (!silent) + { + // When playback follows a fast mouse movement by "stuttering" + // at maximum playback, don't make stutters too short to be useful. + if (maxed && duration < minStutter) + return false; + + const long diff = lrint(speed * duration); + if (s0 < s1) + s0 = s1 - diff; + else + s0 = s1 + diff; + } } else { // adjust end + const long diff = lrint(speed * duration); if (s0 < s1) s1 = s0 + diff; else s1 = s0 - diff; + + // Adjust s1 again, and duration, if s1 is out of bounds. (Assume s0 is in bounds.) + if (s1 != s0) + { + const long newS1 = std::max(minSample, std::min(maxSample, s1)); + if (s1 != newS1) + { + long newDuration = long(duration * double(newS1 - s0) / (s1 - s0)); + s1 = newS1; + if (newDuration == 0) + // Enqueue a silent scrub with s0 == s1 + ; + else + // Shorten + duration = newDuration; + } + } } mS0 = s0; @@ -614,7 +655,8 @@ private: ? s0 + lrint(duration * end) // end is a speed : lrint(end * mRate); // end is a time const bool success = - entry.Init(s0, s1, duration, previous, maxSpeed, mMinStutter, maySkip); + entry.Init(s0, s1, duration, previous, maxSpeed, mMinStutter, + mMinSample, mMaxSample, maySkip); if (success) mLastScrubTimeMillis = clockTime; return success; @@ -625,6 +667,7 @@ private: unsigned mTrailingIdx; unsigned mMiddleIdx; unsigned mLeadingIdx; + const long mMinSample, mMaxSample; const double mRate; const long mMinStutter; wxLongLong mLastScrubTimeMillis; @@ -1787,6 +1830,7 @@ int AudioIO::StartStream(WaveTrackArray playbackTracks, { mScrubQueue = new ScrubQueue(mT0, mT1, options.scrubStartClockTimeMillis, + 0.0, options.maxScrubTime, sampleRate, maxScrubSpeed, minScrubStutter); mScrubDuration = 0; mSilentScrub = false; diff --git a/src/AudioIO.h b/src/AudioIO.h index 5f27aecc6..b08d9dc25 100644 --- a/src/AudioIO.h +++ b/src/AudioIO.h @@ -90,6 +90,7 @@ struct AudioIOStartStreamOptions , maxScrubSpeed(1.0) , minScrubStutter(0.0) , scrubStartClockTimeMillis(-1) + , maxScrubTime(0.0) #endif {} @@ -117,6 +118,9 @@ struct AudioIOStartStreamOptions // Scrubbing needs the time of start of the mouse movement that began // the scrub: wxLongLong scrubStartClockTimeMillis; + + // usually from TrackList::GetEndTime() + double maxScrubTime; #endif }; diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 5aac0f745..ea2dd3234 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -2381,6 +2381,7 @@ bool TrackPanel::MaybeStartScrubbing(wxMouseEvent &event) // but it may be varied during the scrub. mMaxScrubSpeed = options.maxScrubSpeed = p->GetTranscriptionToolBar()->GetPlaySpeed(); + options.maxScrubTime = mTracks->GetEndTime(); const bool cutPreview = false; const bool backwards = time1 < time0; #ifdef EXPERIMENTAL_SCRUBBING_SCROLL_WHEEL @@ -2412,11 +2413,7 @@ bool TrackPanel::MaybeStartScrubbing(wxMouseEvent &event) bool TrackPanel::ContinueScrubbing(wxCoord position, bool maySkip) { wxCoord leadPosition = position; - double newEnd = - std::max(0.0, - std::min(PositionToTime(leadPosition, GetLeftOffset()), - mTracks->GetEndTime() - )); + double newEnd = PositionToTime(leadPosition, GetLeftOffset()); if (maySkip) // Cause OnTimer() to suppress the speed display