Sound tweaks (#2215)

* 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.
This commit is contained in:
ceski 2025-03-02 07:45:30 -08:00 committed by GitHub
parent 4681e5aeb2
commit 4fcf30323d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 373 additions and 222 deletions

View File

@ -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;
}
@ -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;
}
@ -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:
@ -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)

View File

@ -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;
@ -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
{
@ -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
{
@ -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;
}
@ -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));
@ -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);
}
static boolean ScaleVolume(int chanvol, int *vol)
{
*vol = (snd_SfxVolume * chanvol) / 15;
if (*vol < 1)
{
return false;
}
else if (*vol > 127)
{
*vol = 127;
}
return true;
return (params->volume > 0);
}
static boolean I_3D_AdjustSoundParams(const mobj_t *listener,
const mobj_t *source, int chanvol,
int *vol, int *sep, int *pri)
const mobj_t *source, sfxparams_t *params)
{
fixed_t dist;
int dist;
if (!ScaleVolume(chanvol, vol))
params->volume = snd_SfxVolume * params->volume_scale / 15;
if (params->volume < 1)
{
return false;
}
else if (params->volume > 127)
{
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)
@ -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);
}
@ -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,

View File

@ -28,30 +28,31 @@
#include "m_fixed.h"
#include "p_mobj.h"
#include "r_main.h"
#include "sounds.h"
#include "tables.h"
static boolean force_flip_pan;
static boolean I_MBF_AdjustSoundParams(const mobj_t *listener,
const mobj_t *source, int chanvol,
int *vol, int *sep, int *pri)
const mobj_t *source,
sfxparams_t *params)
{
fixed_t adx, ady, dist;
int adx, ady, dist;
angle_t angle;
// haleyjd 05/29/06: allow per-channel volume scaling
*vol = (snd_SfxVolume * chanvol) / 15;
params->volume = snd_SfxVolume * params->volume_scale / 15;
if (*vol < 1)
if (params->volume < 1)
{
return false;
}
else if (*vol > 127)
else if (params->volume > 127)
{
*vol = 127;
params->volume = 127;
}
*sep = NORM_SEP;
params->separation = NORM_SEP;
if (!source || source == players[displayplayer].mo)
{
@ -75,20 +76,28 @@ static boolean I_MBF_AdjustSoundParams(const mobj_t *listener,
if (ady > adx)
{
dist = adx, adx = ady, ady = dist;
const int temp = adx;
adx = ady;
ady = temp;
}
dist = adx ? FixedDiv(
adx, finesine[(tantoangle[FixedDiv(ady, adx) >> DBITS] + ANG90)
>> ANGLETOFINESHIFT])
: 0;
if (adx)
{
const int slope = FixedDiv(ady, adx) >> DBITS;
const int angle = tantoangle[slope] >> ANGLETOFINESHIFT;
dist = FixedDiv(adx, finecosine[angle]);
}
else
{
dist = 0;
}
if (!dist) // killough 11/98: handle zero-distance as special case
{
return true;
}
if (dist > S_CLIPPING_DIST >> FRACBITS)
if (dist >= S_CLIPPING_DIST)
{
return false;
}
@ -107,35 +116,38 @@ static boolean I_MBF_AdjustSoundParams(const mobj_t *listener,
angle >>= ANGLETOFINESHIFT;
// stereo separation
*sep = NORM_SEP - FixedMul(S_STEREO_SWING >> FRACBITS, finesine[angle]);
params->separation -= FixedMul(S_STEREO_SWING, finesine[angle]);
}
// volume calculation
if (dist > S_CLOSE_DIST >> FRACBITS)
if (dist > S_CLOSE_DIST)
{
*vol = *vol * ((S_CLIPPING_DIST >> FRACBITS) - dist) / S_ATTENUATOR;
params->volume =
params->volume * (S_CLIPPING_DIST - dist) / S_ATTENUATOR;
}
// haleyjd 09/27/06: decrease priority with volume attenuation
*pri = *pri + (127 - *vol);
params->priority += (127 - params->volume);
if (*pri > 255) // cap to 255
if (params->priority > 255) // cap to 255
{
*pri = 255;
params->priority = 255;
}
return (*vol > 0);
return (params->volume > 0);
}
void I_MBF_UpdateSoundParams(int channel, int volume, int separation)
static void I_MBF_UpdateSoundParams(int channel, const sfxparams_t *params)
{
int separation = params->separation;
// SoM 7/1/02: forceFlipPan accounted for here
if (force_flip_pan)
{
separation = 254 - separation;
}
I_OAL_SetVolume(channel, volume);
I_OAL_SetVolume(channel, params->volume);
I_OAL_SetPan(channel, separation);
}
@ -165,7 +177,10 @@ const sound_module_t sound_mbf_module =
NULL,
I_OAL_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,

View File

@ -39,10 +39,10 @@
#include "w_wad.h"
#include "z_zone.h"
#define OAL_ROLLOFF_FACTOR 1
#define OAL_ROLLOFF_FACTOR 0.5f
#define OAL_SPEED_OF_SOUND 343.3f
// 128 map units per 3 meters (https://doomwiki.org/wiki/Map_unit).
#define OAL_MAP_UNITS_PER_METER (128.0f / 3.0f)
// 16 mu/ft (https://www.doomworld.com/idgames/docs/editing/metrics)
#define OAL_METERS_PER_MAP_UNIT 0.01905f
#define OAL_SOURCE_RADIUS 32.0f
#define OAL_DEFAULT_PITCH 1.0f
@ -248,8 +248,7 @@ void I_OAL_ResetSource2D(int channel)
alSource3f(oal->sources[channel], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(oal->sources[channel], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSourcei(oal->sources[channel], AL_ROLLOFF_FACTOR, 0);
alSourcef(oal->sources[channel], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(oal->sources[channel], AL_SOURCE_RELATIVE, AL_TRUE);
}
@ -272,7 +271,7 @@ void I_OAL_ResetSource3D(int channel, boolean point_source)
point_source ? 0.0f : OAL_SOURCE_RADIUS);
}
alSourcei(oal->sources[channel], AL_ROLLOFF_FACTOR, OAL_ROLLOFF_FACTOR);
alSourcef(oal->sources[channel], AL_ROLLOFF_FACTOR, OAL_ROLLOFF_FACTOR);
alSourcei(oal->sources[channel], AL_SOURCE_RELATIVE, AL_FALSE);
}
@ -337,8 +336,8 @@ static void UpdateUserSoundSettings(void)
if (oal_snd_module == SND_MODULE_3D)
{
oal->absorption = (ALfloat)snd_absorption / 2.0f;
alDopplerFactor((ALfloat)snd_doppler * snd_doppler / 100.0f);
oal->absorption = (ALfloat)snd_absorption;
alDopplerFactor((ALfloat)snd_doppler / 5.0f);
oal_use_doppler = (snd_doppler > 0);
}
else
@ -359,9 +358,8 @@ static void ResetParams(void)
{
I_OAL_ResetSource2D(i);
alSource3i(oal->sources[i], AL_DIRECTION, 0, 0, 0);
alSourcei(oal->sources[i], AL_MAX_DISTANCE, S_ATTENUATOR);
alSourcei(oal->sources[i], AL_REFERENCE_DISTANCE,
S_CLOSE_DIST >> FRACBITS);
alSourcei(oal->sources[i], AL_REFERENCE_DISTANCE, S_CLOSE_DIST);
alSourcei(oal->sources[i], AL_MAX_DISTANCE, S_CLIPPING_DIST);
}
// Spatialization is required even for 2D panning emulation.
if (oal->SOFT_source_spatialize)
@ -378,12 +376,12 @@ static void ResetParams(void)
alListeneriv(AL_ORIENTATION, default_orientation);
if (oal->EXT_EFX)
{
alListenerf(AL_METERS_PER_UNIT, 1.0f / OAL_MAP_UNITS_PER_METER);
alListenerf(AL_METERS_PER_UNIT, OAL_METERS_PER_MAP_UNIT);
}
// Context state parameters.
alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED); // OpenAL 1.1 Specs, 3.4.2.
alSpeedOfSound(OAL_SPEED_OF_SOUND * OAL_MAP_UNITS_PER_METER);
alSpeedOfSound(OAL_SPEED_OF_SOUND / OAL_METERS_PER_MAP_UNIT);
UpdateUserSoundSettings();
}
@ -735,6 +733,33 @@ void I_OAL_StopSound(int channel)
alSourceStop(oal->sources[channel]);
}
void I_OAL_PauseSound(int channel)
{
if (!oal)
{
return;
}
alSourcePause(oal->sources[channel]);
}
void I_OAL_ResumeSound(int channel)
{
ALint state;
if (!oal)
{
return;
}
alGetSourcei(oal->sources[channel], AL_SOURCE_STATE, &state);
if (state == AL_PAUSED)
{
alSourcePlay(oal->sources[channel]);
}
}
boolean I_OAL_SoundIsPlaying(int channel)
{
ALint state;
@ -749,6 +774,20 @@ boolean I_OAL_SoundIsPlaying(int channel)
return (state == AL_PLAYING);
}
boolean I_OAL_SoundIsPaused(int channel)
{
ALint state;
if (!oal)
{
return false;
}
alGetSourcei(oal->sources[channel], AL_SOURCE_STATE, &state);
return (state == AL_PAUSED);
}
void I_OAL_SetVolume(int channel, int volume)
{
if (!oal)

View File

@ -62,8 +62,14 @@ boolean I_OAL_StartSound(int channel, struct sfxinfo_s *sfx, float pitch);
void I_OAL_StopSound(int channel);
void I_OAL_PauseSound(int channel);
void I_OAL_ResumeSound(int channel);
boolean I_OAL_SoundIsPlaying(int channel);
boolean I_OAL_SoundIsPaused(int channel);
void I_OAL_SetVolume(int channel, int volume);
void I_OAL_SetPan(int channel, int separation);

View File

@ -38,7 +38,7 @@ static LPALBUFFERCALLBACKSOFT alBufferCallbackSOFT;
static ALuint callback_buffer;
static ALuint callback_source;
#define SQUARE_WAVE_AMP 0x2000
#define SQUARE_WAVE_AMP 0x1000 // Chocolate Doom: 0x2000
static SDL_mutex *sound_lock;
static int mixing_freq;
@ -381,10 +381,11 @@ static boolean I_PCS_CacheSound(sfxinfo_t *sfx)
}
static boolean I_PCS_AdjustSoundParams(const mobj_t *listener,
const mobj_t *source, int chanvol,
int *vol, int *sep, int *pri)
const mobj_t *source,
sfxparams_t *params)
{
fixed_t adx, ady, approx_dist;
fixed_t adx, ady;
int approx_dist;
if (!source || source == players[displayplayer].mo)
{
@ -403,9 +404,9 @@ static boolean I_PCS_AdjustSoundParams(const mobj_t *listener,
ady = abs(listener->y - source->y);
// From _GG1_ p.428. Appox. eucledian distance fast.
approx_dist = adx + ady - ((adx < ady ? adx : ady) >> 1);
approx_dist = (adx + ady - ((adx < ady ? adx : ady) >> 1)) >> FRACBITS;
if (approx_dist > S_CLIPPING_DIST)
if (approx_dist >= S_CLIPPING_DIST)
{
return false;
}
@ -413,19 +414,19 @@ static boolean I_PCS_AdjustSoundParams(const mobj_t *listener,
// volume calculation
if (approx_dist < S_CLOSE_DIST)
{
*vol = snd_SfxVolume;
params->volume = snd_SfxVolume;
}
else
{
// distance effect
*vol = (snd_SfxVolume * ((S_CLIPPING_DIST - approx_dist) >> FRACBITS))
/ S_ATTENUATOR;
params->volume =
snd_SfxVolume * (S_CLIPPING_DIST - approx_dist) / S_ATTENUATOR;
}
return (*vol > 0);
return (params->volume > 0);
}
static void I_PCS_UpdateSoundParams(int channel, int volume, int separation)
static void I_PCS_UpdateSoundParams(int channel, const sfxparams_t *params)
{
// adjust PC Speaker volume
alSourcef(callback_source, AL_GAIN, (float)snd_SfxVolume / 15);
@ -502,7 +503,10 @@ const sound_module_t sound_pcs_module =
NULL,
I_PCS_StartSound,
I_PCS_StopSound,
NULL,
NULL,
I_PCS_SoundIsPlaying,
NULL,
I_PCS_ShutdownSound,
I_PCS_ShutdownModule,
I_OAL_DeferUpdates,

View File

@ -78,8 +78,6 @@ typedef struct
sfxinfo_t *sfx;
boolean enabled;
// haleyjd 06/16/08: unique id number
int idnum;
} channel_info_t;
static channel_info_t channelinfo[MAX_CHANNELS];
@ -123,14 +121,14 @@ static void StopChannel(int channel)
// Returns false if no sound should be played.
//
boolean I_AdjustSoundParams(const mobj_t *listener, const mobj_t *source,
int chanvol, int *vol, int *sep, int *pri)
sfxparams_t *params)
{
if (!snd_init)
{
return false;
}
return sound_module->AdjustSoundParams(listener, source, chanvol, vol, sep, pri);
return sound_module->AdjustSoundParams(listener, source, params);
}
//
@ -139,7 +137,7 @@ boolean I_AdjustSoundParams(const mobj_t *listener, const mobj_t *source,
// Changes sound parameters in response to stereo panning and relative location
// change.
//
void I_UpdateSoundParams(int channel, int volume, int separation)
void I_UpdateSoundParams(int channel, const sfxparams_t *params)
{
if (!snd_init)
{
@ -153,7 +151,7 @@ void I_UpdateSoundParams(int channel, int volume, int separation)
}
#endif
sound_module->UpdateSoundParams(channel, volume, separation);
sound_module->UpdateSoundParams(channel, params);
}
void I_UpdateListenerParams(const mobj_t *listener)
@ -262,9 +260,8 @@ int I_GetSfxLumpNum(sfxinfo_t *sfx)
// active sounds, which is maintained as a given number
// of internal channels. Returns a free channel.
//
int I_StartSound(sfxinfo_t *sfx, int vol, int sep, int pitch)
int I_StartSound(sfxinfo_t *sfx, const sfxparams_t *params, int pitch)
{
static unsigned int id = 0;
int channel;
if (!snd_init)
@ -297,9 +294,8 @@ int I_StartSound(sfxinfo_t *sfx, int vol, int sep, int pitch)
channelinfo[channel].sfx = sfx;
channelinfo[channel].enabled = true;
channelinfo[channel].idnum = id++; // give the sound a unique id
I_UpdateSoundParams(channel, vol, sep);
I_UpdateSoundParams(channel, params);
float step = (pitch == NORM_PITCH) ? 1.0f : steptable[pitch];
@ -336,6 +332,46 @@ void I_StopSound(int channel)
StopChannel(channel);
}
void I_PauseSound(int channel)
{
if (!snd_init || !sound_module->PauseSound)
{
return;
}
#ifdef RANGECHECK
if (channel < 0 || channel >= MAX_CHANNELS)
{
I_Error("I_PauseSound: channel out of range");
}
#endif
if (channelinfo[channel].enabled)
{
sound_module->PauseSound(channel);
}
}
void I_ResumeSound(int channel)
{
if (!snd_init || !sound_module->ResumeSound)
{
return;
}
#ifdef RANGECHECK
if (channel < 0 || channel >= MAX_CHANNELS)
{
I_Error("I_ResumeSound: channel out of range");
}
#endif
if (channelinfo[channel].enabled)
{
sound_module->ResumeSound(channel);
}
}
//
// I_SoundIsPlaying
//
@ -358,29 +394,21 @@ boolean I_SoundIsPlaying(int channel)
return sound_module->SoundIsPlaying(channel);
}
//
// I_SoundID
//
// haleyjd: returns the unique id number assigned to a specific instance
// of a sound playing on a given channel. This is required to make sure
// that the higher-level sound code doesn't start updating sounds that have
// been displaced without it noticing.
//
int I_SoundID(int channel)
boolean I_SoundIsPaused(int channel)
{
if (!snd_init)
if (!snd_init || !sound_module->SoundIsPaused)
{
return 0;
return false;
}
#ifdef RANGECHECK
if (channel < 0 || channel >= MAX_CHANNELS)
{
I_Error("I_SoundID: channel out of range\n");
I_Error("I_SoundIsPaused: channel out of range");
}
#endif
return channelinfo[channel].idnum;
return sound_module->SoundIsPaused(channel);
}
//

View File

@ -29,7 +29,7 @@
// when to clip out sounds
// Does not fit the large outdoor areas.
#define S_CLIPPING_DIST (1200 << FRACBITS)
#define S_CLIPPING_DIST 1200
// Distance to origin when sounds should be maxed out.
// This should relate to movement clipping resolution
@ -39,9 +39,9 @@
// killough 12/98: restore original
// #define S_CLOSE_DIST (160<<FRACBITS)
#define S_CLOSE_DIST (200 << FRACBITS)
#define S_CLOSE_DIST 200
#define S_ATTENUATOR ((S_CLIPPING_DIST - S_CLOSE_DIST) >> FRACBITS)
#define S_ATTENUATOR (S_CLIPPING_DIST - S_CLOSE_DIST)
// Adjustable by menu.
// [FG] moved here from i_sound.c
@ -50,7 +50,7 @@
#define NORM_PITCH 128
#define NORM_PRIORITY 64
#define NORM_SEP 128
#define S_STEREO_SWING (96 << FRACBITS)
#define S_STEREO_SWING 96
#define SND_SAMPLERATE 44100
@ -65,8 +65,8 @@ void I_ShutdownSound(void);
//
struct mobj_s;
struct sfxinfo_s;
struct sfxparams_s;
typedef struct sound_module_s
{
@ -75,13 +75,16 @@ typedef struct sound_module_s
boolean (*AllowReinitSound)(void);
boolean (*CacheSound)(struct sfxinfo_s *sfx);
boolean (*AdjustSoundParams)(const struct mobj_s *listener,
const struct mobj_s *source, int chanvol,
int *vol, int *sep, int *pri);
void (*UpdateSoundParams)(int channel, int vol, int sep);
const struct mobj_s *source,
struct sfxparams_s *params);
void (*UpdateSoundParams)(int channel, const struct sfxparams_s *params);
void (*UpdateListenerParams)(const struct mobj_s *listener);
boolean (*StartSound)(int channel, struct sfxinfo_s *sfx, float pitch);
void (*StopSound)(int channel);
void (*PauseSound)(int channel);
void (*ResumeSound)(int channel);
boolean (*SoundIsPlaying)(int channel);
boolean (*SoundIsPaused)(int channel);
void (*ShutdownSound)(void);
void (*ShutdownModule)(void);
void (*DeferUpdates)(void);
@ -113,32 +116,34 @@ void I_SetChannels(void);
int I_GetSfxLumpNum(struct sfxinfo_s *sfxinfo);
// Starts a sound in a particular sound channel.
int I_StartSound(struct sfxinfo_s *sound, int vol, int sep, int pitch);
int I_StartSound(struct sfxinfo_s *sound, const struct sfxparams_s *params,
int pitch);
// Stops a sound channel.
void I_StopSound(int handle);
void I_PauseSound(int handle);
void I_ResumeSound(int handle);
// Called by S_*() functions
// to see if a channel is still playing.
// Returns 0 if no longer playing, 1 if playing.
boolean I_SoundIsPlaying(int handle);
boolean I_SoundIsPaused(int handle);
// Outputs adjusted volume, separation, and priority from the sound module.
// Returns false if no sound should be played.
boolean I_AdjustSoundParams(const struct mobj_s *listener,
const struct mobj_s *source, int chanvol, int *vol,
int *sep, int *pri);
const struct mobj_s *source,
struct sfxparams_s *params);
// Updates the volume, separation,
// and pitch of a sound channel.
void I_UpdateSoundParams(int handle, int vol, int sep);
void I_UpdateSoundParams(int handle, const struct sfxparams_s *params);
void I_UpdateListenerParams(const struct mobj_s *listener);
void I_DeferSoundUpdates(void);
void I_ProcessSoundUpdates(void);
// haleyjds
int I_SoundID(int handle);
//
// MUSIC I/O
//

View File

@ -253,6 +253,22 @@ static void M_ExtHelpNextScreen(int choice);
static void M_ExtHelp(int choice);
static void M_DrawExtHelp(void);
static void M_PauseSound(void)
{
if (!paused && gamestate == GS_LEVEL && !demoplayback && !netgame)
{
S_PauseSound();
}
}
static void M_ResumeSound(void)
{
if (!paused && gamestate == GS_LEVEL && !demoplayback && !netgame)
{
S_ResumeSound();
}
}
//
// SetNextMenu
//
@ -1700,12 +1716,14 @@ static void M_QuickLoad(void)
{
if (netgame && !demoplayback) // killough 5/26/98: add !demoplayback
{
M_StartSound(sfx_swtchn);
M_StartMessage(s_QLOADNET, NULL, false); // Ty 03/27/98 - externalized
return;
}
if (demorecording) // killough 5/26/98: exclude during demo recordings
{
M_StartSound(sfx_swtchn);
M_StartMessage("you can't quickload\n"
"while recording a demo!\n\n" PRESSKEY,
NULL, false); // killough 5/26/98: not externalized
@ -1746,6 +1764,7 @@ static void M_EndGameResponse(int ch)
quickSaveSlot = -1;
currentMenu->lastOn = itemOn;
S_StopChannels();
MN_ClearMenus();
D_StartTitle();
}
@ -2168,6 +2187,7 @@ void MN_ClearMenus(void)
I_SetSensorEventState(false);
G_ClearInput();
M_ResumeSound();
}
static boolean MenuBack(void)
@ -2437,19 +2457,15 @@ boolean M_ShortcutResponder(const event_t *ev)
if (M_InputActivated(input_help)) // Help key
{
MN_StartControlPanel();
currentMenu = &HelpDef; // killough 10/98: new help screen
currentMenu->prevMenu = NULL;
itemOn = 0;
M_StartSound(sfx_swtchn);
return true;
}
if (M_InputActivated(input_savegame)) // Save Game
{
MN_StartControlPanel();
M_StartSound(sfx_swtchn);
M_SaveGame(0);
return true;
}
@ -2457,7 +2473,6 @@ boolean M_ShortcutResponder(const event_t *ev)
if (M_InputActivated(input_loadgame)) // Load Game
{
MN_StartControlPanel();
M_StartSound(sfx_swtchn);
M_LoadGame(0);
return true;
}
@ -2467,19 +2482,18 @@ boolean M_ShortcutResponder(const event_t *ev)
MN_StartControlPanel();
currentMenu = &SoundDef;
itemOn = currentMenu->lastOn;
M_StartSound(sfx_swtchn);
return true;
}
if (M_InputActivated(input_quicksave)) // Quicksave
{
M_StartSound(sfx_swtchn);
M_QuickSave();
return true;
}
if (M_InputActivated(input_endgame)) // End game
{
M_PauseSound();
M_StartSound(sfx_swtchn);
M_EndGame(0);
return true;
@ -2494,13 +2508,13 @@ boolean M_ShortcutResponder(const event_t *ev)
if (M_InputActivated(input_quickload)) // Quickload
{
M_StartSound(sfx_swtchn);
M_QuickLoad();
return true;
}
if (M_InputActivated(input_quit)) // Quit DOOM
{
M_PauseSound();
M_StartSound(sfx_swtchn);
M_QuitDOOM(0);
return true;
@ -3088,6 +3102,7 @@ boolean M_Responder(event_t *ev)
I_SetSensorEventState(false);
G_ClearInput();
menuactive = false;
M_ResumeSound();
M_StartSound(sfx_swtchx);
return true;
}
@ -3117,7 +3132,6 @@ boolean M_Responder(event_t *ev)
{
I_ShowMouseCursor(menu_input != pad_mode);
MN_StartControlPanel();
M_StartSound(sfx_swtchn);
return true;
}
return false;
@ -3372,6 +3386,9 @@ void MN_StartControlPanel(void)
I_SetSensorEventState(true);
G_ClearInput();
M_PauseSound();
M_StartSound(sfx_swtchn);
}
//

