Audio Resources#

This chapter explains how audio files become playable resources.

In Godot-FmodPlayer, the commonly used resource is FmodAudioStream. You can think of it as the Godot-side object that stores audio data and playback settings. When it is actually played, it creates a Sound under the hood and plays through a Channel managed by a player or by the system.

Choose a Loading Mode First#

There is one main choice: use Stream for long audio, and Sample for short sound effects.

Sound type

Recommended mode

Reason

Background music

MODE_STREAM

The file is usually large, so reading while playing saves memory.

Long narration or long ambience

MODE_STREAM

The playback time is long, so loading everything into memory is not ideal.

UI sounds and button sounds

MODE_SAMPLE

The file is short and should respond quickly.

Weapons, footsteps, and pickup sounds

MODE_SAMPLE

They may trigger frequently, so low latency matters more.

Very short sounds that play only once

Either can work

Choose based on your project’s memory and latency needs.

See also Stream and Sample for these concepts.

FmodAudioStream#

FmodAudioStream is the most commonly used audio resource class. It stores audio data and the creation mode, such as whether the sound streams, loads as a sample, or loops.

Common Creation Modes#

Flag

Description

MODE_STREAM

Streams audio, suitable for music and long audio.

MODE_SAMPLE

Sample playback, suitable for short sound effects and low-latency playback.

MODE_LOOP

Loops playback.

MODE_LOOP_BIDI

Bidirectional looping, similar to playing back and forth.

These flags can be combined with |:

var flags := FmodAudioStream.MODE_STREAM | FmodAudioStream.MODE_LOOP

Load from a File#

Prefer res:// paths so exported projects stay consistent.

var music := FmodAudioStream.load_from_file(
    "res://music/bgm.ogg",
    FmodAudioStream.MODE_STREAM | FmodAudioStream.MODE_LOOP
)

var hit := FmodAudioStream.load_from_file(
    "res://sfx/hit.wav",
    FmodAudioStream.MODE_SAMPLE
)

After loading, you can assign it directly to a player:

@onready var music_player := $FmodAudioStreamPlayer

func _ready():
    music_player.stream = music
    music_player.bus = "Music"
    music_player.play()

Load from Memory#

If audio comes from an encrypted package, the network, a save file, or your own loading flow, put the binary data into audio_data.

func load_from_bytes(data: PackedByteArray) -> FmodAudioStream:
    var stream := FmodAudioStream.new()
    stream.audio_data = data
    stream.mode_flags = FmodAudioStream.MODE_SAMPLE
    return stream

When using this method, keep the resource object alive while the sound is playing. Do not free the object that stores the data before playback finishes.

Preload Common Sound Effects#

Short sound effects are often played repeatedly. You can load them when the scene starts and reuse them later.

extends Node

var sfx := {}

func _ready():
    sfx["hit"] = FmodAudioStream.load_from_file(
        "res://sfx/hit.wav",
        FmodAudioStream.MODE_SAMPLE
    )
    sfx["pickup"] = FmodAudioStream.load_from_file(
        "res://sfx/pickup.wav",
        FmodAudioStream.MODE_SAMPLE
    )

func play_sfx(name: String):
    if not sfx.has(name):
        push_error("SFX not found: " + name)
        return

    var player := FmodAudioStreamPlayer.new()
    add_child(player)
    player.stream = sfx[name]
    player.bus = "SFX"
    player.play()

    await get_tree().create_timer(3.0).timeout
    player.queue_free()

If your project plays many overlapping short sound effects, you can go further and use a player object pool. For beginners, the approach above is easier to understand.

Background Music Playlist#

Music usually uses MODE_STREAM. Add MODE_LOOP when it needs to loop.

extends Node

@onready var player := $FmodAudioStreamPlayer
var tracks: Array[FmodAudioStream] = []
var current_index := 0

func _ready():
    tracks.append(FmodAudioStream.load_from_file(
        "res://music/track_0.ogg",
        FmodAudioStream.MODE_STREAM
    ))
    tracks.append(FmodAudioStream.load_from_file(
        "res://music/track_1.ogg",
        FmodAudioStream.MODE_STREAM
    ))

    play_track(0)

func play_track(index: int):
    current_index = index
    player.stream = tracks[index]
    player.bus = "Music"
    player.play()

Query Audio Information#

FmodAudioStream can query length and access the underlying Sound.

func print_stream_info(stream: FmodAudioStream):
    print("loaded: ", stream.is_data_loaded())
    print("length: ", stream.get_length())

    var sound := stream.get_sound()
    if sound:
        print("sound length: ", sound.get_length())

Normal playback usually does not require direct access to FmodSound. Get it only when you need lower-level information, callbacks, or special playback control.

Supported Formats#

Common formats include .wav, .ogg, .mp3, .flac, .aiff, and some module music formats such as .mod, .xm, .s3m, and .it.

Practical suggestions:

  • Prefer ogg or mp3 for music.

  • Prefer wav for short sound effects.

  • When seamless looping matters, test loop points with ogg or wav first.

  • Always test special formats on the target platform before export.

Common Issues#

The first playback of a sound effect has latency#

Load short sound effects with MODE_SAMPLE and preload them before entering the scene.

Music uses too much memory#

Check whether the music was loaded with MODE_SAMPLE. Long music should usually use MODE_STREAM.

Looping does not work#

Make sure the creation mode includes MODE_LOOP:

stream.mode_flags = FmodAudioStream.MODE_STREAM | FmodAudioStream.MODE_LOOP

File cannot be found after packaging#

Prefer res:// paths and make sure the audio files are included by Godot’s export rules.

Recommendations#

  • Long music and long ambience: MODE_STREAM.

  • Short sound effects, UI sounds, and frequently triggered sounds: MODE_SAMPLE.

  • Load common short sound effects ahead of time to avoid a stall on first playback.

  • Use playback nodes first when possible. Touch Sound and Channel only when you need lower-level control.