Load the sounds of a project ahead of their first play
A sound was fetched and decoded on its first Play sound. That play started late, its beginning was not heard, and a graph that tuned the voice in the meantime had moved on by the time it started. Images and fonts were already loaded when a project opens. Sounds now are too. - projectFiles lists the sounds of a project, and preloadProjectFiles hands them to the new soundLibrary.preload. That covers the editor and the published game. - Preloading opens no audio device. It decodes with an OfflineAudioContext at 48 kHz. The real AudioContext is still made on the first play, and a source resamples where the device runs at another rate. - A run started right after opening a project can still find a sound loading. It then starts late as before. Tests: - sound-library: a preload makes only the offline context, and a play after it starts at once, opening the device only then. - sound-library + project-files: 18 tests, green. - e2e 34 on melektaus-atx: ALL PASSED, 30 checks. - Counter-check: decoding with the real AudioContext again fails the new test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ded0022903
commit
ed2b58b3c0
5 files changed
+72
-8
No files matched your search
@@ -194,6 +194,39 @@ describe('the sound library', () => {
|
||||
expect(sources.filter((s) => s.started)).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('loads ahead of the first play without opening the device, so that play starts at once', async () => {
|
||||
const opened: string[] = [];
|
||||
vi.stubGlobal(
|
||||
'AudioContext',
|
||||
class {
|
||||
constructor() {
|
||||
opened.push('device');
|
||||
return fakeContext();
|
||||
}
|
||||
},
|
||||
);
|
||||
vi.stubGlobal(
|
||||
'OfflineAudioContext',
|
||||
class {
|
||||
constructor() {
|
||||
opened.push('offline');
|
||||
return fakeContext();
|
||||
}
|
||||
},
|
||||
);
|
||||
const library = new SoundLibrary();
|
||||
library.preload([FILE, OTHER, '']);
|
||||
await settle();
|
||||
await arrive();
|
||||
expect(opened).toEqual(['offline']);
|
||||
expect(library.stats()).toMatchObject({ decoded: 2, started: 0 });
|
||||
// No await: the voice runs in the frame that asked for it, not once the bytes are in.
|
||||
const voice = library.play(FILE, 1, false);
|
||||
expect(library.stats()).toMatchObject({ started: 1, playing: 1 });
|
||||
expect(library.tune(voice, {})).toBe(true);
|
||||
expect(opened).toEqual(['offline', 'device']);
|
||||
});
|
||||
|
||||
it('remembers what it last started, so a muted check can see it at all', async () => {
|
||||
const library = new SoundLibrary();
|
||||
library.play(FILE, 0.25, true);
|
||||
|
||||
Reference in new issue
Block a user