game-maker / suite (push) Successful in 12m1s
Sounds follow the road fonts already paved: the file goes to the server content-addressed under its sha256, the project keeps a named asset that points at it, and nothing is ever re-encoded. The format is read from the file's own signature, not from what the browser claims - the same .m4a arrives as audio/mp4, audio/x-m4a or as nothing at all. Playing is two nodes. "Play sound" takes the asset and may raise or lower its volume; every call is its own voice, so two jumps in a row are two jumps heard. Its loop input is a choice of three - from the asset, on, off - because a checkbox has to spend one of its two positions on "not set" and would lose a case: an asset that loops could then never be played once. Below the graph core stays browser-free: NodeContext hands out an asset id, BehaviorSystem resolves it against the project and folds the asset's own volume and loop into the call, and only viewport/SoundLibrary knows about Web Audio. A run without a sink plays nothing instead of throwing. The CI browser is muted, so the ear is no witness: the debug hook counts started and stopped voices, and step 34 reads that counter.
20 lines
826 B
TypeScript
20 lines
826 B
TypeScript
/**
|
||
* What the runtime needs of the outside world to make a noise – the counterpart of `Input` on the
|
||
* way out. The browser side of it is `viewport/SoundLibrary`; a test (and a run started before
|
||
* anything wired one in) gets `SILENT_AUDIO` and plays to nobody.
|
||
*
|
||
* Files, not asset ids: resolving the id is the `BehaviorSystem`'s job, because it is the one
|
||
* holding the project. Everything below this line only knows bytes and voices.
|
||
*/
|
||
export interface AudioSink {
|
||
/** Starts one voice. `volume` is final (0–1) and every call overlaps whatever is already playing. */
|
||
play(file: string, volume: number, loop: boolean): void;
|
||
/** Silences every voice of that file; `''` silences all of them. */
|
||
stop(file: string): void;
|
||
}
|
||
|
||
export const SILENT_AUDIO: AudioSink = {
|
||
play: () => {},
|
||
stop: () => {},
|
||
};
|