Skip to content
Bartholomew Ho edited this page Nov 9, 2026 · 1 revision

Audio

Play your own sounds through the game's audio. Sounds are heard from where they are (a car, or a spot in the world), so they get distance and direction like the game's own sounds. Load a sound once, then play it as often as you like.

Thread: any. Audio, Sound and SoundChannel can all be used from any thread.

Example

Play a looped hum.wav (shipped in your mod's folder) on your car, at half volume.

private Sound _hum;
private SoundChannel _playing;

protected override void OnInit()
{
    _hum = Audio.LoadSound(Path.Combine(ModFolder, "hum.wav"), looped: true);
    Game.Tick += () =>
    {
        if (Audio.IsReady && Player.Car is { } car && (_playing is null || !_playing.IsPlaying))
            _playing = _hum.PlayOn(car, volume: 0.5f);
    };
}
Private _hum As Sound
Private _playing As SoundChannel

Protected Overrides Sub OnInit()
    _hum = Audio.LoadSound(IO.Path.Combine(ModFolder, "hum.wav"), looped:=True)
    AddHandler Game.Tick, Sub()
                              Dim car = Player.Car
                              If Audio.IsReady AndAlso car IsNot Nothing AndAlso (_playing Is Nothing OrElse Not _playing.IsPlaying) Then
                                  _playing = _hum.PlayOn(car, volume:=0.5F)
                              End If
                          End Sub
End Sub

Call _playing.Stop() to stop it.

Members

Audio

Member What it does
IsReady (property, bool) True once the game's audio can be used (the game's code is as expected).
LoadSound(string path, bool looped = false) (method, returns Sound) A sound from a file (a .wav). The same file loaded again gives the same sound.
LoadSound(byte[] file, bool looped = false) (method, returns Sound) A sound from a whole sound file in memory (a .wav).
MixSound(byte[]? intro, byte[][] bed, float seconds, bool looped = false, float crossfadeSeconds = 0.02f) (method, returns Sound?) One long sound made of pieces: the bed sounds play one after another in turn, each crossfading into the next, for seconds, with intro (if any) played over the start. Good for a long sound that shouldn't sound like a loop, like an engine or a hiss. Null if the pieces can't be used (see Notes).
StopAll() (method) Stops every sound that's playing (with a short fade).

Sound

A sound you loaded. Play it as often as you like, even several times at once.

Member What it does
Looped (property, bool) True if it plays over and over until stopped.
Seconds (property, float) How long it is, in seconds. 60 if the file isn't a 16-bit WAV (its length isn't known).
Play(float volume = 1) (method, returns SoundChannel) Plays it where you hear from (the camera), at volume (0 to 1).
PlayOn(Vehicle car, float volume = 1) (method, returns SoundChannel) Plays it from car, following it. You hear it from wherever the camera is, like the car's engine.
PlayAt(Vector3 position, float volume = 1) (method, returns SoundChannel) Plays it from a spot in the world.

SoundChannel

One sound that's playing.

Member What it does
Volume (property, float, get/set) How loud, 0 to 1.
FullVolumeWithin (property, float, get/set) Full volume within this many metres of the sound. Default 10.
SilentBeyond (property, float, get/set) Fades to silence this many metres away. Default 250.
Position (property, Vector3?, get/set) Where it plays from, for a sound started with PlayAt. Set it to move the sound.
IsPlaying (property, bool) True until it has finished or been stopped (and faded out).
Stop() (method) Stops it, with a short fade.

Notes

  • Use WAV files. 16-bit WAVs are made mono at the rate the game mixes at, and the game places them in 3D itself. Any other file goes to the game's audio as it is.
  • The game's own volume sliders don't change these sounds.
  • Loading is cheap to repeat: a sound with the same file contents (and the same looped) is only made once, even across mods and reloads. The game keeps it for the session.
  • A sound may take a moment to start the first time it plays, while it's being prepared.
  • There is no Doppler effect (no pitch change when things move fast).
  • Play, PlayOn and PlayAt throw InvalidOperationException if the game isn't ready yet, or if audio is off on this game build.
  • A sound on a car stops by itself when the car goes away, or when the game pauses.
  • Position only changes a sound started with PlayAt. On other sounds, and when set to Nothing/null, it does nothing.
  • Volume is kept between 0 and 1 when it's used. SilentBeyond is always at least 1 metre more than FullVolumeWithin.
  • A sound that isn't looped and isn't a 16-bit WAV is treated as 60 seconds long.
  • MixSound returns null if bed is empty, if seconds is 0 or less, if any piece isn't a mono or stereo 16-bit WAV, if the pieces don't all have the same sample rate, or if a piece is too short for the crossfade.
  • LoadSound(string path, ...) reads the file straight away, so a missing file throws.
  • If your mod is reloaded, the sounds it was playing stop.
  • On a game build the SDK doesn't support, audio switches itself off: IsReady stays false and platform.log says so.

See also

Clone this wiki locally