Skip to content

Blend previous-track skip like the forward skip - #131

Merged
sanylax0 merged 1 commit into
mainfrom
claude/smooth-previous-skip-ihiqy8
Jul 27, 2026
Merged

sanylax0 merged 1 commit into
mainfrom
claude/smooth-previous-skip-ihiqy8

Conversation

@sanylax2

Copy link
Copy Markdown
Collaborator

What & why

previous() hard-cut into the earlier track via startCurrentFresh(), while next() runs a smooth 5-second crossfade. This routes the previous-track step through the same beginTransition(isUserInitiatedSkip:) path, so stepping back now blends — beatmatched, harmonic-mixed, vocal-aware — instead of cutting, matching the forward skip.

How

In Player.previous(), when stepping to a distinct earlier track, compute the back-target and hand it to beginTransition(..., isUserInitiatedSkip: true) — the exact machinery next() uses — after materializing the outgoing deck so there's audio to fade.

Existing invariants are all preserved:

  • Restart-current (>3s in) stays a hard restart — a crossfade of a track into itself would echo.
  • History walk still consumes exactly one entry.
  • Skip refund still happens exactly once: a user skip blend doesn't refund again on completion (finishTransition skips the refund for user skips), so the single refund holds whether we blend or hard-cut.

Hard-cut fallbacks (mirroring next()), so nothing regresses in edge cases:

  • CoreAudio can't start,
  • under a second of outgoing audio remains (too short to read as a blend),
  • no distinct earlier track (single-track queue, or history points at the current track) — a self-blend would just echo.

A new guard makes a second press during an in-flight skip a no-op, mirroring next(); acting on it would cancel the blend, walk history a second time (dropping the entry the first press consumed), and double-refund the skip.

Behavior note for device testing

To match next()'s "one skip per blend" semantics, a rapid double-press of previous now advances one track per completed 5s blend (the second press is ignored until the first lands) rather than jumping back several at once. If you'd prefer rapid multi-rewind, that's a easy follow-up — flag it after device testing.

Testing

  • Added PlayerPreviousSkipTests.testPreviousDuringUserSkipIsIgnored pinning that a press during an in-flight skip neither walks history twice, nor double-refunds, nor builds the audio stack.
  • The Playback module imports AVFoundation, so it (and this test) build/run on macOS + simulator only — not the Linux ContinuityCore CI. Device/blend verification is the owner's on a real iPhone.

🤖 Generated with Claude Code

https://claude.ai/code/session_016C9cyymf6W5k6SaGiYvdXN


Generated by Claude Code

previous() hard-cut into the earlier track via startCurrentFresh(), while
next() runs a smooth 5s crossfade. Route the previous-track step through the
same beginTransition(isUserInitiatedSkip:) path so stepping back blends
(beatmatched/harmonic/vocal-aware) instead of cutting.

Preserves every existing invariant: the >3s restart-current branch stays a
hard restart, the history walk still consumes exactly one entry, and the
forward-skip refund still happens exactly once (a user skip blend doesn't
refund again on completion). Falls back to a hard cut when audio can't start,
when under a second of outgoing audio remains, or when there is no distinct
earlier track (single-track queue / history points at the current track) —
a self-blend would just echo. Adds a guard so a second press during an
in-flight skip is a no-op, mirroring next(), with a test pinning that it
neither walks history twice nor double-refunds nor builds the audio stack.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016C9cyymf6W5k6SaGiYvdXN
@sanylax0
sanylax0 marked this pull request as ready for review July 27, 2026 05:13
@sanylax0
sanylax0 merged commit 008a358 into main Jul 27, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants