AudioBox Agent
A Java agent that loads with the game and exposes the game’s own FMOD calls to Lua as the global AudioBoxFMOD. It exposes FMOD and nothing else: it finds and plays no music by itself. Mods decide what to play. Player, Extras and any mod of your own use the same global. The jar ships inside AudioBox Player, as common/audiobox-agent.jar.
Why it exists
Vanilla Lua can play sounds declared in item scripts, through sound emitters. It needs every sound declared ahead of time, and it has no way to seek, report position or length, pause and resume, muffle one channel, apply a low-pass or DSP effect, change distances at runtime, check whether a channel went virtual or how audible it is, read the environment parameters, or handle voice buffers.
It also has a memory cost. In the decompiled 42.21 game code, the file loader opens each sound with mode 16 (18 when looping), never sets the stream flag, and never releases the result, so everything it loads stays loaded. FMOD’s documentation says a file opened without a stream flag is decoded in full into memory. At 44.1 kHz stereo, three minutes of 16-bit audio is about 32 MB, so one twelve-track album loaded that way would hold roughly 380 MB, and every further album adds its own share. The decoding itself has not been measured in game.
The agent opens files by path at runtime with the stream flag (mode 144), so FMOD decodes a small buffer as the track plays instead of the whole file. Player and Extras release each sound when its track stops, so memory use stays flat however much music you own. Your music is not limited to what scripts declared at startup, and tracks can be sought, paused, muffled and synced between players, which the vanilla system cannot do at all.
Install and check
- Copy
audiobox-agent.jarfrom AudioBox Player’scommonfolder into the game’s install folder, next toProjectZomboid64.json. - Add this as the first entry of
vmArgsinProjectZomboid64.json. It has to be there or in the.batfile; Steam’s Launch Options field cannot load it:"-javaagent:audiobox-agent.jar", - If you start the game with
ProjectZomboid64.batinstead, add-javaagent:audiobox-agent.jarright after".\jre64\bin\java.exe"on both of its java lines. - Replace the jar only with the game fully closed. The agent writes a log file beside the jar.
- In the Lua console,
pairs(AudioBoxFMOD)lists every exposed function name. If a newly added function isnil, the game is still running an older jar.
The server-side Lua of Player and Extras never calls the agent, so a dedicated server does not need the line (not yet tried on a real server). The global is present again after every Lua reload. Guard your calls with if AudioBoxFMOD then so your mod still loads without the agent.
Only trust the official agent
A Java agent runs inside the game with the game’s full permissions. If a mod ships its own copy of audiobox-agent.jar, do not trust it: a modified agent can do more than bridge FMOD to Lua, including running arbitrary code. Take the agent only from the official AudioBox Player download. Mods built on the agent should list AudioBox Player as a required mod and never bundle a copy of their own.
The 35 functions
Every public static of AudioBoxFMOD is exposed to Lua under its own name, and handles are plain numbers passed back in. “Observed in game” means it appears in the project’s proven-facts record. Calls on a finished channel return 3.
| Call | Returns | Does | Status |
|---|---|---|---|
FMOD_System_CreateSound(String path, long mode) | long | Opens a file by path and returns a sound handle. 0 means failure. | Observed in game |
FMOD_System_PlaySound(long sound, boolean paused) | long | Starts a sound and returns a channel handle. | Observed in game |
FMOD_Channel_SetVolume(long channel, float volume) | int | Sets the channel volume. | Observed in game |
FMOD_Channel_SetPaused(long channel, boolean paused) | int | Pauses or resumes. | Observed in game |
FMOD_Channel_Stop(long channel) | int | Stops the channel. | Observed in game |
FMOD_Channel_IsPlaying(long channel) | boolean | False once a track reaches its natural end. | Observed in game |
FMOD_Sound_Release(long sound) | int | Frees the sound. | Observed in game |
FMOD_Channel_Set3DAttributes(long channel, float x, y, z, vx, vy, vz) | int | Places the channel in the world; volume and panning follow. | Observed in game |
FMOD_Channel_Set3DMinMaxDistance(long channel, float min, float max) | int | Sets the fade distances. | Observed in game |
FMOD_Channel_Set3DLevel(long channel, float level) | int | Level 0 flattens panning. | Observed in game |
FMOD_Sound_GetLength(long sound, long timeunit) | long | Length; unit 1 is milliseconds. | Observed in game |
FMOD_Channel_GetPosition(long channel, int postype) | long | Current position; type 1 is milliseconds. | Observed in game |
FMOD_Channel_SetPosition(long channel, long position) | int | Seeks mid-playback. | Observed in game |
FMOD_Channel_Set3DOcclusion(long channel, float, float) | int | Muffles a channel. Player uses it for walls and vehicles. | Observed in game |
FMOD_Channel_SetPriority(long channel, int priority) | int | Priority 0 keeps a channel from going virtual under sound load. | Observed in game |
FMOD_Channel_IsVirtual(long channel) | boolean | Whether FMOD has made the channel virtual (silent). | Observed in game |
FMOD_GetGlobalParameter(String name) | float | Reads a game environment parameter. Unknown names return -999. | Observed in game |
FMOD_Channel_SetPitch(long channel, float pitch) | int | Playback speed. Player uses it for fast forward, rewind and sync. | Used by Player and Extras |
FMOD_Channel_SetLoopCount(long channel, int count) | int | -1 loops forever (open the sound with loop flag 2). | Used by Player and Extras |
FMOD_Sound_SetLoopCount(long sound, int count) | int | Loop count on the sound. | Not used by a shipped mod yet |
FMOD_Channel_SetMode(long channel, long mode) | int | Changes a channel’s mode flags, for example 2D (8) or 3D (16). | Not used by a shipped mod yet |
FMOD_Channel_SetPan(long channel, float pan) | int | Stereo pan. | Not used by a shipped mod yet |
FMOD_Channel_Set3DSpread(long channel, float spread) | int | 3D spread angle. | Not used by a shipped mod yet |
FMOD_Channel_Set3DDopplerLevel(long channel, float level) | int | Doppler effect amount. | Not used by a shipped mod yet |
FMOD_Channel_GetAudibility(long channel) | float | How audible the channel currently is. | Not used by a shipped mod yet |
FMOD_Channel_SetLowPassGain(long channel, float gain) | int | Low-pass gain on a channel. | Not used by a shipped mod yet |
FMOD_System_CreateDSPByType(long type) | long | Creates a DSP effect and returns its handle. | Not used by a shipped mod yet |
FMOD_Channel_AddDSP(long channel, int index, long dsp) | int | Adds a DSP to a channel. | Not used by a shipped mod yet |
FMOD_Channel_RemoveDSP(long channel, long dsp) | int | Removes a DSP from a channel. | Not used by a shipped mod yet |
FMOD_Channel_GetNumDSPs(long channel) | int | Counts the DSPs on a channel. | Not used by a shipped mod yet |
FMOD_DSP_SetParameterFloat(long dsp, int index, float value) | int | Sets a float parameter. | Not used by a shipped mod yet |
FMOD_DSP_SetParameterInt(long dsp, int index, int value) | int | Sets an integer parameter. | Not used by a shipped mod yet |
FMOD_DSP_SetWetDryMix(long dsp, float, float, float) | int | Sets the wet and dry mix. | Not used by a shipped mod yet |
FMOD_DSP_SetBypass(long dsp, long bypass) | int | Bypasses a DSP. | Not used by a shipped mod yet |
FMOD_DSP_Release(long dsp) | int | Frees a DSP. | Not used by a shipped mod yet |
Mode flags
Values read from the game’s own constants: stream 128, 3D 16, 2D 8, loop 2, accurate time 16384. Add them together. Modes run in game include 136, 144 (stream plus 3D), 16520 and 16522.
Environment parameters
The game’s global parameters Inside (-1 in a vehicle, 1 in a house), RoomSize, ClosestWallDistance and RainIntensity can be read by name and describe the listener. RoomType stayed nan in testing and the cause is not traced.
Formats
mp3, ogg and FLAC are proven in game. Other formats that the game’s fmod.dll can decode have not been tried. The game’s engine cannot play Opus.
Example: stream, place, seek, clean up
if AudioBoxFMOD then
local sound = AudioBoxFMOD.FMOD_System_CreateSound("C:/Music/track.ogg", 144)
if sound ~= 0 then
local ch = AudioBoxFMOD.FMOD_System_PlaySound(sound, true)
AudioBoxFMOD.FMOD_Channel_SetPriority(ch, 0)
AudioBoxFMOD.FMOD_Channel_SetVolume(ch, 0.8)
AudioBoxFMOD.FMOD_Channel_Set3DAttributes(ch, x, y, z, 0, 0, 0)
AudioBoxFMOD.FMOD_Channel_Set3DMinMaxDistance(ch, 1, 20)
AudioBoxFMOD.FMOD_Channel_SetPaused(ch, false)
local lengthMs = AudioBoxFMOD.FMOD_Sound_GetLength(sound, 1)
local posMs = AudioBoxFMOD.FMOD_Channel_GetPosition(ch, 1)
AudioBoxFMOD.FMOD_Channel_SetPosition(ch, 90000)
AudioBoxFMOD.FMOD_Channel_Stop(ch)
AudioBoxFMOD.FMOD_Sound_Release(sound)
end
end
Example: loop a track and speed it up
local sound = AudioBoxFMOD.FMOD_System_CreateSound(path, 144 + 2)
local ch = AudioBoxFMOD.FMOD_System_PlaySound(sound, false)
AudioBoxFMOD.FMOD_Channel_SetLoopCount(ch, -1)
AudioBoxFMOD.FMOD_Channel_SetPitch(ch, 1.04)
Limits
Only calls that take and return plain values are exposed, because most of FMOD’s getters want raw native addresses and a bad address can crash the game. Calls that need pointers or buffers (ID3 tags, voice recording, raw sample buffers) need a helper written in the agent first, and are not available yet.
AudioBox Player
Plays player-made content packs (albums) in radios, a CD player and a record player, through the AudioBox Agent. The agent ships inside Player, and it has to be added to the game’s ProjectZomboid64.json or ProjectZomboid64.bat file (see the Agent tab) for Player to work. It does not go in Steam’s Launch Options field. Player is its own system on top of vanilla: its media has its own item types and ids, nothing of vanilla’s media is replaced, and uninstalling leaves vanilla radios intact. Albums come from separate content-pack mods, which you can make with AudioBox Deck.
Formats and devices
| Format | Plays on |
|---|---|
| CD | Radio (red) and CD Player |
| Cassette | Radio (black, the ValuTech) |
| Vinyl | Record Player (a Player item). AudioBox Extras adds a jukebox that plays vinyl too. |
An item is one album in one format, and all formats of an album share one track list. The Record Player’s radio panel does not open while it is carried, and it has no headphone option; its model changes while it plays.
Using it
- Drag media into the slot, as with vanilla. A transport row (previous, play, stop, next, loop, shuffle) replaces the play button when Player media is inserted.
- On CDs and cassettes, hold previous to rewind and next to fast forward.
- Loop cycles off, track, album. Shuffle avoids playing the same track twice in a row. Both are kept on the radio.
- Ejecting stops playback and returns the item.
- Cassettes and vinyl have basic controls by default: no shuffle and no track repeat, only loop album. Sandbox options give them the full row. CDs always have the full row.
- Switching the device off, or a dead battery, stops the music.
How it sounds
- Placed and floor radios are 3D: the volume fades out to the device’s sound range, and panning is eased in over the first few tiles. The sound range is the radio’s own, multiplied by a sandbox setting.
- A carried radio, or a player inside a vehicle, plays flat at full device volume. A vehicle radio heard from outside is 3D.
- Walls and vehicle bodies muffle the sound. A sealed building room or a sealed vehicle each holds back part of it, and about nine tenths is held back when both ends are sealed. Open doors and windows let sound out; a vehicle is sealed only when its windows and doors are shut. Flat radios are never muffled. A sandbox option can also muffle sound between indoor spaces.
- Playing radios draw zombies, as vanilla radios do. Headphones or earbuds in a carried radio keep it private: strictly 2D, no zombie draw.
- Radios placed in a building with power stop draining their battery, which they still need to switch on. The battery carries on in an outage. Carried and outdoor radios drain as in vanilla.
Sandbox options
| Option | Default | Effect |
|---|---|---|
EnableCassette | On | Off removes the black radio’s slot and makes cassettes inert. |
EnableVinyl | On | Off makes vinyl and record players do nothing. CDs are always on. |
CassetteFullControls | Off | Gives cassettes the full transport row. |
VinylFullControls | Off | Gives vinyl the full transport row. |
BuildingPower | On | Placed radios in powered buildings stop draining their battery. Applies to all placed radios, not only Player media. |
RangeMultiplier | 2.0 | 1 to 5. How much farther Player media is heard from placed and floor radios than the radio’s normal range. Zombie attraction scales with it. Set by the server in multiplayer. |
IndoorMuffle | Off | Off, between buildings, or between buildings and rooms. Closed doors, closed windows and walls each hold back part of the sound, and open doors and broken windows hold back nothing. |
LootRate | 50 | 0 to 100 percent. Chance that each Player CD or cassette the game spawns in a container is kept. |
LootMaxPerContainer | 1 | 1 to 10. A container never holds more Player CDs and cassettes than this. |
DebugLog | Off | Writes diagnostic lines to the console log. |
Loot
Player’s items are added to the places vanilla CDs spawn, and the Record Player to the places red radios spawn. Each format shares one vanilla CD’s spawn weight among its albums, then the two loot options above thin it out.
For pack makers
A content pack is an ordinary mod that registers formats and albums with Player (registry contract version 1). Player registers its own three formats this way:
AudioBoxPlayer.Registry.registerFormat({
version = 1,
id = "player.cassette",
name = "Cassette",
playsOn = { "Base.RadioBlack" },
option = "EnableCassette",
lootLike = "Disc_Retail",
basicControls = "CassetteFullControls",
scrub = true,
})
- Format:
version,id,name,playsOn(device full types), and optionallyoption(a sandbox boolean that switches it off),lootLike(a vanilla item whose spawn entries it mirrors),basicControls(a sandbox boolean name) andscrub(allows fast forward and rewind). - Album, with
AudioBoxPlayer.Registry.registerAlbum:version,id,modId,title,artist,cover,tracks(each withfileandtitle), anditems, a table from format id to item full type.
Album ids must be unique across every installed pack. AudioBox Deck writes all of this for you.
Multiplayer
Credits
The cassette model is taken from “Sony Walkman Professional WM-D6C” (skfb.ly/pyoqt) by Nedotyopa, licensed under Creative Commons Attribution 4.0. Only the cassette tape was isolated for the mod.
The Record Player’s model and texture are modified assets from True Music by iBrRus: the model was rebuilt for an on state and an off state, and the texture was modified.
AudioBox Extras
Optional additions built on AudioBox. It requires AudioBox Player and the AudioBox Agent (which ships with Player). Player does not need Extras. New content is added to it over time.
Audio cable and speakers
- Audio Cable: a craftable item (Electrical category, Electricity 1). It needs pliers, one copper scrap and one duct tape. Snips turn a cable back into copper scrap. Twelve cables bundle into an Audio Cable Bundle, and a bundle unbundles into twelve.
- Channels: right-click a cable in the inventory and choose Set Cable Channel, from 1 to 4. Set the channel before using the cable.
- Audio Link slot: appears in the radio window of radios that play Player media. Drag a cable in. Vehicle radios and TVs do not get the slot.
- Speakers: a speaker cabinet (the two speaker tiles, or any tile whose name contains “speaker”) takes a cable in its own window. While a radio holding a cable of the same channel is playing, the speaker plays that audio too, as long as it is within range and the radio is not a vehicle radio or on headphones.
- Each speaker has its own volume control and shows Playing or Idle. Stand next to it to open the window. Speakers draw zombies like radios do.
- Audio is not sent through the cable: the speaker opens its own stream of the same album and track, and keeps it in step with the radio by nudging the pitch and seeking when it drifts far.
Jukebox
The Oldies Jukebox plays AudioBox Player vinyl albums. It holds up to 10 records, has its own volume, a sound range of 20 tiles (the distance over which the music fades out), and needs power: a generator, or the grid inside a room. Its play modes are standard, loop album, shuffle within the record, and all records in the jukebox. When the jukebox is on, the vanilla jukebox’s looping skip sound is silenced.
Sandbox options
| Option | Default | Effect |
|---|---|---|
EnableAudioCable | On | Off disables cables and the Audio Link slot, and speakers stay plain furniture. |
SpeakerLinkRange | 20 | 5 to 100 tiles between a radio and a speaker on the same channel. Counted on the ground plane only, so floors add no distance. 20 is the generator’s range. |
EnableJukebox | On | Off leaves the jukebox as plain furniture. On also silences the vanilla jukebox skip sound. |
SilenceJukeboxSound | Off | Silences the skip sound by itself when the jukebox is off. |
DebugLog | Off | Writes diagnostic lines to the console log. |
AudioBox Deck
A visual editor for AudioBox Player content packs. No Lua, no item scripts, no folder juggling. Everything it needs, including the audio converter, is inside one jar.
Run it
Needs Java 17 or newer (free); the launcher opens the download page if it is missing. Double-click the launcher for your system: Run AudioBox Deck.bat on Windows, Run AudioBox Deck.command on macOS (first time: right-click, Open), run.sh on Linux. Tested on Windows and Linux; the macOS build is included but has not been run yet.
Make a pack
- Fill in Pack settings: name, Mod ID (made from the name), description, optional icon and poster. Without artwork, it is made from your first cover.
- Drag an album folder into the window, or use + From folder. Title, artist, track order and titles, lengths and the cover (
cover.jpg,folder.pngand so on) are read from the files. Tags come from OGG (Vorbis and Opus) and MP3 (ID3v2); anything else falls back to the file name. With no cover image in the folder, art embedded in OGG, MP3 or FLAC tags is used. - Optionally press Look up on MusicBrainz to fetch the official title, artist, track titles and front cover. You pick the release and tick what to take; nothing changes until you press Apply.
- Rename, reorder or remove tracks, change the cover, and pick CD, Cassette and Vinyl.
- Check the Checks panel. Red problems block export; amber ones are advice.
- Press Export pack and choose your
Zomboid/modsfolder.
File, Open existing pack folder loads a finished pack for editing. Save project keeps unfinished work as a .abpack file.
What it writes
<ModId>/mod.info, icon.png, poster.png (also inside 42/)
<ModId>/42/media/lua/shared/<ModId>/Register.lua
<ModId>/42/media/scripts/<ModId>_Items.txt
<ModId>/common/audio/<album-folder>/01-Track-Title.ogg, cover.jpg
Album id is artist.title in lower case, the item is TitleCD, TitleCassette or TitleVinyl, and the folder is a slug of the title. Colliding titles get unique names. Re-exporting skips unchanged audio and never deletes anything. Album ids must be unique across installed packs, so the Mod ID and artist and title matter. Nothing Deck writes into a pack mentions Deck.
Local copy or Workshop folder
- Local copy: for your own game or server. MP3, OGG and FLAC are copied as they are. Opus and any other format the game cannot play is converted to MP3.
- Workshop upload folder: the layout the game’s uploader expects (
workshop.txt,preview.png,Contents/mods/<ModId>/). OGG and MP3 are kept; FLAC and WAV are converted to MP3 (LAME, about 190 kbps) to keep Workshop items small.workshop.txtis written withvisibility=private. Leave “Existing item ID” empty for a new item, or paste an ID to update one you uploaded.
About visibility. Packs are exported as private so that new content packs do not flood the Workshop. Deck cannot force you to keep it that way, and you can change the setting in workshop.txt or on the Workshop page. It would be greatly appreciated if you left your pack unlisted instead of public, and posted the link to it in the AudioBox discussion topic on the Steam Workshop.
Audio the game cannot play
The game’s sound engine cannot play Opus, so Deck converts it. Online converters often repackage Opus as .ogg, .mp3 or .wav, so Deck judges every track by what is inside the file, never by its name. Anything that is not Ogg Vorbis or MP3 (Opus, AAC, Speex, FLAC inside Ogg, compressed audio in a WAV) is converted to MP3 on export in both modes, and the Checks panel names each such track. A real MP3 or Vorbis file with the wrong extension is kept and filed under its true one.
Built-in converter
The jar contains unmodified LGPL builds of FFmpeg 8.1.2 for Windows, Linux and macOS (Intel and Apple silicon), from the JavaCPP Presets project. The first time it is needed, the copy for your system is unpacked to ~/.audiobox-pack-builder/ffmpeg and run as a separate program. It also supplies track lengths for MP3, WAV and FLAC, and lets Deck read WebP and other unusual cover images. If it cannot start, everything else still works and only conversion is off. To use your own ffmpeg, set ABPB_FFMPEG to its path.
Item art
An album with a cover gets its own look in the game. For each ticked format, Deck places the cover (its middle square) into a template to make a 32x32 inventory icon and a world-model texture. Cassettes can be tinted under Cassette colour; black is the standard. CD and vinyl are not tinted. Deck ships no models: each item reuses Player’s mesh with the album’s own texture. Untick Make icons and textures from the cover on an album to keep Player’s own look. A preview under the album form shows what will be made.
MusicBrainz lookup
The only part of Deck that uses the internet, and only when you press the button. It sends the album’s title and artist to musicbrainz.org and asks coverartarchive.org for the front cover, at one request per second as MusicBrainz requires. MusicBrainz data is public domain (CC0); cover images belong to their rights holders, so keep only ones you have the right to ship.
If a lookup fails, press the button again. Deck only connects to the internet for the length of a lookup, and the connection can time out early.
Cancelling
Anything slow shows a progress overlay with a Cancel button (or press Esc). Cancelling an import, an open or a lookup throws away what was read so far. Cancelling or failing an export is safe too: audio and covers are copied first, each under a temporary name, and mod.info, Register.lua and the item script are written last in one quick step, so a stopped export never leaves a mod that lists missing audio. A folder the export started is removed again, and an existing pack keeps its three files exactly as they were.
Languages
Deck follows your system language and can be switched from the Language menu. English, German, French, Russian and Chinese are built in. To add or improve a language, put a file named with the game’s own language code (DE.properties, PTBR.properties and so on) in an i18n folder next to the jar; TRANSLATING.md in the Deck folder explains the format. Chinese, Japanese, Korean and Thai need a suitable system font. Text without a translation shows in English.