From 9317f753bc8bb6ecc9b0ded4058ab97282f9e45a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 22 Mar 2026 10:58:04 -0400 Subject: [PATCH] S_StartSoundAtVolumeEx: Allow applying EFX to individual sounds S_StartSoundAtVolume has been expanded to allow you to pass EFX info to it. Just set the effect and the vars for the effect and OpenAL will handle the rest. Can be used in the future for all sorts of things. I_SoundIsPlaying still needs to be modified to account for sounds lasting longer audibly then they do as a source. --- src/i_sound.h | 47 +++++++++++++++++- src/p_enemy.c | 13 +++++ src/s_sound.c | 31 ++++++++++-- src/s_sound.h | 7 ++- src/sdl/al_sound.c | 115 ++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 196 insertions(+), 17 deletions(-) diff --git a/src/i_sound.h b/src/i_sound.h index 7a5b826d2..60d82f62f 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -18,6 +18,14 @@ #include "sounds.h" #include "command.h" +#ifdef HAVE_OPENAL +#include "AL/al.h" +#include "AL/alc.h" +#include "AL/alext.h" +#include "AL/efx.h" +#include "AL/efx-presets.h" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -37,6 +45,36 @@ typedef enum { MU_MID_EX, // Non-native MIDI } musictype_t; +typedef enum +{ + EFFECT_NONE = 0, + EFFECT_REVERB, + EFFECT_DISTORTION, +} effecttypes_t; + +typedef struct +{ + // flags for effects +#ifdef HAVE_OPENAL + ALuint effect; + ALuint slot; +#endif + UINT32 type; + float var1; + float var2; + float var3; + float var4; + float var5; + float var6; + float var7; + float var8; + float var9; + float var10; + float var11; + float var12; + float var13; +} efx_t; + /** \brief Sound subsystem runing and waiting */ extern UINT8 sound_started; @@ -83,7 +121,7 @@ void I_ShutdownSound(void); \return sfx handle */ -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel); +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx); /** \brief Stops a sound channel. @@ -105,6 +143,8 @@ void I_UpdateSound(void); */ boolean I_SoundIsPlaying(INT32 handle); + + /** \brief Updates the sfx handle \param handle sfx handle @@ -114,7 +154,7 @@ boolean I_SoundIsPlaying(INT32 handle); \return void */ -void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch); +void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx); /** \brief The I_SetSfxVolume function @@ -246,6 +286,9 @@ boolean I_FadeSong(UINT8 target_volume, UINT32 ms, void (*callback)(void)); boolean I_FadeOutStopSong(UINT32 ms); boolean I_FadeInPlaySong(UINT32 ms, boolean looping); +efx_t *I_CreateEFX(efx_t *efx); +void I_DeleteEFX(efx_t *efx); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/p_enemy.c b/src/p_enemy.c index 22b41afbe..59ffab2d3 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -15,6 +15,7 @@ #include "dehacked.h" #include "doomdef.h" #include "g_game.h" +#include "i_sound.h" #include "p_local.h" #include "p_setup.h" #include "r_main.h" @@ -3233,11 +3234,23 @@ void A_AttractChase(void *thing) actor->target->player->ringboost += K_GetKartRingPower(actor->target->player, true); actor->target->player->ringtime += K_GetKartRingPower(actor->target->player, true); +//#define EFXTEST +#ifdef EFXTEST + efx_t efx; + S_InitEFXArray(&efx); + efx.type = EFFECT_REVERB; + S_StartSoundAtVolumeEx(actor->target, sfx_s1b5, actor->target->player->ringvolume, &efx); +#else S_StartSoundAtVolume(actor->target, sfx_s1b5, actor->target->player->ringvolume); +#endif if (actor->target->player->rings <= 10) { +#ifdef EFXTEST + S_StartSoundAtVolumeEx(actor->target, sfx_ringlw, 255 - actor->target->player->rings*10, &efx); +#else S_StartSoundAtVolume(actor->target, sfx_ringlw, 255 - actor->target->player->rings*10); +#endif } if (actor->target->player->ringboost > (4*TICRATE + TICRATE/2)) diff --git a/src/s_sound.c b/src/s_sound.c index 79cda0d74..6c518c1ea 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -317,6 +317,7 @@ static void SetChannelsNum(void) { channels[i].sfxinfo = 0; channels[i].origin = NULL; + channels[i].efx = NULL; } S_ResetCaptions(); @@ -525,7 +526,7 @@ static INT32 S_ScaleVolumeWithSplitscreen(INT32 volume) ) / FRACUNIT; } -void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) +void S_StartSoundAtVolumeEx(const void *origin_p, sfxenum_t sfx_id, INT32 volume, efx_t *efx) { const mobj_t *origin = (const mobj_t *)origin_p; const sfxenum_t actual_id = sfx_id; @@ -730,7 +731,17 @@ void S_StartSoundAtVolume(const void *origin_p, sfxenum_t sfx_id, INT32 volume) channels[cnum].sfxinfo = sfx; channels[cnum].origin = origin; channels[cnum].volume = initial_volume; - channels[cnum].handle = I_StartSound(sfx_id, S_GetSoundVolume(sfx, volume), sep, pitch, priority, cnum); + + if (efx != NULL && efx->type != EFFECT_NONE) + { + channels[cnum].efx = I_CreateEFX(efx); + } + else + { + channels[cnum].efx = NULL; + } + + channels[cnum].handle = I_StartSound(sfx_id, S_GetSoundVolume(sfx, volume), sep, pitch, priority, cnum, channels[cnum].efx); } } @@ -951,7 +962,7 @@ notinlevel: } if (audible) - I_UpdateSoundParams(c->handle, S_GetSoundVolume(c->sfxinfo, volume), sep, pitch); + I_UpdateSoundParams(c->handle, S_GetSoundVolume(c->sfxinfo, volume), sep, pitch, c->efx); else S_StopChannel(cnum); } @@ -1021,6 +1032,8 @@ static void S_StopChannel(INT32 cnum) } c->origin = NULL; + I_DeleteEFX(c->efx); + c->efx = NULL; } // @@ -2943,3 +2956,15 @@ void ModFilter_OnChange(void) openmpt_module_set_render_param(openmpt_mhandle, OPENMPT_MODULE_RENDER_INTERPOLATIONFILTER_LENGTH, cv_modfilter.value); } #endif + +void S_InitEFXArray(efx_t *efx) +{ + if (efx == NULL) + return; + + efx->type = EFFECT_NONE; + efx->var1 = efx->var2 = efx->var3 = -255; + efx->var4 = efx->var5 = efx->var6 = -255; + efx->var7 = efx->var8 = efx->var9 = -255; + efx->var10 = efx->var11 = efx->var12 = efx->var13 = -255; +} diff --git a/src/s_sound.h b/src/s_sound.h index c038e5375..2f471a19a 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -88,6 +88,8 @@ struct channel_t // handle of the sound being played INT32 handle; + // EFX + efx_t *efx; }; struct caption_t { @@ -139,7 +141,8 @@ boolean S_SoundDisabled(void); void S_StartSound(const void *origin, sfxenum_t sound_id); // Will start a sound at a given volume. -void S_StartSoundAtVolume(const void *origin, sfxenum_t sound_id, INT32 volume); +void S_StartSoundAtVolumeEx(const void *origin_p, sfxenum_t sfx_id, INT32 volume, efx_t *efx); +#define S_StartSoundAtVolume(origin, sound_id, volume) S_StartSoundAtVolumeEx(origin, sound_id, volume, NULL) // Stop sound for thing at void S_StopSound(void *origin); @@ -345,6 +348,8 @@ void S_StartSoundName(void *mo, const char *soundname); void S_StopSoundByID(void *origin, sfxenum_t sfx_id); void S_StopSoundByNum(sfxenum_t sfxnum); +void S_InitEFXArray(efx_t *efx); + #ifndef HW3SOUND #define S_StartAttackSound S_StartSound #define S_StartScreamSound S_StartSound diff --git a/src/sdl/al_sound.c b/src/sdl/al_sound.c index 2bd57b89e..e71388abc 100644 --- a/src/sdl/al_sound.c +++ b/src/sdl/al_sound.c @@ -391,14 +391,6 @@ void I_StartupSound(void) LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv); #undef LOAD_PROC - // Start EFX - // TODO: Discuss and see if we even want EFX flags for sounds and implement system if so. - //alGenEffects(1, &audio.effect); - //TRY(alEffecti, audio.effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION); - //TRY(alEffectf, audio.effect, AL_DISTORTION_EDGE, AL_DISTORTION_MAX_EDGE); - //alGenAuxiliaryEffectSlots(1, &audio.effectslot); - //alAuxiliaryEffectSloti(audio.effectslot, AL_EFFECTSLOT_EFFECT, audio.effect); - audio.music = INVALID_HANDLE; audio.bufferindex = 0; @@ -984,7 +976,7 @@ void I_FreeSfx(sfxinfo_t *sfx) sfx->lumpnum = LUMPERROR; } -void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch) +void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx) { if (handle == INVALID_HANDLE) return; @@ -1003,9 +995,14 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch) pan = pan * 0.5f; // 0.5 = sin(30') for a +/- 30 degree arc TRY(alSourcei, source, AL_SOURCE_RELATIVE, AL_TRUE); TRY(alSource3f, source, AL_POSITION, pan, 0, -sqrtf(1.0f - pan*pan)); + + if (efx != NULL && TRY(alIsEffect, efx->effect) && TRY(alIsAuxiliaryEffectSlot, efx->slot)) + { + TRY(alSource3i, source, AL_AUXILIARY_SEND_FILTER, efx->slot, 0, AL_FILTER_NULL); + } } -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx) { ALuint source; if (!TRY(alGenSources, 1, &source)) @@ -1023,7 +1020,7 @@ INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priori return INVALID_HANDLE; } - I_UpdateSoundParams(source, vol, sep, pitch); + I_UpdateSoundParams(source, vol, sep, pitch, efx); if (!TRY(alSourcePlay, source)) { @@ -1898,4 +1895,100 @@ boolean I_FadeInPlaySong(UINT32 ms, boolean looping) return false; } +efx_t *I_CreateEFX(efx_t *efx) +{ + LOCKAUDIO; + + efx_t *efxc = Z_Calloc(sizeof(efx_t), PU_STATIC, NULL); + + if (efxc == NULL) + I_Error("OpenAL: Ran out of memory generating EFX.\n"); + + if (efx != NULL) + memcpy(efxc, efx, sizeof(efx_t)); + + // Init effects and slots. + TRY(alGenEffects, 1, &efxc->effect); + TRY(alGenAuxiliaryEffectSlots, 1, &efxc->slot); + + if (TRY(alIsEffect, efxc->effect) && TRY(alIsAuxiliaryEffectSlot, efxc->slot)) + { + switch (efxc->type) + { + case EFFECT_REVERB: + TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + if (efxc->var1 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_DENSITY, efxc->var1); + if (efxc->var2 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_DIFFUSION, efxc->var2); + if (efxc->var3 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_GAIN, efxc->var3); + if (efxc->var4 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_GAINHF, efxc->var4); + if (efxc->var5 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_DECAY_TIME, efxc->var5); + if (efxc->var6 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_DECAY_HFRATIO, efxc->var6); + if (efxc->var7 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_REFLECTIONS_GAIN, efxc->var7); + if (efxc->var8 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_REFLECTIONS_DELAY, efxc->var8); + if (efxc->var9 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_LATE_REVERB_GAIN, efxc->var9); + if (efxc->var10 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_LATE_REVERB_DELAY, efxc->var10); + if (efxc->var11 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efxc->var11); + if (efxc->var12 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efxc->var12); + if (efxc->var13 != -255) + TRY(alEffectf, efxc->effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efxc->var13); + + break; + case EFFECT_DISTORTION: + TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION); + + if (efxc->var1 != -255) + TRY(alEffectf, efxc->effect, AL_DISTORTION_EDGE, efxc->var1); + if (efxc->var2 != -255) + TRY(alEffectf, efxc->effect, AL_DISTORTION_GAIN, efxc->var2); + if (efxc->var3 != -255) + TRY(alEffectf, efxc->effect, AL_DISTORTION_LOWPASS_CUTOFF, efxc->var3); + if (efxc->var4 != -255) + TRY(alEffectf, efxc->effect, AL_DISTORTION_EQCENTER, efxc->var4); + if (efxc->var5 != -255) + TRY(alEffectf, efxc->effect, AL_DISTORTION_EQBANDWIDTH, efxc->var5); + break; + } + + TRY(alAuxiliaryEffectSloti, efxc->slot, AL_EFFECTSLOT_EFFECT, efxc->effect); + return efxc; + } + + Z_Free(efxc); + + return NULL; +} + +void I_DeleteEFX(efx_t *efx) +{ + LOCKAUDIO; + + if (efx == NULL) + return; + + if (TRY(alIsEffect, efx->effect)) + { + TRY(alDeleteEffects, 1, &efx->effect); + } + + if (TRY(alIsAuxiliaryEffectSlot, efx->slot)) + { + TRY(alDeleteAuxiliaryEffectSlots, 1, &efx->slot); + } + + Z_Free(efx); +} + #endif // defined(HAVE_OPENAL)