Skip to content

Native Audio Builder

Drop your sounds and get a complete FiveM resource that plays them as real game audio: the .awc wave bank and .dat54.rel sound data built right here (no CodeWalker step), the data_file lines, and Lua to load the bank and play sounds on the UI, on an entity or at a position, synced if you want. Based on lb-nativeaudio.

Config & CodeAudio, AWC, DownloadRead the docs

Why native audio

Most servers play custom sounds through NUI (an HTML audio tag in a hidden browser page). That works, but the game does not know the sound exists: no 3D position, no distance falloff, no game volume slider, and every client runs a browser page for it. Native audio puts your files into the game's own audio system, so PlaySoundFrontend, PlaySoundFromEntity andPlaySoundFromCoord play them like any Rockstar sound. Looking for a base game sound instead? Use theSound Browser.

Native audio needs three things, and this page builds all of them:

  • An .awc bank (audio wave container) that holds the audio itself, mono 16 bit, as IMA ADPCM or plain PCM.
  • A .dat54.rel with the sound data: one simple sound per wave, a sound set that maps the names you use in Lua to those sounds, and a volume variable you can change while a sound plays.
  • fxmanifest data_file lines that tell FiveM to mount the wave pack and load the sound data.

How to use it

  1. Drop your files. Each file becomes a sound, named after the file. A dropped folder with sub folders gives one sound set per sub folder.
  2. Check the names. The name and sound set are the two strings you pass to the play natives. Everything is lower case, use letters, digits and _.
  3. Tick Loop for sounds that should repeat until you stop them (alarms, ringtones, engine hums).
  4. Click play to hear what the game will get: the audio after the sample rate change, the mono downmix and the codec.
  5. Download the zip, put the my_sounds folder in your resources, ensure my_sounds and run/my_sounds_test in game.

This page can not play the files in the game itself, so test the resource on your own server before you ship it.

What is in the zip

my_sounds/
  fxmanifest.lua
  client.lua                      load the bank, play, stop, free
  server.lua                      optional, synced playback
  audio/dlc_my_sounds/sounds.awc  the wave bank
  audio/data/my_sounds_sounds.dat54.rel
codewalker_source/                optional, for editing later
  sounds.awc.xml
  sounds/*.wav
  my_sounds_sounds.dat54.rel.xml

The manifest lines look like this. The sound data path drops the 54.rel part of the file name, the wave pack path is the folder around the .awc:

files {
    'audio/data/my_sounds_sounds.dat54.rel',
    'audio/dlc_my_sounds/sounds.awc',
}

data_file 'AUDIO_SOUNDDATA' 'audio/data/my_sounds_sounds.dat'
data_file 'AUDIO_WAVEPACK' 'audio/dlc_my_sounds'

Playing the sounds from Lua

A bank has to be loaded before its sounds play. The generated client.lua does it on start and gives you these functions (also as exports):

-- load once (client.lua does this for you)
while not RequestScriptAudioBank('dlc_my_sounds/sounds', false) do Wait(0) end

PlayNative('beep', 'my_sounds_set')                          -- UI sound
PlayNativeOnEntity('horn', 'my_sounds_set', vehicle)         -- follows the entity
PlayNativeAtCoords('alarm', 'my_sounds_set', coords, 30.0)   -- heard up to 30 m

local id = PlayNative('ringtone', 'my_sounds_set', true)     -- looped
SetNativeVolume(id, 0.5)                                     -- 0.0 to 1.0
StopNative(id)                                               -- stop and free the id

From another resource: exports['my_sounds']:PlayNative('beep', 'my_sounds_set'). One shot sounds free their sound id when they finish. Looped sounds keep their id until you call StopNative, so keep it around.

For everyone nearby to hear a sound, the server has to tell them. server.lua checks each player's distance (OneSync) and sends the sound to the ones in range: exports['my_sounds']:PlayAtCoords('alarm', 'my_sounds_set', coords, 30.0). The play natives also have an isNetwork argument, but it does not load your bank on the other clients, so the event approach is the reliable one.

Settings that matter

  • ADPCM or PCM. ADPCM is a quarter of the size and fine for effects, voice and most music. Very hard edged synth sounds (square waves) lose detail in ADPCM, use PCM for those.
  • Sample rate. 32 kHz keeps banks small and is plenty for effects. Use 44.1 or 48 kHz for music. Every sound in a bank uses the same rate here.
  • Bank size. RequestScriptAudioBank loads the whole bank into memory. Keep long music or big packs in a bank of their own and load it only when you need it.
  • Unique names. Sound sets share one namespace with every game sound, so give them your own prefix. The page warns when a set already exists in the base game and when two names hash to the same value.
  • Stereo files are mixed down to mono. Multichannel banks (the stereo format radio uses) are not built here.

Editing the bank later

To edit the bank later, open CodeWalker RPF Explorer, turn on edit mode, and drag sounds.awc.xml (with thesounds folder of WAVs next to it) and the .dat54.rel.xml into a folder. CodeWalker builds the binary files, drag them back into the resource.

Credits and sources