From 4cc6eef47391b56add81ba46bae885ea86a87ced Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 12 Sep 2023 00:44:15 +0300 Subject: [PATCH 1/6] Add ATTN_LOOP_NONE hack. Needed because value 0 for loop_attenuation means default attenuation. --- inc/shared/shared.h | 1 + src/common/msg.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/inc/shared/shared.h b/inc/shared/shared.h index 018f0d875..babf24342 100644 --- a/inc/shared/shared.h +++ b/inc/shared/shared.h @@ -1186,6 +1186,7 @@ enum { }; // sound attenuation values +#define ATTN_LOOP_NONE -1 // ugly hack for remaster #define ATTN_NONE 0 // full volume the entire level #define ATTN_NORM 1 #define ATTN_IDLE 2 diff --git a/src/common/msg.c b/src/common/msg.c index b2f9547f6..2e72c6a5e 100644 --- a/src/common/msg.c +++ b/src/common/msg.c @@ -480,12 +480,18 @@ void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, const entity out->alpha = Q_clip_uint8(ext->alpha * 255.0f); out->scale = Q_clip_uint8(ext->scale * 16.0f); out->loop_volume = Q_clip_uint8(ext->loop_volume * 255.0f); - out->loop_attenuation = Q_clip_uint8(ext->loop_attenuation * 64.0f); + // encode ATTN_STATIC (192) as 0, and ATTN_LOOP_NONE (-1) as 192 + if (ext->loop_attenuation == ATTN_LOOP_NONE) { + out->loop_attenuation = 192; + } else { + out->loop_attenuation = Q_clip_uint8(ext->loop_attenuation * 64.0f); + if (out->loop_attenuation == 192) + out->loop_attenuation = 0; + } // save network bandwidth if (out->alpha == 255) out->alpha = 0; if (out->scale == 16) out->scale = 0; if (out->loop_volume == 255) out->loop_volume = 0; - if (out->loop_attenuation == 192) out->loop_attenuation = 0; } } @@ -1897,8 +1903,13 @@ void MSG_ParseDeltaEntity(entity_state_t *to, to->sound = w & 0x3fff; if (w & 0x4000) ext->loop_volume = MSG_ReadByte() / 255.0f; - if (w & 0x8000) - ext->loop_attenuation = MSG_ReadByte() / 64.0f; + if (w & 0x8000) { + int b = MSG_ReadByte(); + if (b == 192) + ext->loop_attenuation = ATTN_LOOP_NONE; + else + ext->loop_attenuation = b / 64.0f; + } } else { to->sound = MSG_ReadByte(); } From dd7ed48d5b39a9562df4b7f761e1f568dc0e5402 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 12 Sep 2023 00:53:42 +0300 Subject: [PATCH 2/6] Support custom volume/attenuation for looped sounds. --- src/client/sound/al.c | 4 ++-- src/client/sound/dma.c | 18 ++++++++++-------- src/client/sound/main.c | 20 ++++++++++++++++++++ src/client/sound/sound.h | 2 ++ 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/client/sound/al.c b/src/client/sound/al.c index 60696bd7f..8933c5d92 100644 --- a/src/client/sound/al.c +++ b/src/client/sound/al.c @@ -386,8 +386,8 @@ static void AL_AddLoopSounds(void) ch->autoframe = s_framecount; ch->sfx = sfx; ch->entnum = ent->number; - ch->master_vol = 1.0f; - ch->dist_mult = SOUND_LOOPATTENUATE; + ch->master_vol = S_GetEntityLoopVolume(ent); + ch->dist_mult = S_GetEntityLoopDistMult(ent); ch->end = s_paintedtime + sc->length; AL_PlayChannel(ch); diff --git a/src/client/sound/dma.c b/src/client/sound/dma.c index b18ec1c0d..bbd2b0e98 100644 --- a/src/client/sound/dma.c +++ b/src/client/sound/dma.c @@ -667,7 +667,7 @@ static void SpatializeOrigin(const vec3_t origin, float master_vol, float dist_m dist = 0; // close enough to be at full volume dist *= dist_mult; // different attenuation levels - if (dma.channels == 1) { + if (dma.channels == 1 || !dist_mult) { rscale = 1.0f; lscale = 1.0f; } else { @@ -727,7 +727,7 @@ static void AddLoopSounds(void) { int i, j; int sounds[MAX_EDICTS]; - float left, right, left_total, right_total; + float left, right, left_total, right_total, vol, att; channel_t *ch; sfx_t *sfx; sfxcache_t *sc; @@ -754,10 +754,12 @@ static void AddLoopSounds(void) num = (cl.frame.firstEntity + i) & PARSE_ENTITIES_MASK; ent = &cl.entityStates[num]; + vol = S_GetEntityLoopVolume(ent); + att = S_GetEntityLoopDistMult(ent); + // find the total contribution of all sounds of this type CL_GetEntitySoundOrigin(ent->number, origin); - SpatializeOrigin(origin, 1.0f, SOUND_LOOPATTENUATE, - &left_total, &right_total); + SpatializeOrigin(origin, vol, att, &left_total, &right_total); for (j = i + 1; j < cl.frame.numEntities; j++) { if (sounds[j] != sounds[i]) continue; @@ -767,8 +769,8 @@ static void AddLoopSounds(void) ent = &cl.entityStates[num]; CL_GetEntitySoundOrigin(ent->number, origin); - SpatializeOrigin(origin, 1.0f, SOUND_LOOPATTENUATE, - &left, &right); + SpatializeOrigin(origin, S_GetEntityLoopVolume(ent), + S_GetEntityLoopDistMult(ent), &left, &right); left_total += left; right_total += right; } @@ -783,8 +785,8 @@ static void AddLoopSounds(void) ch->leftvol = min(left_total, 1.0f); ch->rightvol = min(right_total, 1.0f); - ch->master_vol = 1.0f; - ch->dist_mult = SOUND_LOOPATTENUATE; // for S_IsFullVolume() + ch->master_vol = vol; + ch->dist_mult = att; // for S_IsFullVolume() ch->autosound = true; // remove next frame ch->sfx = sfx; ch->pos = s_paintedtime % sc->length; diff --git a/src/client/sound/main.c b/src/client/sound/main.c index 96b99abf2..9ebfe43b0 100644 --- a/src/client/sound/main.c +++ b/src/client/sound/main.c @@ -812,6 +812,26 @@ void S_BuildSoundList(int *sounds) } } +float S_GetEntityLoopVolume(const centity_state_t *ent) +{ + if (ent->loop_volume) + return ent->loop_volume; + + return 1.0f; +} + +float S_GetEntityLoopDistMult(const centity_state_t *ent) +{ + if (ent->loop_attenuation) { + if (ent->loop_attenuation == ATTN_LOOP_NONE) + return 0; + if (ent->loop_attenuation != ATTN_STATIC) + return ent->loop_attenuation * 0.0005f; + } + + return SOUND_LOOPATTENUATE; +} + /* ============ S_Update diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index efa7667a6..7aaef5e2e 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -180,5 +180,7 @@ sfxcache_t *S_LoadSound(sfx_t *s); channel_t *S_PickChannel(int entnum, int entchannel); void S_IssuePlaysound(playsound_t *ps); void S_BuildSoundList(int *sounds); +float S_GetEntityLoopVolume(const centity_state_t *ent); +float S_GetEntityLoopDistMult(const centity_state_t *ent); bool OGG_Load(sizebuf_t *sz); From 0228439979b1e4c4051912bc8119d7f07d2f0817 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 12 Sep 2023 16:08:48 +0300 Subject: [PATCH 3/6] Support remaster sound culling rules. --- inc/client/client.h | 5 +++ src/client/sound/sound.h | 5 --- src/server/entities.c | 70 +++++++++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 31 deletions(-) diff --git a/inc/client/client.h b/inc/client/client.h index 62d49b474..51809eabc 100644 --- a/inc/client/client.h +++ b/inc/client/client.h @@ -25,6 +25,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CHAR_WIDTH 8 #define CHAR_HEIGHT 8 +// only begin attenuating sound volumes when outside the FULLVOLUME range +#define SOUND_FULLVOLUME 80 + +#define SOUND_LOOPATTENUATE 0.003f + #if USE_CLIENT #define MAX_LOCAL_SERVERS 16 diff --git a/src/client/sound/sound.h b/src/client/sound/sound.h index 7aaef5e2e..dce2abac8 100644 --- a/src/client/sound/sound.h +++ b/src/client/sound/sound.h @@ -140,11 +140,6 @@ extern const sndapi_t snd_openal; //==================================================================== -// only begin attenuating sound volumes when outside the FULLVOLUME range -#define SOUND_FULLVOLUME 80 - -#define SOUND_LOOPATTENUATE 0.003f - extern sndstarted_t s_started; extern bool s_active; extern sndapi_t s_api; diff --git a/src/server/entities.c b/src/server/entities.c index 1c64fa711..784341399 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -374,6 +374,31 @@ fix_old_origin(client_t *client, entity_packed_t *state, edict_t *ent, int e) } #endif +static bool SV_EntityVisible(client_t *client, edict_t *ent, byte *mask) +{ + if (ent->num_clusters == -1) + // too many leafs for individual check, go by headnode + return CM_HeadnodeVisible(CM_NodeNum(client->cm, ent->headnode), mask); + + // check individual leafs + for (int i = 0; i < ent->num_clusters; i++) + if (Q_IsBitSet(mask, ent->clusternums[i])) + return true; + + return false; +} + +static bool SV_EntityAttenuatedAway(vec3_t org, edict_t *ent) +{ + float dist = Distance(org, ent->s.origin); + float dist_mult = SOUND_LOOPATTENUATE; + + if (ent->x.loop_attenuation && ent->x.loop_attenuation != ATTN_STATIC) + dist_mult = ent->x.loop_attenuation * 0.0005f; + + return (dist - SOUND_FULLVOLUME) * dist_mult > 1.0f; +} + /* ============= SV_BuildClientFrame @@ -384,7 +409,7 @@ copies off the playerstat and areabits. */ void SV_BuildClientFrame(client_t *client) { - int e, i; + int e; vec3_t org; edict_t *ent; edict_t *clent; @@ -502,34 +527,27 @@ void SV_BuildClientFrame(client_t *client) } } - if (ent_visible) - { - // beams just check one point for PHS - if (ent->s.renderfx & RF_BEAM) { - if (!Q_IsBitSet(clientphs, ent->clusternums[0])) - ent_visible = false; - } - else { - if (cull_nonvisible_entities) { - if (ent->num_clusters == -1) { - // too many leafs for individual check, go by headnode - if (!CM_HeadnodeVisible(CM_NodeNum(client->cm, ent->headnode), clientpvs)) - ent_visible = false; - } else { - // check individual leafs - for (i = 0; i < ent->num_clusters; i++) - if (Q_IsBitSet(clientpvs, ent->clusternums[i])) - break; - if (i == ent->num_clusters) - ent_visible = false; // not visible - } - } + // beams just check one point for PHS + // remaster uses different sound culling rules + bool beam_cull = ent->s.renderfx & RF_BEAM; + bool sound_cull = client->csr->extended && ent->s.sound; + if (beam_cull || cull_nonvisible_entities) { + if (!SV_EntityVisible(client, ent, (beam_cull || sound_cull) ? clientphs : clientpvs)) + ent_visible = false; // not visible + } + + // don't send sounds if they will be attenuated away + if (sound_cull) { + if (SV_EntityAttenuatedAway(org, ent)) { if (!ent->s.modelindex) - // don't send sounds if they will be attenuated away - if (Distance(org, ent->s.origin) > 400) - ent_visible = false; + ent_visible = false; + if (ent_visible && !beam_cull && !SV_EntityVisible(client, ent, clientpvs)) + ent_visible = false; } + } else if (!ent->s.modelindex) { + if (Distance(org, ent->s.origin) > 400) + ent_visible = false; } } From f48bfb59af9812d9f420c1e4fa6158d9da571ebd Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Tue, 12 Sep 2023 16:08:58 +0300 Subject: [PATCH 4/6] Support SVF_NOCULL. --- src/server/entities.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/entities.c b/src/server/entities.c index 784341399..ddeba1df5 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -517,7 +517,7 @@ void SV_BuildClientFrame(client_t *client) ent_visible = true; // ignore if not touching a PV leaf - if (ent != clent) { + if (ent != clent && !(client->csr->extended && ent->svflags & SVF_NOCULL)) { // check area if (clientcluster >= 0 && !CM_AreasConnected(client->cm, clientarea, ent->areanum)) { // doors can legally straddle two areas, so From ecc76718cdc58f5cd689d37a03aa5244cf56de33 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Sun, 17 Sep 2023 01:32:09 +0300 Subject: [PATCH 5/6] Make looped sound attenuation a bit higher. --- inc/client/client.h | 2 ++ src/client/sound/main.c | 2 +- src/server/entities.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/inc/client/client.h b/inc/client/client.h index 51809eabc..e4e0233d7 100644 --- a/inc/client/client.h +++ b/inc/client/client.h @@ -30,6 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #define SOUND_LOOPATTENUATE 0.003f +#define SOUND_LOOPATTENUATE_MULT 0.0006f + #if USE_CLIENT #define MAX_LOCAL_SERVERS 16 diff --git a/src/client/sound/main.c b/src/client/sound/main.c index 9ebfe43b0..c5ddf219d 100644 --- a/src/client/sound/main.c +++ b/src/client/sound/main.c @@ -826,7 +826,7 @@ float S_GetEntityLoopDistMult(const centity_state_t *ent) if (ent->loop_attenuation == ATTN_LOOP_NONE) return 0; if (ent->loop_attenuation != ATTN_STATIC) - return ent->loop_attenuation * 0.0005f; + return ent->loop_attenuation * SOUND_LOOPATTENUATE_MULT; } return SOUND_LOOPATTENUATE; diff --git a/src/server/entities.c b/src/server/entities.c index ddeba1df5..2c296aa06 100644 --- a/src/server/entities.c +++ b/src/server/entities.c @@ -394,7 +394,7 @@ static bool SV_EntityAttenuatedAway(vec3_t org, edict_t *ent) float dist_mult = SOUND_LOOPATTENUATE; if (ent->x.loop_attenuation && ent->x.loop_attenuation != ATTN_STATIC) - dist_mult = ent->x.loop_attenuation * 0.0005f; + dist_mult = ent->x.loop_attenuation * SOUND_LOOPATTENUATE_MULT; return (dist - SOUND_FULLVOLUME) * dist_mult > 1.0f; } From c418ff7eeced91c9a281d29449fce78038b71ddd Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 19 Oct 2023 14:05:44 +0300 Subject: [PATCH 6/6] Add support for 24-bit PCM in WAV. Some WAV files from re-release contain 24-bit PCM. Truncate to 16. --- src/client/sound/mem.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/src/client/sound/mem.c b/src/client/sound/mem.c index 42c78192b..890c49d6c 100644 --- a/src/client/sound/mem.c +++ b/src/client/sound/mem.c @@ -115,6 +115,9 @@ static bool GetWavinfo(sizebuf_t *sz) case 16: s_info.width = 2; break; + case 24: + s_info.width = 3; + break; default: Com_DPrintf("%s has bad width\n", s_info.name); return false; @@ -179,6 +182,27 @@ static bool GetWavinfo(sizebuf_t *sz) return true; } +static void ConvertSamples(void) +{ + uint16_t *data = (uint16_t *)s_info.data; + int count = s_info.samples * s_info.channels; + +// sigh. truncate 24 bit to 16 + if (s_info.width == 3) { + for (int i = 0; i < count; i++) + data[i] = RL32(&s_info.data[i * 3]) >> 8; + s_info.width = 2; + return; + } + +#if USE_BIG_ENDIAN + if (s_info.width == 2) { + for (int i = 0; i < count; i++) + data[i] = LittleShort(data[i]); + } +#endif +} + /* ============== S_LoadSound @@ -227,15 +251,8 @@ sfxcache_t *S_LoadSound(sfx_t *s) goto fail; } -#if USE_BIG_ENDIAN - if (s_info.format == FORMAT_PCM && s_info.width == 2) { - uint16_t *data = (uint16_t *)s_info.data; - int count = s_info.samples * s_info.channels; - - for (int i = 0; i < count; i++) - data[i] = LittleShort(data[i]); - } -#endif + if (s_info.format == FORMAT_PCM) + ConvertSamples(); sc = s_api.upload_sfx(s);