From 9061274cdc3fd5f770eb02f689c28389736ac37a Mon Sep 17 00:00:00 2001 From: NepDisk Date: Sun, 22 Mar 2026 20:21:38 -0400 Subject: [PATCH] Add per map global EFX via mapheader --- extras/udmf-spec.txt | 17 ++- src/d_netcmd.c | 3 + src/deh_soc.c | 71 +++++++++ src/deh_tables.c | 24 +++ src/doomstat.h | 5 + src/i_sound.h | 16 +- src/p_setup.c | 37 ++++- src/p_spec.c | 4 + src/r_defs.h | 2 + src/s_sound.c | 18 ++- src/s_sound.h | 3 + src/sdl/al_sound.c | 357 +++++++++++++++++++++++++++---------------- 12 files changed, 404 insertions(+), 153 deletions(-) diff --git a/extras/udmf-spec.txt b/extras/udmf-spec.txt index 6e6b29626..08c185bc2 100644 --- a/extras/udmf-spec.txt +++ b/extras/udmf-spec.txt @@ -214,6 +214,7 @@ BlanKart's namespace implements the following additional fields: invertencore = ; // true = encore remap rules are inverted. flatlighting = ; // true = directional lighting is forced off. forcedirectionallighting = ; // true = directional lighting is forced on. + noaudioeffects = ; // true = global audio effects for objects in this sector are disabled. nostepup = ; // true = objects can't step up. doublestepup = ; // true = objects have increased step up. nostepdown = ; // true = objects can't step down. @@ -225,12 +226,13 @@ BlanKart's namespace implements the following additional fields: zoomtubestart = ; // true = sector is start of a zoom tube. zoomtubeend = ; // true = sector is end of a zoom tube. - speedpad = ; // true = players are launched forward by this sector. - finishline = ; // true = players gain a lap or finish the race in this sector. Used for legacy support. - sneakerpanel = ; // true = players are speed boosted forward by this sector. - waterpanel = ; // true = players are speed boosted forward by this sector and are able to drive on water. - redpogospring = ; // true = players are bounced into the air by this sector. - yellowpogospring = ; // true = players are bounced into the air and then speedcapped by this sector. + speedpad = ; // true = players are launched forward by this sector. + finishline = ; // true = players gain a lap or finish the race in this sector. Used for legacy support. + sneakerpanel = ; // true = players are speed boosted forward by this sector. + waterpanel = ; // true = players are speed boosted forward by this sector and are able to drive on water. + redpogospring = ; // true = players are bounced into the air by this sector. + yellowpogospring = ; // true = players are bounced into the air and then speedcapped by this sector. + walltransfer = ; // true = players are allowed to slide up walls from this sector. repeatspecial = ; // true = repeatable action. continuousspecial = ; // true = action is executed every game tick. @@ -313,3 +315,6 @@ BK 1.0: 10.02.2025 BK 1.0: 11.03.2025 - Fixed up some typos. - Added more effects. + +BK 1.0 22.03.2026 +- Added more effects. diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 2212afee5..075291a65 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1437,6 +1437,9 @@ void D_RegisterClientCommands(void) CV_RegisterVar(&cv_digmusicvolume); CV_RegisterVar(&cv_numChannels); + // al_sound.c + CV_RegisterVar(&cv_soundefx); + // screen.c CV_RegisterVar(&cv_fullscreen); CV_RegisterVar(&cv_renderview); diff --git a/src/deh_soc.c b/src/deh_soc.c index ae2e7467b..29e567d4e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1270,6 +1270,77 @@ void readlevelheader(MYFILE *f, char * name) else mapheaderinfo[num]->use_terrain = false; } + // Global EFX + else if (fastcmp(word, "GLOBALEFX")) + { + mapheaderinfo[num]->globalEFX->type = get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR1")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var1 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR2")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var2 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR3")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var3 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR4")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var4 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR5")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var5 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR6")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var6 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR7")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var7 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR8")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var8 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR9")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var9 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR10")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var10 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR11")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var11 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR12")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var12 = flonum ? flonum : get_number(word2); + } + else if (fastcmp(word, "GLOBALEFXVAR13")) + { + float flonum = atof(word2); + mapheaderinfo[num]->globalEFX->var13 = flonum ? flonum : get_number(word2); + } + // ignored for compatibility else if (fastcmp(word, "NEXTLEVEL") || fastcmp(word, "TIMEATTACK") || fastcmp(word, "RECORDATTACK")) continue; diff --git a/src/deh_tables.c b/src/deh_tables.c index 3794bf3a2..04ebd63be 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -14,6 +14,7 @@ #include "d_ticcmd.h" #include "doomdef.h" // Constants #include "s_sound.h" // Sound constants +#include "i_sound.h" #include "info.h" // Mobj, state, sprite, etc constants #include "m_menu.h" // Menu constants #include "y_inter.h" // Intermission constants @@ -537,6 +538,7 @@ const char *const MSF_LIST[] = { "INVERTENCORE", "FLATLIGHTING", "DIRECTIONLIGHTING", + "NOEFX", NULL }; @@ -559,6 +561,10 @@ const char *const SSF_LIST[] = { "FINISHLINE", "ZOOMTUBESTART", "ZOOMTUBEEND", + "NOPHYSICSFLOOR", + "NOPHYSICSCEILING", + "GRAVITYOVERRIDE", + "WALLTRANSFER", NULL }; @@ -1863,5 +1869,23 @@ struct int_const_s const INT_CONST[] = { {"TICCMD_USINGTILT", TICCMD_USINGTILT}, {"TICCMD_EXCESSTILT", TICCMD_EXCESSTILT}, + // EFX + {"EFFECT_NONE", EFFECT_NONE}, + {"EFFECT_REVERB", EFFECT_REVERB}, + {"EFFECT_CHORUS", EFFECT_CHORUS}, + {"EFFECT_DISTORTION", EFFECT_DISTORTION}, + {"EFFECT_ECHO", EFFECT_ECHO}, + {"EFFECT_PITCHSHIFT", EFFECT_PITCHSHIFT}, + {"EFFECT_RINGMOD", EFFECT_RINGMOD}, + {"EFFECT_COMPRESSOR", EFFECT_COMPRESSOR}, + {"EFFECT_EQ", EFFECT_EQ}, + + {"CHORUSWAVE_SINUSOID", CHORUSWAVE_SINUSOID}, + {"CHORUSWAVE_TRIANGLE", CHORUSWAVE_TRIANGLE}, + + {"RINGMOD_SIN", RINGMOD_SIN}, + {"RINGMOD_SAW", RINGMOD_SAW}, + {"RINGMOD_SQUARE", RINGMOD_SQUARE}, + {NULL,0} }; diff --git a/src/doomstat.h b/src/doomstat.h index 909cffac5..806bd7a7a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -29,6 +29,8 @@ extern "C" { // We need the player data structure as well. #include "d_player.h" +#include "i_sound.h" + // ============================= // Selected map etc. // ============================= @@ -435,6 +437,9 @@ struct mapheader_t boolean use_terrain; ///< Whether to use gameplay affecting Terrain effects or not (leaves visuals alone) INT32 base_track_complexity; ///< Decides what the base track compexity for the current map is. fixed_t track_modifier_max; ///< Decides what the modifier max for the current map is. + + // EFX + efx_t *globalEFX; ///< Decides what global EFX for the current map is. ONLY USE FOR TYPE AND VARS. }; diff --git a/src/i_sound.h b/src/i_sound.h index bdd6609a5..8bb431263 100644 --- a/src/i_sound.h +++ b/src/i_sound.h @@ -58,13 +58,16 @@ typedef enum EFFECT_EQ, } effecttypes_t; -#ifdef HAVE_OPENAL typedef enum { +#ifdef HAVE_OPENAL CHORUSWAVE_SINUSOID = AL_CHORUS_WAVEFORM_SINUSOID, CHORUSWAVE_TRIANGLE = AL_CHORUS_WAVEFORM_TRIANGLE, -} choruswaves_t; +#else + CHORUSWAVE_SINUSOID = 0, + CHORUSWAVE_TRIANGLE = 0, #endif +} choruswaves_t; typedef enum { @@ -142,7 +145,7 @@ void I_ShutdownSound(void); \return sfx handle */ -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx); +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx, const void *origin); /** \brief Stops a sound channel. @@ -175,7 +178,7 @@ boolean I_SoundIsPlaying(INT32 handle); \return void */ -void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx); +void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx, const void *origin); /** \brief The I_SetSfxVolume function @@ -311,6 +314,11 @@ efx_t *I_CreateEFX(efx_t *efx); float I_GetEFXTail(efx_t *efx); void I_DeleteEFX(efx_t *efx); +void I_CreateGlobalEFX(efx_t *efx); +void I_DeleteGlobalEFX(void); + +extern consvar_t cv_soundefx; + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/p_setup.c b/src/p_setup.c index c003e10ee..3021b317c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -26,6 +26,7 @@ #include "i_time.h" #include "i_video.h" // for I_FinishUpdate().. +#include "r_defs.h" #include "r_sky.h" #include "i_system.h" @@ -470,6 +471,7 @@ static void P_ClearSingleMapHeaderInfo(INT16 num) P_ClearMapHeaderLighting(&mapheaderinfo[num]->lighting); P_ClearMapHeaderLighting(&mapheaderinfo[num]->lighting_encore); mapheaderinfo[num]->use_encore_lighting = false; + S_InitEFXArray(mapheaderinfo[num]->globalEFX); #if 1 // equivalent to "FlickyList = DEMO" P_SetDemoFlickies(num); #else // equivalent to "FlickyList = NONE" @@ -529,6 +531,11 @@ void P_AllocMapHeader(INT16 i) mapheaderinfo[i]->minimapPic = NULL; mapheaderinfo[i]->cup = NULL; mapheaderinfo[i]->flickies = NULL; + mapheaderinfo[i]->globalEFX = Z_Calloc(sizeof(efx_t), PU_STATIC, NULL); + + if (mapheaderinfo[i]->globalEFX == NULL) + I_Error("P_AllocMapHeader: Not enough memory to allocate new global mapheader EFX (ID %d).", i); + nummapheaders++; } P_ClearSingleMapHeaderInfo(i); @@ -1892,6 +1899,8 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char sectors[i].flags |= MSF_FLATLIGHTING; else if (fastcmp(param, "forcedirectionallighting") && fastcmp("true", val)) sectors[i].flags |= MSF_DIRECTIONLIGHTING; + else if (fastcmp(param, "noaudioeffects") && fastcmp("true", val)) + sectors[i].flags |= MSF_NOEFX; else if (fastcmp(param, "nostepup") && fastcmp("true", val)) sectors[i].specialflags |= SSF_NOSTEPUP; else if (fastcmp(param, "doublestepup") && fastcmp("true", val)) @@ -1916,20 +1925,20 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char sectors[i].specialflags |= SSF_YELLOWPOGOSPRING; else if (fastcmp(param, "fan") && fastcmp("true", val)) sectors[i].specialflags |= SSF_FAN; + else if (fastcmp(param, "finishline") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_FINISHLINE; else if (fastcmp(param, "zoomtubestart") && fastcmp("true", val)) sectors[i].specialflags |= SSF_ZOOMTUBESTART; else if (fastcmp(param, "zoomtubeend") && fastcmp("true", val)) sectors[i].specialflags |= SSF_ZOOMTUBEEND; - else if (fastcmp(param, "finishline") && fastcmp("true", val)) - sectors[i].specialflags |= SSF_FINISHLINE; - else if (fastcmp(param, "gravityoverride") && fastcmp("true", val)) - sectors[i].specialflags |= SSF_GRAVITYOVERRIDE; - else if (fastcmp(param, "walltransfer") && fastcmp("true", val)) - sectors[i].specialflags |= SSF_WALLTRANSFER; else if (fastcmp(param, "nophysics_floor") && fastcmp("true", val)) sectors[i].specialflags |= SSF_NOPHYSICSFLOOR; else if (fastcmp(param, "nophysics_ceiling") && fastcmp("true", val)) sectors[i].specialflags |= SSF_NOPHYSICSCEILING; + else if (fastcmp(param, "gravityoverride") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_GRAVITYOVERRIDE; + else if (fastcmp(param, "walltransfer") && fastcmp("true", val)) + sectors[i].specialflags |= SSF_WALLTRANSFER; else if (fastcmp(param, "friction")) sectors[i].friction = FLOAT_TO_FIXED(atof(val)); else if (fastcmp(param, "gravity")) @@ -3109,6 +3118,12 @@ static void P_WriteTextmap(void) fprintf(f, "ripple_ceiling = true;\n"); if (wsectors[i].flags & MSF_INVERTENCORE) fprintf(f, "invertencore = true;\n"); + if (wsectors[i].flags & MSF_FLATLIGHTING) + fprintf(f, "flatlighting = true;\n"); + if (wsectors[i].flags & MSF_DIRECTIONLIGHTING) + fprintf(f, "forcedirectionallighting = true;\n"); + if (wsectors[i].flags & MSF_NOEFX) + fprintf(f, "noaudioeffects = true;\n"); if (wsectors[i].specialflags & SSF_NOSTEPUP) fprintf(f, "nostepup = true;\n"); if (wsectors[i].specialflags & SSF_DOUBLESTEPUP) @@ -3133,14 +3148,20 @@ static void P_WriteTextmap(void) fprintf(f, "yellowpogospring = true;\n"); if (wsectors[i].specialflags & SSF_FAN) fprintf(f, "fan = true;\n"); + if (wsectors[i].specialflags & SSF_FINISHLINE) + fprintf(f, "finishline = true;\n"); if (wsectors[i].specialflags & SSF_ZOOMTUBESTART) fprintf(f, "zoomtubestart = true;\n"); if (wsectors[i].specialflags & SSF_ZOOMTUBEEND) fprintf(f, "zoomtubeend = true;\n"); - if (wsectors[i].specialflags & SSF_FINISHLINE) - fprintf(f, "finishline = true;\n"); + if (wsectors[i].specialflags & SSF_NOPHYSICSFLOOR) + fprintf(f, "nophysics_floor = true;\n"); + if (wsectors[i].specialflags & SSF_NOPHYSICSCEILING) + fprintf(f, "nophysics_ceiling = true;\n"); if (wsectors[i].specialflags & SSF_GRAVITYOVERRIDE) fprintf(f, "gravityoverride = true;\n"); + if (wsectors[i].specialflags & SSF_WALLTRANSFER) + fprintf(f, "walltransfer = true;\n"); if (wsectors[i].friction != ORIG_FRICTION) fprintf(f, "friction = %f;\n", FIXED_TO_FLOAT(wsectors[i].friction)); if (wsectors[i].gravity != FRACUNIT) diff --git a/src/p_spec.c b/src/p_spec.c index 3c9893f3e..196aa275d 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -6956,6 +6956,10 @@ void P_InitSpecials(void) // Set weather curWeather = globalweather = mapheaderinfo[gamemap-1]->weather; + + // Set global EFX + S_DeleteGlobalEFX(); + S_CreateGlobalEFX(mapheaderinfo[gamemap-1]->globalEFX); } void P_ApplyFlatAlignment(sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling) diff --git a/src/r_defs.h b/src/r_defs.h index e5bfd2771..277d676c5 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -363,6 +363,8 @@ typedef enum MSF_FLATLIGHTING = 1<<13, // force it on (even if it was disabled) MSF_DIRECTIONLIGHTING = 1<<14, + // Disable Audio EFX + MSF_NOEFX = 1<<15, } sectorflags_t; // Per-sector bot controller override diff --git a/src/s_sound.c b/src/s_sound.c index d82ec7304..1ed7e2f8e 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -745,7 +745,7 @@ void S_StartSoundAtVolumeEx(const void *origin_p, sfxenum_t sfx_id, INT32 volume channels[cnum].efx = NULL; } - channels[cnum].handle = I_StartSound(sfx_id, S_GetSoundVolume(sfx, volume), sep, pitch, priority, cnum, channels[cnum].efx); + channels[cnum].handle = I_StartSound(sfx_id, S_GetSoundVolume(sfx, volume), sep, pitch, priority, cnum, channels[cnum].efx, channels[cnum].origin); } } @@ -979,7 +979,7 @@ notinlevel: if (audible) { - I_UpdateSoundParams(c->handle, S_GetSoundVolume(c->sfxinfo, volume), sep, pitch, c->efx); + I_UpdateSoundParams(c->handle, S_GetSoundVolume(c->sfxinfo, volume), sep, pitch, c->efx, c->origin); } else S_StopChannel(cnum); @@ -2884,6 +2884,7 @@ static void Command_RestartAudio_f(void) S_StopMusic(); S_StopSounds(); S_ClearSfx(); + S_DeleteGlobalEFX(); I_ShutdownMusic(); I_ShutdownSound(); I_StartupSound(); @@ -2897,7 +2898,10 @@ static void Command_RestartAudio_f(void) S_StartSound(NULL, sfx_strpst); if (Playing()) // Gotta make sure the player is in a level + { + S_CreateGlobalEFX(mapheaderinfo[gamemap-1]->globalEFX); P_RestoreMusic(&players[consoleplayer]); + } else M_ChangeMenuMusic(); } @@ -2989,3 +2993,13 @@ void S_InitEFXArray(efx_t *efx) efx->var7 = efx->var8 = efx->var9 = -255; efx->var10 = efx->var11 = efx->var12 = efx->var13 = -255; } + +void S_CreateGlobalEFX(efx_t *efx) +{ + I_CreateGlobalEFX(efx); +} + +void S_DeleteGlobalEFX(void) +{ + I_DeleteGlobalEFX(); +} diff --git a/src/s_sound.h b/src/s_sound.h index a5a911ff6..0e796949c 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -353,7 +353,10 @@ void S_StartSoundName(void *mo, const char *soundname); void S_StopSoundByID(void *origin, sfxenum_t sfx_id); void S_StopSoundByNum(sfxenum_t sfxnum); +// EFX void S_InitEFXArray(efx_t *efx); +void S_CreateGlobalEFX(efx_t *efx); +void S_DeleteGlobalEFX(void); #ifndef HW3SOUND #define S_StartAttackSound S_StartSound diff --git a/src/sdl/al_sound.c b/src/sdl/al_sound.c index f10d22fb3..00dd6cc20 100644 --- a/src/sdl/al_sound.c +++ b/src/sdl/al_sound.c @@ -79,6 +79,7 @@ typedef enum #include "../i_threads.h" #include "../i_system.h" // I_Sleep #include "../fastcmp.h" +#include "../r_defs.h" #include @@ -143,6 +144,13 @@ static void (*fading_callback)(void); static boolean fading_do_callback; static boolean fading_nocleanup; +static void SoundEFX_OnChange(void) +{ + COM_ImmedExecute("restartaudio"); +} + +consvar_t cv_soundefx = CVAR_INIT ("soundefx", "On", CV_SAVE|CV_CALL|CV_NOINIT, CV_OnOff, SoundEFX_OnChange); + // any access (read/write) to this struct MUST lock the mutex typedef struct audiostate_s { @@ -159,6 +167,13 @@ typedef struct audiostate_s float loop_point; boolean looping; + struct + { + boolean enabled; + ALuint effect; + ALuint slot; + } globalefx; + boolean startplay; boolean shutdown; } audiostate_t; @@ -976,11 +991,14 @@ void I_FreeSfx(sfxinfo_t *sfx) sfx->lumpnum = LUMPERROR; } -void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx) +void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t *efx, const void *origin) { + LOCKAUDIO; + if (handle == INVALID_HANDLE) return; + const mobj_t *originmobj = (const mobj_t *)origin; ALuint source = handle; TRY(alSourcef, source, AL_GAIN, sfx_volume * (vol / 255.0f)); TRY(alSourcef, source, AL_PITCH, pitch / 128.0f); @@ -996,13 +1014,23 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch, efx_t 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)) + if (cv_soundefx.value && !dedicated) { - TRY(alSource3i, source, AL_AUXILIARY_SEND_FILTER, efx->slot, 0, AL_FILTER_NULL); + if (efx != NULL && TRY(alIsEffect, efx->effect) && TRY(alIsAuxiliaryEffectSlot, efx->slot)) + { + TRY(alSource3i, source, AL_AUXILIARY_SEND_FILTER, efx->slot, 0, AL_FILTER_NULL); + } + else if ((((originmobj != NULL) && originmobj->type && originmobj->subsector->sector->flags & MSF_NOEFX) || (origin != NULL)) + && audio.globalefx.enabled + && TRY(alIsEffect, audio.globalefx.effect) + && TRY(alIsAuxiliaryEffectSlot, audio.globalefx.slot)) + { + TRY(alSource3i, source, AL_AUXILIARY_SEND_FILTER, audio.globalefx.slot, 0, AL_FILTER_NULL); + } } } -INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx) +INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel, efx_t *efx, const void * origin) { ALuint source; if (!TRY(alGenSources, 1, &source)) @@ -1020,7 +1048,7 @@ INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priori return INVALID_HANDLE; } - I_UpdateSoundParams(source, vol, sep, pitch, efx); + I_UpdateSoundParams(source, vol, sep, pitch, efx, origin); if (!TRY(alSourcePlay, source)) { @@ -1895,10 +1923,142 @@ boolean I_FadeInPlaySong(UINT32 ms, boolean looping) return false; } +static void I_HandleEFXType(efx_t *efx, ALuint effect) +{ + switch (efx->type) + { + case EFFECT_REVERB: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_REVERB_DENSITY, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_REVERB_DIFFUSION, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_REVERB_GAIN, efx->var3); + if (efx->var4 != -255) + TRY(alEffectf, effect, AL_REVERB_GAINHF, efx->var4); + if (efx->var5 != -255) + TRY(alEffectf, effect, AL_REVERB_DECAY_TIME, efx->var5); + if (efx->var6 != -255) + TRY(alEffectf, effect, AL_REVERB_DECAY_HFRATIO, efx->var6); + if (efx->var7 != -255) + TRY(alEffectf, effect, AL_REVERB_REFLECTIONS_GAIN, efx->var7); + if (efx->var8 != -255) + TRY(alEffectf, effect, AL_REVERB_REFLECTIONS_DELAY, efx->var8); + if (efx->var9 != -255) + TRY(alEffectf, effect, AL_REVERB_LATE_REVERB_GAIN, efx->var9); + if (efx->var10 != -255) + TRY(alEffectf, effect, AL_REVERB_LATE_REVERB_DELAY, efx->var10); + if (efx->var11 != -255) + TRY(alEffectf, effect, AL_REVERB_AIR_ABSORPTION_GAINHF, efx->var11); + if (efx->var12 != -255) + TRY(alEffectf, effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx->var12); + if (efx->var13 != -255) + TRY(alEffectf, effect, AL_REVERB_ROOM_ROLLOFF_FACTOR, efx->var13); + break; + case EFFECT_CHORUS: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_CHORUS_WAVEFORM, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_CHORUS_PHASE, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_CHORUS_RATE, efx->var3); + if (efx->var4 != -255) + TRY(alEffectf, effect, AL_CHORUS_DEPTH, efx->var4); + if (efx->var5 != -255) + TRY(alEffectf, effect, AL_CHORUS_FEEDBACK, efx->var5); + if (efx->var6 != -255) + TRY(alEffectf, effect, AL_CHORUS_DELAY, efx->var6); + break; + case EFFECT_DISTORTION: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_DISTORTION_EDGE, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_DISTORTION_GAIN, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_DISTORTION_LOWPASS_CUTOFF, efx->var3); + if (efx->var4 != -255) + TRY(alEffectf, effect, AL_DISTORTION_EQCENTER, efx->var4); + if (efx->var5 != -255) + TRY(alEffectf, effect, AL_DISTORTION_EQBANDWIDTH, efx->var5); + break; + case EFFECT_ECHO: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_ECHO_DELAY, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_ECHO_LRDELAY, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_ECHO_DAMPING, efx->var3); + if (efx->var4 != -255) + TRY(alEffectf, effect, AL_ECHO_FEEDBACK, efx->var4); + if (efx->var5 != -255) + TRY(alEffectf, effect, AL_ECHO_SPREAD, efx->var5); + break; + case EFFECT_PITCHSHIFT: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_PITCH_SHIFTER_COARSE_TUNE, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_PITCH_SHIFTER_FINE_TUNE , efx->var2); + break; + case EFFECT_RINGMOD: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_RING_MODULATOR_FREQUENCY, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_RING_MODULATOR_HIGHPASS_CUTOFF, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_RING_MODULATOR_WAVEFORM, efx->var3); + break; + case EFFECT_COMPRESSOR: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_COMPRESSOR_ONOFF, efx->var1); + break; + case EFFECT_EQ: + TRY(alEffecti, effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER); + + if (efx->var1 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_LOW_GAIN, efx->var1); + if (efx->var2 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_LOW_CUTOFF, efx->var2); + if (efx->var3 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID1_GAIN, efx->var3); + if (efx->var4 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID1_CENTER, efx->var4); + if (efx->var5 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID1_WIDTH, efx->var5); + if (efx->var6 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID2_GAIN, efx->var6); + if (efx->var7 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID2_CENTER, efx->var7); + if (efx->var8 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_MID2_WIDTH, efx->var8); + if (efx->var9 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_HIGH_GAIN, efx->var9); + if (efx->var10 != -255) + TRY(alEffectf, effect, AL_EQUALIZER_HIGH_CUTOFF, efx->var10); + break; + } +} + efx_t *I_CreateEFX(efx_t *efx) { LOCKAUDIO; + if (!cv_soundefx.value || dedicated) + return NULL; + efx_t *efxc = Z_Calloc(sizeof(efx_t), PU_STATIC, NULL); if (efxc == NULL) @@ -1913,134 +2073,7 @@ efx_t *I_CreateEFX(efx_t *efx) 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_CHORUS: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_WAVEFORM, efxc->var1); - if (efxc->var2 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_PHASE, efxc->var2); - if (efxc->var3 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_RATE, efxc->var3); - if (efxc->var4 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_DEPTH, efxc->var4); - if (efxc->var5 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_FEEDBACK, efxc->var5); - if (efxc->var6 != -255) - TRY(alEffectf, efxc->effect, AL_CHORUS_DELAY, efxc->var6); - 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; - case EFFECT_ECHO: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_ECHO_DELAY, efxc->var1); - if (efxc->var2 != -255) - TRY(alEffectf, efxc->effect, AL_ECHO_LRDELAY, efxc->var2); - if (efxc->var3 != -255) - TRY(alEffectf, efxc->effect, AL_ECHO_DAMPING, efxc->var3); - if (efxc->var4 != -255) - TRY(alEffectf, efxc->effect, AL_ECHO_FEEDBACK, efxc->var4); - if (efxc->var5 != -255) - TRY(alEffectf, efxc->effect, AL_ECHO_SPREAD, efxc->var5); - - break; - case EFFECT_PITCHSHIFT: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_PITCH_SHIFTER_COARSE_TUNE, efxc->var1); - if (efxc->var2 != -255) - TRY(alEffectf, efxc->effect, AL_PITCH_SHIFTER_FINE_TUNE , efxc->var2); - break; - case EFFECT_RINGMOD: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_RING_MODULATOR_FREQUENCY, efxc->var1); - if (efxc->var2 != -255) - TRY(alEffectf, efxc->effect, AL_RING_MODULATOR_HIGHPASS_CUTOFF, efxc->var2); - if (efxc->var3 != -255) - TRY(alEffectf, efxc->effect, AL_RING_MODULATOR_WAVEFORM, efxc->var3); - - break; - case EFFECT_COMPRESSOR: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_COMPRESSOR_ONOFF, efxc->var1); - break; - case EFFECT_EQ: - TRY(alEffecti, efxc->effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER); - - if (efxc->var1 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_LOW_GAIN, efxc->var1); - if (efxc->var2 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_LOW_CUTOFF, efxc->var2); - if (efxc->var3 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID1_GAIN, efxc->var3); - if (efxc->var4 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID1_CENTER, efxc->var4); - if (efxc->var5 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID1_WIDTH, efxc->var5); - if (efxc->var6 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID2_GAIN, efxc->var6); - if (efxc->var7 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID2_CENTER, efxc->var7); - if (efxc->var8 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_MID2_WIDTH, efxc->var8); - if (efxc->var9 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_HIGH_GAIN, efxc->var9); - if (efxc->var10 != -255) - TRY(alEffectf, efxc->effect, AL_EQUALIZER_HIGH_CUTOFF, efxc->var10); - break; - } + I_HandleEFXType(efxc, efxc->effect); TRY(alAuxiliaryEffectSloti, efxc->slot, AL_EFFECTSLOT_EFFECT, efxc->effect); return efxc; @@ -2055,6 +2088,9 @@ float I_GetEFXTail(efx_t *efx) { LOCKAUDIO; + if (!cv_soundefx.value || dedicated) + return 0; + if (efx == NULL) return 0; @@ -2096,4 +2132,59 @@ void I_DeleteEFX(efx_t *efx) Z_Free(efx); } +void I_CreateGlobalEFX(efx_t *efx) +{ + LOCKAUDIO; + + if (!cv_soundefx.value || dedicated) + return; + + if (efx == NULL) + return; + + // Init effects and slots. + TRY(alGenEffects, 1, &audio.globalefx.effect); + TRY(alGenAuxiliaryEffectSlots, 1, &audio.globalefx.slot); + + if (TRY(alIsEffect, audio.globalefx.effect) && TRY(alIsAuxiliaryEffectSlot, audio.globalefx.slot)) + { + I_HandleEFXType(efx, audio.globalefx.effect); + TRY(alAuxiliaryEffectSloti, audio.globalefx.slot, AL_EFFECTSLOT_EFFECT, audio.globalefx.effect); + audio.globalefx.enabled = true; + return; + } + + if (TRY(alIsEffect, audio.globalefx.effect)) + { + TRY(alDeleteEffects, 1, &audio.globalefx.effect); + } + + if (TRY(alIsAuxiliaryEffectSlot, audio.globalefx.slot)) + { + TRY(alDeleteAuxiliaryEffectSlots, 1, &audio.globalefx.slot); + } + + audio.globalefx.enabled = false; +} + +void I_DeleteGlobalEFX(void) +{ + LOCKAUDIO; + + if (audio.globalefx.enabled == false) + return; + + if (TRY(alIsEffect, audio.globalefx.effect)) + { + TRY(alDeleteEffects, 1, &audio.globalefx.effect); + } + + if (TRY(alIsAuxiliaryEffectSlot, audio.globalefx.slot)) + { + TRY(alDeleteAuxiliaryEffectSlots, 1, &audio.globalefx.slot); + } + + audio.globalefx.enabled = false; +} + #endif // defined(HAVE_OPENAL)