The Great Normalization

Volume division is now handled exclusively by VOLUME_DIV and NOWHERE ELSE!!!

And use fixed-point math for volume calculation in mixer_sound to avoid
precision loss
This commit is contained in:
GenericHeroGuy 2025-11-11 21:46:15 +01:00
parent cc911adce4
commit b87ffce6ce
6 changed files with 43 additions and 53 deletions

View file

@ -566,10 +566,10 @@ extern int compuncommitted;
#define NO_PNG_LUMPS
#endif
/// Divide volume of music and sounds by this much (loudest sounds on earth)
#define VOLUME_DIVIDER 4
#define USER_VOLUME_SCALE 2
#define MAX_VOLUME ( 100 * VOLUME_DIVIDER / USER_VOLUME_SCALE )
// Volume scale is 0-100 in new mixer. 100 is treated as -0dB or 100% gain. No more weirdness to work around SDL_mixer
// problems
#define MAX_VOLUME 100
#ifdef HAVE_CURL
#define MASTERSERVER

View file

@ -121,7 +121,7 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch);
\return void
*/
void I_SetSfxVolume(int volume);
void I_SetSfxVolume(UINT8 volume);
/// ------------------------
// MUSIC SYSTEM
@ -230,7 +230,7 @@ void I_ResumeSong(void);
\return void
*/
void I_SetMusicVolume(int volume);
void I_SetMusicVolume(UINT8 volume);
boolean I_SetSongTrack(INT32 track);

View file

