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
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* What the editor loads ahead of the first draw: every stored file a project's assets name, so an
|
||||
* animation or an animated tile does not blink out the first time it reaches a frame of its own.
|
||||
* animation or an animated tile does not blink out the first time it reaches a frame of its own,
|
||||
* and the first play of a sound is not late.
|
||||
*/
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import type { Asset } from '../../src/core/model/Asset';
|
||||
@@ -12,6 +13,7 @@ const PNG_B = `${'b'.repeat(64)}.webp`;
|
||||
const FONT = `${'c'.repeat(64)}.woff2`;
|
||||
const CEL_A = `${'d'.repeat(64)}.cel`;
|
||||
const CEL_B = `${'e'.repeat(64)}.cel`;
|
||||
const SOUND = `${'f'.repeat(64)}.ogg`;
|
||||
|
||||
function projectWith(assets: unknown[]) {
|
||||
const project = createEmptyProject('p', 'P');
|
||||
@@ -20,7 +22,7 @@ function projectWith(assets: unknown[]) {
|
||||
}
|
||||
|
||||
describe('the files a project names', () => {
|
||||
it('lists every texture, font and cel, drawn somewhere or not', () => {
|
||||
it('lists every texture, font, cel and sound, used somewhere or not', () => {
|
||||
const project = projectWith([
|
||||
{
|
||||
id: 't1',
|
||||
@@ -57,15 +59,22 @@ describe('the files a project names', () => {
|
||||
{ id: 'f3', cels: { l: CEL_A } },
|
||||
],
|
||||
},
|
||||
{ id: 's', type: 'sound', name: 'Blip', props: {}, file: SOUND },
|
||||
]);
|
||||
expect(projectFiles(project)).toEqual({ textures: [PNG_A, PNG_B], fonts: [FONT], cels: [CEL_A, CEL_B] });
|
||||
expect(projectFiles(project)).toEqual({
|
||||
textures: [PNG_A, PNG_B],
|
||||
fonts: [FONT],
|
||||
cels: [CEL_A, CEL_B],
|
||||
sounds: [SOUND],
|
||||
});
|
||||
});
|
||||
|
||||
it('leaves out a name that is no stored file', () => {
|
||||
const project = projectWith([
|
||||
{ id: 't', type: 'texture', name: 'Failed', props: {}, file: '', width: 0, height: 0, frames: [] },
|
||||
{ id: 'f', type: 'font', name: 'Failed', props: {}, file: 'x.woff2' },
|
||||
{ id: 's', type: 'sound', name: 'Failed', props: {}, file: '' },
|
||||
]);
|
||||
expect(projectFiles(project)).toEqual({ textures: [], fonts: [], cels: [] });
|
||||
expect(projectFiles(project)).toEqual({ textures: [], fonts: [], cels: [], sounds: [] });
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user