The preview engines (canvas-compositor.ts / html-video.ts) pick the audible clip per-frame via primaryActiveClip(), which falls through to lower tracks when track 0 has a gap at the current time. The reference ffmpeg backend (backends/ts/src/render.ts) builds its audio chain only from track 0's own clip windows (topTrackIndex = 0, atrim per clip).
Result: a window where track 0 is empty but track 1 has a clip plays track 1's audio in preview but exports silent. The backend comment ("audio is the one that plays, matching the preview engines") only holds when track 0 has no gaps.
Repro: 2 video tracks; track 0 clip at 0–5s and 8–10s, track 1 clip at 0–10s. Preview plays track 1 audio during 5–8s; exported mp4 is silent there.
Suggested fix: make the export audio chain follow the same top-down fall-through as primaryActiveClip() (per gap segment), or document single-track audio as the contract and mute lower tracks in preview.
Found while integrating 0.8.5 into iplex (ipmotionmc/iplex#1810) — the vendored lambda mirrors the reference backend, so it inherits the divergence.
The preview engines (
canvas-compositor.ts/html-video.ts) pick the audible clip per-frame viaprimaryActiveClip(), which falls through to lower tracks when track 0 has a gap at the current time. The reference ffmpeg backend (backends/ts/src/render.ts) builds its audio chain only from track 0's own clip windows (topTrackIndex = 0, atrim per clip).Result: a window where track 0 is empty but track 1 has a clip plays track 1's audio in preview but exports silent. The backend comment ("audio is the one that plays, matching the preview engines") only holds when track 0 has no gaps.
Repro: 2 video tracks; track 0 clip at 0–5s and 8–10s, track 1 clip at 0–10s. Preview plays track 1 audio during 5–8s; exported mp4 is silent there.
Suggested fix: make the export audio chain follow the same top-down fall-through as
primaryActiveClip()(per gap segment), or document single-track audio as the contract and mute lower tracks in preview.Found while integrating 0.8.5 into iplex (ipmotionmc/iplex#1810) — the vendored lambda mirrors the reference backend, so it inherits the divergence.