Skip to content

fix: seek through the host funnel so far sections work off the <audio> element - #10

Merged
byrongamatos merged 2 commits into
mainfrom
fix/canonical-seek-funnel
Jul 15, 2026
Merged

fix: seek through the host funnel so far sections work off the <audio> element#10
byrongamatos merged 2 commits into
mainfrom
fix/canonical-seek-funnel

Conversation

@byrongamatos

@byrongamatos byrongamatos commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Symptom (tester)

The section-map bar at the top of the song only seeks to sections close to the playhead; clicking a distant section doesn't move playback.

Root cause

The plugin seeked by writing document.getElementById('audio').currentTime directly. That worked when the <audio> element was playback. It no longer is: a feedpak full-mix now plays through JUCE native output, whose seek is jucePlayer.seek() — reachable only via the host's canonical _audioSeek funnel (window.feedBack.seek). Writing the raw element's currentTime never reaches JUCE, so a section click moved the muted clock element but not the actual audio. Far jumps were plainly wrong; near ones looked close enough to pass. (The tester's hunch — "audio streaming changes, stems don't all load at once" — was directionally right: playback moved off the raw <audio> element.)

Fix

Route every reposition (click + wheel) through window.feedBack.seek(time, reason):

  • moves whichever backend is actually playing — JUCE native, or the streaming stems worklet (which reseeks on the song:seek event the funnel emits);
  • keeps the highway clock in sync (_audioSeek calls highway.setTime);
  • lets notedetect suppress detection across the seek transient (it listens for song:seek).

Wheel nudges read the current position from the host clock (highway.getTime()) rather than the possibly-stale <audio> element. The old raw-element path (pause/seek/resume) stays only as a fallback for a host that predates the seek API.

Tests

Click + wheel now assert the funnel is called with the correct time and the raw element is left untouched; a new test pins _smNow reading the host clock; the legacy fallback (raw currentTime + pause/resume) is still covered. 11/11 green.

Note

Most impactful for the JUCE-native path (desktop feedpak full-mix — the common gig case). In stems mode both old and new code reach the stems currentTime shim, so behaviour there is unchanged. Wants an on-device confirm.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Enhanced section map seeking to stay synchronized with host playback timing.
    • Improved click and wheel seeking with fine-control support and automatic clamping to valid track bounds.
  • Bug Fixes
    • More reliable seeking behavior when host seek controls are unavailable, using continued audio-based fallback.
  • Chores
    • Bumped the plugin version from 1.0.0 to 1.1.0.
  • Tests
    • Updated coverage to validate host-driven seeking (including reasons) and fallback behavior.

…> element

The section map jumped only to sections near the playhead. It seeked by
poking `document.getElementById('audio').currentTime` directly, which used
to be the single source of truth for playback. It no longer is: a feedpak
full-mix plays through JUCE native output, whose seek is `jucePlayer.seek()`
(reached only via the host's canonical `_audioSeek` funnel) — writing the raw
element's currentTime never moves it. So a section click updated the muted
clock element but not the actual playback; far jumps were obviously wrong
while near ones looked close enough to pass.

Route every reposition (click + wheel) through `window.feedBack.seek()`
instead. It moves whichever backend is playing — JUCE native, or the
streaming stems worklet, which only reseeks on the `song:seek` event the
funnel emits — keeps the highway clock in sync, and lets notedetect suppress
detection across the seek transient. Read the current position from the host
clock (`highway.getTime()`) for the wheel nudge. The old raw-element path
stays only as a fallback for a host that predates the seek API.

Tests: click + wheel now assert the funnel is called with the right time
(raw element untouched); fallback path still covered; wheel reads the host
clock. 11/11 green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5383aba0-1053-45ec-82e5-b46079daa93d

📥 Commits

Reviewing files that changed from the base of the PR and between 74c8b44 and 3806463.

📒 Files selected for processing (2)
  • screen.js
  • tests/screen.test.js

📝 Walkthrough

Walkthrough

Section map clicks and wheel seeks now use the host playback clock and a centralized seek funnel, with audio-element fallback behavior. Tests cover host routing, clamping, reason values, and fallback seeking. The plugin manifest version increases to 1.1.0.

Changes

Section map seeking

Layer / File(s) Summary
Canonical seek routing
screen.js
_smNow() prefers the host playback clock, while _smSeek() routes click and wheel seeks through the host API or legacy audio fallback.
Seek behavior validation and release metadata
tests/screen.test.js, plugin.json
Tests verify host-funnel calls, host-clock timing, clamping, reason values, and audio fallback behavior; the manifest version changes to 1.1.0.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SectionMap
  participant screen_js
  participant HostSeekAPI
  participant AudioElement
  SectionMap->>screen_js: click or wheel target time
  screen_js->>HostSeekAPI: seek(time, reason) when available
  HostSeekAPI-->>screen_js: host-managed seek
  screen_js->>AudioElement: pause, seek, and resume when host API is unavailable
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clearly related to the main change, describing host-funnel seeking for section-map playback.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/canonical-seek-funnel

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/screen.test.js (1)

119-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test title claims duration clamping but only asserts the lower bound.

The test name mentions clamping to [0, duration], but the body only drives the backward/negative case. Consider adding a forward-direction case asserting the seek clamps at _smDuration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/screen.test.js` around lines 119 - 132, Extend the _smOnWheel test to
cover forward scrolling beyond the configured duration, asserting the seek
target clamps to _smDuration (100) with reason sectionmap-wheel. Keep the
existing backward case and prevented-default assertion unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@screen.js`:
- Around line 74-88: Update _smSeek to clamp the seek time to the full valid
range [0, _smDuration], preserving its existing lower-bound handling. Use the
centrally clamped value for both host.seek and the legacy audio fallback so
_smOnClick and _smOnWheel cannot seek beyond the duration.

---

Nitpick comments:
In `@tests/screen.test.js`:
- Around line 119-132: Extend the _smOnWheel test to cover forward scrolling
beyond the configured duration, asserting the seek target clamps to _smDuration
(100) with reason sectionmap-wheel. Keep the existing backward case and
prevented-default assertion unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4538469d-370e-46a7-b430-3ffa655bc372

📥 Commits

Reviewing files that changed from the base of the PR and between f62fe2e and 74c8b44.

📒 Files selected for processing (3)
  • plugin.json
  • screen.js
  • tests/screen.test.js

Comment thread screen.js
CodeRabbit: _smOnClick passed a raw pct*duration through, and _smSeek only
clamped the lower bound — a pct just over 1 at the bar's right edge could
seek past the end. Clamp to [0, _smDuration] centrally so click and wheel
are consistent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@byrongamatos
byrongamatos merged commit 33953e9 into main Jul 15, 2026
2 of 3 checks passed
@byrongamatos
byrongamatos deleted the fix/canonical-seek-funnel branch July 15, 2026 21:57
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.

1 participant