Difference between revisions of "Soundscripts"
m (→Operator stacks: added "prestart_stack") |
|||
(54 intermediate revisions by 19 users not shown) | |||
Line 1: | Line 1: | ||
− | [[ | + | {{toc-right}} |
− | Soundscripts are | + | '''Soundscripts''' contain "sound entries" that are used to wrap Source-specific playback instructions around WAV or MP3 files. |
+ | |||
+ | A sound entry can define the meaning of a sound to NPCs, its pitch and volume, how far away it can be heard from (attenuation), and can be used to randomise which precise sound file is played. [[#Operator stacks|Operator stacks]] {{since|{{portal2}}}} can be used to define even more complex behaviours. | ||
+ | |||
+ | Soundscripts are loaded ''on the server only'' from: | ||
− | + | *<code>scripts/game_sounds_manifest.txt</code> | |
+ | *<code>maps/<mapname>_level_sounds.txt</code> | ||
− | + | All filepaths within a soundscript are relative to the sound folder. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | ==Example entry== | ||
+ | <pre> | ||
+ | entry.name | ||
+ | { | ||
+ | channel CHAN_AUTO | ||
+ | volume VOL_NORM | ||
+ | pitch PITCH_NORM | ||
+ | soundlevel SNDLVL_NORM | ||
+ | wave common/null.wav | ||
+ | } | ||
+ | </pre> | ||
If a value has a space or tab character within it, wrap it in "quote marks". | If a value has a space or tab character within it, wrap it in "quote marks". | ||
{{tip|To have a random numeric value chosen every time the sound plays, type a lower bound and a higher bound, separated by a comma. Example: <code>volume 0.45,0.65</code>.}} | {{tip|To have a random numeric value chosen every time the sound plays, type a lower bound and a higher bound, separated by a comma. Example: <code>volume 0.45,0.65</code>.}} | ||
− | + | ==Commands== | |
− | + | ===Wave / rndwave=== | |
− | |||
− | |||
− | == Commands == | ||
− | |||
− | ===Wave=== | ||
− | |||
Filename of the sound to play. | Filename of the sound to play. | ||
− | + | <pre> | |
− | + | wave common/blah1.wav | |
− | + | </pre> | |
You can also have the engine pick from a list of random files. A given sound won't repeat until all of the others have played. Note that the random choice is decided by the server, not the client. | You can also have the engine pick from a list of random files. A given sound won't repeat until all of the others have played. Note that the random choice is decided by the server, not the client. | ||
+ | <pre> | ||
+ | rndwave | ||
+ | { | ||
+ | wave common/blah1.wav | ||
+ | wave common/blah2.wav | ||
+ | wave common/blah3.wav | ||
+ | } | ||
+ | </pre> | ||
− | + | {{note|The sound file MUST be in a folder within the <code>sounds</code> folder. So (sound/)folder/sound.wav will work, while (sound/)sound.wav will not.}} | |
− | |||
− | |||
− | |||
− | |||
− | |||
===Volume=== | ===Volume=== | ||
− | |||
A number between 0 and 1, where 1 is the sound's original volume. <code>VOL_NORM</code> will insert your mod's default volume, which will probably be <code>1</code>. | A number between 0 and 1, where 1 is the sound's original volume. <code>VOL_NORM</code> will insert your mod's default volume, which will probably be <code>1</code>. | ||
===Pitch=== | ===Pitch=== | ||
+ | Any number between 0 and 255, where 100 is the sound's original pitch and 255 is very high. | ||
− | + | *PITCH_LOW = 95 | |
− | + | *PITCH_HIGH = 120 | |
− | * PITCH_LOW = 95 | ||
− | * PITCH_HIGH = 120 | ||
===Channel=== | ===Channel=== | ||
− | + | Channels are used to categorize sounds in a way that NPCs, and game logic in general, can understand. | |
− | {{ | + | {{confirm|There is a limit of 256 channels total: 224 Static, 32 Dynamic that can play at any given time.}} |
− | + | :: '' Exceeding this will result in a channel allocation error, preventing sounds from playing. '' | |
;CHAN_AUTO | ;CHAN_AUTO | ||
:Default, generic channel. | :Default, generic channel. | ||
;CHAN_WEAPON | ;CHAN_WEAPON | ||
− | :Player and NPC | + | :Player and NPC weapons. |
;CHAN_VOICE | ;CHAN_VOICE | ||
− | :Voiceover dialogue. | + | :Voiceover dialogue. Used for regular voice lines, etc. |
+ | ;CHAN_VOICE2 | ||
+ | :Additional voice channel. Used in TF2 for the announcer. | ||
;CHAN_ITEM | ;CHAN_ITEM | ||
− | :Generic physics impact sounds, health/suit chargers, | + | :Generic physics impact sounds, health/suit chargers, {{ent|+use}} sounds. |
;CHAN_BODY | ;CHAN_BODY | ||
:Clothing, ragdoll impacts, footsteps, knocking/pounding/punching etc. | :Clothing, ragdoll impacts, footsteps, knocking/pounding/punching etc. | ||
;CHAN_STREAM | ;CHAN_STREAM | ||
− | :Sounds that can be delayed by an async load, i.e. aren't responses to particular events | + | :Sounds that can be delayed by an async load, i.e. aren't responses to particular events. {{confirm|This won't make the sound actually stream; use the * prefix for that.}} |
;CHAN_REPLACE | ;CHAN_REPLACE | ||
:Used when playing sounds through console commands. | :Used when playing sounds through console commands. | ||
;CHAN_STATIC | ;CHAN_STATIC | ||
− | : | + | :A constant/background sound that doesn't require any reaction. |
;CHAN_VOICE_BASE | ;CHAN_VOICE_BASE | ||
:Network voice data (online voice communications) | :Network voice data (online voice communications) | ||
;CHAN_USER_BASE+<number> | ;CHAN_USER_BASE+<number> | ||
− | :Custom channels can be defined here. | + | :Custom channels can be defined here (Allocates a channel for the desire sound entry). |
===SoundLevel=== | ===SoundLevel=== | ||
+ | The sound's [[Wikipedia:Attenuation|attenuation]]; how fast it drops away. The engine starts running into trouble below 60dB. | ||
− | The sound | + | The following list contains all default sound levels, their attenuation value, real world examples, and in-game examples. All values and real world examples were taken from <code>soundflags.h</code>. |
{| class=standard-table | {| class=standard-table | ||
!Code | !Code | ||
− | !Value | + | !Attenuation Value |
− | ! | + | !Real World |
+ | !In Game | ||
|- | |- | ||
| SNDLVL_NONE | | SNDLVL_NONE | ||
| 0 | | 0 | ||
− | | | + | | Everywhere |
+ | | {{l4d2}}: Music disconnected from environment (Ex: checkpoint music, credit music, mob music) | ||
|- | |- | ||
| SNDLVL_20dB | | SNDLVL_20dB | ||
| | | | ||
| Rustling leaves | | Rustling leaves | ||
+ | | | ||
|- | |- | ||
| SNDLVL_25dB | | SNDLVL_25dB | ||
| | | | ||
| Whispering | | Whispering | ||
+ | | | ||
|- | |- | ||
| SNDLVL_30dB | | SNDLVL_30dB | ||
| | | | ||
| Library | | Library | ||
+ | | | ||
|- | |- | ||
| SNDLVL_35dB | | SNDLVL_35dB | ||
+ | | | ||
| | | | ||
| | | | ||
|- | |- | ||
| SNDLVL_40dB | | SNDLVL_40dB | ||
+ | | | ||
| | | | ||
| | | | ||
Line 111: | Line 125: | ||
| | | | ||
| Refrigerator | | Refrigerator | ||
+ | | | ||
|- | |- | ||
| SNDLVL_50dB | | SNDLVL_50dB | ||
| 3.9 | | 3.9 | ||
| Average home | | Average home | ||
+ | | | ||
|- | |- | ||
| SNDLVL_55dB | | SNDLVL_55dB | ||
| 3.0 | | 3.0 | ||
+ | | | ||
| | | | ||
|- | |- | ||
Line 123: | Line 140: | ||
| 2.0 | | 2.0 | ||
| Normal conversation, clothes dryer | | Normal conversation, clothes dryer | ||
+ | | | ||
|- | |- | ||
| SNDLVL_65dB | | SNDLVL_65dB | ||
| 1.5 | | 1.5 | ||
| Washing machine, dishwasher | | Washing machine, dishwasher | ||
+ | | | ||
|- | |- | ||
| SNDLVL_STATIC | | SNDLVL_STATIC | ||
| 1.25 | | 1.25 | ||
+ | | | ||
| | | | ||
|- | |- | ||
Line 135: | Line 155: | ||
| 1.0 | | 1.0 | ||
| Car, vacuum cleaner, mixer, electric sewing machine | | Car, vacuum cleaner, mixer, electric sewing machine | ||
+ | | {{l4d2}}: Moustachio whack smash and pop-up | ||
|- | |- | ||
| '''SNDLVL_NORM''' | | '''SNDLVL_NORM''' | ||
| 0.8 | | 0.8 | ||
| Busy traffic | | Busy traffic | ||
+ | | {{l4d2}}: Lilpeanut audible | ||
|- | |- | ||
| SNDLVL_80dB | | SNDLVL_80dB | ||
| 0.7 | | 0.7 | ||
− | | | + | | Mini-bike, alarm clock, noisy restaurant, office tabulator, outboard motor, passing snowmobile |
+ | | {{l4d2}}: Jukebox, music spitter spit pile as source, | ||
|- | |- | ||
| '''SNDLVL_TALKING''' | | '''SNDLVL_TALKING''' | ||
| 0.7 | | 0.7 | ||
+ | | | ||
| Valve's chosen dialogue attenuation | | Valve's chosen dialogue attenuation | ||
|- | |- | ||
Line 151: | Line 175: | ||
| 0.6 | | 0.6 | ||
| Average factory, electric shaver | | Average factory, electric shaver | ||
+ | | {{l4d2}}: Moustachio strength attract | ||
|- | |- | ||
| SNDLVL_90dB | | SNDLVL_90dB | ||
| 0.5 | | 0.5 | ||
| Screaming child, passing motorcycle, convertible ride on freeway | | Screaming child, passing motorcycle, convertible ride on freeway | ||
+ | | {{l4d2}}: Moustachio strength attract | ||
|- | |- | ||
| SNDLVL_95dB | | SNDLVL_95dB | ||
Line 163: | Line 189: | ||
| 0.4 | | 0.4 | ||
| Subway train, diesel truck, woodworking shop, pneumatic drill, boiler shop, jackhammer | | Subway train, diesel truck, woodworking shop, pneumatic drill, boiler shop, jackhammer | ||
+ | | {{l4d2}}: Music coop player in danger AKA tags (ledge hanging, pinned down by SI) | ||
|- | |- | ||
| SNDLVL_105dB | | SNDLVL_105dB | ||
| | | | ||
| Helicopter, power mower | | Helicopter, power mower | ||
+ | | | ||
|- | |- | ||
| SNDLVL_110dB | | SNDLVL_110dB | ||
| | | | ||
| Snowmobile (drivers seat), inboard motorboat, sandblasting | | Snowmobile (drivers seat), inboard motorboat, sandblasting | ||
+ | | {{l4d2}}: Boomer alert close | ||
|- | |- | ||
| SNDLVL_120dB | | SNDLVL_120dB | ||
| | | | ||
| Car horn, propeller aircraft | | Car horn, propeller aircraft | ||
+ | | {{l4d2}}: Boomer alert | ||
+ | |- | ||
+ | | SNDLVL_125dB | ||
+ | | | ||
+ | | | ||
+ | | {{l4d2}}: Boomer alert far | ||
|- | |- | ||
| SNDLVL_130dB | | SNDLVL_130dB | ||
| | | | ||
| Air raid siren | | Air raid siren | ||
+ | | {{l4d2}}: Carousel music during crescendo event | ||
|- | |- | ||
| ''' SNDLVL_GUNFIRE''' | | ''' SNDLVL_GUNFIRE''' | ||
| 0.27 | | 0.27 | ||
| Threshold of pain, gunshot, jet engine | | Threshold of pain, gunshot, jet engine | ||
+ | | | ||
|- | |- | ||
| SNDLVL_140dB | | SNDLVL_140dB | ||
| 0.2 | | 0.2 | ||
| | | | ||
+ | | | ||
+ | |- | ||
+ | | SNDLVL_145dB | ||
+ | | | ||
+ | | | ||
+ | | {{l4d2}}: Wandering witch music ("lost little witch") | ||
|- | |- | ||
| SNDLVL_150dB | | SNDLVL_150dB | ||
| 0.2 | | 0.2 | ||
| | | | ||
+ | | {{l4d2}}: Concert music, parade music, zombie choir | ||
|- | |- | ||
| SNDLVL_180dB | | SNDLVL_180dB | ||
| | | | ||
| Rocket launching | | Rocket launching | ||
+ | | | ||
|} | |} | ||
+ | |||
+ | {{confirm|It may be possible to pass a literal number value ("150" as opposed to "SNDLVL_150") and freely choose any number between 0 and 255.}} | ||
+ | |||
+ | ==Operator stacks== | ||
+ | {{Game link|Portal 2}} introduced [[Sound operators|Operator Stacks]], which are used to add complex behaviour to sounds. To enable them, you must set <code>soundentry_version</code> to <code>2</code>. | ||
+ | |||
+ | There are three types of stack, each triggered at different times: | ||
+ | *<code>prestart_stack</code> | ||
+ | *<code>start_stack</code> | ||
+ | *<code>update_stack</code> | ||
+ | *<code>stop_stack</code> | ||
+ | |||
+ | In each case you can either start from scratch or use the <code>import_stack</code> command to extend a template defined in <code>scripts/sound_operator_stacks.txt</code>. | ||
+ | |||
+ | ===Example=== | ||
+ | <syntaxhighlight lang=php highlight=14-31> | ||
+ | VFX.LightFlickerEnd | ||
+ | { | ||
+ | channel CHAN_AUTO | ||
+ | soundlevel SNDLVL_105db | ||
+ | volume 1.0 | ||
+ | rndwave | ||
+ | { | ||
+ | wave "vfx/light_flicker/light_flicker_end_01.wav" | ||
+ | wave "vfx/light_flicker/light_flicker_end_02.wav" | ||
+ | wave "vfx/light_flicker/light_flicker_end_03.wav" | ||
+ | wave "vfx/light_flicker/light_flicker_end_04.wav" | ||
+ | } | ||
+ | |||
+ | soundentry_version 2 | ||
+ | |||
+ | operator_stacks | ||
+ | { | ||
+ | start_stack // applied when the sound begins | ||
+ | { | ||
+ | import_stack "P2_exclusion_time_blocker_start" // defined in scripts/sound_operator_stacks.txt | ||
+ | |||
+ | // We are now extending/configuring P2_exclusion_time_blocker_start | ||
+ | |||
+ | block_entries // prevents another sound from playing | ||
+ | { | ||
+ | input_duration 0.25 // seconds to block for | ||
+ | match_entry "World.LightFlickerEnd" // the sound entry to block | ||
+ | match_entity false // only on the same entity that this sound is playing from? | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ===Templates=== | ||
+ | There are [[Sound operators|28 operators]] used in Portal 2, but they are re-configured and combined in hundreds of different ways. Most of the resulting "stacks" are very specific, and this page will only deal with the more general ones. | ||
+ | |||
+ | {{todo|Work out a sane way of documenting all this!}} | ||
+ | |||
+ | ====limit_sound==== | ||
+ | Limits the maximum number of sounds that can be played at once, either by sound name or entity. A sound will not stop itself from playing. | ||
+ | |||
+ | <syntaxhighlight lang=php> | ||
+ | import_stack "P2_poly_limiting_start" | ||
+ | |||
+ | limit_sound | ||
+ | { | ||
+ | match_entry "VFX.OGSignFlicker" | ||
+ | input_max_entries 3.000000 | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====position_array==== | ||
+ | Smoothly transitions a sound from one location to up to eight others as the player moves through a map. An unreleased tool can auto-generate these. Position 1 is where the sound was emitted from. | ||
+ | |||
+ | {{confirm|The tool mentioned above ''may'' be in the files of [[Dino D-Day]].}} | ||
+ | |||
+ | <syntaxhighlight lang=php> | ||
+ | import_stack "p2_update_dialog_spatial_cave" | ||
+ | |||
+ | position_array | ||
+ | { | ||
+ | input_entry_count 3 | ||
+ | // position 2 | ||
+ | input_position_1[0] 2129 | ||
+ | input_position_1[1] -850 | ||
+ | input_position_1[2] -1267 | ||
+ | // position 3 | ||
+ | input_position_2[0] 1473 | ||
+ | input_position_2[1] -1200 | ||
+ | input_position_2[2] -1343 | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | ====play_entry==== | ||
+ | Plays another sound entry. | ||
+ | |||
+ | <syntaxhighlight lang=php> | ||
+ | import_stack "stop_and_play" | ||
+ | |||
+ | play_entry | ||
+ | { | ||
+ | entry_name VFX.FizzlerDestroy | ||
+ | } | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | === Games that Support Sound Operator Stacks === | ||
+ | |||
+ | ===== First Party Games ===== | ||
+ | :;{{Game link|Portal 2}} | ||
+ | :;{{Game link|Counter-Strike: Global Offensive}} | ||
+ | :;{{Game link|Dota 2}} | ||
+ | ::''Dota 2 runs on Source 2. The Sound Operator Stack system has been greatly expanded upon, being a WIP. Many Sound Operator names have been changed.'' | ||
+ | ===== Third Party Games ===== | ||
+ | :;{{Game link|Day of Infamy}} | ||
+ | :;{{Game link|Insurgency}} | ||
==Sound Characters== | ==Sound Characters== | ||
− | |||
The first two characters of a WAV's name are scanned for the following: | The first two characters of a WAV's name are scanned for the following: | ||
Line 204: | Line 360: | ||
:Streams from the disc, get flushed soon after. Use for one-off dialogue files or music. | :Streams from the disc, get flushed soon after. Use for one-off dialogue files or music. | ||
;<code>#</code> - CHAR_DRYMIX | ;<code>#</code> - CHAR_DRYMIX | ||
− | :Bypasses [[Digital Signal Processing|DSP]]. | + | :Bypasses [[Digital Signal Processing|DSP]] and affected by the user's music volume setting. |
+ | {{Warning| Using this character on a sound entry utilizing an <code>update_stack</code> where the volume is zeroed out, whether by the <code>update_stack</code> or by the sound | ||
+ | entry itself(<code>volume 0.0</code>), will cause an <code>update_stack</code> loop.Not only does this have nagative performance implications, the sound will consume an audio channel until the loop is interrupted or the sound is stopped. {{confirm}}}} | ||
;<code>@</code> - CHAR_OMNI | ;<code>@</code> - CHAR_OMNI | ||
− | :Non-directional; | + | :Non-directional sound; plays "everywhere", similar to SNDLVL_NONE, except it fades with distance from its source based on its sound level. |
;<code>></code> - CHAR_DOPPLER | ;<code>></code> - CHAR_DOPPLER | ||
− | :Doppler encoded stereo: left for heading towards the | + | :Doppler encoded stereo: left for heading towards the listener and right for heading away. |
;<code><</code> - CHAR_DIRECTIONAL | ;<code><</code> - CHAR_DIRECTIONAL | ||
− | :Stereo with direction: left channel for front facing, right channel for rear facing. Mixed based on listener's direction. | + | :Stereo with direction: left channel for front facing, right channel for rear facing. Mixed based on listener's direction. {{todo|Relationship with <code>CHAR_DIRSTEREO</code> in {{csgo}}?}} |
;<code>^</code> - CHAR_DISTVARIANT | ;<code>^</code> - CHAR_DISTVARIANT | ||
− | :Distance-variant stereo. Left channel is close, right channel is far. Transition distance is hard-coded; see below. | + | :Distance-variant stereo. Left channel is close, right channel is far. Transition distance is hard-coded; [[#Distance_variance_in_Source|see below]]. |
;<code>)</code> - CHAR_SPATIALSTEREO | ;<code>)</code> - CHAR_SPATIALSTEREO | ||
− | : | + | :''Spatializes'' both channels, allowing them to be placed at specific locations within the world; [[#Spatial_Stereo|see below]]. {{note|Sometimes "'''('''" must be used instead; [[#Spatial_Stereo|see below]].}} |
;<code>}</code> - CHAR_FAST_PITCH | ;<code>}</code> - CHAR_FAST_PITCH | ||
:Forces low quality, non-interpolated pitch shift. | :Forces low quality, non-interpolated pitch shift. | ||
− | ;<code>$</code> - CHAR_CRITICAL | + | ;<code>$</code> - CHAR_CRITICAL {{removed|{{csgo}}}} |
:Memory resident; cache locked. | :Memory resident; cache locked. | ||
− | ;<code>!</code> - CHAR_SENTENCE | + | ;<code>!</code> - CHAR_SENTENCE {{since|{{src09}}}} |
:An NPC [[sentence]]. | :An NPC [[sentence]]. | ||
;<code>?</code> - CHAR_USERVOX | ;<code>?</code> - CHAR_USERVOX | ||
:Voice chat data. You shouldn't ever need to use this. | :Voice chat data. You shouldn't ever need to use this. | ||
+ | |||
+ | ;<code>&</code> - CHAR_HRTF_FORCE {{only|{{csgo}}}} | ||
+ | :Indicates wav should use HRTF spatialization for all entities (including owners). | ||
+ | ;<code>~</code> - CHAR_HRTF {{only|{{csgo}}}} | ||
+ | :Indicates wav should use HRTF spatialization for non-owners. | ||
+ | ;<code>`</code> - CHAR_HRTF_BLEND {{only|{{csgo}}}} | ||
+ | :Indicates wav should use HRTF spatialization for non-owners, blended with stereo for sounds sufficiently close. | ||
+ | ;<code>+</code> - CHAR_RADIO {{only|{{csgo}}}} | ||
+ | :Indicates a 'radio' sound -- should be played without spatialization | ||
+ | ;<code>(</code> - CHAR_DIRSTEREO {{only|{{csgo}}}} | ||
+ | :Indicates directional stereo wav (like doppler) | ||
+ | ;<code>$</code> - CHAR_SUBTITLED {{only|{{csgo}}}} | ||
+ | :Indicates the subtitles are forced | ||
+ | ;<code>%</code> - CHAR_MUSIC {{only|{{csgo}}}} | ||
+ | :Indicates main menu music | ||
+ | |||
+ | For example: | ||
+ | <pre> | ||
+ | )weapons/m4a1/m4_shoot.wav | ||
+ | |||
+ | *@npc/vo/announcer/specialoffer.wav | ||
+ | </pre> | ||
+ | |||
+ | ===Spatial Stereo=== | ||
+ | Adding <code>)</code> in front of a stereo sound name in the soundscript such as ")weapons/m4a1/m4_shoot.wav" tells the sound engine that it is a ''spatialized'' sound; this allows the sound to emit from a specific location within the world. When not used, stereo sounds play in a fixed 2-channel orientation and cannot be panned to simulate a location. Single-channel files do not require <code>)</code> before the filename and will be ''spatialized'' automatically. | ||
+ | |||
+ | ====Soundscapes==== | ||
+ | Soundscapes have special needs. Stereo wave files used in <code>PlayRandom</code> require that <code>(</code> is placed before the filename. <code>PlayLooping</code> still uses <code>)</code> but <code>(</code> will spatialize the two channels separately for an alternate effect; <code>(</code> sounds more environmental, but the exact nature of this behavior is unknown. Generic soundscripts can sometimes use <code>(</code> to gain the same stereo spatialization that occurs in <code>PlayLooping</code>. | ||
For example: | For example: | ||
− | + | <syntaxhighlight lang=php> | |
+ | wave ")ambient/stereo_alarm.wav" // Typical usage in a standard soundscript | ||
+ | </syntaxhighlight> | ||
− | + | But in soundscapes: | |
− | = | + | <syntaxhighlight lang=php> |
+ | playrandom | ||
+ | { | ||
+ | time 33,68 | ||
+ | volume .6,1 | ||
+ | pitch 90,105 | ||
+ | position 0 | ||
+ | rndwave | ||
+ | { | ||
+ | wave "ambient/mono_siren.wav" // Mono files are always spatialized properly | ||
+ | wave ")ambient/stereo_alarm.wav" // WRONG; sound will not be spatialized | ||
+ | wave "(ambient/stereo_siren.wav" // Correct; sound will be spatialized normally | ||
+ | } | ||
+ | } | ||
+ | </syntaxhighlight> | ||
− | + | <syntaxhighlight lang=php> | |
+ | PlayLooping | ||
+ | { | ||
+ | volume .6 | ||
+ | pitch 100 | ||
+ | position 0 | ||
+ | wave ")ambient/stereo_siren.wav" // standard spatialization; both channels originate at same location | ||
+ | //wave "(ambient/stereo_siren.wav" // stereo spatialization; one of the channels is spatialized alternatively | ||
+ | } | ||
+ | </syntaxhighlight> | ||
===Distance variance in Source=== | ===Distance variance in Source=== | ||
+ | Adding <code>^</code> in front of a sound name, such as "^weapons/explode3.wav" tells the sound engine that it is a distance based sound. The left channel of the .wav is the 'near' sound that will play when the sound originates close to you, and the right channel is the 'far' sound that will play when the sound originates far from you. If the ^ mark is not used in the soundscript the sound is treated as stereo with no directionality or distance. This is a different feature than the sndlvl entry to control attenuation. This distant variant feature allows you to play two different sounds (but using only one file) and cross-fading between the two depending on how far away the sound originates. | ||
+ | |||
+ | The fade distances are hardcoded to begin at 240 world units and end at 1320 world units, and cannot be changed in custom maps or mods. | ||
− | + | ==See also== | |
+ | *{{ent|ambient_generic}} | ||
+ | *[[Soundscape]] | ||
+ | *[[L4D_Soundscripts|Left 4 Dead Soundscripts]] | ||
+ | *[http://www.podcast17.com/interviews/audio/mike-morasky/ Podcast 17 Mike Morasky Interview] - Discussion about audio production and insight into the evolution of the sound system. | ||
==References== | ==References== | ||
+ | *src/public/soundflags.h | ||
+ | *src/public/soundchars.h | ||
+ | *scripts/game_sounds_header.txt | ||
+ | *scripts/game_sounds.txt | ||
+ | *scripts/game_sounds_manifest.txt | ||
− | + | [[Category:Sound System]] | |
− | |||
− | |||
− | |||
− |
Latest revision as of 00:11, 22 February 2021
Soundscripts contain "sound entries" that are used to wrap Source-specific playback instructions around WAV or MP3 files.
A sound entry can define the meaning of a sound to NPCs, its pitch and volume, how far away it can be heard from (attenuation), and can be used to randomise which precise sound file is played. Operator stacks (in all games since ) can be used to define even more complex behaviours.
Soundscripts are loaded on the server only from:
scripts/game_sounds_manifest.txt
maps/<mapname>_level_sounds.txt
All filepaths within a soundscript are relative to the sound folder.
Example entry
entry.name { channel CHAN_AUTO volume VOL_NORM pitch PITCH_NORM soundlevel SNDLVL_NORM wave common/null.wav }
If a value has a space or tab character within it, wrap it in "quote marks".

volume 0.45,0.65
.Commands
Wave / rndwave
Filename of the sound to play.
wave common/blah1.wav
You can also have the engine pick from a list of random files. A given sound won't repeat until all of the others have played. Note that the random choice is decided by the server, not the client.
rndwave { wave common/blah1.wav wave common/blah2.wav wave common/blah3.wav }

sounds
folder. So (sound/)folder/sound.wav will work, while (sound/)sound.wav will not.Volume
A number between 0 and 1, where 1 is the sound's original volume. VOL_NORM
will insert your mod's default volume, which will probably be 1
.
Pitch
Any number between 0 and 255, where 100 is the sound's original pitch and 255 is very high.
- PITCH_LOW = 95
- PITCH_HIGH = 120
Channel
Channels are used to categorize sounds in a way that NPCs, and game logic in general, can understand.

- Exceeding this will result in a channel allocation error, preventing sounds from playing.
- CHAN_AUTO
- Default, generic channel.
- CHAN_WEAPON
- Player and NPC weapons.
- CHAN_VOICE
- Voiceover dialogue. Used for regular voice lines, etc.
- CHAN_VOICE2
- Additional voice channel. Used in TF2 for the announcer.
- CHAN_ITEM
- Generic physics impact sounds, health/suit chargers,
+use
sounds. - CHAN_BODY
- Clothing, ragdoll impacts, footsteps, knocking/pounding/punching etc.
- CHAN_STREAM
- Sounds that can be delayed by an async load, i.e. aren't responses to particular events.
Confirm:This won't make the sound actually stream; use the * prefix for that.
- CHAN_REPLACE
- Used when playing sounds through console commands.
- CHAN_STATIC
- A constant/background sound that doesn't require any reaction.
- CHAN_VOICE_BASE
- Network voice data (online voice communications)
- CHAN_USER_BASE+<number>
- Custom channels can be defined here (Allocates a channel for the desire sound entry).
SoundLevel
The sound's attenuation; how fast it drops away. The engine starts running into trouble below 60dB.
The following list contains all default sound levels, their attenuation value, real world examples, and in-game examples. All values and real world examples were taken from soundflags.h
.

Operator stacks
Portal 2 introduced Operator Stacks, which are used to add complex behaviour to sounds. To enable them, you must set
soundentry_version
to 2
.
There are three types of stack, each triggered at different times:
prestart_stack
start_stack
update_stack
stop_stack
In each case you can either start from scratch or use the import_stack
command to extend a template defined in scripts/sound_operator_stacks.txt
.
Example
VFX.LightFlickerEnd
{
channel CHAN_AUTO
soundlevel SNDLVL_105db
volume 1.0
rndwave
{
wave "vfx/light_flicker/light_flicker_end_01.wav"
wave "vfx/light_flicker/light_flicker_end_02.wav"
wave "vfx/light_flicker/light_flicker_end_03.wav"
wave "vfx/light_flicker/light_flicker_end_04.wav"
}
soundentry_version 2
operator_stacks
{
start_stack // applied when the sound begins
{
import_stack "P2_exclusion_time_blocker_start" // defined in scripts/sound_operator_stacks.txt
// We are now extending/configuring P2_exclusion_time_blocker_start
block_entries // prevents another sound from playing
{
input_duration 0.25 // seconds to block for
match_entry "World.LightFlickerEnd" // the sound entry to block
match_entity false // only on the same entity that this sound is playing from?
}
}
}
}
Templates
There are 28 operators used in Portal 2, but they are re-configured and combined in hundreds of different ways. Most of the resulting "stacks" are very specific, and this page will only deal with the more general ones.
To do: Work out a sane way of documenting all this!
limit_sound
Limits the maximum number of sounds that can be played at once, either by sound name or entity. A sound will not stop itself from playing.
import_stack "P2_poly_limiting_start"
limit_sound
{
match_entry "VFX.OGSignFlicker"
input_max_entries 3.000000
}
position_array
Smoothly transitions a sound from one location to up to eight others as the player moves through a map. An unreleased tool can auto-generate these. Position 1 is where the sound was emitted from.

import_stack "p2_update_dialog_spatial_cave"
position_array
{
input_entry_count 3
// position 2
input_position_1[0] 2129
input_position_1[1] -850
input_position_1[2] -1267
// position 3
input_position_2[0] 1473
input_position_2[1] -1200
input_position_2[2] -1343
}
play_entry
Plays another sound entry.
import_stack "stop_and_play"
play_entry
{
entry_name VFX.FizzlerDestroy
}
Games that Support Sound Operator Stacks
First Party Games
Portal 2
Counter-Strike: Global Offensive
Dota 2
- Dota 2 runs on Source 2. The Sound Operator Stack system has been greatly expanded upon, being a WIP. Many Sound Operator names have been changed.
Third Party Games
Sound Characters
The first two characters of a WAV's name are scanned for the following:
*
- CHAR_STREAM- Streams from the disc, get flushed soon after. Use for one-off dialogue files or music.
#
- CHAR_DRYMIX- Bypasses DSP and affected by the user's music volume setting.

update_stack
where the volume is zeroed out, whether by the update_stack
or by the sound
entry itself(volume 0.0
), will cause an update_stack
loop.Not only does this have nagative performance implications, the sound will consume an audio channel until the loop is interrupted or the sound is stopped. [confirm]@
- CHAR_OMNI- Non-directional sound; plays "everywhere", similar to SNDLVL_NONE, except it fades with distance from its source based on its sound level.
>
- CHAR_DOPPLER- Doppler encoded stereo: left for heading towards the listener and right for heading away.
<
- CHAR_DIRECTIONAL- Stereo with direction: left channel for front facing, right channel for rear facing. Mixed based on listener's direction. To do: Relationship with
CHAR_DIRSTEREO
in?
^
- CHAR_DISTVARIANT- Distance-variant stereo. Left channel is close, right channel is far. Transition distance is hard-coded; see below.
)
- CHAR_SPATIALSTEREO- Spatializes both channels, allowing them to be placed at specific locations within the world; see below.
Note: Sometimes "(" must be used instead; see below.
}
- CHAR_FAST_PITCH- Forces low quality, non-interpolated pitch shift.
$
- CHAR_CRITICAL (removed in)
- Memory resident; cache locked.
!
- CHAR_SENTENCE (in all games since)
- An NPC sentence.
?
- CHAR_USERVOX- Voice chat data. You shouldn't ever need to use this.
&
- CHAR_HRTF_FORCE (only in)
- Indicates wav should use HRTF spatialization for all entities (including owners).
~
- CHAR_HRTF (only in)
- Indicates wav should use HRTF spatialization for non-owners.
`
- CHAR_HRTF_BLEND (only in)
- Indicates wav should use HRTF spatialization for non-owners, blended with stereo for sounds sufficiently close.
+
- CHAR_RADIO (only in)
- Indicates a 'radio' sound -- should be played without spatialization
(
- CHAR_DIRSTEREO (only in)
- Indicates directional stereo wav (like doppler)
$
- CHAR_SUBTITLED (only in)
- Indicates the subtitles are forced
%
- CHAR_MUSIC (only in)
- Indicates main menu music
For example:
)weapons/m4a1/m4_shoot.wav *@npc/vo/announcer/specialoffer.wav
Spatial Stereo
Adding )
in front of a stereo sound name in the soundscript such as ")weapons/m4a1/m4_shoot.wav" tells the sound engine that it is a spatialized sound; this allows the sound to emit from a specific location within the world. When not used, stereo sounds play in a fixed 2-channel orientation and cannot be panned to simulate a location. Single-channel files do not require )
before the filename and will be spatialized automatically.
Soundscapes
Soundscapes have special needs. Stereo wave files used in PlayRandom
require that (
is placed before the filename. PlayLooping
still uses )
but (
will spatialize the two channels separately for an alternate effect; (
sounds more environmental, but the exact nature of this behavior is unknown. Generic soundscripts can sometimes use (
to gain the same stereo spatialization that occurs in PlayLooping
.
For example:
wave ")ambient/stereo_alarm.wav" // Typical usage in a standard soundscript
But in soundscapes:
playrandom
{
time 33,68
volume .6,1
pitch 90,105
position 0
rndwave
{
wave "ambient/mono_siren.wav" // Mono files are always spatialized properly
wave ")ambient/stereo_alarm.wav" // WRONG; sound will not be spatialized
wave "(ambient/stereo_siren.wav" // Correct; sound will be spatialized normally
}
}
PlayLooping
{
volume .6
pitch 100
position 0
wave ")ambient/stereo_siren.wav" // standard spatialization; both channels originate at same location
//wave "(ambient/stereo_siren.wav" // stereo spatialization; one of the channels is spatialized alternatively
}
Distance variance in Source
Adding ^
in front of a sound name, such as "^weapons/explode3.wav" tells the sound engine that it is a distance based sound. The left channel of the .wav is the 'near' sound that will play when the sound originates close to you, and the right channel is the 'far' sound that will play when the sound originates far from you. If the ^ mark is not used in the soundscript the sound is treated as stereo with no directionality or distance. This is a different feature than the sndlvl entry to control attenuation. This distant variant feature allows you to play two different sounds (but using only one file) and cross-fading between the two depending on how far away the sound originates.
The fade distances are hardcoded to begin at 240 world units and end at 1320 world units, and cannot be changed in custom maps or mods.
See also
ambient_generic
- Soundscape
- Left 4 Dead Soundscripts
- Podcast 17 Mike Morasky Interview - Discussion about audio production and insight into the evolution of the sound system.
References
- src/public/soundflags.h
- src/public/soundchars.h
- scripts/game_sounds_header.txt
- scripts/game_sounds.txt
- scripts/game_sounds_manifest.txt