mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-22 11:22:18 -04:00
add 4-band equalizer based on the OpenAL extension (config only) (#1714)
* add 4-band equalizer based on the OpenAL extension (config only) * add comment * another comment * expose equalizer settings to config * remove EQUALIZER_DEFAULT string * allow to toggle "Apply Equalizer" in the menu * implement Equalizer presets The presets are exemplary for now and need some fine-tuning. * remove header * back to gain percent scale, dB scale is not fine-grained enough * apply patch by @ceski-1 (thank you!) * shorten preset names for now * Revert "back to gain percent scale, dB scale is not fine-grained enough" This reverts commit 3210cb07d67f71c4025e73b8b56387e45a0dc995. * a little clean-up * declare SetEqualizer as static * Expose center and bandwidth settings * Increase gain for temporary presets * Add preamp * Add placeholder EQ menu * Use an alternate set of presets * disable EQ tab in the General menu * give equalizer presets less abstract names * adjust equalizer preset preamp gains @ceski-1 I will need your confirmation here * Use safer dB ranges * Simplify * Formatting --------- Co-authored-by: ceski <56656010+ceski-1@users.noreply.github.com>
This commit is contained in:
parent
480cf488d4
commit
f8d1dfc078
263
src/i_oalsound.c
263
src/i_oalsound.c
@ -58,6 +58,8 @@
|
||||
# define FUNCTION_CAST(T, ptr) (T)(ptr)
|
||||
#endif
|
||||
|
||||
#define ALFUNC(T, ptr) (ptr = FUNCTION_CAST(T, alGetProcAddress(#ptr)))
|
||||
|
||||
static int snd_resampler;
|
||||
static boolean snd_limiter;
|
||||
static boolean snd_hrtf;
|
||||
@ -119,10 +121,8 @@ static void InitDeferred(void)
|
||||
|
||||
if (alIsExtensionPresent("AL_SOFT_deferred_updates") == AL_TRUE)
|
||||
{
|
||||
alDeferUpdatesSOFT = FUNCTION_CAST(
|
||||
LPALDEFERUPDATESSOFT, alGetProcAddress("alDeferUpdatesSOFT"));
|
||||
alProcessUpdatesSOFT = FUNCTION_CAST(
|
||||
LPALPROCESSUPDATESSOFT, alGetProcAddress("alProcessUpdatesSOFT"));
|
||||
ALFUNC(LPALDEFERUPDATESSOFT, alDeferUpdatesSOFT);
|
||||
ALFUNC(LPALPROCESSUPDATESSOFT, alProcessUpdatesSOFT);
|
||||
|
||||
if (alDeferUpdatesSOFT && alProcessUpdatesSOFT)
|
||||
{
|
||||
@ -208,8 +208,7 @@ void I_OAL_SetResampler(void)
|
||||
return;
|
||||
}
|
||||
|
||||
alGetStringiSOFT =
|
||||
FUNCTION_CAST(LPALGETSTRINGISOFT, alGetProcAddress("alGetStringiSOFT"));
|
||||
ALFUNC(LPALGETSTRINGISOFT, alGetStringiSOFT);
|
||||
|
||||
if (!alGetStringiSOFT)
|
||||
{
|
||||
@ -334,8 +333,7 @@ const char **I_OAL_GetResamplerStrings(void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
alGetStringiSOFT =
|
||||
FUNCTION_CAST(LPALGETSTRINGISOFT, alGetProcAddress("alGetStringiSOFT"));
|
||||
ALFUNC(LPALGETSTRINGISOFT, alGetStringiSOFT);
|
||||
|
||||
if (!alGetStringiSOFT)
|
||||
{
|
||||
@ -352,9 +350,223 @@ const char **I_OAL_GetResamplerStrings(void)
|
||||
return strings;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
EQ_PRESET_OFF,
|
||||
EQ_PRESET_CLASSICAL,
|
||||
EQ_PRESET_ROCK,
|
||||
EQ_PRESET_VOCAL,
|
||||
NUM_EQ_PRESETS
|
||||
} eq_preset_t;
|
||||
|
||||
static eq_preset_t snd_equalizer;
|
||||
static int snd_eq_preamp;
|
||||
static int snd_eq_low_gain;
|
||||
static int snd_eq_low_cutoff;
|
||||
static int snd_eq_mid1_gain;
|
||||
static int snd_eq_mid1_center;
|
||||
static int snd_eq_mid1_width;
|
||||
static int snd_eq_mid2_gain;
|
||||
static int snd_eq_mid2_center;
|
||||
static int snd_eq_mid2_width;
|
||||
static int snd_eq_high_gain;
|
||||
static int snd_eq_high_cutoff;
|
||||
|
||||
static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
|
||||
static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
|
||||
static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
|
||||
static LPALGENEFFECTS alGenEffects;
|
||||
static LPALDELETEEFFECTS alDeleteEffects;
|
||||
static LPALISEFFECT alIsEffect;
|
||||
static LPALEFFECTI alEffecti;
|
||||
static LPALEFFECTF alEffectf;
|
||||
static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
|
||||
static LPALGENFILTERS alGenFilters;
|
||||
static LPALDELETEFILTERS alDeleteFilters;
|
||||
static LPALISFILTER alIsFilter;
|
||||
static LPALFILTERI alFilteri;
|
||||
static LPALFILTERF alFilterf;
|
||||
|
||||
static void InitEqualizer(void)
|
||||
{
|
||||
ALCint iSends = 0;
|
||||
|
||||
if (!oal || !oal->EXT_EFX)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the actual number of Auxiliary Sends available on each Source.
|
||||
|
||||
alcGetIntegerv(oal->device, ALC_MAX_AUXILIARY_SENDS, 1, &iSends);
|
||||
|
||||
if (iSends < 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ALFUNC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
|
||||
ALFUNC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
|
||||
ALFUNC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
|
||||
ALFUNC(LPALGENEFFECTS, alGenEffects);
|
||||
ALFUNC(LPALDELETEEFFECTS, alDeleteEffects);
|
||||
ALFUNC(LPALISEFFECT, alIsEffect);
|
||||
ALFUNC(LPALEFFECTI, alEffecti);
|
||||
ALFUNC(LPALEFFECTF, alEffectf);
|
||||
ALFUNC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
|
||||
ALFUNC(LPALGENFILTERS, alGenFilters);
|
||||
ALFUNC(LPALDELETEFILTERS, alDeleteFilters);
|
||||
ALFUNC(LPALISFILTER, alIsFilter);
|
||||
ALFUNC(LPALFILTERI, alFilteri);
|
||||
ALFUNC(LPALFILTERF, alFilterf);
|
||||
}
|
||||
|
||||
void I_OAL_SetEqualizer(void)
|
||||
{
|
||||
static ALuint uiEffectSlot = AL_INVALID;
|
||||
static ALuint uiEffect = AL_INVALID;
|
||||
static ALuint uiFilter = AL_INVALID;
|
||||
|
||||
if (!alGenAuxiliaryEffectSlots ||
|
||||
!alDeleteAuxiliaryEffectSlots ||
|
||||
!alIsAuxiliaryEffectSlot ||
|
||||
!alGenEffects ||
|
||||
!alDeleteEffects ||
|
||||
!alIsEffect ||
|
||||
!alEffecti ||
|
||||
!alEffectf ||
|
||||
!alAuxiliaryEffectSloti ||
|
||||
!alGenFilters ||
|
||||
!alDeleteFilters ||
|
||||
!alIsFilter ||
|
||||
!alFilteri ||
|
||||
!alFilterf)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Unload all effects first.
|
||||
|
||||
if (alIsAuxiliaryEffectSlot(uiEffectSlot))
|
||||
{
|
||||
for (int i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
alSourcei(oal->sources[i], AL_DIRECT_FILTER, AL_FILTER_NULL);
|
||||
alSource3i(oal->sources[i], AL_AUXILIARY_SEND_FILTER,
|
||||
AL_EFFECTSLOT_NULL, 0, AL_FILTER_NULL);
|
||||
}
|
||||
|
||||
alDeleteAuxiliaryEffectSlots(1, &uiEffectSlot);
|
||||
}
|
||||
|
||||
if (alIsEffect(uiEffect))
|
||||
{
|
||||
alDeleteEffects(1, &uiEffect);
|
||||
}
|
||||
|
||||
if (alIsFilter(uiFilter))
|
||||
{
|
||||
alDeleteFilters(1, &uiFilter);
|
||||
}
|
||||
|
||||
if (snd_equalizer == EQ_PRESET_OFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply equalizer effect.
|
||||
|
||||
alGenAuxiliaryEffectSlots(1, &uiEffectSlot);
|
||||
alGenEffects(1, &uiEffect);
|
||||
alGenFilters(1, &uiFilter);
|
||||
alEffecti(uiEffect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER);
|
||||
|
||||
// AL_LOWPASS_GAIN actually controls overall gain for the filter it's
|
||||
// applied to (OpenAL Effects Extension Guide 1.1, pp. 16-17, 135).
|
||||
|
||||
alFilteri(uiFilter, AL_FILTER_TYPE, AL_FILTER_LOWPASS);
|
||||
|
||||
// Gains vary from 0.251 up to 3.981, which means from -12dB attenuation
|
||||
// up to +12dB amplification, i.e. 20*log10(gain).
|
||||
|
||||
#define DB_TO_GAIN(db) powf(10.0f, (db) / 20.0f)
|
||||
#define EQ_GAIN(db) ((ALfloat)BETWEEN(0.251f, 3.981f, DB_TO_GAIN(db)))
|
||||
#define LP_GAIN(db) ((ALfloat)BETWEEN(0.063f, 1.0f, DB_TO_GAIN(db)))
|
||||
#define OCTAVE(x) ((ALfloat)BETWEEN(0.01f, 1.0f, (x) / 100.0f))
|
||||
|
||||
// Low
|
||||
alEffectf(uiEffect, AL_EQUALIZER_LOW_GAIN, EQ_GAIN(snd_eq_low_gain));
|
||||
alEffectf(uiEffect, AL_EQUALIZER_LOW_CUTOFF, (ALfloat)snd_eq_low_cutoff);
|
||||
|
||||
// Mid 1
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID1_GAIN, EQ_GAIN(snd_eq_mid1_gain));
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID1_CENTER, (ALfloat)snd_eq_mid1_center);
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID1_WIDTH, OCTAVE(snd_eq_mid1_width));
|
||||
|
||||
// Mid 2
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID2_GAIN, EQ_GAIN(snd_eq_mid2_gain));
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID2_CENTER, (ALfloat)snd_eq_mid2_center);
|
||||
alEffectf(uiEffect, AL_EQUALIZER_MID2_WIDTH, OCTAVE(snd_eq_mid2_width));
|
||||
|
||||
// High
|
||||
alEffectf(uiEffect, AL_EQUALIZER_HIGH_GAIN, EQ_GAIN(snd_eq_high_gain));
|
||||
alEffectf(uiEffect, AL_EQUALIZER_HIGH_CUTOFF, (ALfloat)snd_eq_high_cutoff);
|
||||
|
||||
alAuxiliaryEffectSloti(uiEffectSlot, AL_EFFECTSLOT_EFFECT, uiEffect);
|
||||
|
||||
for (int i = 0; i < MAX_CHANNELS; i++)
|
||||
{
|
||||
// Mute the dry path.
|
||||
alFilterf(uiFilter, AL_LOWPASS_GAIN, 0.0f);
|
||||
alSourcei(oal->sources[i], AL_DIRECT_FILTER, uiFilter);
|
||||
|
||||
// Keep the wet path.
|
||||
alFilterf(uiFilter, AL_LOWPASS_GAIN, LP_GAIN(snd_eq_preamp));
|
||||
alSource3i(oal->sources[i], AL_AUXILIARY_SEND_FILTER, uiEffectSlot, 0,
|
||||
uiFilter);
|
||||
}
|
||||
}
|
||||
|
||||
void I_OAL_EqualizerPreset(void)
|
||||
{
|
||||
struct
|
||||
{
|
||||
int *var;
|
||||
int val[NUM_EQ_PRESETS];
|
||||
} eq_presets[] =
|
||||
{ // Preamp Off, Classical, Rock, Vocal
|
||||
{&snd_eq_preamp, { 0, -4, -5, -4}}, // -24 to 0
|
||||
|
||||
// Low
|
||||
{&snd_eq_low_gain, { 0, 4, 0, -2}}, // -12 to 12
|
||||
{&snd_eq_low_cutoff, { 200, 125, 200, 125}}, // 50 to 800
|
||||
|
||||
// Mid 1
|
||||
{&snd_eq_mid1_gain, { 0, 1, 3, 3}}, // -12 to 12
|
||||
{&snd_eq_mid1_center, { 500, 200, 250, 650}}, // 200 to 3000
|
||||
{&snd_eq_mid1_width, { 100, 100, 100, 100}}, // 1 to 100
|
||||
|
||||
// Mid 2
|
||||
{&snd_eq_mid2_gain, { 0, 0, 1, 3}}, // -12 to 12
|
||||
{&snd_eq_mid2_center, { 3000, 3000, 3000, 1550}}, // 1000 to 8000
|
||||
{&snd_eq_mid2_width, { 100, 100, 100, 100}}, // 1 to 100
|
||||
|
||||
// High
|
||||
{&snd_eq_high_gain, { 0, 2, 5, 1}}, // -12 to 12
|
||||
{&snd_eq_high_cutoff, { 6000, 8000, 6000, 10000}}, // 4000 to 16000
|
||||
};
|
||||
|
||||
for (int i = 0; i < arrlen(eq_presets); i++)
|
||||
{
|
||||
*eq_presets[i].var = eq_presets[i].val[snd_equalizer];
|
||||
}
|
||||
|
||||
I_OAL_SetEqualizer();
|
||||
}
|
||||
|
||||
static void UpdateUserSoundSettings(void)
|
||||
{
|
||||
I_OAL_SetResampler();
|
||||
I_OAL_SetEqualizer();
|
||||
|
||||
if (oal_snd_module == SND_MODULE_3D)
|
||||
{
|
||||
@ -469,6 +681,39 @@ void I_OAL_BindSoundVariables(void)
|
||||
BIND_NUM(snd_doppler, 0, 0, 10,
|
||||
"[OpenAL 3D] Doppler effect (0 = Off; 10 = Max)");
|
||||
BIND_BOOL(snd_limiter, false, "Use sound output limiter");
|
||||
|
||||
BIND_NUM(snd_equalizer, EQ_PRESET_OFF, EQ_PRESET_OFF, EQ_PRESET_VOCAL,
|
||||
"Equalizer preset (0 = Off; 1 = Classical; 2 = Rock; 3 = Vocal");
|
||||
BIND_NUM(snd_eq_preamp, 0, -24, 0,
|
||||
"Equalizer preamp gain [dB]");
|
||||
|
||||
// Low
|
||||
BIND_NUM(snd_eq_low_gain, 0, -12, 12,
|
||||
"Equalizer low frequency range gain [dB]");
|
||||
BIND_NUM(snd_eq_low_cutoff, 200, 50, 800,
|
||||
"Equalizer low cut-off frequency [Hz]");
|
||||
|
||||
// Mid 1
|
||||
BIND_NUM(snd_eq_mid1_gain, 0, -12, 12,
|
||||
"Equalizer mid1 frequency range gain [dB]");
|
||||
BIND_NUM(snd_eq_mid1_center, 500, 200, 3000,
|
||||
"Equalizer mid1 center frequency [Hz]");
|
||||
BIND_NUM(snd_eq_mid1_width, 100, 1, 100,
|
||||
"Equalizer mid1 bandwidth [octave] (1 = 0.01; 100 = 1.0)");
|
||||
|
||||
// Mid 2
|
||||
BIND_NUM(snd_eq_mid2_gain, 0, -12, 12,
|
||||
"Equalizer mid2 frequency range gain [dB]");
|
||||
BIND_NUM(snd_eq_mid2_center, 3000, 1000, 8000,
|
||||
"Equalizer mid2 center frequency [Hz]");
|
||||
BIND_NUM(snd_eq_mid2_width, 100, 1, 100,
|
||||
"Equalizer mid2 bandwidth [octave] (1 = 0.01; 100 = 1.0)");
|
||||
|
||||
// High
|
||||
BIND_NUM(snd_eq_high_gain, 0, -12, 12,
|
||||
"Equalizer high frequency range gain [dB]");
|
||||
BIND_NUM(snd_eq_high_cutoff, 6000, 4000, 16000,
|
||||
"Equalizer high cut-off frequency [Hz]");
|
||||
}
|
||||
|
||||
boolean I_OAL_InitSound(int snd_module)
|
||||
@ -519,6 +764,8 @@ boolean I_OAL_InitSound(int snd_module)
|
||||
(alcIsExtensionPresent(oal->device, "ALC_EXT_EFX") == ALC_TRUE);
|
||||
oal->EXT_SOURCE_RADIUS =
|
||||
(alIsExtensionPresent("AL_EXT_SOURCE_RADIUS") == AL_TRUE);
|
||||
|
||||
InitEqualizer();
|
||||
InitDeferred();
|
||||
ResetParams();
|
||||
|
||||
|
@ -70,4 +70,8 @@ void I_OAL_SetPan(int channel, int separation);
|
||||
|
||||
void I_OAL_BindSoundVariables(void);
|
||||
|
||||
void I_OAL_SetEqualizer(void);
|
||||
|
||||
void I_OAL_EqualizerPreset(void);
|
||||
|
||||
#endif
|
||||
|
@ -308,6 +308,7 @@ enum
|
||||
str_gamma,
|
||||
str_sound_module,
|
||||
str_resampler,
|
||||
str_equalizer_preset,
|
||||
|
||||
str_mouse_accel,
|
||||
|
||||
@ -2054,6 +2055,8 @@ static void SetMidiPlayer(void)
|
||||
S_RestartMusic();
|
||||
}
|
||||
|
||||
static const char *equalizer_preset_strings[] = {"Off", "Classical", "Rock", "Vocal"};
|
||||
|
||||
static setup_menu_t gen_settings2[] = {
|
||||
|
||||
{"Sound Volume", S_THERMO, M_X_THRM8, M_THRM_SPC, {"sfx_volume"},
|
||||
@ -2075,6 +2078,9 @@ static setup_menu_t gen_settings2[] = {
|
||||
// [FG] play sounds in full length
|
||||
{"Disable Sound Cutoffs", S_ONOFF, M_X, M_SPC, {"full_sounds"}},
|
||||
|
||||
{"Equalizer Preset", S_CHOICE, M_X, M_SPC, {"snd_equalizer"}, m_null, input_null,
|
||||
str_equalizer_preset, I_OAL_EqualizerPreset},
|
||||
|
||||
{"Resampler", S_CHOICE | S_NEXT_LINE, M_X, M_SPC, {"snd_resampler"}, m_null,
|
||||
input_null, str_resampler, I_OAL_SetResampler},
|
||||
|
||||
@ -2088,6 +2094,47 @@ static setup_menu_t gen_settings2[] = {
|
||||
MI_END
|
||||
};
|
||||
|
||||
/*
|
||||
static setup_menu_t gen_settings_eq[] = {
|
||||
{"Preamp dB", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_preamp"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Low Gain dB", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_low_gain"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Mid 1 Gain dB", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid1_gain"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Mid 2 Gain dB", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid2_gain"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"High Gain dB", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_high_gain"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
|
||||
{"Low Cutoff Hz", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_low_cutoff"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Mid 1 Center Hz", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid1_center"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Mid 2 Center Hz", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid2_center"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"High Cutoff Hz", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_high_cutoff"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
|
||||
{"Mid 1 Width Oct", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid1_width"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
{"Mid 2 Width Oct", S_THERMO | S_THRM_SIZE11, M_X_THRM11, M_THRM_SPC,
|
||||
{"snd_eq_mid2_width"}, m_null, input_null, str_empty, I_OAL_SetEqualizer},
|
||||
|
||||
MI_END
|
||||
};
|
||||
*/
|
||||
|
||||
static const char **GetResamplerStrings(void)
|
||||
{
|
||||
const char **strings = I_OAL_GetResamplerStrings();
|
||||
@ -3804,6 +3851,7 @@ static const char **selectstrings[] = {
|
||||
gamma_strings,
|
||||
sound_module_strings,
|
||||
NULL, // str_resampler
|
||||
equalizer_preset_strings,
|
||||
NULL, // str_mouse_accel
|
||||
default_skill_strings,
|
||||
default_complevel_strings,
|
||||
|
Loading…
x
Reference in New Issue
Block a user