<!-- fivemad.com, Markdown source of https://fivemad.com/docs/tools/native-audio-builder -->
> Source: https://fivemad.com/docs/tools/native-audio-builder
> Section: Tools
> Tags: audio, awc, dat54, sounds, PlaySoundFrontend, native audio
> Tool: https://fivemad.com/tools/native-audio-builder
> Last updated: 2026-09-22
> Site map for assistants: https://fivemad.com/llms.txt

# Native Audio Builder

Turn WAV, MP3 or OGG files into a FiveM native audio resource and play them from Lua on the UI, on an entity or at a position, synced if you want.

The Native Audio Builder turns your sound files into a complete FiveM resource that plays them as real game audio: the `.awc` wave bank, the `.dat54.rel` sound data, `fxmanifest.lua` with the right `data_file` lines, and Lua to load the bank and play sounds. No CodeWalker step is needed. It is for script devs who want custom sounds without a NUI page.

## What it is for

Most servers play custom sounds through NUI, a hidden browser page with an audio tag. 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` and `PlaySoundFromCoord` play them like any Rockstar sound.

Typical uses: phone ringtones and notification sounds, a siren or horn attached to a vehicle, an alarm at a bank that everyone nearby hears, UI clicks for a custom menu, door buzzers and radio chatter.

Looking for a base game sound instead? Use the [Sound Browser](/docs/tools/sound-browser).

## Quick start

1. Open the tool and use **Choose audio files** or **Choose folder**, or drag files or a folder onto the page.
2. Check each sound's **Name** and **Sound set**. These are the two strings you pass to the play functions.
3. Set **Resource name** in the **Bank** panel (for example `my_sounds`). The wave pack, data file and default sound set follow it.
4. Press play on a row to hear what the game will get.
5. Tick **Loop** for sounds that should repeat until you stop them.
6. Fix anything shown in red, then press **Download resource**.
7. Unzip, put the `my_sounds` folder in your resources, add `ensure my_sounds` and run `/my_sounds_test` in game.

## Input

- Formats: WAV, MP3 and OGG work everywhere. FLAC, M4A, AAC, Opus and WebM work when your browser can decode them. Other files are skipped with a count.
- Up to 200 sounds per bank.
- Stereo and multichannel files are mixed down to mono, and every file is converted to the bank's sample rate. The row shows the length, the channel change and the rate change (for WAVs), for example `2.40 s, 2 ch to mono, 44100 to 32000 Hz`.
- Each file becomes one sound named after the file: lowercase, anything other than letters and digits becomes `_`, cut at 48 characters. `Door Buzzer (2).wav` becomes `door_buzzer_2`. A second file with the same name in the same set gets `_2`, `_3` and so on.
- The sound set comes from the folder the file is in. Drop `in/phone/ring.mp3` and `in/alerts/beep.wav` and you get the sets `phone` and `alerts`. Files dropped without a folder go into the **Default sound set**.
- Sounds whose name contains `loop` or `alarm`, or that sit in a set called `ringtone` or `ringtones`, start with **Loop** on.

Drop more files anywhere on the page at any time to add them. **Clear** removes every sound.

> [!NOTE]
> Everything runs in your browser. Your audio is decoded and converted locally and the zip is built on your PC. Nothing is uploaded.

## The sound list

Each row has:

| Control | What it does |
|---|---|
| Play / Pause | Preview after conversion: sample rate, mono downmix, trimming, normalizing, the codec, the row's volume and loop. What you hear is close to what the game plays. |
| Name | The sound name, first argument of the play natives. Lowercase letters, digits, `_` and `-`. |
| Sound set | The sound set name. Lowercase letters, digits and `_`. Existing sets are suggested as you type. |
| Volume dB | Volume stored in the sound, from `-60` to `+6`. Default `0`. |
| Loop | The sound repeats until you call `StopNative` (or `StopSound`). |
| Remove | Removes the sound from the bank. |

Under each row you see a small waveform, the source file name, length and conversion info, and **Copy call**, which copies a ready line like `exports['my_sounds']:PlayNative('beep', 'my_sounds_set')`. Problems for that sound are listed right under it.

## Bank settings

| Setting | What it does | Default |
|---|---|---|
| Resource name | Folder name of the resource and the name you `ensure`. Lowercase letters, digits, `_` or `-`. Changing it also updates the three names below while you have not edited them yourself. | `my_sounds` |
| Wave pack | Folder that holds the bank inside `audio/`, and the first half of the bank path in Lua. | `dlc_my_sounds` |
| Bank | File name of the `.awc`, second half of the bank path. | `sounds` |
| Data file | File name of the `.dat54.rel`. | `my_sounds_sounds` |
| Default sound set | Set for files dropped without a folder. **Apply to all** puts every sound in this set. | `my_sounds_set` |
| Codec | **ADPCM** is 4x smaller and lossy. **PCM** is lossless and 4x bigger. | ADPCM |
| Sample rate | 48000, 44100, 32000, 24000 or 22050 Hz. Every sound in the bank uses the same rate. | 32000 Hz |
| Category | The mix group the game puts the sounds in: `scripted_louder` or `scripted`. | `scripted_louder` |
| Trim silence | Cuts silence at the start and end, so sounds fire on time. | on |
| Normalize | Raises or lowers each sound so its peak sits at -1 dBFS. | off |
| Synced playback | Adds `server.lua` to play a sound for every player nearby. | on |
| CodeWalker source | Adds the `.awc.xml`, `.rel.xml` and WAVs next to the resource, for editing later. | on |

Wave pack, Bank and Data file allow lowercase letters, digits and `_` only.

The summary card shows the number of sounds, the total length and an estimated `.awc` size. Changing the sample rate, trim or normalize reconverts every sound; the download button waits until that is done ("Converting audio...").

### Choosing codec and rate

- **ADPCM** is fine for effects, voice and most music. Very hard edged synth sounds (square waves) lose detail, use PCM for those.
- **32 kHz** keeps banks small and is plenty for effects and UI sounds. Use 44.1 or 48 kHz for music.
- The whole bank is loaded into memory when a script requests it. Keep long music or big packs in a bank of their own (a second resource) and load it only when you need it.

## Checks

Errors block the download, warnings do not.

| Level | Check |
|---|---|
| Error | Resource name, Wave pack, Bank or Data file with characters that are not allowed; sound name with characters other than lowercase a-z, 0-9, `_`, `-`; name over 64 characters; sound set with characters other than lowercase a-z, 0-9, `_`; the same name twice in one sound set; two names that clash inside the bank or with each other (rename one); a sound that is empty after conversion (for example pure silence with Trim on); volume outside -60 to +6 dB; a sound set that already exists in the base game; a file the browser could not decode. |
| Warning | A sound longer than 30 seconds (the whole bank sits in memory once loaded). |

## Output

### What is in the zip

**Download resource** saves `<resource>.zip`:

```text
my_sounds/
  fxmanifest.lua
  client.lua                              load the bank, play, stop, free
  server.lua                              only with Synced playback
  audio/dlc_my_sounds/sounds.awc          the wave bank
  audio/data/my_sounds_sounds.dat54.rel   the sound data
