Use when: sonido DayZ, CfgSoundShaders, SoundSet, sound not playing, no sound on dedicated server, PlaySoundSet, NoiseSystem, bunker radio, HEAVY_BREATHING, GetEnvironmentNoiseReduction, IsHeadlessOrDedicatedServer, sandstorm noise, VegetationSounds. Audio is client-only. Not particles: dayz-particles; not UI: dayz-ui-development.
Installs into .claude/skills of the current project.
Are you the author of Dayz Sound System?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/willy92wins-dayz-sound-system)
---
name: dayz-sound-system
description: "Use when: sonido DayZ, CfgSoundShaders, SoundSet, sound not playing, no sound on dedicated server, PlaySoundSet, NoiseSystem, bunker radio, HEAVY_BREATHING, GetEnvironmentNoiseReduction, IsHeadlessOrDedicatedServer, sandstorm noise, VegetationSounds. Audio is client-only. Not particles: dayz-particles; not UI: dayz-ui-development."
---
# DayZ Sound System (Enforce Script + config)
Verified reference for mod audio. Citations are `path:line` against vanilla v1.24 decompiled scripts
(±3 drift) and two real mods used as prior art (IMPWMODPart2 weapons, DoorLockSystem). The full
deep-dive with every signature lives in `references/sonido-deep-dive.md` — load it for AbstractWave
events, DynamicMusicPlayer internals, or PlayerSoundManager handlers. 1.30 Exp cites:
`references/dayz-1-30-sound.md`.
## The one rule that explains most bugs
**Audio is client-only.** `SEffectManager.Init()` runs only on clients (`3_game/effectmanager.c:498-512`)
and `Object.PlaySoundSet` is guarded by `if (g_Game && !g_Game.IsDedicatedServer())`
(`3_game/entities/object.c:1245`). Any `Play*` call on a dedicated server is a silent no-op.
To make a sound happen "from the server", you synchronize a state change and let each client play it:
the official vehicle for that is `StartItemSoundServer` (below), or your own SyncVar +
`OnVariablesSynchronized`.
(hasta 1.29 / still on `Object.PlaySoundSet` in 1.30: the guard is `object.c:1249` —
`if ( g_Game && !g_Game.IsDedicatedServer() )`.)
(desde 1.30 Exp: item/player sound **handlers** use `g_Game.IsHeadlessOrDedicatedServer()` so headless
clients are skipped too — `ItemSoundHandler.c:121`, `PlayerSoundManager.c:105`,
`DayZPlayerCfgSounds.c:335`. Proto: `Game.c:1132-1136`. `[EXACT]`: `references/dayz-1-30-sound.md`.)
## Decision table — which API when
| Situation | Use |
|---|---|
| One-shot 3D sound at a position (client code) | `SEffectManager.PlaySound("Set", pos)` (`effectmanager.c:169+`) |
| Sound that follows an object (client code) | `SEffectManager.PlaySoundOnObject("Set", obj)` or `obj.PlaySoundSet(snd, "Set", fadeIn, fadeOut, loop)` (`object.c:1243-1321`) |
| Server-driven item sound, synced to all clients | `StartItemSoundServer(id)` / `StopItemSoundServer(id)` (`4_world/entities/itembase.c:4468-4508`) |
| Sound at a memory point of the model | `PlaySoundSetAtMemoryPoint(...)` (`object.c:1293+`) |
| Animation-bound audio (footsteps, gestures) | AnimEvents in the anim config — engine plays them client-side automatically |
| Building door/alarm | `building.PlaySound/PlaySoundLoop` (native on Building; prior art DoorLockSystem `ActionUnlockDLSDoor.c:63,73`) |
| Make AI/infected hear something | `g_Game.GetNoiseSystem().AddNoise/AddNoisePos/AddNoiseTarget` (`3_game/noise.c:1-23`) — server side |
| Ambient music zone | `DynamicMusicPlayer.RegisterDynamicLocation` (`dynamicmusicplayer.c:289`) |
| (since 1.30 Exp) Per-world static music boxes | Subclass `DynamicMusicPlayerRegistry` and `RegisterTrackLocationStaticMultiRectangle` (`DynamicMusicPlayerRegistryNasdara.c:39-67`, wired `missionBase.c:130-132`) |
| (since 1.30 Exp) Radio tuned to bunker frequency | Set `SOUND_BUNKER_STATIC_NOISE` on the transmitter; `IsTunedToBunkerFrequency()` (`TransmitterBase.c:6,135-137`, proto on `ItemTransmitter` in `InventoryItem.c:25`) |
| (since 1.30 Exp) Per-bush / static vegetation footsteps | `CfgNonAIVehicles <class> VegetationSounds` via `StaticObjectType` (`StaticObjectType.c:13-47`); macro `CUSTOM_PLAYER_MOVEMENT_SOUNDSETS` (`basicDefines.hpp:310-338`) |
Cleanup matters: every `SEffectManager.Play*` registers a ref; call `SEffectManager.DestroyEffect(eff)`
or set autodestroy, or you leak (`effectmanager.c:41-44`).
## Config: CfgSoundShaders + CfgSoundSets
Files: `.ogg` (universal in mods) or `.wav`; referenced **without extension**, path relative to the
mod root (real example: `samples[] = {{"IMPWMODPart2\Weapons\Automatic\Sounds\Rifle1Mid", 1}}`).
```cpp
// config.cpp — minimal working pair (pattern from real mod, IMPWMODPart2 ...\Sounds\config.cpp:27-36)
class CfgSoundShaders
{
class MyMod_Roll_SoundShader
{
samples[] = {{"MyMod\Sounds\roll_loop", 1}}; // {path-no-extension, random weight}
volume = 1.0;
range = 40; // meters
rangeCurve[] = {{0, 1}, {20, 0.8}, {40, 0}}; // inline attenuation curve
// or: rangeCurve = "closeShotCurve"; // reference a vanilla CfgSoundCurves name
};
};
class CfgSoundSets
{
class MyMod_Roll_SoundSet
{
soundShaders[] = {"MyMod_Roll_SoundShader"};
};
};
```
Cleaner for variants: inherit a vanilla base via forward declaration (real example,
`IMPWMODPart2\Weapons\Automatic\F2000\Sounds\config.cpp:22-45`):
```cpp
class base_closeShot_SoundShader; // forward-declare vanilla base
class My_closeShot_SoundShader : base_closeShot_SoundShader
{
samples[] = {{"MyMod\Sounds\my_close", 1}};
volume = 0.8;
};
class CfgSoundSets
{
class Rifle_Shot_Base_SoundSet; // forward-declare vanilla base
class My_Shot_SoundSet : Rifle_Shot_Base_SoundSet
{
soundShaders[] = {"My_closeShot_SoundShader", "My_midShot_SoundShader", "My_distShot_SoundShader"};
};
};
```
Extra SoundSet properties (`sound3DProcessingType`, `volumeCurve`, `spatial`) exist on vanilla bases
but were not verifiable in local source — inherit a vanilla set rather than hand-rolling them.
## Script API core (`3_game/sound.c`, `3_game/effects/effectsound.c`)
- `SoundParams("SetName")` → validates/loads a SoundSet (:137-144).
- `SoundObjectBuilder(params)` → `AddEnvSoundVariables(pos)` / `AddVariable(name, val)` →
`BuildSoundObject()` (:82-108).
- `SoundObject.SetParent(entity)` / `SetPosition(pos)` / `SetKind(WaveKind.X)` (:111-134).
- Play: `g_Game.GetSoundScene().Play3D(so, sob)` / `Play2D(...)` (:53-79; access `game.c:734`).
- `AbstractWave` handle: `Play/Stop/Loop(bool)/SetVolumeRelative(0..1)/SetFadeInFactor/
SetFadeOutFactor/SetDoppler/GetLength/GetCurrPosition` + `GetEvents()` ScriptInvokers
(Started/Stopped/Loaded/HeaderLoaded/Ended) (:146-230).
- `EffectSound` (high-level wrapper): `SetSoundSet/SetSoundLoop/SetSoundFadeIn/Out/SetSoundVolume/
SoundPlay/SoundStop/IsSoundPlaying` + its own invokers — what `PlaySoundSet` returns.
(desde 1.30 Exp: if `m_SoundFadeInDuration > 0`, `Event_OnSoundWaveStarted` calls `SetSoundVolume(0)`
so the first frame is silent — `EffectSound.c:549-555`. `[EXACT]`: `references/dayz-1-30-sound.md`.)
- `WaveKind` enum: WAVEEFFECT, WAVEEFFECTEX, WAVESPEECH, WAVEMUSIC, WAVEENVIRONMENT, WAVEWEAPONS,
WAVEATTALWAYS, WAVEUI... (:1-14) — controls mixer category (and thus user volume sliders).
- Global category volumes only: `AbstractSoundScene.SetSoundVolume(vol, time)/SetMusicVolume/...`
(:64-75) — there is no per-instance "master volume" beyond `SetVolumeRelative`.
## Server→client item sound (the official pattern)
1. Register sets in `InitItemSounds()` (`itembase.c:4448-4465`):
```c
override void InitItemSounds()
{
super.InitItemSounds();
ItemSoundHandler handler = GetItemSoundHandler();
handler.AddSound(SoundConstants.ITEM_DEPLOY, "MyMod_Deploy_SoundSet");
SoundParameters params = new SoundParameters();
params.m_Loop = true;
handler.AddSound(SoundConstants.ITEM_DEPLOY_LOOP, "MyMod_Loop_SoundSet", params);
}
```
2. Fire from server: `StartItemSoundServer(SoundConstants.ITEM_DEPLOY)` /
`StopItemSoundServer(SoundConstants.ITEM_DEPLOY_LOOP)` (`itembase.c:4468-4508`).
3. Client side is automatic: `OnVariablesSynchronized` dispatches `m_SoundSyncPlay/m_SoundSyncStop`
to `PlayItemSoundClient/StopItemSoundClient` (`itembase.c:3319-3332`).
Limits: int IDs up to `ITEM_SOUNDS_MAX = 63` (`3_game/constants.c:415-435`); only ONE play + ONE stop
can be in flight per sync tick by design (`4_world/classes/soundhandlers/itemsoundhandler.c:19-20`) —
sync vars are cleared ~100 ms later via CallLater.
For non-item state sounds, the generic pattern is the same: server sets a SyncVar → client plays in
`OnVariablesSynchronized` (remote clients never see one-frame server states otherwise).
## NoiseSystem (AI hearing)
```c
// 3_game/noise.c:1-23 — server side
g_Game.GetNoiseSystem().AddNoise(entity, noiseParams, multiplier); // at entity
g_Game.GetNoiseSystem().AddNoisePos(entity, pos, noiseParams, mult); // at position
g_Game.GetNoiseSystem().AddNoiseTarget(pos, lifetimeSec, noiseParams); // positional DECOY with duration
NoiseParams np = new NoiseParams(); np.Load("name_in_CfgNoises"); // or LoadFromPath
```
(hasta 1.29: Rain/wind reduce effective noise via `NoiseAIEvaluate.GetNoiseReduction(g_Game.GetWeather())`
(used by player steps, `4_world/entities/dayzplayerimplement.c:3204-3208`).)
(desde 1.30 Exp: climate is native. Query `GetGame().GetNoiseSystem().GetEnvironmentNoiseReduction(pos)`
— `exp\scripts\scripts\3_Game\Noise.c:13`. `GetNoiseReduction` / `GetNoiseReductionByWeather` are
`[Obsolete]` (`SensesAIEvaluate.c:92`, `Weather.c:454`). Player steps pass only
`NoiseAIEvaluate.GetNoiseMultiplier(this)` (`DayZPlayerImplement.c:3472-3474`). Infected
`AddNoise(this, sound_event.m_NoiseParams)` has no weather multiplier (`ZombieBase.c:597-600`).
Tune rain/snow/fog/wind/sandstorm in `class AIParams` (`exp\dz\DZ\data\aiconfigs\config.cpp:19-27`).
Do not also multiply `AddNoise` by a script weather factor — native attenuation would double-dampen.)
Weapon shots define
`class NoiseShoot { strength = 82; type = "shot"; }` in the weapon config (real example
`IMPWMODPart2\Weapons\Automatic\MCXSpear\config.cpp:73-77`). `AddNoiseTarget` is the tool for
distraction devices: infected investigate a position that has no entity.
## Environment sound controllers
`SetSoundControllerOverride(name, value, action)` / `MuteAllSoundControllers()` /
`ResetAllSoundControllers()` (`3_game/sound.c:38-48`). Controller names (from the proto docs): rain,
night, meadow, trees, hills, houses, windy, deadBody, sea, forest, altitudeGround, altitudeSea,
daytime, shooting, coast, waterDepth, overcast, fog, snowfall, caveSmall, caveBig.
## What does NOT exist / classic confabulations
| Confabulation | Reality |
|---|---|
| `SEffectManager` works on server | Client-only; `InitServer()` exists for particles, not sound (`effectmanager.c:498-512`) |
| `PlaySoundSet` audible on dedicated server | Guarded no-op (`object.c:1245`) — sync state instead |
| `GetGame().CreateSoundOnObject(...)` returns EffectSound | Returns `SoundOnVehicle` entity (`game.c:691`; class `3_game/entities/soundonvehicle.c:1-4`) — legacy, prefer SEffectManager |
| `DynamicMusicPlayer.PlayTrack("...")` | Private; public API is `SetCategory(...)` + `RegisterDynamicLocation` (`dynamicmusicplayer.c:511,289`) |
| `OnSoundEvent` override on ItemBase | Does not exist — use ItemSoundHandler or PlaySoundSet manually |
| Several simultaneous synced sounds via StartItemSoundServer | One play + one stop per sync by protocol (`itemsoundhandler.c:19-20`) |
| Per-sound master volume API | Only `SetVolumeRelative(0..1)` per wave; shader `volume` is fixed config |
| samples[] with file extension | Engine infers `.ogg` — paths go extension-less (all prior-art configs) |
(desde 1.30 Exp: the `PlaySoundSet` row above is still true for `Object.PlaySoundSet`. Item/player
**handlers** additionally skip headless via `IsHeadlessOrDedicatedServer()`. Do not write
`GetNoiseReductionByWeather()` into new mods — `[Obsolete]`; use `GetEnvironmentNoiseReduction(pos)`
or `AIParams`.)
## Recipes
**A. Local loop tied to movement (e.g. rolling object) — pure client**
```c
EffectSound m_RollSound;
void UpdateRollAudio() // call from client-side update
{
bool moving = GetVelocity(this).Length() > 0.5;
if (moving && !m_RollSound)
PlaySoundSet(m_RollSound, "MyMod_Roll_SoundSet", 0.1, 0.5, true); // loop
else if (!moving && m_RollSound)
StopSoundSet(m_RollSound); // respects fade-out
}
```
Position is already replicated to clients, so no server involvement is needed for the audio itself.
**B. Server-triggered impact sound** — register a set in `InitItemSounds()`, call
`StartItemSoundServer(id)` from the server event (e.g. `EOnContact`), done.
**C. Distraction noise (server)**
```c
NoiseParams np = new NoiseParams();
np.Load("FlareLight"); // any CfgNoises entry; verify name in config dump
g_Game.GetNoiseSystem().AddNoiseTarget(pos, 30, np, 2.0);
```
(desde 1.30 Exp: do not multiply that `2.0` by a weather reduction you computed in script.)
**D. Music zone** — `RegisterDynamicLocation(this, locationType, radius)` on spawn,
`UnregisterDynamicLocation(this)` on delete; track = SoundSet with `WaveKind.WAVEMUSIC`.
(desde 1.30 Exp: a custom world should also subclass `DynamicMusicPlayerRegistry` like
`DynamicMusicPlayerRegistryNasdara` and construct it from `missionBase` world switch.)
## Cross-skill pointers
- `enforce-script-reference` — SyncVars/OnVariablesSynchronized mechanics, CfgSoundSets params table
(Llama extraction section), config.cpp rules.
- `dayz-physics-engine` — contact events that typically drive impact sounds.
- `dayz-particles` — SEffectManager also owns particles; same lifecycle/leak rules.
- `dayz-ai-patterns` — how the eAI/infected consume NoiseSystem events.
## DayZ 1.30 Exp (build 1.30.164014)
What changes, what breaks, and the migration checklist. `[EXACT]` blocks: `references/dayz-1-30-sound.md`.
Deep-dive updates: `references/sonido-deep-dive.md`. Shared AI noise: skill `dayz-ai-patterns` (its 1.30 noise section).
**What changes**
- Native noise attenuation + `GetEnvironmentNoiseReduction(pos)`; `AIParams` adds snow/fog/wind/sandstorm multipliers.
- `IsHeadlessOrDedicatedServer()` on item/player sound paths. `Object.PlaySoundSet` still uses `IsDedicatedServer()`.
- `EffectSound` zeros volume at wave start when fade-in is set.
- `EPlayerSoundEventID.HEAVY_BREATHING` / `HeavyBreathEvent1` (anim 907); silicosis requests it.
- Per-world `DynamicMusicPlayerRegistry*` + `DynamicMusicPlayerTimeOfDay.Translate` (MORNING/NOON/AFTERNOON→DAY, EVENING→NIGHT).
- Transmitters: `SOUND_BUNKER_STATIC_NOISE` / `IsTunedToBunkerFrequency()`.
- `StaticObjectType` + `CUSTOM_PLAYER_MOVEMENT_SOUNDSETS` for vegetation step sounds (digest H).
- `[CHANGELOG]` `SoundHitType` / `GetSoundHitType()` (T189758): **not** present in Enforce `SurfaceInfo.c` on this build (digest K). Do not call them.
**What breaks for a 1.29 audio / stealth mod**
1. `[Obsolete]` on `GetNoiseReductionByWeather` / `NoiseAIEvaluate.GetNoiseReduction`.
2. Double-damp if you still pass a weather multiplier into `AddNoise`.
3. Custom radios that ignore bunker frequency never play `bunkerbroadcast_staticnoise_SoundSet`.
4. Subclassing `~InfectedSoundEventBase` to `Stop()` without `if (g_Game)` can crash on shutdown (`SoundEvents.c:12-16`).
5. Looped sounds with fade-in now start at volume 0 — if you relied on the 1.29 first-frame peak, levels will differ.
**Migration checklist**
- [ ] AI-heard factor: `GetEnvironmentNoiseReduction(pos)`; balance via `AIParams`, not script weather math.
- [ ] New client play/stop: `IsHeadlessOrDedicatedServer()`.
- [ ] Custom transmitter: set `SOUND_BUNKER_STATIC_NOISE` and `SetSynchDirty()` on frequency change (vanilla `SetNextFrequency` already does).
- [ ] Custom world music: subclass `DynamicMusicPlayerRegistry`, register boxes with `RegisterTrackLocationStaticMultiRectangle`.
- [ ] Custom bushes: `VegetationSounds` on the `CfgNonAIVehicles` class, or the `CUSTOM_PLAYER_MOVEMENT_SOUNDSETS` macro.
- [ ] Do not call `SurfaceInfo.GetSoundHitType` — not in this Enforce dump.
- [ ] Load `references/sonido-deep-dive.md` for player-event and NoiseSystem signature tables.