fix(runtime): restore clip gain after the prewarm probe on the no-graph path - #22
Merged
Merged
Conversation
…ip audio The decoder pre-warm drops the clip's gain to 0, plays briefly to fill the decode buffer, then restores the level it snapshotted. The snapshot read `graph?.outputGainNode.gain.value ?? 0`, but clips whose source is cross-origin deliberately have no Web Audio graph — `isWebAudioSafeMediaSource` keeps them on `element.volume`, because MediaElementAudioSourceNode outputs silence for a non-CORS source. For those clips the optional chain yielded undefined and the `?? 0` default made the restore write `volume = 0`. Nothing repairs that: the volume effect's deps are `[finalVolume, muted]` and neither changes when playback starts, so the clip plays picture with no sound until a remount or a gain change. Snapshot from whichever stage the clip actually uses instead. Standalone FreeCut never saw this because blob:/OPFS sources are same-origin and always graph-routed. Covers both the .then and .catch restores, and the ordered volume writes so a restore cannot coincidentally land on the pre-mute value.
…-warm Both the .then and the .catch gated the gain restore behind !isPlaying, not just the pause. If transport starts while the pre-warm's play() promise is still pending, neither branch runs and the clip keeps playing at gain 0 — the same picture-with-no-sound symptom, and unlike the cross-origin default this one reaches the Web Audio graph path too, so standalone FreeCut is affected as well. Nothing repairs it: the volume effect's deps are [finalVolume, muted] and pressing play changes neither, so a clip without fades stays silent for its full duration. Only the pause is playback state's business. Restore in `finally` and gate just the pause, matching the sibling video pre-warm in video-content.tsx. Restoring while transport runs is correct: previousGain is whatever the volume effect last committed, so a muted or zero-volume clip restores a correct 0 and stays silent, and a clip inside a fade is overwritten by the next effect run within a frame.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
pitch-corrected-audio.tsxprewarms an audio element by briefly playing it muted, then restoring the prior gain. The restore read:On the only path that has no graph,
?? 0restores zero — permanent silence for that clip.Two defects, not one:
?? 0default. Fixed by branching ongraphand falling back tocurrentAudio.volume, the real prior value.!isPlaying. The restore only ran on one branch, so it could be skipped entirely. Now unconditional via.finally(restoreGain).Why FreeCut's own dev environment never saw it
The buggy branch is unreachable locally. FreeCut dev loads media as
blob:/OPFS, which always constructs a graph. CodePress serves media from S3 presigned URLs, which never do. The bug is only reachable from a host embedding, which is why it survived in-repo testing.Verification
Regression test added at
pitch-corrected-audio.test.tsxcovering both the no-graph restore value and the unconditional-restore path.Acceptance
Ships in 0.3.7. Acceptance test is CodePress PR #6092, which goes green once the CodePress pin moves to 0.3.7.