[Tutorial] Custom Soundscapes

Ravidge

Grand Vizier
aa
May 14, 2008
1,544
2,818
Custom Soundscapes

What?
Sometimes it can be hard to find an official soundscape that fits your map. So a custom soundscape can be used to create the ambiance you want.

How?
I will write a very simple and short soundscape file. Hopefully it will be enough for you guys to see how easy it is to add a special feeling to any map.

Hold up! What is a Soundscape?!
This soundscape tutorial should help answer any questions about standard soundscapes.

----

Soundscapes are textfiles, meaning they are very lightweight. So it's a great way to make your map a little more unique without increasing the .bsp size!

It's amazing, so let's get started.

The first thing you need to do is create your soundscape file with a proper name and in the correct location.

A map named "ctf_examplemap_a3" must have its soundscape file named "soundscapes_ctf_examplemap_a3.txt".

cp_testmap_b1 -> soundscapes_cp_testmap_b1.txt
plr_tutorial_rc -> soundscapes_plr_tutorial_rc.txt
<yourmapname> -> soundscapes_<yourmapname>.txt

And the .txt goes in the tf/scripts folder. If you can't find it, go ahead and create it.

Nice! Now that all preparations are complete we can start working. Excuse the swedish interface, I hope it won't distract too much! :)
soundscapes_tut1.png

For this map I decided I wanted 2 custom soundscapes, one for outside and one for inside ambiance. It's of course possible to create more if needed.

soundscapes_tut2.png

dsp = Digital Signal Processor. Basically it adds echoes and reverb to playing sounds. Textures already do this automatically depending on their materialtype, and it's not really that important in tf2. I've never used anything but "1" (default behaviour) for my soundscapes. [List of dsp effects (thanks SgtBarlow)]

Let's actually add some sound... finally.
To find what sounds you can use, open the sound browser inside Hammer, it also tells you the file path.
soundscapes_tut3.png

... Let's explain what just happened.
Firstly, I added a "playlooping" rule/function. As expected from the name it will loop any sound endlessly.
Inside the brackets useful keyvalues are found/written.
"volume" is a float value between 0 (silent) and 1 (max volume).
"pitch" is a percentage value. A value of 100 means it will play the sound without any pitch modifications.
"wave" is the file path to the sound played.

This soundscape (example.outside) now plays are very generic outdoors sound. It's not very interesting to listen to. To spice it up a little we can mix in some more looping tracks. (just copy-paste the previous "playlooping" and switch the "wave" path.)
soundscapes_tut4.png

This should be exciting enough for background noise. But I want more birds. But a "playlooping" of a birdsong is very very VERY annoying to listen to, luckily there's another function called "playrandom".

soundscapes_tut5.png

"playrandom" is used for anything that isn't a looping sound.
Here we find some new keyvalues:
"time" is a value in seconds. The time between playing each sound.
"rndwave" is an array of "wave"s. Everytime the "playrandom" fires, it will pick a random sound to play from the ones listed.

You may notice theres 2 values in some of the keyvalues. These are optional intervals increasing the randomness of the sounds. Values are separated with a comma (,).
Between every 10 to 30 seconds it will play a sound. The sound will be between volume .5 to 1 but it will always have normal pitch (of course you can have random pitch too).

Perfect.
Now there is only 1 thing left, sound positions!
Thankfully they are incredibly easy to create. It's just a normal "playrandom" (or "playlooping") like the one we just created but with an extra keyvalue; "position".

soundscapes_tut6.png

"position" can be anything between 0 to 7. You can only have 8 soundpositions for each soundscape.
In my case I can have a maximum of 8 for "example.outside", and 8 for "example.inside". But I think 1 is enough this time.
"attenuation" is a float value between 0 and 1. It determines how fast the sound will fade when moving away from the soundposition.



That is basically all there is to it, now I can use the exact same method to make the "example.inside" soundscape. There are no limit to how many "playlooping" or "playrandom" you can have in a soundscape. Don't get too crazy with the random demoman burp soundpositions though :)

To put the soundscape in the map, just do it as you would with any valve soundscape, just put the name of your custom soundscape in the env_soundscape (for this tutorial it would be example.outside or example.inside).

