Documentation Index
Fetch the complete documentation index at: https://mintlify.com/twhl-community/halflife-unified-sdk/llms.txt
Use this file to discover all available pages before exploring further.
The Half-Life Unified SDK ships a new sound system built on top of OpenAL that fixes long-standing bugs in the original engine audio code, removes or dramatically raises many hard-coded limits, and adds support for modern audio features such as EFX room effects and HRTF-based spatial audio. It handles music, regular sound effects, and sentence playback through a unified pipeline.
The OpenAL library is distributed as openal-hlu.dll rather than the standard openal32.dll name. This avoids conflicts with the older OpenAL version that the Half-Life engine itself loads on Linux.
| Format | Notes |
|---|
Wave (.wav) | Includes IMA-ADPCM encoded files |
| MP3 | — |
| Ogg Vorbis | — |
| Ogg Opus | — |
| FLAC | — |
| WavPack | — |
| Musepack | — |
Loggers
The sound system uses several named loggers for its subsystems:
| Logger | Purpose |
|---|
sentences | Diagnostics, warnings, and errors during sentences.json file loading |
sound | Diagnostics, warnings, and errors during sound playback |
sound.cache | Client-side sound cache |
sound.sentences | Client-side sentences system |
Music Playback
Music playback works similarly to the engine’s built-in cd and mp3 commands but with two important differences:
- Music does not stop when the player changes level.
- There is no internal file count limit.
The MP3Volume engine cvar controls music volume and is adjusted by the music volume slider in the options dialog.
Entities
The ambient_music entity can be placed in a map to trigger music playback. See the entities overview for details.
music Command
The music command is the single entry point for all music playback and replaces the engine’s cd and mp3 commands.
music <command> [arguments]
| Subcommand | Syntax | Description |
|---|
on | music on | Enables music playback |
off | music off | Disables music playback and stops any currently playing music |
reset | music reset | Enables music playback and stops any currently playing music |
play | music play <relative_filename> | Plays the specified file once |
loop | music loop <relative_filename> | Loops the specified file |
stop | music stop | Stops any music that is currently playing |
fadeout | music fadeout | Fades out and stops any music that is playing. Fadeout duration is controlled by the MP3FadeTime engine cvar |
pause | music pause | Pauses any music that is currently playing |
resume | music resume | Resumes music if it was paused |
info | music info | Prints the current filename and volume if music is playing or paused |
Sound and Sentence Playback
Sound and sentence playback uses OpenAL for distance attenuation, volume, and room effects via the EFX extension (OpenAL’s counterpart to EAX).
Room Effects
Room effects use parameters closely matching the original EAX implementation, but the results are not identical. The original Half-Life (like Quake) used software mixing regardless of the audio API, performing distance calculations in software before passing audio to fixed-position 3D sources. The engine placed four 3D sources at the corners of a 2×2-unit box centred on the player to approximate spatialization.
The new sound system lets OpenAL handle distance calculations natively, so sound sources work correctly with the EFX extension. The room effects are accurate, but they will sound different from the original engine’s output because the underlying approach has changed.
The volume engine cvar controls overall sound volume and is adjusted by the sound effects volume slider in the options dialog.
Changes to Sound System Limits
The following limits from the original engine have been raised or removed:
| Property | Original Limit | New Limit |
|---|
| Concurrent sounds (static + dynamic + ambient) | 128 | Unlimited |
| Sound precaches | 512 | 65 535 |
| Sentences | 1 536 | 65 535 |
| Sentence groups | 200 | Unlimited |
| Sentences in a group | 32 | Unlimited |
| Sentence name length | 15 ASCII characters | Unlimited |
| Words in a sentence | 32 | Unlimited |
| Unique sounds (server + client) | 1 024 | Unlimited |
| Sentence line length | 511 characters | Unlimited |
| Sentences configuration files | 1 | Multiple supported |
Additional improvements beyond limit increases:
- Sentences are no longer cut off after pausing and resuming.
- Sentence groups now allow non-sequential sentence numbering.
- Sentences and sentence groups can be redefined in later-loaded configuration files.
- EAX room effects are implemented via EFX.
- Aureal A3D functionality is implemented via HRTF (experimental).
- Sounds with attenuation
0 now play at the player’s position, fixing ambient_generic Play Everywhere sounds that incorrectly used spatialization in the original engine.
Sentences Configuration Files
Half-Life’s sentences.txt file is replaced with a JSON-based format. The SDK supports loading multiple files and allows sentences and sentence groups to be redefined, enabling map-specific replacements and additions.
The default file is sound/sentences.json. Additional files can be added through map configuration files.
Syntax
A sentences file is a JSON object with two optional fields:
Sentences — an array of sentence definition strings. Each string contains the sentence name followed by the words in the sentence, using the same syntax as the original sentences.txt.
Groups — an object where each key is a group name and each value is an array of sentence names belonging to that group.
Unlike sentences.txt, sentence names in this format do not automatically create sentence groups. Groups must be declared explicitly in the Groups object. This prevents accidental group creation, allows multiple groups to share sentences, and allows groups to be redefined without redefining the individual sentences.
If a sentence or group with the same name appears in a later-loaded file, its contents are replaced. If a group is redefined with fewer sentences, the extra sentences are removed.
Example
{
"Sentences": [
// A sentence with a single word
"NULLSENT common/null",
// A sentence that does not create a group
"NULLGR0 common/null",
// Seven sentences without a group
"HG_GREN0 hgrunt/clik(p120) grenade! clik",
"HG_GREN1 hgrunt/(t30) clik take!(e75) cover!(s5) clik",
"HG_GREN2 hgrunt/clik clik oh! shit! clik",
"HG_GREN3 hgrunt/(p110 t40) clik(p120) get!(e78) down!(t30) clik",
"HG_GREN4 hgrunt/clik(p110) (t40) of!(e75) god! clik(p110)",
"HG_GREN5 hgrunt/clik no! clik",
"HG_GREN6 hgrunt/clik move! clik(p120)"
],
"Groups": {
// A group called "NULLGR" with one sentence
"NULLGR": [
"NULLGR0"
],
// A group called "HG_GREN" with seven sentences
"HG_GREN": [
"HG_GREN0",
"HG_GREN1",
"HG_GREN2",
"HG_GREN3",
"HG_GREN4",
"HG_GREN5",
"HG_GREN6"
]
}
}
See Also
Console Commands and Variables
cl_snd_room_off
Default: 0. Mirrors the engine’s room_off cvar. When set to 1, all EFX-based room effects are disabled and sounds play as if room type 0 is in use.
cl_snd_playstatic and cl_snd_playdynamic
cl_snd_playstatic <sound_name> [volume] [attenuation] [pitch]
cl_snd_playdynamic <sound_name> [volume] [attenuation] [pitch]
Play a sound on the player entity. cl_snd_playstatic uses CHAN_STATIC; cl_snd_playdynamic uses CHAN_VOICE.
| Parameter | Default | Range | Notes |
|---|
volume | 1 | [0, 1] | |
attenuation | 0.8 | [0, +∞] | 0.8 is normal — equivalent to ambient_generic large radius |
pitch | 100 | [1, 255] | 100 is unaltered pitch |
cl_snd_stopsound
Stops all sounds that are currently playing.
cl_snd_hrtf_enabled
Enables or disables Head-Related Transfer Functions (HRTF) for binaural 3D audio.
Enabling HRTF when using a debug build of the OpenAL Soft library will cause significant performance issues.
cl_snd_hrtf_implementation
When set to a non-empty string, this cvar specifies the name of the HRTF implementation to prefer. If the named implementation does not exist, or if the cvar is empty, the default implementation is used. OpenAL Soft only provides its built-in HRTF implementation by default.
cl_snd_hrtf_list_implementations
Prints the list of available HRTF implementations to the console.