From: bones_was_here Date: Sun, 10 Mar 2024 16:23:03 +0000 (+1000) Subject: Merge PR 'Muffle sounds when the player is under water' X-Git-Url: https://git.xonotic.org/?a=commitdiff_plain;h=cf08534c0fda3dd55275603a29285d4acaf9f0cf;hp=c1bc0951402274b2d01e3b6e3edb5e32ac70f174;p=xonotic%2Fdarkplaces.git Merge PR 'Muffle sounds when the player is under water' See https://github.com/DarkPlacesEngine/darkplaces/pull/140 Signed-off-by: bones_was_here --- diff --git a/client.h b/client.h index fc44f348..9523196d 100644 --- a/client.h +++ b/client.h @@ -1135,6 +1135,9 @@ typedef struct client_state_s // used by EntityState5_ReadUpdate skeleton_t *engineskeletonobjects; + + // used by underwater sound filter (snd_waterfx) + qbool view_underwater; } client_state_t; diff --git a/snd_main.c b/snd_main.c index 821ed7b4..03d7e33e 100644 --- a/snd_main.c +++ b/snd_main.c @@ -183,6 +183,7 @@ cvar_t snd_spatialization_prologic_frontangle = {CF_CLIENT | CF_ARCHIVE, "snd_sp cvar_t snd_spatialization_occlusion = {CF_CLIENT | CF_ARCHIVE, "snd_spatialization_occlusion", "1", "enable occlusion testing on spatialized sounds, which simply quiets sounds that are blocked by the world; 1 enables PVS method, 2 enables LineOfSight method, 3 enables both"}; // Cvars declared in snd_main.h (shared with other snd_*.c files) +cvar_t snd_waterfx = {CF_CLIENT | CF_ARCHIVE, "snd_waterfx", "1", "underwater sound filter strength"}; cvar_t _snd_mixahead = {CF_CLIENT | CF_ARCHIVE, "_snd_mixahead", "0.15", "how much sound to mix ahead of time"}; cvar_t snd_streaming = {CF_CLIENT | CF_ARCHIVE, "snd_streaming", "1", "enables keeping compressed ogg sound files compressed, decompressing them only as needed, otherwise they will be decompressed completely at load (may use a lot of memory); when set to 2, streaming is performed even if this would waste memory"}; cvar_t snd_streaming_length = {CF_CLIENT | CF_ARCHIVE, "snd_streaming_length", "1", "decompress sounds completely if they are less than this play time when snd_streaming is 1"}; @@ -812,6 +813,7 @@ void S_Init(void) Cvar_RegisterVariable(&ambient_fade); Cvar_RegisterVariable(&snd_noextraupdate); Cvar_RegisterVariable(&snd_show); + Cvar_RegisterVariable(&snd_waterfx); Cvar_RegisterVariable(&_snd_mixahead); Cvar_RegisterVariable(&snd_swapstereo); // for people with backwards sound wiring Cvar_RegisterVariable(&snd_channellayout); @@ -1850,7 +1852,6 @@ void S_StaticSound (sfx_t *sfx, vec3_t origin, float fvol, float attenuation) S_PlaySfxOnChannel (sfx, target_chan, CHANNELFLAG_FORCELOOP, origin, fvol, attenuation, true, 0, 0, 0, 1.0f); } - /* =================== S_UpdateAmbientSounds @@ -1870,7 +1871,10 @@ static void S_UpdateAmbientSounds (void) if (cl.worldmodel && cl.worldmodel->brush.AmbientSoundLevelsForPoint) cl.worldmodel->brush.AmbientSoundLevelsForPoint(cl.worldmodel, listener_origin, ambientlevels, sizeof(ambientlevels)); + // Calc ambient sound levels + S_SetUnderwaterIntensity(); + for (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++) { chan = &channels[ambient_channel]; diff --git a/snd_main.h b/snd_main.h index ff5e43f1..1ce9e169 100644 --- a/snd_main.h +++ b/snd_main.h @@ -125,6 +125,7 @@ extern snd_ringbuffer_t *snd_renderbuffer; extern qbool snd_threaded; // enables use of snd_usethreadedmixing, provided that no sound hacks are in effect (like timedemo) extern qbool snd_usethreadedmixing; // if true, the main thread does not mix sound, soundtime does not advance, and neither does snd_renderbuffer->endframe, instead the audio thread will call S_MixToBuffer as needed +extern struct cvar_s snd_waterfx; extern struct cvar_s _snd_mixahead; extern struct cvar_s snd_swapstereo; extern struct cvar_s snd_streaming; @@ -152,6 +153,8 @@ extern qbool simsound; // Architecture-independent functions // ==================================================================== +void S_SetUnderwaterIntensity(void); + void S_MixToBuffer(void *stream, unsigned int frames); qbool S_LoadSound (struct sfx_s *sfx, qbool complain); diff --git a/snd_mix.c b/snd_mix.c index 736d6ea1..9d5c2e54 100644 --- a/snd_mix.c +++ b/snd_mix.c @@ -310,6 +310,66 @@ static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_p } + +/* +=============================================================================== + +UNDERWATER EFFECT + +Muffles the intensity of sounds when the player is underwater + +=============================================================================== +*/ + +static struct +{ + float intensity; + float alpha; + float accum[SND_LISTENERS]; +} +underwater = {0.f, 1.f, {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}}; + +void S_SetUnderwaterIntensity(void) +{ + float target = cl.view_underwater ? bound(0.f, snd_waterfx.value, 2.f) : 0.f; + + if (underwater.intensity < target) + { + underwater.intensity += cl.realframetime * 4.f; + underwater.intensity = min(underwater.intensity, target); + } + else if (underwater.intensity > target) + { + underwater.intensity -= cl.realframetime * 4.f; + underwater.intensity = max(underwater.intensity, target); + } + + underwater.alpha = exp(-underwater.intensity * log(12.f)); +} + +static void S_UnderwaterFilter(int endtime) +{ + int i; + int sl; + + if (!underwater.intensity) + { + if (endtime > 0) + for (sl = 0; sl < SND_LISTENERS; sl++) + underwater.accum[sl] = paintbuffer[endtime-1].sample[sl]; + return; + } + + for (i = 0; i < endtime; i++) + for (sl = 0; sl < SND_LISTENERS; sl++) + { + underwater.accum[sl] += underwater.alpha * (paintbuffer[i].sample[sl] - underwater.accum[sl]); + paintbuffer[i].sample[sl] = underwater.accum[sl]; + } +} + + + /* =============================================================================== @@ -580,6 +640,9 @@ void S_MixToBuffer(void *stream, unsigned int bufferframes) S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels); + S_UnderwaterFilter(totalmixframes); + + #ifdef CONFIG_VIDEO_CAPTURE if (!snd_usethreadedmixing) S_CaptureAVISound(paintbuffer, totalmixframes); diff --git a/view.c b/view.c index 53567b95..e8eaec7e 100644 --- a/view.c +++ b/view.c @@ -1059,6 +1059,7 @@ void V_CalcViewBlend(void) supercontents = CL_PointSuperContents(vieworigin); if (supercontents & SUPERCONTENTS_LIQUIDSMASK) { + cl.view_underwater = true; r_refdef.frustumscale_x *= 1 - (((sin(cl.time * 4.7) + 1) * 0.015) * r_waterwarp.value); r_refdef.frustumscale_y *= 1 - (((sin(cl.time * 3.0) + 1) * 0.015) * r_waterwarp.value); if (supercontents & SUPERCONTENTS_LAVA) @@ -1083,6 +1084,7 @@ void V_CalcViewBlend(void) } else { + cl.view_underwater = false; cl.cshifts[CSHIFT_CONTENTS].destcolor[0] = 0; cl.cshifts[CSHIFT_CONTENTS].destcolor[1] = 0; cl.cshifts[CSHIFT_CONTENTS].destcolor[2] = 0;