When fine-tuning the soundscape it's a good idea to have tf2 running and just use console command "soundscape_flush" to reload the soundscape and hear any changes you made.

When packing a soundscape into your bsp remember that the filename must be the same as the map, ALWAYS! Very often I forget to change the version number on the soundscape when updating my maps... very frustrating.
It should be packed in the /scripts folder inside the bsp.

----

I hope this tutorial helps! If I missed something be sure to point it out, ask questions if you don't understand. Good luck!
 
Last edited:

Ravidge

Grand Vizier
aa
May 14, 2008
1,544
2,818
Sound positions are not all that different from ambient_generics.

Say you have a spytech base, and your soundscape has a general underground ambiance. But in the corner you have a few computers and a printer, that should generate some noises.

One solution would be to have ambient_generics either looping a sound, or setting it up to fire via a logic_timer.

But the more elegant and easier solution would be a soundscape position. Setting it up to randomly play one of the many (with random volume and pitch) blip-blop sounds tf2 computers make :)

They are also used to create directional sound. Since the soundscape plays directly to the player (not from the env_soundscape entity), using sound positions to have birdsong actually sound from the trees can give a subtle touch to the atmosphere.
Or croaking frogs from a small pond in the map.

The advantage of soundpositions over ambient_generics is really that it can play more than 1 sound, and then loop them with a random timer.
 

grazr

Old Man Mutant Ninja Turtle
aa
Mar 4, 2008
5,441
3,814
Do the sound positions allow seperate/additional sounds to be played then? I mean, i understand that they do, but.. how is this implemented in the editor?

I've noticed in HL2 that certain soundscapes are connected via positions, this was explained as allowing the sounds to transition between each other more effectively. But my understanding seems to have changed here. Although, the engine has been upgraded twice since.

I'm assuming that an info_target allows the sounds to be cast from said position as opposed to directly for the player as would otherwise be the case?

What i can't seem to grasp is how individual sounds within a soundscape are setup to be played. It sounds like it is a 'position' entry... thing, but then how do you play them all at once from that one source, or only the 'second' alternative sound from the main soundscape.

some in editor screenshots might be helpful of the soundscape entry's and what's actually happening.. i've tried experimenting with the 2fort soundscape manifest but nothing ever seems to work the way i want it. I always end up using basic proxy's and ambient generics. Which seems to also be the case for 2fort's intel rooms, ironicly.

It's probably really basic, infact i'm sure it is.

It's like:

You can have a position that is undifined. This would play the default soundscape and the additional soundscape sounds from the relavent soundscape?

A defined position with a location. The defualt soundscape plays with a directional soundscape from the defined position?

I understand how the entity is supposed to function. What it is capable of doing. But it seems awefully messy and confusing to actually implement its functions because of the names of functions of the entity, and what the actual end results are.

If my questions make any sense?
 
Last edited:

Ravidge

Grand Vizier
aa
May 14, 2008
1,544
2,818
I'm not sure I understand the question completely... but:
A sound position will play its sounds in addition to the main sounds in that soundscape. A position will not cancel out any other sounds in the soundscape.

Let's look at 2fort.
It has this env_soundscape
http://dl.getdropbox.com/u/1281220/ss2.jpg
which at sound position 2 points to
http://dl.getdropbox.com/u/1281220/ss1.jpg

According to soundscapes_2fort.txt
http://dl.getdropbox.com/u/1281220/ss3.png
There should be some engine noise coming from that train.
All the sound files in the blue box will always be heard (non-directional) aslong as the soundscape "2fort.OutdoorPond" is active. The sound position (directional) is only played if you are close enough to the source to hear it.

You can load up 2fort (in-game) to check the end result.
 
Last edited:

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
The sections outside Ravidge's blue box with with "position" indexes (random cow/bird sounds and the two train sounds) will play whenever the soundscape is active, but they are tied to a specific position in 3D space and will have volume falloff (attenuation) with distance from that point. Info_target entities are used in the Soundscape entity properties as the targets for indexes 0,1,2 to designate the 3D coordinates of the sounds, and regardless of how close you are to one of them they won't play unless the soundscape is active.


