Skip to content

Commit

Permalink
Sound tweaks (#2215)
Browse files Browse the repository at this point in the history
* Remove unused idnum tracking

* Seamlessly pause and resume sounds

Side effect: No more chainsaw "rev up" sound when pausing game.

* Update listener before updating sound sources

Make sure the sound sources are fed the latest listener data. This shouldn't matter with the call to I_DeferSoundUpdates, but just in case.

* Skip unnecessary listener calculations

No need to constantly update the listener when the menu is open (single player only), the game is paused, or no game is being played.

* Fix initial mobj->oldz when spawning mobj

mobj->oldz should be set after mobj->z is initialized. See Crispy Doom.

* Improve doppler effect for listener

Uses the correct velocity calculation.

* Improve doppler effect for sources

Uses the correct velocity calculation.

* Adjust doppler effect scaling range

With the changes made to the velocity calculations, the doppler effect thermo should be linear (0.0 to 2.0, 0.2 steps).

* Defer doppler effect thermo action

Resetting the OpenAL 3D sound module is slow.

* Use a standard map units to meters conversion factor

16 map units per foot or 0.01905 meters per map unit (https://www.doomworld.com/idgames/docs/editing/metrics). Same as the speedometer widget.

* Misc. sound refactoring

* Use parameters structure for sound functions

* Improve sound curve

Sound attenuation over distance is now more gradual when using the OpenAL 3D sound module. Previously, there was a more pronounced drop off near the sound distance limit. This uses a different roll-off factor, so the air absorption factor has been adjusted to preserve the same effect as before.

* Reduce PC speaker square wave amplitude

It was way too loud in comparison to the other sound modules.
  • Loading branch information
ceski-1 authored Mar 2, 2025
1 parent 4681e5a commit 4fcf303
Show file tree
Hide file tree
Showing 14 changed files with 372 additions and 221 deletions.
19 changes: 15 additions & 4 deletions src/g_game.c
Original file line number Diff line number Diff line change
Expand Up @@ -1321,9 +1321,15 @@ boolean G_Responder(event_t* ev)
if (M_InputActivated(input_pause))
{
if (paused ^= 2)
{
S_PauseSound();
S_PauseMusic();
}
else
{
S_ResumeSound();
S_ResumeMusic();
}
return true;
}

Expand All @@ -1343,7 +1349,6 @@ boolean G_Responder(event_t* ev)
((ev->type == ev_keydown) ||
(ev->type == ev_mouseb_down) ||
(ev->type == ev_joyb_down)) ?
(!menuactive ? S_StartSound(NULL,sfx_swtchn) : true),
MN_StartControlPanel(), true : false;
}

Expand Down Expand Up @@ -2992,9 +2997,15 @@ void G_Ticker(void)

case BTS_PAUSE:
if ((paused ^= 1))
S_PauseSound();
{
S_PauseSound();
S_PauseMusic();
}
else
S_ResumeSound();
{
S_ResumeSound();
S_ResumeMusic();
}
break;

case BTS_SAVEGAME:
Expand Down Expand Up @@ -3892,7 +3903,7 @@ void G_InitNew(skill_t skill, int episode, int map)
if (paused)
{
paused = false;
S_ResumeSound();
S_ResumeMusic();
}

if (skill > sk_nightmare)
Expand Down
126 changes: 57 additions & 69 deletions src/i_3dsound.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ typedef struct oal_source_params_s
{
ALfloat position[3];
ALfloat velocity[3];
boolean use_3d;
boolean positional;
boolean point_source;
fixed_t z;
} oal_source_params_t;
Expand Down Expand Up @@ -86,11 +86,14 @@ static void CalcListenerParams(const mobj_t *listener,
lis->position[1] = FIXED_TO_ALFLOAT(player->viewz);
lis->position[2] = FIXED_TO_ALFLOAT(-listener->y);

if (oal_use_doppler)
if (oal_use_doppler && listener->interp == true)
{
lis->velocity[0] = FIXED_TO_ALFLOAT(listener->momx) * TICRATE;
lis->velocity[1] = FIXED_TO_ALFLOAT(listener->momz) * TICRATE;
lis->velocity[2] = FIXED_TO_ALFLOAT(-listener->momy) * TICRATE;
lis->velocity[0] =
FIXED_TO_ALFLOAT(listener->x - listener->oldx) * TICRATE;
lis->velocity[1] =
FIXED_TO_ALFLOAT(listener->z - listener->oldz) * TICRATE;
lis->velocity[2] =
FIXED_TO_ALFLOAT(listener->oldy - listener->y) * TICRATE;
}
else
{
Expand Down Expand Up @@ -137,12 +140,14 @@ static void CalcSourceParams(const mobj_t *source, oal_source_params_t *src)
src->position[1] = FIXED_TO_ALFLOAT(src->z);
src->position[2] = FIXED_TO_ALFLOAT(-source->y);

// Doppler effect only applies to monsters and projectiles.
if (oal_use_doppler && src->point_source)
// Doppler effect only applies to projectiles and other players.
if (oal_use_doppler && src->point_source && source->interp == true
&& (source->flags & (MF_MISSILE | MF_SKULLFLY)
|| source->type == MT_PLAYER))
{
src->velocity[0] = FIXED_TO_ALFLOAT(source->momx) * TICRATE;
src->velocity[1] = FIXED_TO_ALFLOAT(source->momz) * TICRATE;
src->velocity[2] = FIXED_TO_ALFLOAT(-source->momy) * TICRATE;
src->velocity[0] = FIXED_TO_ALFLOAT(source->x - source->oldx) * TICRATE;
src->velocity[1] = FIXED_TO_ALFLOAT(source->z - source->oldz) * TICRATE;
src->velocity[2] = FIXED_TO_ALFLOAT(source->oldy - source->y) * TICRATE;
}
else
{
Expand All @@ -152,11 +157,11 @@ static void CalcSourceParams(const mobj_t *source, oal_source_params_t *src)
}
}

static void CalcHypotenuse(fixed_t adx, fixed_t ady, fixed_t *dist)
static void CalcHypotenuse(int adx, int ady, int *dist)
{
if (ady > adx)
{
const fixed_t temp = adx;
const int temp = adx;
adx = ady;
ady = temp;
}
Expand All @@ -174,24 +179,22 @@ static void CalcHypotenuse(fixed_t adx, fixed_t ady, fixed_t *dist)
}

static void CalcDistance(const mobj_t *listener, const mobj_t *source,
oal_source_params_t *src, fixed_t *dist)
oal_source_params_t *src, int *dist)
{
const fixed_t adx =
abs((listener->x >> FRACBITS) - (source->x >> FRACBITS));
const fixed_t ady =
abs((listener->y >> FRACBITS) - (source->y >> FRACBITS));
fixed_t distxy;
const int adx = abs((listener->x >> FRACBITS) - (source->x >> FRACBITS));
const int ady = abs((listener->y >> FRACBITS) - (source->y >> FRACBITS));
int distxy;

CalcHypotenuse(adx, ady, &distxy);

// Treat monsters and projectiles as point sources.
// Treat monsters, projectiles, and other players as point sources.
src->point_source =
(source->thinker.function.p1 != (actionf_p1)P_DegenMobjThinker
&& source->info && source->actualheight);

if (src->point_source)
{
fixed_t adz;
int adz;
// Vertical distance is from player's view to middle of source's sprite.
src->z = source->z + (source->actualheight >> 1);
adz = abs((listener->player->viewz >> FRACBITS) - (src->z >> FRACBITS));
Expand All @@ -206,104 +209,79 @@ static void CalcDistance(const mobj_t *listener, const mobj_t *source,
}
}

static boolean CalcVolumePriority(fixed_t dist, int *vol, int *pri)
static boolean CalcVolumePriority(int dist, sfxparams_t *params)
{
int pri_volume;

if (dist == 0)
{
return true;
}
else if (dist >= (S_CLIPPING_DIST >> FRACBITS))
else if (dist >= S_CLIPPING_DIST)
{
return false;
}
else if (dist <= (S_CLOSE_DIST >> FRACBITS))
{
pri_volume = *vol;
}
else if (dist > S_ATTENUATOR)
else if (dist > S_CLOSE_DIST)
{
// OpenAL inverse distance model never reaches zero volume. Gradually
// ramp down the volume as the distance approaches the limit.
pri_volume = *vol * ((S_CLIPPING_DIST >> FRACBITS) - dist)
/ (S_CLOSE_DIST >> FRACBITS);
*vol = pri_volume;
}
else
{
// Range where OpenAL inverse distance model applies. Calculate volume
// for priority bookkeeping but let OpenAL handle the real volume.
// Simplify formula for OAL_ROLLOFF_FACTOR = 1:
pri_volume = *vol * (S_CLOSE_DIST >> FRACBITS) / dist;
params->volume =
params->volume * (S_CLIPPING_DIST - dist) / S_ATTENUATOR;
}

// Decrease priority with volume attenuation.
*pri += (127 - pri_volume);
params->priority += (127 - params->volume);

if (*pri > 255)
if (params->priority > 255)
{
*pri = 255;
params->priority = 255;
}

return (pri_volume > 0);
return (params->volume > 0);
}

static boolean ScaleVolume(int chanvol, int *vol)
static boolean I_3D_AdjustSoundParams(const mobj_t *listener,
const mobj_t *source, sfxparams_t *params)
{
*vol = (snd_SfxVolume * chanvol) / 15;
int dist;

params->volume = snd_SfxVolume * params->volume_scale / 15;

if (*vol < 1)
if (params->volume < 1)
{
return false;
}
else if (*vol > 127)
{
*vol = 127;
}

return true;
}

static boolean I_3D_AdjustSoundParams(const mobj_t *listener,
const mobj_t *source, int chanvol,
int *vol, int *sep, int *pri)
{
fixed_t dist;

if (!ScaleVolume(chanvol, vol))
else if (params->volume > 127)
{
return false;
params->volume = 127;
}

if (!source || source == players[displayplayer].mo || !listener
|| !listener->player)
{
src.use_3d = false;
src.positional = false;
return true;
}

CalcDistance(listener, source, &src, &dist);

if (!CalcVolumePriority(dist, vol, pri))
if (!CalcVolumePriority(dist, params))
{
return false;
}

src.use_3d = true;
src.positional = true;
CalcSourceParams(source, &src);

return true;
}

static void I_3D_UpdateSoundParams(int channel, int volume, int separation)
static void I_3D_UpdateSoundParams(int channel, const sfxparams_t *params)
{
if (src.use_3d)
if (src.positional)
{
I_OAL_UpdateSourceParams(channel, src.position, src.velocity);
}

I_OAL_SetVolume(channel, volume);
I_OAL_SetVolume(channel, params->volume);
}

static void I_3D_UpdateListenerParams(const mobj_t *listener)
Expand All @@ -315,13 +293,20 @@ static void I_3D_UpdateListenerParams(const mobj_t *listener)
return;
}

// Only update when listener is moving.
if ((menuactive && !netgame && !demoplayback) || paused
|| gamestate != GS_LEVEL)
{
return;
}

CalcListenerParams(listener, &lis);
I_OAL_UpdateListenerParams(lis.position, lis.velocity, lis.orientation);
}

static boolean I_3D_StartSound(int channel, sfxinfo_t *sfx, float pitch)
{
if (src.use_3d)
if (src.positional)
{
I_OAL_ResetSource3D(channel, src.point_source);
}
Expand Down Expand Up @@ -354,7 +339,10 @@ const sound_module_t sound_3d_module =
I_3D_UpdateListenerParams,
I_3D_StartSound,
I_OAL_StopSound,
I_OAL_PauseSound,
I_OAL_ResumeSound,
I_OAL_SoundIsPlaying,
I_OAL_SoundIsPaused,
I_OAL_ShutdownSound,
I_OAL_ShutdownModule,
I_OAL_DeferUpdates,
Expand Down
Loading

0 comments on commit 4fcf303

Please sign in to comment.