https://gitlab.synchro.net/main/sbbs/-/commit/2a84663b40f5bfa854195657
Modified Files:
src/doors/syncdoom/i_termsound.c src/doors/syncduke/Game/src/actors.c config.c duke3d.h sounds.c src/doors/syncduke/syncduke_stubs.c src/doors/termgfx/audio_mgr.c audio_mgr.h
Log Message:
doors: terminal-audio fidelity overhaul (SFX latency, ambiences, voices)
One-shot SFX (termgfx, both doors):
- The SFX channels are now a voice-stealing pool: flush the target channel
before queuing so each holds at most one live sound. Un-flushed channel
FIFOs backed up during firefights (30-45 SFX/sec into 8 channels) and
played gunshots out seconds late -- audio "continued after the fight".
- Channel choice is busy-aware: each queue records when its sample ends
(exact PCM geometry for Doom lumps and VOC transcodes, WAV byte-rate
otherwise) and new sounds take a finished channel, stealing the one
closest to done only when all are live. Blind rotation truncated any
long sample (rocket launch, chopper flyby) as soon as 8 later sounds
arrived inside its play time; DOS mixed 32 voices and never hit this.
- SyncDOOM coalesces same-sfx re-triggers within 40ms (SyncDuke's FX path
already had a burst window); near-simultaneous duplicates are inaudible
but each still cost a Load+Queue on the shared socket.
- Both dispatch paths log a one-time warning when a sound sample is
missing from the loaded GRP (content diagnosis, e.g. shareware).
Looping ambiences (termgfx + the Duke engine's missing-callback seams --
our headless shim has no audiolib voice-DONE callback, which the engine's
sound bookkeeping silently relied on):
- Queue loops ACTIVE (full volume) and set the real level via A;Volume:
a positional ambience first heard at its radius edge is queued at
volume 0, and SyncTERM never un-mutes such a voice (the E1L1 fire bin
was permanently silent) -- works around that SyncTERM bug.
- A full loop pool no longer steals a channel: loop_start reports failure
and the MUSICANDSFX handler leaves the sprite un-triggered to retry
when a channel frees, instead of stopping a loop the engine still
thinks is playing (ambiences went permanently silent mid-session).
- FX_StopAllSounds (menu, save-load, death) bumps a generation; the
ambient handler re-arms once per generation -- zeroing the stale
ambient play-counts globally, then each sprite's own trigger -- so a
looping ambience resumes on return to the game (the projector stayed
silent after ESC/menu or loading a save). The zeroing is deliberately
once-per-generation: several sprites can share one lotag (E1L1 has 4x
wind), and a per-sprite reset wiped a just-restarted loop's count,
leaving it playing but untracked (never panned or attenuated).
- stopenvsound now removes the exact SoundOwner entry it stopped;
routing it through TestCallBack removed the first MUSICANDSFX owner it
found, desyncing the owner list whenever sprites share a lotag, so an
ambience refused to restart on radius re-entry.
- Continuous soundm&2 ambiences (FIRE_CRACKLE, WIND_AMBIENCE, ...) now
LOOP: DOS kept them going by re-firing one-shots from the DONE
callback; looping the sample gives the same continuous result and puts
them in the per-frame FX_Pan3D update, so they attenuate and pan with
player movement like the original.
- Multi-instance ambiences restored (up to 4, as DOS's SoundOwner[][4]):
the single-instance guard now only covers true &1 loops, so a distant
wind sprite can't hold the one instance and block a nearby one.
- The ambient ON/OFF radius gate gets +1024 hysteresis so a tight-radius
source (the cinema projector, ht=2000) doesn't flicker on/off as the
player shifts around at its edge.
Live-validated over SyncTERM: gunshot timing, rocket/chopper full length, projector/fire-bin/rooftop-wind ambiences (continuous + pan + attenuate + menu/save-load resume), and Duke's kill quips.
Co-Authored-By: Claude Opus 4.8 <
noreply@anthropic.com>
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net