Decode a clip from a file of its own, not its whole sound (#349)
A clip was cut from its sound's file, so a game decoded the whole file for it and held it for as long as the page was open. A long recording played through a few short clips cost the recording. Every clip now has a copy of its cut as Opus, with Stream on or off, and a game decodes that instead. - StreamKeeper makes the copy of each clip whether its sound streams or not. Stream only decides whether a sound gets a copy of its own. - clipCopyTable says which cut decodes from which copy. The sound library loads the copy for a clip unless the whole file is decoded already. Then the clip is cut from that as before. - projectFiles decodes the whole file ahead only where something may play the sound itself: no clips, a clip without a fitting copy, or the sound's id anywhere in an asset that can name one. That last test walks the data, not the fields, so no place is missed. - A copy that cannot be had falls back to the whole file. A library that bakes keeps to the whole files, as the bake's fingerprint does. Tests: - Gate: CHECK EXIT 0, 280 files, 4319 tests (7 new: streams +4, sound-library +3). - e2e 34: ALL PASSED, 108 checks (2 new). With Stream off a fresh library decodes the ten-second reversed clip's copy and not the five-minute file. It is the cut made from the original to within 0.0091 a sample and 0.013 dB in any 20 ms. Once a node plays the sound itself, the whole file is decoded ahead again. - e2e 65: all passed with this change. - Counter-checks red as they should be: the library ignoring copies, the whole file always decoded ahead, clip copies only with Stream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2764919bb8
commit
82e96e680f
10 files changed
+332
-42
No files matched your search
@@ -2763,6 +2763,39 @@ export async function sound(t) {
|
||||
JSON.stringify(exact),
|
||||
);
|
||||
|
||||
// 34h-5. With Stream off the clip keeps its copy, and a game only playing the sound through it
|
||||
// decodes the copy, not the five minutes. The counter-proof plays the sound itself: then the
|
||||
// whole file is decoded ahead again.
|
||||
await mutate(`__gm.state.project.assets.find((a) => a.id === 'sn-long').props.stream = false;`);
|
||||
await evaluate('__gm.streams.idle()');
|
||||
const keptCopies = await json("__gm.streams.copies('sn-long')");
|
||||
const freshly = async () =>
|
||||
JSON.parse(await evaluate(`__gm.streams.fresh(${JSON.stringify(clipName)}).then(JSON.stringify)`));
|
||||
const fresh = await freshly();
|
||||
check(
|
||||
'with Stream off the clip keeps a copy of its cut, and a game decodes that rather than the whole file, as the cut sounds',
|
||||
keptCopies?.sound === null &&
|
||||
keptCopies.clips[0]?.stream?.from === clipName &&
|
||||
fresh?.ahead.includes(clipName) &&
|
||||
!fresh.ahead.includes(long.file) &&
|
||||
fresh.whole === false &&
|
||||
fresh.decoded === fresh.ahead.length &&
|
||||
fresh.played?.length === 10 * 48000 &&
|
||||
fresh.played.wanted === fresh.played.length &&
|
||||
fresh.played.level < 0.5 &&
|
||||
fresh.played.worst < 0.1,
|
||||
JSON.stringify({ keptCopies, fresh }),
|
||||
);
|
||||
await startWith(playsLong);
|
||||
const freshWhole = await freshly();
|
||||
check(
|
||||
'once the game plays the sound itself, its whole file is decoded ahead again',
|
||||
freshWhole?.ahead.includes(long.file) &&
|
||||
!freshWhole.ahead.includes(clipName) &&
|
||||
freshWhole.whole === true,
|
||||
JSON.stringify({ ahead: freshWhole?.ahead, whole: freshWhole?.whole }),
|
||||
);
|
||||
|
||||
await mutate(`
|
||||
const p = __gm.state.project;
|
||||
p.assets = p.assets.filter((a) => !['sn-long', 'sn-bus', ${JSON.stringify(longSong.id)}].includes(a.id));
|
||||
|
||||
Reference in new issue
Block a user