View File

@ -2588,7 +2588,7 @@ static setup_menu_t sfx_settings1[] = {
MI_GAP,
{"Doppler Effect", S_THERMO, CNTR_X, M_THRM_SPC, {"snd_doppler"},
{"Doppler Effect", S_THERMO | S_ACTION, CNTR_X, M_THRM_SPC, {"snd_doppler"},
.strings_id = str_percent, .action = SetSoundModule},
MI_END

View File

@ -870,15 +870,6 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
// NULL head of sector list // phares 3/13/98
mobj->touching_sectorlist = NULL;
// [AM] Do not interpolate on spawn.
mobj->interp = false;
// [AM] Just in case interpolation is attempted...
mobj->oldx = mobj->x;
mobj->oldy = mobj->y;
mobj->oldz = mobj->z;
mobj->oldangle = mobj->angle;
// set subsector and/or block links
P_SetThingPosition(mobj);
@ -890,6 +881,15 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ?
mobj->ceilingz - mobj->height : z;
// [AM] Do not interpolate on spawn.
mobj->interp = false;
// [AM] Just in case interpolation is attempted...
mobj->oldx = mobj->x;
mobj->oldy = mobj->y;
mobj->oldz = mobj->z;
mobj->oldangle = mobj->angle;
mobj->thinker.function.p1 = (actionf_p1)P_MobjThinker;
mobj->above_thing = mobj->below_thing = 0; // phares

View File

@ -46,12 +46,11 @@ typedef struct channel_s
{
sfxinfo_t *sfxinfo; // sound information (if null, channel avail.)
const mobj_t *origin; // origin of sound
int volume; // volume scale value for effect -- haleyjd 05/29/06
int volume_scale; // volume scale value for effect -- haleyjd 05/29/06
int handle; // handle of the sound being played
int o_priority; // haleyjd 09/27/06: stored priority value
int priority; // current priority value
int singularity; // haleyjd 09/27/06: stored singularity value
int idnum; // haleyjd 09/30/06: unique id num for sound event
} channel_t;
// the set of channels available
@ -129,9 +128,9 @@ void S_StopChannels(void)
// haleyjd: added priority scaling
//
static int S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source,
int chanvol, int *vol, int *sep, int *pri)
sfxparams_t *params)
{
return I_AdjustSoundParams(listener, source, chanvol, vol, sep, pri);
return I_AdjustSoundParams(listener, source, params);
}
//
@ -141,8 +140,7 @@ static int S_AdjustSoundParams(const mobj_t *listener, const mobj_t *source,
// haleyjd 09/27/06: fixed priority/singularity bugs
// Note that a higher priority number means lower priority!
//
static int S_getChannel(const mobj_t *origin, sfxinfo_t *sfxinfo, int priority,
int singularity)
static int S_getChannel(const mobj_t *origin, int priority, int singularity)
{
// channel number to use
int cnum;
@ -213,9 +211,8 @@ static int S_getChannel(const mobj_t *origin, sfxinfo_t *sfxinfo, int priority,
static void StartSound(const mobj_t *origin, int sfx_id,
pitchrange_t pitch_range, rumble_type_t rumble_type)
{
int sep, pitch, o_priority, priority, singularity, cnum, handle;
int volumeScale = 127;
int volume = snd_SfxVolume;
int pitch, o_priority, singularity, cnum, handle;
sfxparams_t params;
sfxinfo_t *sfx;
// jff 1/22/98 return if sound is not enabled
@ -242,17 +239,17 @@ static void StartSound(const mobj_t *origin, int sfx_id,
// Initialize sound parameters
pitch = NORM_PITCH;
params.volume_scale = 127;
// haleyjd: modified so that priority value is always used
// haleyjd: also modified to get and store proper singularity value
o_priority = priority = sfx->priority;
o_priority = params.priority = sfx->priority;
singularity = sfx->singularity;
// Check to see if it is audible, modify the params
// killough 3/7/98, 4/25/98: code rearranged slightly
if (!S_AdjustSoundParams(players[displayplayer].mo, origin, volumeScale,
&volume, &sep, &priority))
if (!S_AdjustSoundParams(players[displayplayer].mo, origin, &params))
{
return;
}
@ -281,7 +278,7 @@ static void StartSound(const mobj_t *origin, int sfx_id,
}
// try to find a channel
if ((cnum = S_getChannel(origin, sfx, priority, singularity)) < 0)
if ((cnum = S_getChannel(origin, params.priority, singularity)) < 0)
{
return;
}
@ -294,7 +291,6 @@ static void StartSound(const mobj_t *origin, int sfx_id,
#endif
channels[cnum].sfxinfo = sfx;
channels[cnum].origin = origin;
while (sfx->link)
{
@ -302,20 +298,19 @@ static void StartSound(const mobj_t *origin, int sfx_id,
}
// Assigns the handle to one of the channels in the mix/output buffer.
handle = I_StartSound(sfx, volume, sep, pitch);
handle = I_StartSound(sfx, &params, pitch);
// haleyjd: check to see if the sound was started
if (handle >= 0)
{
channels[cnum].handle = handle;
// haleyjd 05/29/06: record volume scale value
// haleyjd 09/27/06: store priority and singularity values (!!!)
channels[cnum].volume = volumeScale;
channels[cnum].o_priority = o_priority; // original priority
channels[cnum].priority = priority; // scaled priority
channels[cnum].origin = origin;
channels[cnum].handle = handle;
channels[cnum].volume_scale = params.volume_scale;
channels[cnum].o_priority = o_priority; // original priority
channels[cnum].priority = params.priority; // scaled priority
channels[cnum].singularity = singularity;
channels[cnum].idnum = I_SoundID(handle); // unique instance id
if (rumble_type != RUMBLE_NONE)
{
@ -505,11 +500,51 @@ void S_UnlinkSound(mobj_t *origin)
}
}
void S_PauseSound(void)
{
if (nosfxparm)
{
return;
}
I_DeferSoundUpdates();
for (int cnum = 0; cnum < snd_channels; cnum++)
{
if (channels[cnum].sfxinfo)
{
I_PauseSound(channels[cnum].handle);
}
}
I_ProcessSoundUpdates();
}
void S_ResumeSound(void)
{
if (nosfxparm)
{
return;
}
I_DeferSoundUpdates();
for (int cnum = 0; cnum < snd_channels; cnum++)
{
if (channels[cnum].sfxinfo)
{
I_ResumeSound(channels[cnum].handle);
}
}
I_ProcessSoundUpdates();
}
//
// Stop and resume music, during game PAUSE.
//
void S_PauseSound(void)
void S_PauseMusic(void)
{
if (mus_playing && !mus_paused)
{
@ -518,7 +553,7 @@ void S_PauseSound(void)
}
}
void S_ResumeSound(void)
void S_ResumeMusic(void)
{
if (mus_playing && mus_paused)
{
@ -554,56 +589,48 @@ void S_UpdateSounds(const mobj_t *listener)
}
I_DeferSoundUpdates();
I_UpdateListenerParams(listener);
for (cnum = 0; cnum < snd_channels; ++cnum)
{
channel_t *c = &channels[cnum];
sfxinfo_t *sfx = c->sfxinfo;
// haleyjd: has this software channel lost its hardware channel?
if (c->idnum != I_SoundID(c->handle))
{
// clear the channel and keep going
memset(c, 0, sizeof(channel_t));
continue;
}
if (sfx)
{
if (I_SoundIsPlaying(c->handle))
{
// initialize parameters
int volume = snd_SfxVolume;
int sep = NORM_SEP;
int pri = c->o_priority; // haleyjd 09/27/06: priority
// check non-local sounds for distance clipping
// or modify their params
if (c->origin && listener != c->origin) // killough 3/20/98
{
if (!S_AdjustSoundParams(listener, c->origin, c->volume,
&volume, &sep, &pri))
// initialize parameters
sfxparams_t params;
params.volume_scale = c->volume_scale;
params.priority = c->o_priority; // haleyjd 09/27/06: priority
if (S_AdjustSoundParams(listener, c->origin, &params))
{
S_StopChannel(cnum);
I_UpdateSoundParams(c->handle, &params);
c->priority = params.priority; // haleyjd
}
else
{
I_UpdateSoundParams(c->handle, volume, sep);
c->priority = pri; // haleyjd
S_StopChannel(cnum);
}
}
I_UpdateRumbleParams(listener, c->origin, c->handle);
}
else // if channel is allocated but sound has stopped, free it
else if (!I_SoundIsPaused(c->handle))
{
// if channel is allocated but sound has stopped, free it
S_StopChannel(cnum);
}
}
}
I_UpdateListenerParams(listener);
I_ProcessSoundUpdates();
I_UpdateRumble();
}

View File

@ -102,10 +102,13 @@ void S_ChangeMusInfoMusic(int lumpnum, int looping);
// Stops the music fer sure.
void S_StopMusic(void);
// Stop and resume music, during game PAUSE.
void S_PauseSound(void);
void S_ResumeSound(void);
// Stop and resume music, during game PAUSE.
void S_PauseMusic(void);
void S_ResumeMusic(void);
void S_RestartMusic(void);
//

View File

@ -23,6 +23,14 @@
#include "doomtype.h"
typedef struct sfxparams_s
{
int volume_scale;
int volume;
int separation;
int priority;
} sfxparams_t;
//
// SoundFX struct.
//