Sound
Sound effects, loops and music that changes with the game.
This covers a sound effect a rule raises, the volume and mute, loops, music and a cutscene's sound. Sound files play through audio, notes through synthaudio, a whole song of devices, tracks and clips through audiodaw, and the volume is kept in the store.
A sound a rule raises
- Put the file in
games/<game>/assets/and add asoundentry for it to the scene's loader catalogue,world.loader.assets. - Write the cue table as
world.audioin the scene file, or once in the manager's<game>.scene.jsonwhen every scene uses it. - Add
storeandaudioto the scene'splugins, theaudioprefab, the volume's starting values in thestoreprefab, and one{ "is": "audio" }entry inactorsahead of every actor that raises a sound in itsbefore. - Put the cue in the kind's definition in
assets/<game>.json, as asoundstable of event to cue. - Raise it in the rule that made the change, with
sound(w, cue, at, from). A sound of the seat's own thing is raisedfromitsplayerrow and is heard on the frame after the key; any other goes on the ledger. - Bind the key that sends the act in
player.client.ts, and give the mute key a function that flips the store'smutedkey on the page.
"world": {
"loader": { "assets": { "knock1": { "type": "sound", "url": "/games/<game>/assets/knock.wav" } } },
"audio": {
"hold": 0.25,
"cues": { "knock": { "sounds": ["knock1"], "gain": 0.8 } },
"volume": { "level": "volume", "muted": "muted" }
},
"store": { "volume": 0.8, "muted": false }
},
"prefabs": { "audio": { "step": 0, "next": 1, "live": [] } }
The definition then holds "sounds": { "bump": "knock" }, and the rule calls sound(w, def(w, me.kind).sounds.bump, undefined, me.id).
Where each piece goes
| Piece | Home |
|---|---|
| The sound file | A sound entry of world.loader.assets |
| The cue table | world.audio |
| Which cue a kind plays | The kind's definition, under sounds |
| Volume and mute | Store keys, named by world.audio.volume, starting values in the store prefab |
| The song playing now | A field of a row, such as the cutscene row's music |
Placed sound
Under render3d's camera a placed sound needs world.audio.space, in metres. Under render2d with a world.render2d it needs world.audio.screen, in canvas pixels. With neither listener every sound plays unplaced.
Loops and music
- Name each loop in
world.audio.loops: one whose gain follows a field of a row, one that follows the camera's height, or a named loop that plays the sound a field names and crossfades overfadeseconds. - Give each song's catalogue entry
"preload": true, so it starts when the field names it. - For music as notes, list the project files in
world.synthaudio.projectsand the field that picks one inworld.synthaudio.music. Name the same store keys inworld.synthaudio.volumeas inworld.audio.volumeso one mute covers both, and liststorebeforesynthaudio. - For a whole song, a project of devices, tracks and clips with every voice made when it loads, use audiodaw. Give the song a kind of the game's own whose look loads the project and plays it, list
audiodawin the scene'splugins, and set Tone's buffer inworld.audiodaw.
A cutscene's sound
Set world.cutscene.mods to { "play": "audio" }, list audio, and stand the ledger's entry ahead of the cutscene row. The cutscene's sound and say cues then name cues of world.audio.cues, and its music cue sets the row's music field for a named loop to play.
Checking it
- Run the kind's test,
yarn vitest run games/<game>/<kind>.sim.test.ts: after the press the entry is on theplayerrow'svoicedlist, or on the ledger for any other row, with the definition's cue. - Run the page test beside
player.client.ts, with anAudioContextstand-in: one sound starts once, through the cue's gain and the store's volume, and the mute key sets that volume to 0. - Play it from
games/<game>/index.htmlwith real key presses, which unlock the browser's audio as a person's would; a script'sresume()before any input leaves it locked. Then run the game's server and openclient.htmlin two tabs: the seat's own sound is heard on the key, and the other tab hears it after.