I've noticed in HL2 that certain soundscapes are connected via positions, this was explained as allowing the sounds to transition between each other more effectively. But my understanding seems to have changed here. Although, the engine has been upgraded twice since.
I'm not sure what you mean, but here's my guesses for two possibilities.

Both soundscapes have a position# pointed to the same info_target:

Suppose you have a long corridor with a 90-degree bend in it, and two soundscapes separated by the bend. At the bend, there's a noisy clacking machine. Both soundscapes could have a position# pointing to the clacky machine, with the same clacky sound defined in both of them.

This means when it crossfades between the two (in the bend) the player doesn't have the strange situation of a machine being silent when he approaches from one direction but noisy when he approaches from another.

One soundscape's position# points to another soundscape.

I'm guessing that it's simply re-using the position information as if it were a plain info_target. This way Soundscape A can have positional "humming" which (as the player progresses) fades into the ambient humming provided by Soundscape B. Thus the Soundscape B's ambient sounds are faded in more naturally, without having to make a bunch of intermediate soundscapes that each have gradually increasing volume. I don't think you can "nest" soundscapes.​

___________________


"Why should I care about soundscape positions when I could use ambient_generic?"

As Ravidge mentioned, they have additional flexibility for looping and random sounds, but there's also occlusion. Here's an example I worked on.

I have a corridor that spirals around a tall hollow column, and at various places inside the column there are motors, splashing water, steam hissing, etc. The corridor, however, needs to be quiet. If it were a real place, there'd be a foot of solid concrete making it quiet.

If I used ambient_generic entities, you'd be able to hear things through walls. So instead there are two soundscapes: One inside the column, one inside the corridor, with the crossover point being the door that separates them. The column's soundscape has several info_target entities linking dripping and humming sounds to particular areas.

No matter how close I get to those spots from the corridor, I can't hear anything since the soundscape is not active. But the instant I step through the doorway, I can start "see" the previously-hidden soundscape and can start to hear all the sounds which were previously "blocked".​
 
Last edited:

SgtBarlow

L1: Registered
Aug 15, 2009
2
7
Just missing the list of DSP effects:

( "dsp" "1" )

DSP Effects
0 : "Normal (off)"
1 : "Generic"
2 : "Metal Small"
3 : "Metal Medium"
4 : "Metal Large"
5 : "Tunnel Small"
6: "Tunnel Medium"
7 : "Tunnel Large"
8 : "Chamber Small"
9 : "Chamber Medium"
10: "Chamber Large"
11: "Bright Small"
12: "Bright Medium"
13: "Bright Large"
14: "Water 1"
15: "Water 2"
16: "Water 3"
17: "Concrete Small"
18: "Concrete Medium"
19: "Concrete Large"
20: "Big 1"
21: "Big 2"
22: "Big 3"
23: "Cavern Small"
24: "Cavern Medium"
25: "Cavern Large"
26: "Weirdo 1"
27: "Weirdo 2"
28: "Weirdo 3"


SOUND LEVELS

ATTN_NONE 0.0f
ATTN_NORM 0.8f 75dB
ATTN_IDLE 2.0f 60dB
ATTN_STATIC 1.25f 66dB
ATTN_RICOCHET 1.5f 65dB
ATTN_GUNFIRE 0.27f 140dB

SNDLVL_50dB = 50, // 3.9
SNDLVL_55dB = 55, // 3.0
SNDLVL_IDLE = 60, // 2.0
SNDLVL_TALKING = 60, // 2.0
SNDLVL_60dB = 60, // 2.0
SNDLVL_65dB = 65, // 1.5
SNDLVL_STATIC = 66, // 1.25
SNDLVL_70dB = 70, // 1.0
SNDLVL_NORM = 75,
SNDLVL_75dB = 75, // 0.8
SNDLVL_80dB = 80, // 0.7
SNDLVL_85dB = 85, // 0.6
SNDLVL_90dB = 90, // 0.5
SNDLVL_95dB = 95,
SNDLVL_100dB = 100, // 0.4
SNDLVL_105dB = 105,
SNDLVL_120dB = 120,
SNDLVL_130dB = 130,
SNDLVL_GUNFIRE = 140, // 0.27
SNDLVL_140dB = 140, // 0.2
SNDLVL_150dB = 150, // 0.2


