Skip to content

3D Directional Audio #44

Open
Open

Description

@adhdandy

This is probably a long shot, but I saw this video about an early Retail version of SS:TSE (patch 1.50 beta) : https://www.youtube.com/watch?v=TQI8nNh8Azg
It made me wonder: Could 3D audio be restored for the Steam release of the Serious Sam The Second Encounter?

Activity

  1. LethalManBoob commented on Feb 26, 2026

    @LethalManBoob

    openal soft works for me with dsoal

  2. vlad54rus commented on Feb 28, 2026

    @vlad54rus

    openal soft works for me with dsoal

    It works but limited to 2D only. No 3D sound positions for proper HRTF. No multichannel output support.

  3. HyperVirusProfi commented on Apr 7, 2026

    @HyperVirusProfi

    Так же с DSOAL пытался крутиться, она у меня работала на более старых версиях патча с каким-то модом вроде, перетаскивал в классику чисто - на некоторых локациях просто космос, в других косяк

    \да было бы круто такое юзать, но хз как это для сэма реализовать

  4. adhdandy commented on Oct 12, 2026

    @adhdandy
    Author

    Findings on how the 1.50 beta differs from the Steam/1.10 engine (from the public 1.10 source, the beta's Engine.dll exports, and DSOAL debug logs of both builds):

    1.10 source / Steam build

    • All spatialization is done in software (CSoundObject::Update3DEffects() → per-ear volume, filter, delay, pitch, phase).
    • The only DirectSound3D use is two fixed mono 3D buffers at (-1,0,0) and (+1,0,0), plus a listener at the origin, used for EAX reverb on the final mix. No per-source position ever reaches an API.
    • Steam under DSOAL log: 6 DSBCAPS_CTRL3D hits, listener at (0,0,0), exactly two buffer SetPosition calls at (-1,0,0) and (+1,0,0). Nothing per-source. This is why DSOAL only gives 2D results here.

    1.50 beta

    • Different sound API in the exports: single volume value, no per-ear setters, no Update3DEffects, a voice pool (CommitPlayingBuffer, ReleasePlayingBuffer, pending list), SetEnvironment(SndEnvFX), and cvars like snd_iMaxVoices, snd_bUseHeadphones, snd_iEmulationType.
    • Under DSOAL: 370 DSBCAPS_CTRL3D buffers; per-buffer SetPosition with continuously changing, roughly unit-length vectors; SetMode (head-relative on some buffers, disabled on others); SetVelocity; SetDopplerFactor; SetRolloffFactor(0). Directional audio is clearly audible on headphones.
    • In my test the beta had mostly missing/muffled effects without DSOAL on modern Windows.

    Conclusion
    The beta did per-source positional audio through DirectSound3D. It passes the engine's own listener-relative direction per sound in head-relative mode, does distance attenuation itself (rolloff 0), and leaves panning to the API. The Steam build doesn't. Restoring this means feeding per-sound direction into a 3D-capable backend.

    Not checked: how the beta's snd_iEmulationType / snd_bUseHeadphones values map to behavior, and the exact SetMode semantics per sound type.

  5. DreamyCecil commented on Oct 12, 2026

    @DreamyCecil
    Member

    I've known about the differences in the sound API between 1.07/1.10 and 1.50 from my own reverse engineering and from looking at leaked Last Chaos source code for reference. You can look at its sound API yourself, I'm pretty sure it's basically identical to clean Serious Engine 1.50: https://github.com/openlastchaos/lastchaos-source-client/tree/master/Engine/Sound

    Other than that, it would be significantly difficult to implement proper 3D audio when the engine itself does not support it. It would need an entire new sound interface on top of the game that would hijack any attempts at playing the sounds and redirecting them to the new API. But I'm not sure how hard it would be to keep track of each individual sound object to keep them in sync with sound objects in the new API in this case.

  6. adhdandy commented on Oct 14, 2026

    @adhdandy
    Author

    6. I've known about the differences in the sound API between 1.07/1.10 and 1.50 from my own reverse engineering and from looking at leaked Last Chaos source code for reference. You can look at its sound API yourself, I'm pretty sure it's basically identical to clean Serious Engine 1.50: https://github.com/openlastchaos/lastchaos-source-client/tree/master/Engine/Sound
    Other than that, it would be significantly difficult to implement proper 3D audio when the engine itself does not support it. It would need an entire new sound interface on top of the game that would hijack any attempts at playing the sounds and redirecting them to the new API. But I'm not sure how hard it would be to keep track of each individual sound object to keep them in sync with sound objects in the new API in this case.

    I've spent some time investigating the differences in 3D audio between the TSE 1.50 beta and the Steam release, and I've documented my findings and a possible implementation approach here:

    Research: https://github.com/adhdandy/serious-sam-ds3d-findings

    I've also documented a potential approach for restoring per-sound spatialization through runtime patches and shadow buffers, without replacing the stock Engine.dll. There are still open questions around sound-object synchronization and playback lifecycle handling, and the proposed implementation has not yet been tested in-game.

    For transparency, this is my first reverse-engineering project, and I relied heavily on AI tools throughout the investigation, including for disassembly analysis, interpreting engine behavior, and developing the proposed design. I've tried to distinguish observed evidence from hypotheses, but the findings and design should be considered a starting point for further verification rather than a proven implementation.

    I'd be very interested in your thoughts, particularly on whether the proposed approach to synchronizing the shadow buffers with the engine's sound objects seems viable. If this looks promising, I'd be happy to continue investigating the outstanding questions.

    The two most useful starting points are findings/99-summary-and-open-questions.md and findings/08-design.md.

  7. DreamyCecil commented on Oct 14, 2026

    @DreamyCecil
    Member

    I'm going to be honest, this is way too much technical information that I don't understand in the slightest. And I don't really understand the point in this research when new code would have to be written on top of the game either way.

    The way I see it right now - if I wanted to implement proper 3D audio to the patch, I would begin by implementing it in the engine itself with a fork of 1.10 and then just copying that code to the patch and patching a few functions to interact with my own sound system instead of the vanilla one from the engine. But I don't know how to do that yet because I've never worked with proper 3D audio before.

  8. LethalManBoob commented on Oct 14, 2026

    @LethalManBoob

    I always figured you can just pass the audio off to openal and let that do the processing for hrtf. Since dsoal on og serious sam does just that.

  9. adhdandy commented on Oct 14, 2026

    @adhdandy
    Author

    8. I'm going to be honest, this is way too much technical information that I don't understand in the slightest. And I don't really understand the point in this research when new code would have to be written on top of the game either way.
    The way I see it right now - if I wanted to implement proper 3D audio to the patch, I would begin by implementing it in the engine itself with a fork of 1.10 and then just copying that code to the patch and patching a few functions to interact with my own sound system instead of the vanilla one from the engine. But I don't know how to do that yet because I've never worked with proper 3D audio before.

    Thanks for the honest reply, and sorry for the wall of text. Short version of what's useful for your 1.10 fork plan:

    How the 1.50 beta does 3D audio (from its Engine.dll plus a DSOAL call log, not yet tested in-game on Steam):

    • Each playing mono 3D sound gets its own DirectSound3D buffer, duplicated from a per-sound template buffer. Stereo sounds, music and Ogg/MP3 stay in the normal software mix.
    • The listener is fixed at the origin and never moves. Rolloff is 0 and doppler is 1.1.
    • The engine still does the distance math itself (falloff and hotspot, as in 1.10). It rotates each sound's position into listener space and passes that to DS3D (z negated, deferred), plus velocity. Volume is computed by the engine and converted to DirectSound's centibel scale. DS3D only does the directional part (panning, HRTF, doppler).
    • One CommitDeferredSettings per frame.
    • Exact numbers and formulas: findings/99-summary-and-open-questions.md, section 1.

    The sync question: in the beta, a sound's playback state lives in the DS buffer. Each frame it asks the buffer whether it is still playing, and when a non-looping sound finishes, the engine object gets stopped. The software mixer simply skips these sounds.

    One trap in Steam/1.10: you can't mute a sound by setting its volume to 0. The mixer stops non-looping zero-volume sounds after one block. You have to skip the sound in MixSound instead (SoundMixer.cpp:624-659).

    If you use the Last Chaos 1.50-era sound source, checking my numbers against it would be the quickest way to confirm or break my findings.

  10. adhdandy commented on Oct 18, 2026

    @adhdandy
    Author

    Quick follow up, I started my implementation of spatial audio here: https://github.com/adhdandy/SuperProject/tree/ds3d-spatial
    Currently unfinished, but in testing it seems to work fine (so far). I will post here when I feel it's ready.

  11. adhdandy commented on Oct 19, 2026

    @adhdandy
    Author

    Update: the spatial audio mode on the ds3d-spatial branch is now ready for testing.

    It restores per-sound directional audio for the Steam release of TSE (1.07), like the 1.50 beta. The stock Engine.dll is not replaced. With the option off, the game behaves as vanilla.

    Requirements (all of these are needed):

    1. DSOAL in the game's Bin folder. It bundles OpenAL Soft and turns DirectSound3D positions into HRTF/binaural output.
    2. EAX selected as the sound interface in the game's audio options (snd_iInterface 2). Plain DirectSound has no 3D listener, so the mode stays off there.
    3. snd_bDS3DSpatial 1 in the console. It is off by default, so nothing changes unless you set it. It's saved with your settings.

    Use headphones. The effect is barely noticeable on speakers. Try a level with lots of Beheaded Kamikaze, i.e. "The City of the Gods".

    Install: s3d-spatial-beta. Use the Core and exe files from the release together. A mix of different builds will not load.

    What to expect:

    • Sounds in the world (enemies, weapons, ambience) come from their actual direction.
    • Music, Ogg/MP3 and stereo sounds are unchanged.
    • snd_iEmulationType (0/1/2) switches between the default algorithm and the two HRTF modes. It applies live.

    Limits:

    • TSE 1.07 Steam only, release build only.
    • Optional: 3D sounds are currently a bit louder than non-3D ones, e.g. voice lines. I'm looking at it.

    What I'd like to know:

    • Does it sound right on your setup? Anything missing, doubled, cut off or stuck?
    • Behavior around pause, level changes, alt-tab and changing audio settings.
    • If something is wrong, attach a DSOAL log (set the DSOAL_LOGFILE and DSOAL_LOGLEVEL environment variables) and say what you did.
  12. jyetcv commented on Oct 19, 2026

    @jyetcv

    @adhdandy
    I'm using dsoal with Proton and it sounds right to me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions