Soundscapes Guide: Ambient Sound for GMod Maps in Hammer
How Source soundscapes work: env_soundscape, proxy and trigger, a script per map, packing it into the BSP and fixes when the map stays silent.
A soundscape is a named entry in a script file that describes a background mix: looping sounds, random one-shots and a reverb effect. In the map you place one env_soundscape per area and enter the name. The engine decides for each player separately which entity currently applies and crossfades when it changes. You write your own soundscapes into the file scripts/soundscapes_<mapname>.txt and pack it into the BSP together with its sounds.
How a soundscape works
The work is split. The server checks for each player which soundscape entity is active and tells the client. The client reads the entry from the script and plays the sounds locally. This means:
- Server and client need the same script. If one side does not know the name, there is silence.
- On a change, loops are crossfaded. The duration is set by
soundscape_fadetime, which is 3 seconds in the Source SDK.
Placing the entities: env_soundscape, proxy and trigger
| Entity | Purpose | Important keyvalues |
|---|---|---|
env_soundscape | Point entity that becomes active through radius and line of sight | Radius (radius, default 128), Soundscape (soundscape), Sound Position 0 to 7 (position0 to position7) |
env_soundscape_proxy | Own location and radius, takes soundscape and positions from another entity | Soundscape Entity (MainSoundscapeName), Radius (radius) |
env_soundscape_triggerable | Like env_soundscape, and additionally switched by a trigger_soundscape | Same as env_soundscape |
trigger_soundscape | Brush trigger that turns on the named entity when entered | Soundscape (soundscape): name of an env_soundscape_triggerable |
The selection rule is stated in the FGD: the active soundscape is the last one that had line of sight to the player while the player was within its radius. The Source SDK source code shows the details:
- Line of sight is checked from the entity to the player. Solid geometry and water block it.
- If several entities meet both conditions, the nearest one wins.
- If none meets the conditions any more, the last one keeps playing.
- A radius of
-1means: line of sight is enough, distance does not matter.
So place the entity in open space and choose a radius that does not reach through doors into the next room. The spawn points need a soundscape too, otherwise players hear nothing until they reach the first entity. For rooms with corners, place several env_soundscape_proxy entities that point to the same main entity. Where line of sight does not match the room layout, for example with glass walls or open courtyards, use trigger_soundscape. According to the Valve Developer Community, an entity that reaches the player through radius and line of sight takes precedence over the trigger, and the env_soundscape_triggerable itself still reacts to radius and line of sight. So place it where players do not come within its radius.
Using existing soundscapes
Which scripts are loaded is listed in scripts/soundscapes_manifest.txt. GMod's manifest lists its own entries such as construct.outside as well as the scripts from Half-Life 2, the episodes, Portal, Counter-Strike: Source, Day of Defeat: Source and Team Fortress 2. The dropdown in the entity only shows a few entries such as GenericIndoor, but you can type any name.
A name in the manifest does not mean the sounds are there. On a current installation, the packages GMod itself ships contain almost all sound files used by the scripts from Half-Life 2, the episodes and Counter-Strike: Source, but only a small part of those from Team Fortress 2 and Day of Defeat: Source. More on this in CS:S and HL2 content in GMod maps.
To audition one, enter sv_cheats 1 in the console and then playsoundscape with a name.
Writing your own script
Create the file scripts/soundscapes_<mapname>.txt, where <mapname> is the name of the BSP without the extension. The engine loads it in addition to the manifest as soon as it exists. Leave the manifest itself untouched. If you rename the map, rename the file with it.
"mymap.hall"
{
"dsp" "1"
"playlooping"
{
"volume" "0.4"
"wave" "ambient/atmosphere/indoor2.wav"
}
"playlooping"
{
"volume" "0.6"
"soundlevel" "SNDLVL_70dB"
"position" "0"
"wave" "yourname/mymap/generator_loop.wav"
}
"playrandom"
{
"time" "8,20"
"volume" "0.3,0.6"
"pitch" "90,110"
"soundlevel" "SNDLVL_75dB"
"position" "random"
"rndwave"
{
"wave" "ambient/levels/canals/drip1.wav"
"wave" "ambient/levels/canals/drip2.wav"
}
}
}
- Name: Soundscape names are shared across all loaded files. A prefix such as
mymap.prevents collisions. dsp: the reverb effect of the area. In the stock scripts,0stands for off and1for the automatic choice.playlooping: a continuous loop. The path given forwaveis relative to thesound/folder. Always statevolume: in the Source SDK code the initial value is 0, and a loop with volume 0 is skipped.playrandom: plays one of the sounds fromrndwaveat random intervals.time,volumeandpitchare ranges written asminimum,maximum,timein seconds.position: Without it, the sound comes evenly from everywhere. The number0refers to the keyvalue Sound Position 0 of the entity, where you enter the name of a target entity, for example aninfo_targetat the generator.randomonly works inplayrandomand places the sound at a different spot near the player each time. A positioned sound inplayrandomalso needssoundlevelorattenuation: in the Source SDK code the level otherwise stays at 0 and the sound plays without falloff, as if it had no position.
Packing the script and sounds into the BSP
Server and players need the script and every custom sound file. As a loose file in a Workshop addon the script does not come along: gmad's whitelist allows only scripts/vehicles/*.txt in the scripts/ folder. The usual way is therefore the map's pakfile. The procedure is described in Pack custom content into a BSP. Two points are specific to soundscapes:
- Sounds that only appear in the script are not referenced anywhere in the map itself. Check the list of an automatic packer by hand for that reason.
- For
playloopingyou need a WAV with a loop marker (cue point), as the stock loops have. Source recognises a loop only by this marker, without it the WAV plays once.
Whether script and sounds have arrived in the pakfile is shown by bspzip -dir or by the Map Scanner, which lists the embedded files.
When ambient_generic fits better
| Soundscape | ambient_generic | |
|---|---|---|
| Meant for | the base mood of an area | a single sound source |
| Control | automatic, by the player's location | through inputs such as PlaySound, StopSound, Volume, FadeIn, FadeOut |
| Who hears it | every player their own mix | all players in range the same |
Use ambient_generic for everything the map is supposed to switch: a machine with an off switch, an alarm, music at the press of a button. According to the FGD, the flags "Start Silent" and "Is NOT Looped" are set on a new entity. It therefore stays silent until an output fires PlaySound. How to wire that up is covered in Hammer inputs and outputs.
Typical problems
- Silence everywhere: Usually the name is wrong, or the file is not named like the map. With
developer 1the console reportsCan't find soundscape: <name>. According to the Valve Developer Community, soundscapes also need a map compiled with VVIS, at least with-fast. - The soundscape does not switch, or switches in the wrong place: The new entity has no line of sight, its radius is too small, or a nearer entity sees into the room through a door.
soundscape_debug 1draws lines to all entities: green for the active one, white for entities in range, red for entities out of range. - Other players are missing sounds: The script or sound files are not packed, or the soundscape uses sounds from a game the players do not have. Test the packed map without your loose files.
- Changes to the script have no effect:
soundscape_flushreloads the scripts without restarting the map.
sv_cheats 1
soundscape_debug 1
playsoundscape mymap.hall
stopsoundscape
soundscape_flush
Commands two to four need sv_cheats 1. The server accepts soundscape_flush only from its own console or from the host of a local server, and in the Source SDK the client-side part it triggers (cl_soundscape_flush) is a cheat command as well.
FAQ
Do all players hear the same soundscape?
No. The active soundscape is determined for each player separately and played on their client. Everyone hears the mix of their own location.
What do the numbers for dsp mean?
Each number stands for a reverb preset. The comments in Valve's own script list, besides 0 (off) and 1 (generic), among others 2 to 4 for metal rooms, 5 to 7 for tunnels, 17 to 19 for concrete rooms and 23 to 25 for caverns, each as small, medium and large, plus 14 to 16 for water.
Do I have to edit soundscapes_manifest.txt?
No. The engine loads a file named scripts/soundscapes_<mapname>.txt by itself, in addition to everything listed in the manifest. The manifest applies to all maps and stays unchanged.