EXAMPLE:

mymap.smallconc.inside
{

"dsp" "18"


"playlooping"
{
"volume" ".5"
"pitch" "100"
"wave" "ambient/inside.wav"
}

"playlooping"
{
"volume" "1"
"pitch" "100"
"position" "1"
"soundlevel" "SNDLVL_85dB"
"wave" "ambient/factory_outdoor.wav"
}

"playlooping"
{
"volume" "1"
"pitch" "100"
"position" "0"
"soundlevel" "SNDLVL_90dB"
"wave" "ambient/machine_hum.wav"
}
}
 

PL-7764

L6: Sharp Member
Aug 4, 2009
376
84
You might want to mention that positions work with "playlooping" sounds as well as "playrandom." Your tutorial made me question whether it would work since you only mentioned it working with the random sounds, but I tried it and looping sounds work. Good for constant positioned sounds, like steam hissing or water running, that need to be constant or just aren't suited to being played at random intervals.

That's an excellent tutorial, other than that one minor gripe. I'm a sound geek so I really, really like things like this. Thanks a bunch! :)
 

XFunc_CaRteR

L5: Dapper Member
May 14, 2009
248
17
I made a soundscape file, same name as my map, but I can't load it in.

This sentence: "And the .txt goes in the tf/scripts folder. If you can't find it, go ahead and create it" ain't clear enough. Where does it go? There are a lot of folders called "tf" scattered throughout the Steam directory.

Do you mean you have to open up a .gcf file and put it in there?

Also, how do you pack something into the "/scripts folder" inside a .bsp file?
 

Terr

Cranky Coder
aa
Jul 31, 2009
1,590
410
Generally "The TF folder" refers to
Code:
c:\program files\steam\steamapps\STEAMUSERNAME\Team Fortress 2\tf\

You never need to modify GCFs.

BSP files can behave a bit like .zip files, which allow you to pack in a whole hierarchy of embedded "files". One tool for doing this is BSPZIP, which comes with SourceSDK and Hammer.

So you'd take
Code:
c:\program files\steam\steamapps\STEAMUSERNAME\Team Fortress 2\tf\scripts\soundscapes_MAPNAME.txt
and embed it into the BSP file, identified as:
Code:
scripts\soundscapes_MAPNAME.txt
 
Last edited:

XFunc_CaRteR

L5: Dapper Member
May 14, 2009
248
17
Can you vary the volume, pitch, attenuation of sounds that are "playlooping"?

e.g...

"playlooping"
{
"volume" "0.4, 0.6"
"pitch" "80,100"
"attenuation" "80,100"
"wave" "ambient/something.wav"
}


...Something like that?
 

obodobear

L4: Comfortable Member
Mar 15, 2016
172
32
Hey I tried to make a custom soundscape but I don't think I made the file right... is the anything you see wrong with it?
 

Attachments

  • soundscapes_pmd_treasuretown.txt
    138 bytes · Views: 305

worMatty

Repacking Evangelist
aa
Jul 22, 2014
1,257
999
Might be because you misspelled treasure.town.
 

obodobear

L4: Comfortable Member
Mar 15, 2016
172
32
Thanks Matty! that seems to have solved it glad u pointed it out
 

FateFighter

L1: Registered
Dec 26, 2022
32
0
"Nothing.noth"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/nothing.mp3"
}
}

"Disco.numa"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoNuma.mp3"
}
}

"Disco.feeling"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/Discofeeling.mp3"
}
}

"Disco.hurtme"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoHurtme.mp3"
}
}

"Disco.oohehe"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoOohehe.mp3"
}
}

"Disco.rainbow"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoRainbow.mp3"
}
}

"Disco.pyro"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoPyro.mp3"
}
}

"Disco.wright"
{
"dsp" "0"
"playlooping"
{
"volume" "1.0"
"pitch" "100"
"wave" "retromusic/DiscoWright.mp3"
}
}


Képernyőfelvétel (204).png
It doesn't work for me, what did I do wrong?