Skip to content
On this page

Sound

TypeSpriteJS has support for sound effects and background music.

Init Audio

To setup the audio engine we use the AudioManager component:

ini
[!music]
@AudioManager:typesprite

This component makes sure that the browser initilaizes the sound early on. It is also the component to control global volume and mute.

ts
// in a component
this.world.sendMessage("GlobalMute", true); // make sure the world contains the AudioManager
this.world.sendMessage("GlobalGain", 0.5); // 0 = silent, 1 = full volume

NOTE User interaction required

HTML5/WebAudio in modern browsers prevent websites to play music or sound effects per default. To enable that you must bring the player to, at least once, click into the game. You might also turn off the silent switch on iOS devices.

Play Background Music

The AudioManager component takes care of playing one channel of background-music:

ts
export class PlayMusicController extends Component {
    changeMusic() {
        this.world.sendMessage("PlayMusic", "assets/bgm/some-long-track.mp3");
    }
    stopMusic() {
        this.world.sendMessage("StopMusic");
    }
}
ts
export class PlayMusicController extends Component {
    @link('AudioManager')
    private audio:AudioManager

    changeMusic() {
        this.audio.playMusic("assets/bgm/some-long-track.mp3")
    }
    stopMusic() {
        this.audio.stopMusic();
    }
}

Play Sound Effects (SFX)

Playing sound effects in TypeSpriteJS is mainly done by using the SoundFxBag component. It honors the global gain and mute option of the AudioManager and has basic support for mixing.

Here we load a single sound effect:

ini
# world.edf

[!Player]
@PlayerController
@SoundFxBag
sounds = {"jump": "assets/sfx/jump.mp3"}

To play this we use:

ts
export class PlayerController extends Component {
    onJump() {
        this.entity.sendMessage("PlaySound", "jump");
    }
}
ts
export class PlayerController extends Component {
    @cmp('SoundFxBag')
    private sfx: SoundFxBag;

    onJump() {
        this.sfx.playSimple("jump")
    }
}

As the bag part of the name SoundFxBag already suggests it supports a list of sound effects:

ini
[!Player]
@PlayerController
@SoundFxBag
sounds "{
    "jump": "assets/sfx/jump.mp3",
    "stop": "assets/sfx/stop.mp3",
    "accel": "assets/sfx/accel.mp3"
}"

Here the Player entity can play jump, stop and accel.

NOTE

Here we use JSON within an EDF file. Unfortunately this really has to be proper JSON. Things like trailing commas will be an issue here.

To make things more interesting we can even mix multiple sounds together:

ini
[!Player]
@PlayerController
@SoundFxBag
sounds "{
    "jump": [
        ["assets/sfx/jump.mp3", 0.5],
        ["assets/sfx/woof.mp3", 1, 1, 0.2]
    ],
    "stop": "assets/sfx/stop.mp3",
    "accel": "assets/sfx/accel.mp3"
}"

Here jump consists of two sound files and when we invoke jump they both will be played. Per sound file we can configure:

  • gain
  • playback rate
  • play delay

The parameter format for mixed sounds look like this

[file:string, gain:number=1, rate:number=1, delay:number=0]

Memory Management in SoundFxBag

TypeSpriteJS manages sounds in the same way as it manages other resources. There is no harm to configure your world objects like this:

ini
[!Player]
@SoundFxBag
sounds = {"damage": "assets/sfx/dmg.mp3"}

[!EnemeyTypeA]
@SoundFxBag
sounds = {"hurt": "assets/sfx/dmg.mp3"}

[!EnemeyTypeB]
@SoundFxBag
sounds "{
  "explode": [
    ["assets/sfx/dmg.mp3", 0.2, 1, 0.5],
    ["assets/sfx/blast.mp3", 0.2]
  ]
}"

assets/sfx/dmg.mp3 would only be loaded once in memory and even could be shared between multiple worlds.

Sound Compatibility

Playing sounds requires browser vendors to aquire mystical fairy dust from ogranizations, so they can play formats like webm, mp3 and ogg. Joke aside: not all sound formats are supported on all operating systems and in all browsers. However, in recent times there seems to be good support for audio/webm.

Hopefully in a later stage TypeSpriteJS can offer more ways to work around this issue.

Use HowlerJS directly (advanced)

In it`s current implementation the audio support is based on howlerjs. For advanced customization you can use the classes directly under the following names:

Howler ClassAccess in TypeSpriteJS
Howlimport {AudioHowl as Howl} from 'typesprite'
Howlerimport {AudioHowlerGlobal as Howler} from 'typesprite'
Soundimport {AudioHowlerSound as Sound} from 'typesprite'

To manage the resources for an Howl object you can use the sound resource type. That way there is no need for manually load and unload sound objects.

ts
import {res, Component, AudioHowl as Howl} from 'typesprite'

export class HowlSoundExample extends Component {
    @res('sound', 'assets/sfx/blast.mp3')
    private blast:any; // sorry, no proper typemapping for now
 
    onUpdate() {
        this.blast.play(); // see Howlerjs docs for all the options here
    }
}

NOTE

At some point TypeSpriteJS might switch to a custom implementation. In that case the Howler-Classes might be removed.