@ -75,8 +75,8 @@ consvar_t stereoreverse = CVAR_INIT ("stereoreverse", "Off", CV_SAVE, CV_OnOff,
static consvar_t precachesound = CVAR_INIT ("precachesound", "Off", CV_SAVE, CV_OnOff, NULL);
// actual general (maximum) sound & music volume, saved into the config
consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "50", CV_SAVE, soundvolume_cons_t, NULL);
consvar_t cv_digmusicvolume = CVAR_INIT ("musicvolume", "50", CV_SAVE, soundvolume_cons_t, NULL);
consvar_t cv_soundvolume = CVAR_INIT ("soundvolume", "80", CV_SAVE, soundvolume_cons_t, NULL);
consvar_t cv_digmusicvolume = CVAR_INIT ("musicvolume", "80", CV_SAVE, soundvolume_cons_t, NULL);
// number of channels available
consvar_t cv_numChannels = CVAR_INIT ("snd_channels", "64", CV_SAVE|CV_CALL, CV_Unsigned, SetChannelsNum);
@ -117,8 +117,6 @@ static CV_PossibleValue_t interpolationfilter_cons_t[] = {{0, "Default"}, {1, "N
consvar_t cv_modfilter = CVAR_INIT ("modfilter", "0", CV_SAVE|CV_CALL, interpolationfilter_cons_t, ModFilter_OnChange);
#endif
#define S_MAX_VOLUME 127
// when to clip out sounds
// Does not fit the large outdoor areas.
// added 2-2-98 in 8 bit volume control (before (1200*0x10000))
@ -778,9 +776,9 @@ void S_UpdateSounds(void)
mobj_t *listenmobj[MAXSPLITSCREENPLAYERS];
// Update sound/music volumes, if changed manually at console
if (actualsfxvolume != cv_soundvolume.value * USER_VOLUME_SCALE)
if (actualsfxvolume != cv_soundvolume.value)
S_SetSfxVolume (cv_soundvolume.value);
if (actualdigmusicvolume != cv_digmusicvolume.value * USER_VOLUME_SCALE)
if (actualdigmusicvolume != cv_digmusicvolume.value)
S_SetDigMusicVolume (cv_digmusicvolume.value);
memset(listener, 0, sizeof(listener));
@ -976,8 +974,7 @@ void S_UpdateClosedCaptions(void)
void S_SetSfxVolume(INT32 volume)
{
//CV_SetValue(&cv_soundvolume, volume);
actualsfxvolume = cv_soundvolume.value * USER_VOLUME_SCALE;
actualsfxvolume = volume;
#ifdef HW3SOUND
hws_mode == HWS_DEFAULT_MODE ? I_SetSfxVolume(volume&0x1F) : HW3S_SetSfxVolume(volume&0x1F);
@ -1454,7 +1451,7 @@ ReadMusicDefFields
}
def->numtracks = i;
def->volume = DEFAULT_MUSICDEF_VOLUME;
def->volume = MAX_VOLUME;
def->legacy = true;
def->next = musicdefstart;
@ -1524,7 +1521,7 @@ ReadMusicDefFields
}
else if (!stricmp(stoken, "volume"))
{
def->volume = atoi(textline) / VOLUME_DIVIDER;
def->volume = atoi(textline);
def->legacy = false;
}
else if (!stricmp(stoken, "contentidunsafe"))
@ -2413,7 +2410,7 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
music_flags = mflags;
music_looping = looping;
musicdef_volume = DEFAULT_MUSICDEF_VOLUME;
musicdef_volume = MAX_VOLUME;
{
UINT8 i = 0;
@ -2518,8 +2515,7 @@ void S_SetMusicVolume(INT32 digvolume)
if (digvolume < 0)
digvolume = cv_digmusicvolume.value;
//CV_SetValue(&cv_digmusicvolume, digvolume);
actualdigmusicvolume = cv_digmusicvolume.value * USER_VOLUME_SCALE;
actualdigmusicvolume = digvolume;
I_SetMusicVolume(digvolume);
}

View file

@ -35,12 +35,6 @@ extern openmpt_module *openmpt_mhandle;
// mask used to indicate sound origin is player item pickup
#define PICKUP_SOUND 0x8000
//
#define SOUND_VOLUME_RANGE 256
#define MAX_SOUND_VOLUME 255
#define DEFAULT_MUSICDEF_VOLUME ( 100 / VOLUME_DIVIDER )
extern consvar_t stereoreverse;
extern consvar_t cv_soundvolume, cv_closedcaptioning, cv_digmusicvolume;

View file

@ -48,6 +48,9 @@
#define BUFFERSIZE 4096
#define BUFFERCOUNT 8
// don't set gain too high, avoids clipping with multiple sounds playing
#define VOLUME_DIV 200.f
typedef enum
{
Int16,
@ -202,7 +205,7 @@ void I_StartupSound(void)
// enable the limiter and disable hrtf
// idk if either is necessary tbh but fuckit
ALCint attrs[] = {
ALC_OUTPUT_LIMITER_SOFT, ALC_TRUE,
ALC_OUTPUT_LIMITER_SOFT, ALC_FALSE, // G: too noticeable
ALC_HRTF_SOFT, ALC_FALSE,
0
};
@ -222,7 +225,7 @@ void I_StartupSound(void)
for (size_t i = 0; i < BUFFERCOUNT; i++)
audio.musicbuffers[i] = INVALID_HANDLE;
music_volume = sfx_volume = 0;
music_volume = sfx_volume = 0.f;
#ifdef HAVE_OPENMPT
CONS_Printf("libopenmpt version: %s\n", openmpt_get_string("library_version"));
@ -285,7 +288,7 @@ void I_ShutdownSound(void)
static boolean I_UpdateMusicVolume(void)
{
LOCKAUDIO;
return TRY(alSourcef, audio.music, AL_GAIN, music_volume*internal_volume*(musicdef_volume/100.f));
return TRY(alSourcef, audio.music, AL_GAIN, music_volume*internal_volume*(musicdef_volume/(float)MAX_VOLUME));
}
static boolean I_QueueNextSample(boolean unqueue)
@ -853,8 +856,8 @@ void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch)
return;
ALuint source = handle;
TRY(alSourcef, source, AL_GAIN, (sfx_volume * (float)vol / 255.0f)/4.0f);
TRY(alSourcef, source, AL_PITCH, (float)pitch / 128.0f);
TRY(alSourcef, source, AL_GAIN, sfx_volume * (vol / 255.0f));
TRY(alSourcef, source, AL_PITCH, pitch / 128.0f);
(void)sep;
}
@ -912,9 +915,9 @@ boolean I_SoundIsPlaying(INT32 handle)
return value == AL_PLAYING;
}
void I_SetSfxVolume(int volume)
void I_SetSfxVolume(UINT8 volume)
{
sfx_volume = (float)volume / 100.f;
sfx_volume = volume / VOLUME_DIV;
}
void I_InitMusic(void)
@ -1051,7 +1054,7 @@ boolean I_SetSongPosition(UINT32 position)
if (audio.music == INVALID_HANDLE)
return false;
if (!TRY(alSourcef, audio.music, AL_SEC_OFFSET, (float)position / 1000.0f))
if (!TRY(alSourcef, audio.music, AL_SEC_OFFSET, position / 1000.0f))
return false;
return true;
@ -1359,11 +1362,11 @@ void I_ResumeSong(void)
alSourcePlay(audio.music);
}
void I_SetMusicVolume(int volume)
void I_SetMusicVolume(UINT8 volume)
{
LOCKAUDIO;
music_volume = (float)volume / 100.f;
music_volume = volume / VOLUME_DIV;
if (audio.music != INVALID_HANDLE)
I_UpdateMusicVolume();
}
@ -1382,7 +1385,7 @@ void I_SetInternalMusicVolume(UINT8 volume)
{
LOCKAUDIO;
internal_volume = volume / 100.0f;
internal_volume = volume / (float)MAX_VOLUME; // don't divide by VOLUME_DIV, this is a multiplier on music volume
if (audio.music != INVALID_HANDLE)
I_UpdateMusicVolume();
}

