1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-02 00:29:41 +02:00

Merge: Scroll-seek improvements

This commit is contained in:
Paul Licameli 2015-05-30 14:29:47 -04:00
commit eca5c25ec0
3 changed files with 78 additions and 32 deletions

View File

@ -403,7 +403,7 @@ struct AudioIO::ScrubQueue
}
~ScrubQueue() {}
bool Producer(double startTime, double end, double maxSpeed, bool bySpeed, bool maySkip)
bool Producer(double end, double maxSpeed, bool bySpeed, bool maySkip)
{
// Main thread indicates a scrubbing interval
@ -415,9 +415,8 @@ struct AudioIO::ScrubQueue
{
Entry &previous = mEntries[(mLeadingIdx + Size - 1) % Size];
if (startTime < 0.0)
// Use the previous end as new start.
startTime = previous.mS1 / mRate;
// Use the previous end as new start.
const double startTime = previous.mS1 / mRate;
// Might reject the request because of zero duration,
// or a too-short "stutter"
const bool success =
@ -518,7 +517,7 @@ private:
bool maxed = false;
// May change the requested speed (or reject)
if (speed > maxSpeed)
if (!adjustStart && speed > maxSpeed)
{
// Reduce speed to the maximum selected in the user interface.
speed = maxSpeed;
@ -579,10 +578,10 @@ private:
{
// 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)
if (duration < minStutter)
return false;
const long diff = lrint(speed * duration);
// Limit diff because this is seeking.
const long diff = lrint(std::min(1.0, speed) * duration);
if (s0 < s1)
s0 = s1 - diff;
else
@ -2413,7 +2412,7 @@ bool AudioIO::IsPaused()
bool AudioIO::EnqueueScrubByPosition(double endTime, double maxSpeed, bool maySkip)
{
if (mScrubQueue)
return mScrubQueue->Producer(-1.0, endTime, maxSpeed, false, maySkip);
return mScrubQueue->Producer(endTime, maxSpeed, false, maySkip);
else
return false;
}
@ -2421,7 +2420,7 @@ bool AudioIO::EnqueueScrubByPosition(double endTime, double maxSpeed, bool maySk
bool AudioIO::EnqueueScrubBySignedSpeed(double speed, double maxSpeed, bool maySkip)
{
if (mScrubQueue)
return mScrubQueue->Producer(-1.0, speed, maxSpeed, true, maySkip);
return mScrubQueue->Producer(speed, maxSpeed, true, maySkip);
else
return false;
}

View File

@ -1049,7 +1049,7 @@ void TrackPanel::OnTimer()
{
wxMouseState state(::wxGetMouseState());
wxCoord position = state.GetX();
const bool seek = mScrubSeekPress || state.LeftIsDown();
const bool seek = mScrubSeekPress || PollIsSeeking();
ScreenToClient(&position, NULL);
if (ContinueScrubbing(position, mScrubHasFocus, seek))
mScrubSeekPress = false;
@ -2322,9 +2322,46 @@ double TrackPanel::FindScrubSpeed(double timeAtMouse) const
result *= -1.0;
return result;
}
double TrackPanel::FindSeekSpeed(double timeAtMouse) const
{
// Map a time (which was mapped from a mouse position)
// to a signed skip speed: a multiplier of the stutter duration,
// by which to advance the play position.
// (The stutter will play at unit speed.)
// Times near the midline of the screen map to skip-less play,
// and the extremes to a value proportional to maximum scrub speed.
// If the maximum scrubbing speed defaults to 1.0 when you begin to scroll-scrub,
// the extreme skipping for scroll-seek needs to be larger to be useful.
static const double ARBITRARY_MULTIPLIER = 10.0;
const double extreme = std::max(1.0, mMaxScrubSpeed * ARBITRARY_MULTIPLIER);
// Width of visible track area, in time terms:
const double screen = mViewInfo->screen;
const double halfScreen = screen / 2.0;
const double origin = mViewInfo->h + halfScreen;
// The snapping zone is this fraction of screen, on each side of the
// center line:
const double snap = 0.05;
const double fraction =
std::max(snap, std::min(1.0, fabs(timeAtMouse - origin) / halfScreen));
double result = 1.0 + ((fraction - snap) / (1.0 - snap)) * (extreme - 1.0);
if (timeAtMouse < origin)
result *= -1.0;
return result;
}
#endif
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
bool TrackPanel::PollIsSeeking()
{
return ::wxGetMouseState().LeftIsDown();
}
bool TrackPanel::IsScrubbing()
{
if (mScrubToken <= 0)
@ -2427,27 +2464,27 @@ bool TrackPanel::MaybeStartScrubbing(wxMouseEvent &event)
return false;
}
bool TrackPanel::ContinueScrubbing(wxCoord position, bool hasFocus, bool maySkip)
bool TrackPanel::ContinueScrubbing(wxCoord position, bool hasFocus, bool seek)
{
// When we don't have focus, enqueue silent scrubs until we regain focus.
if (!hasFocus)
return gAudioIO->EnqueueScrubBySignedSpeed(0, mMaxScrubSpeed, maySkip);
return gAudioIO->EnqueueScrubBySignedSpeed(0, mMaxScrubSpeed, false);
const double newEnd = PositionToTime(position, GetLeftOffset());
const double time = PositionToTime(position, GetLeftOffset());
if (maySkip)
if (seek)
// Cause OnTimer() to suppress the speed display
mScrubSpeedDisplayCountdown = 1;
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
if (mSmoothScrollingScrub && !maySkip) {
const double speed = FindScrubSpeed(newEnd);
return gAudioIO->EnqueueScrubBySignedSpeed(speed, mMaxScrubSpeed, maySkip);
if (mSmoothScrollingScrub) {
const double speed = seek ? FindSeekSpeed(time) : FindScrubSpeed(time);
return gAudioIO->EnqueueScrubBySignedSpeed(speed, mMaxScrubSpeed, seek);
}
else
#endif
return gAudioIO->EnqueueScrubByPosition
(newEnd, maySkip ? 1.0 : mMaxScrubSpeed, maySkip);
(time, seek ? 1.0 : mMaxScrubSpeed, seek);
}
bool TrackPanel::StopScrubbing()
@ -7348,19 +7385,20 @@ void TrackPanel::DrawEverythingElse(wxDC * dc,
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
void TrackPanel::DrawScrubSpeed(wxDC &dc)
{
// Halt scrubbing and associated display when some other program
// has focus
if (!mScrubHasFocus)
return;
// Don't draw it during stutter play with shift down
if (!::wxGetMouseState().LeftDown() && (
mScrubSpeedDisplayCountdown > 0
const bool seeking = PollIsSeeking();
if (// Draw for (non-scroll) scrub, sometimes, but never for seek
(!seeking && mScrubSpeedDisplayCountdown > 0)
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
|| mSmoothScrollingScrub
// Draw always for scroll-scrub and for scroll-seek
|| mSmoothScrollingScrub
#endif
)) {
) {
int panelWidth, panelHeight;
GetSize(&panelWidth, &panelHeight);
@ -7373,16 +7411,23 @@ void TrackPanel::DrawScrubSpeed(wxDC &dc)
const double speed =
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
mSmoothScrollingScrub
? FindScrubSpeed(PositionToTime(xx, GetLeftOffset()))
? seeking
? FindSeekSpeed(PositionToTime(xx, GetLeftOffset()))
: FindScrubSpeed(PositionToTime(xx, GetLeftOffset()))
:
#endif
mMaxScrubSpeed;
mMaxScrubSpeed;
const wxChar *format =
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
mSmoothScrollingScrub ? wxT("%+.2f")
mSmoothScrollingScrub
? seeking
? wxT("%+.2fX")
: wxT("%+.2f")
:
#endif
wxT("%.2f");
wxT("%.2f");
wxString text(wxString::Format(format, speed));
static const wxFont labelFont(24, wxSWISS, wxNORMAL, wxNORMAL);

View File

@ -302,9 +302,11 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
#ifdef EXPERIMENTAL_SCRUBBING_SMOOTH_SCROLL
double FindScrubSpeed(double timeAtMouse) const;
double FindSeekSpeed(double timeAtMouse) const;
#endif
#ifdef EXPERIMENTAL_SCRUBBING_BASIC
static bool PollIsSeeking();
bool IsScrubbing();
void MarkScrubStart(
wxCoord xx
@ -313,7 +315,7 @@ class AUDACITY_DLL_API TrackPanel:public wxPanel {
#endif
);
bool MaybeStartScrubbing(wxMouseEvent &event);
bool ContinueScrubbing(wxCoord position, bool hasFocus, bool maySkip);
bool ContinueScrubbing(wxCoord position, bool hasFocus, bool seek);
bool StopScrubbing();
#endif