codewalker_source/                        only with CodeWalker source
  sounds.awc.xml
  sounds/*.wav
  my_sounds_sounds.dat54.rel.xml
```

Put only the `my_sounds` folder in your server's resources. `codewalker_source` is for you, not for the server. The message under the button shows the exact size of the `.awc` and `.dat54.rel` after the download.

The code tabs under the list show `client.lua`, `server.lua` (with Synced playback), `fxmanifest.lua`, the `.rel.xml` and the `.awc.xml` before you download.

### fxmanifest.lua

```lua title="fxmanifest.lua"
fx_version 'cerulean'
game 'gta5'
lua54 'yes'

description 'Native audio bank built with fivemad.com/tools/native-audio-builder'

client_script 'client.lua'
server_script 'server.lua'

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

-- sound data: the path of the .dat54.rel without "54.rel"
data_file 'AUDIO_SOUNDDATA' 'audio/data/my_sounds_sounds.dat'
-- wave pack: the folder that holds the .awc bank
data_file 'AUDIO_WAVEPACK' 'audio/dlc_my_sounds'
```

```cfg title="server.cfg"
ensure my_sounds
```

> [!IMPORTANT]
> The `AUDIO_SOUNDDATA` path ends in `.dat`, not `.dat54.rel`, and `AUDIO_WAVEPACK` points at the folder, not the `.awc`. Both files must also be in `files { }`, or clients never download them. The generated manifest already does this, keep it that way if you merge it into another resource.

### client.lua

The generated `client.lua` loads the bank when the resource starts (it waits up to 10 seconds and prints an error if the bank does not load) and releases it when the resource stops. It defines these functions, all also available as exports:

| Function | What it does | Returns |
|---|---|---|
| `PlayNative(name, soundSet, loop)` | 2D sound (UI, phone, notifications) via `PlaySoundFrontend`. | sound id |
| `PlayNativeOnEntity(name, soundSet, entity, loop)` | 3D sound that follows a ped, vehicle or prop via `PlaySoundFromEntity`. | sound id |
| `PlayNativeAtCoords(name, soundSet, coords, range, loop)` | 3D sound at a position via `PlaySoundFromCoord`. `range` defaults to `20.0`. | sound id |
| `SetNativeVolume(id, volume)` | Changes the volume of a playing sound, `0.0` to `1.0`. | |
| `StopNative(id)` | Stops the sound and frees its id. | |

One shot sounds free their sound id by themselves when they finish. Looped sounds keep their id until you call `StopNative`, so store it. The `loop` argument only controls that cleanup; whether a sound actually repeats is set by the **Loop** toggle when you build the bank.

It also registers a test command named after the resource: `/my_sounds_test` plays every sound one after the other (looped ones for 5 seconds), `/my_sounds_test beep` plays just one.

## Examples

Inside the same resource (add your code to `client.lua` or another client script of the resource):

```lua title="client.lua"
-- UI sound
PlayNative('beep', 'my_sounds_set')

-- follows the vehicle
local veh = GetVehiclePedIsIn(PlayerPedId(), false)
PlayNativeOnEntity('horn', 'my_sounds_set', veh)

-- heard up to 30 m from the bank door
PlayNativeAtCoords('alarm', 'my_sounds_set', vector3(150.2, -1040.5, 29.4), 30.0)

-- looped ringtone at half volume, stopped later
local id = PlayNative('ringtone', 'my_sounds_set', true)
SetNativeVolume(id, 0.5)
Wait(8000)
StopNative(id)
```

From another resource, use the exports:

```lua title="phone/client.lua"
local ring = exports['my_sounds']:PlayNative('ringtone', 'phone', true)

RegisterNetEvent('phone:answered', function()
    exports['my_sounds']:StopNative(ring)
end)
```

### Synced playback

For everyone nearby to hear a sound, the server has to tell them. With **Synced playback** on, `server.lua` exports two functions that check each player's distance (needs OneSync) and send the sound only to players in range:

```lua title="bank_robbery/server.lua"
-- everyone within 30 m of the vault hears the alarm
exports['my_sounds']:PlayAtCoords('alarm', 'my_sounds_set', vector3(255.0, 225.0, 101.9), 30.0)

-- everyone within 30 m (the default) hears the horn on that networked vehicle
exports['my_sounds']:PlayOnEntity('horn', 'my_sounds_set', vehicle)
```

`PlayAtCoords` defaults to a 20 m range, `PlayOnEntity` to 30 m. The play natives also have an `isNetwork` argument, but it does not load your bank on the other clients, so the server event approach is the reliable one.

## Editing the bank later

With **CodeWalker source** on, the zip has everything to rebuild the bank in CodeWalker: open RPF Explorer, turn on edit mode, and drag `sounds.awc.xml` (with the `sounds` 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. Or drop the WAVs into this tool again and download a new bank.

## Common mistakes

- **No sound at all.** The bank did not load: check the F8 console for "could not load audio bank", then check the `data_file` lines and that both files are in `files { }`. Restart the resource after changing the manifest and reconnect.
- **Wrong sound set or name.** Both strings are case sensitive in your scripts. Copy them with **Copy call**.
- **Sound plays only for you.** `PlayNative` is local. Use the server exports with Synced playback for sounds others must hear.
- **Looping sound never stops.** Keep the id returned by the play function and call `StopNative(id)`.
- **Name clash with the game.** Sound sets share one namespace with every game sound, so give them your own prefix. The tool refuses sets that already exist in the base game.
- **Huge bank.** A bank with ten minutes of music at 48 kHz is loaded into memory as a whole. Split music into its own resource.

## Limitations

- The page cannot play the finished `.awc` and `.rel` in the game itself, so test the resource on your own server before you ship it.
- Output is mono. Multichannel banks (the stereo format radio stations use) are not built here.
- One sample rate, codec and category per bank.
- Up to 200 sounds per bank.
- Files you drop are kept only for this page visit. After a reload, drop them again.

Based on [lb-nativeaudio](https://github.com/lbphone/lb-nativeaudio) by LB Scripts.

## Related tools

- [Sound Browser](/docs/tools/sound-browser) for base game sounds and sound sets
- [fxmanifest Generator](/docs/tools/fxmanifest-generator)
- [Vehicle Pack Validator](/docs/tools/vehicle-pack-validator) checks engine sound `data_file` lines in car packs