View file

@ -80,6 +80,9 @@ write netcode into the sound code, OKAY?
static UINT16 BUFFERSIZE = 2048;
static UINT16 SAMPLERATE = 44100;
// don't set gain too high, avoids clipping with multiple sounds playing
#define VOLUME_DIV (200*FRACUNIT)
#ifdef HAVE_OPENMPT
#include "libopenmpt/libopenmpt.h"
#endif
@ -145,7 +148,7 @@ static void var_cleanup(void)
else
fading_nocleanup = false; // use it once, set it back immediately
internal_volume = 100;
internal_volume = MAX_VOLUME;
}
#if defined (HAVE_GME) && defined (HAVE_ZLIB)
@ -261,13 +264,9 @@ void I_UpdateSound(void)
/// SFX
/// ------------------------
static int
get_real_sfx_volume (int vol)
static UINT8 get_real_sfx_volume(UINT8 vol)
{
const int scale = SOUND_VOLUME_RANGE / MIX_MAX_VOLUME;
const int divider = VOLUME_DIVIDER * scale;
const int volume = ( vol + 1 ) / divider * sfx_volume / 100;
return volume;
return FixedMul(vol, FixedMul(FixedDiv2(MIX_MAX_VOLUME, 255), FixedDiv2(sfx_volume*FRACUNIT, VOLUME_DIV)));
}
// this is as fast as I can possibly make it.
@ -551,7 +550,6 @@ void I_FreeSfx(sfxinfo_t *sfx)
INT32 I_StartSound(sfxenum_t id, UINT8 vol, UINT8 sep, UINT8 pitch, UINT8 priority, INT32 channel)
{
//UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127
UINT8 volume = get_real_sfx_volume(vol);
INT32 handle = Mix_PlayChannel(channel, S_sfx[id].data, 0);
Mix_Volume(handle, volume);
@ -573,14 +571,13 @@ boolean I_SoundIsPlaying(INT32 handle)
void I_UpdateSoundParams(INT32 handle, UINT8 vol, UINT8 sep, UINT8 pitch)
{
//UINT8 volume = (((UINT16)vol + 1) * (UINT16)sfx_volume) / 62; // (256 * 31) / 62 == 127
UINT8 volume = get_real_sfx_volume(vol);
Mix_Volume(handle, volume);
Mix_SetPanning(handle, min((UINT16)(0xff-sep)<<1, 0xff), min((UINT16)(sep)<<1, 0xff));
(void)pitch;
}
void I_SetSfxVolume(int volume)
void I_SetSfxVolume(UINT8 volume)
{
sfx_volume = volume;
}
@ -592,10 +589,10 @@ void I_SetSfxVolume(int volume)
static int attenuate(int scale)
{
// attenuate scale by all volumes as percentages
return scale
* musicdef_volume / 100
* internal_volume / 100
* music_volume / 100;
fixed_t vol = FixedDiv2(music_volume*FRACUNIT, VOLUME_DIV);
vol = FixedMul(vol, FixedDiv2(internal_volume, MAX_VOLUME));
vol = FixedMul(vol, FixedDiv2(musicdef_volume, MAX_VOLUME));
return FixedMul(scale, vol);
}
static UINT32 get_adjusted_position(UINT32 position)
@ -1464,7 +1461,7 @@ void I_ResumeSong(void)
songpaused = false;
}
void I_SetMusicVolume(int volume)
void I_SetMusicVolume(UINT8 volume)
{
if (!I_SongPlaying())
return;
@ -1560,7 +1557,7 @@ boolean I_FadeSongFromVolume(UINT8 target_volume, UINT8 source_volume, UINT32 ms
{
INT16 volume_delta;
source_volume = min(source_volume, 100);
source_volume = min(source_volume, MAX_VOLUME);
volume_delta = (INT16)(target_volume - source_volume);
I_StopFadingSong();
@ -1630,7 +1627,7 @@ boolean I_FadeOutStopSong(UINT32 ms)
boolean I_FadeInPlaySong(UINT32 ms, boolean looping)
{
if (I_PlaySong(looping))
return I_FadeSongFromVolume(100, 0, ms, NULL);
return I_FadeSongFromVolume(MAX_VOLUME, 0, ms, NULL);
return false;
}