Skip to content

fix(core,player,studio): bound trimmed audio playback to the clip window#1430

Open
vanceingalls wants to merge 2 commits into
mainfrom
fix/parent-proxy-trim
Open

fix(core,player,studio): bound trimmed audio playback to the clip window#1430
vanceingalls wants to merge 2 commits into
mainfrom
fix/parent-proxy-trim

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Problem

Trimmed audio clips kept playing past the clip edge — the audio ran on to the source file's natural end even though the timeline clip ended earlier. This happened across every audio path, so fixing one didn't fix the symptom in the Studio.

Root cause

Three independent paths each ignored the clip's authored window (data-duration / media-start):

  1. Parent audio proxy (<hyperframes-player> when iframe autoplay is blocked) — the proxy played to the source end and never re-read live trims.
  2. Runtime element gating (core/runtime) — the duration resolver computed clip length only from source-file length capped by host-composition duration, never consulting the element's own data-duration.
  3. WebAudio transport — the audible path in the Studio (the iframe <audio> is muted while WebAudio plays the decoded buffer). schedulePlayback called AudioBufferSourceNode.start(when, offset) with no duration, so the buffer played from the trim offset to the file's natural end regardless of the clip length.

Confirmed live: audioOwner: "runtime", the iframe <audio> was muted: true + paused: true at its trimmed edge (element gating worked), but WebAudio kept the buffer running — so the trim never bound the audible output.

Fix

  • WebAudio (webAudioTransport.ts + init.ts): schedulePlayback now takes the clip's data-duration and passes a bounded duration to start(when, offset, duration), so the buffer stops at the trimmed edge. Past-end schedules are skipped.
  • Runtime element gating (init.ts): the duration resolver caps each clip by min(sourceLength, hostWindow, ownDataDuration), so a trimmed <audio>/<video> element pauses at its edge.
  • Parent proxy (parent-media.ts): the proxy re-reads its source clip's live data-start/data-duration each tick and pauses outside the clip window, resuming on re-entry.

Studio trim UX (same root area)

  • Resize (useTimelineEditing.ts): a start-edge drag now live-patches the media-start/playback-start offset to the iframe, so dragging the left edge trims into the source instead of only repositioning the clip.
  • Waveform (AudioWaveform.tsx + useRenderClipContent.ts): the rendered peaks are windowed to the trimmed slice [mediaStart, mediaStart + duration·rate], so the waveform tracks the clip edges instead of squeezing the whole file into the clip width.

Tests

  • webAudioTransport.test.ts: 5 new cases for the clip-duration bound (in-progress, future, past-end skip, rate scaling, unbounded-when-omitted).
  • parent-media.test.ts: pause past trimmed end; re-read live data-duration.

Verification

In Studio: trim the music clip, play past the trimmed edge → audio now goes silent at the edge (previously ran to the source end). Untrimmed playback unchanged.

🤖 Generated with Claude Code

When iframe autoplay is blocked, audible playback is promoted to a parent-frame
audio proxy. The proxy read the clip's data-start/data-duration once at adopt
time and mirrorTime() only skipped (never paused) the element outside that
window — so a trimmed/moved music clip kept playing the full source past its
on-timeline end, even though the iframe element was correctly paused.

Fix: the proxy keeps a reference to its source iframe element and re-reads
data-start/data-duration each mirror tick (live trims/moves apply), pauses the
proxy when the playhead leaves [start, start+duration), and resumes it when the
playhead re-enters during parent-owned playback.

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

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>

Copy link
Copy Markdown
Collaborator Author

Trimmed audio played to the source file's natural end instead of
stopping at the clip edge, on every audio path:

- WebAudio (the audible path in Studio): schedulePlayback now passes
  the clip's data-duration as the third start() arg, so the decoded
  buffer stops at the trimmed edge instead of running to the file end.
- Runtime element gating: the duration resolver caps each clip by its
  own data-duration (min of source length, host window, authored
  duration), so a trimmed <audio>/<video> element pauses at its edge.

Studio trim UX:

- Resize live-patches the media-start/playback-start offset, so a
  start-edge drag trims into the source instead of only repositioning
  the clip.
- AudioWaveform windows the rendered peaks to the trimmed slice so the
  waveform tracks the clip edges.

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

Co-authored-by: Miguel Ángel <miguel07alm@protonmail.com>
@vanceingalls vanceingalls changed the title fix(player): bound the parent audio proxy to its clip window fix(core,player,studio): bound trimmed audio playback to the clip window Jun 14, 2026
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