diff options
-rw-r--r-- | Alc/ALu.c | 40 | ||||
-rw-r--r-- | Alc/effects/distortion.c | 6 | ||||
-rw-r--r-- | Alc/effects/echo.c | 10 | ||||
-rw-r--r-- | Alc/effects/equalizer.c | 34 | ||||
-rw-r--r-- | Alc/effects/reverb.c | 7 | ||||
-rw-r--r-- | OpenAL32/Include/alFilter.h | 43 | ||||
-rw-r--r-- | OpenAL32/Include/alu.h | 13 | ||||
-rw-r--r-- | OpenAL32/alFilter.c | 12 | ||||
-rw-r--r-- | include/math_defs.h | 15 |
9 files changed, 116 insertions, 64 deletions
@@ -667,18 +667,20 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; + DryGainHF = maxf(DryGainHF, 0.0001f); + DryGainLF = maxf(DryGainLF, 0.0001f); for(c = 0;c < num_channels;c++) { voice->Direct.Filters[c].ActiveType = AF_None; if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass; if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( - &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, DryGainHF, - hfscale, 0.0f + &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, + DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, DryGainLF, - lfscale, 0.0f + &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, + DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } } @@ -686,18 +688,20 @@ ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const A { ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; + WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); for(c = 0;c < num_channels;c++) { voice->Send[i].Filters[c].ActiveType = AF_None; if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass; if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass; ALfilterState_setParams( - &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, WetGainHF[i], - hfscale, 0.0f + &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, + WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, WetGainLF[i], - lfscale, 0.0f + &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, + WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } @@ -1139,32 +1143,36 @@ ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCconte { ALfloat hfscale = ALSource->Direct.HFReference / Frequency; ALfloat lfscale = ALSource->Direct.LFReference / Frequency; + DryGainHF = maxf(DryGainHF, 0.0001f); + DryGainLF = maxf(DryGainLF, 0.0001f); voice->Direct.Filters[0].ActiveType = AF_None; if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass; if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( - &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, DryGainHF, - hfscale, 0.0f + &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, + DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f) ); ALfilterState_setParams( - &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, DryGainLF, - lfscale, 0.0f + &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, + DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f) ); } for(i = 0;i < NumSends;i++) { ALfloat hfscale = ALSource->Send[i].HFReference / Frequency; ALfloat lfscale = ALSource->Send[i].LFReference / Frequency; + WetGainHF[i] = maxf(WetGainHF[i], 0.0001f); + WetGainLF[i] = maxf(WetGainLF[i], 0.0001f); voice->Send[i].Filters[0].ActiveType = AF_None; if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass; if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass; ALfilterState_setParams( - &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, WetGainHF[i], - hfscale, 0.0f + &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, + WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f) ); ALfilterState_setParams( - &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, WetGainLF[i], - lfscale, 0.0f + &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, + WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f) ); } } diff --git a/Alc/effects/distortion.c b/Alc/effects/distortion.c index 22e05c70..221cec39 100644 --- a/Alc/effects/distortion.c +++ b/Alc/effects/distortion.c @@ -72,14 +72,16 @@ static ALvoid ALdistortionState_update(ALdistortionState *state, ALCdevice *Devi /* Bandwidth value is constant in octaves */ bandwidth = (cutoff / 2.0f) / (cutoff * 0.67f); ALfilterState_setParams(&state->lowpass, ALfilterType_LowPass, 1.0f, - cutoff / (frequency*4.0f), bandwidth); + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); /* Bandpass filter */ cutoff = Slot->EffectProps.Distortion.EQCenter; /* Convert bandwidth in Hz to octaves */ bandwidth = Slot->EffectProps.Distortion.EQBandwidth / (cutoff * 0.67f); ALfilterState_setParams(&state->bandpass, ALfilterType_BandPass, 1.0f, - cutoff / (frequency*4.0f), bandwidth); + cutoff / (frequency*4.0f), calc_rcpQ_from_bandwidth(cutoff / (frequency*4.0f), bandwidth) + ); ComputeAmbientGains(Device, Slot->Gain, state->Gain); } diff --git a/Alc/effects/echo.c b/Alc/effects/echo.c index b852a096..f5a53c36 100644 --- a/Alc/effects/echo.c +++ b/Alc/effects/echo.c @@ -85,8 +85,7 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL { ALfloat pandir[3] = { 0.0f, 0.0f, 0.0f }; ALuint frequency = Device->Frequency; - ALfloat gain = Slot->Gain; - ALfloat lrpan; + ALfloat gain, lrpan; state->Tap[0].delay = fastf2u(Slot->EffectProps.Echo.Delay * frequency) + 1; state->Tap[1].delay = fastf2u(Slot->EffectProps.Echo.LRDelay * frequency); @@ -96,9 +95,12 @@ static ALvoid ALechoState_update(ALechoState *state, ALCdevice *Device, const AL state->FeedGain = Slot->EffectProps.Echo.Feedback; + gain = minf(1.0f - Slot->EffectProps.Echo.Damping, 0.01f); ALfilterState_setParams(&state->Filter, ALfilterType_HighShelf, - 1.0f - Slot->EffectProps.Echo.Damping, - LOWPASSFREQREF/frequency, 0.0f); + gain, LOWPASSFREQREF/frequency, + calc_rcpQ_from_slope(gain, 0.75f)); + + gain = Slot->Gain; /* First tap panning */ pandir[0] = -lrpan; diff --git a/Alc/effects/equalizer.c b/Alc/effects/equalizer.c index 6a5ed549..244667ab 100644 --- a/Alc/effects/equalizer.c +++ b/Alc/effects/equalizer.c @@ -93,29 +93,37 @@ static ALboolean ALequalizerState_deviceUpdate(ALequalizerState *UNUSED(state), static ALvoid ALequalizerState_update(ALequalizerState *state, ALCdevice *device, const ALeffectslot *slot) { ALfloat frequency = (ALfloat)device->Frequency; + ALfloat gain, freq_mult; ComputeAmbientGains(device, slot->Gain, state->Gain); - /* Calculate coefficients for the each type of filter */ + /* Calculate coefficients for the each type of filter. Note that the shelf + * filters' gain is for the reference frequency, which is the centerpoint + * of the transition band. + */ + gain = sqrtf(slot->EffectProps.Equalizer.LowGain); + freq_mult = slot->EffectProps.Equalizer.LowCutoff/frequency; ALfilterState_setParams(&state->filter[0], ALfilterType_LowShelf, - sqrtf(slot->EffectProps.Equalizer.LowGain), - slot->EffectProps.Equalizer.LowCutoff/frequency, - 0.0f); + gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + ); + gain = slot->EffectProps.Equalizer.Mid1Gain; + freq_mult = slot->EffectProps.Equalizer.Mid1Center/frequency; ALfilterState_setParams(&state->filter[1], ALfilterType_Peaking, - sqrtf(slot->EffectProps.Equalizer.Mid1Gain), - slot->EffectProps.Equalizer.Mid1Center/frequency, - slot->EffectProps.Equalizer.Mid1Width); + gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid1Width) + ); + gain = slot->EffectProps.Equalizer.Mid2Gain; + freq_mult = slot->EffectProps.Equalizer.Mid2Center/frequency; ALfilterState_setParams(&state->filter[2], ALfilterType_Peaking, - sqrtf(slot->EffectProps.Equalizer.Mid2Gain), - slot->EffectProps.Equalizer.Mid2Center/frequency, - slot->EffectProps.Equalizer.Mid2Width); + gain, freq_mult, calc_rcpQ_from_bandwidth(freq_mult, slot->EffectProps.Equalizer.Mid2Width) + ); + gain = sqrtf(slot->EffectProps.Equalizer.HighGain); + freq_mult = slot->EffectProps.Equalizer.HighCutoff/frequency; ALfilterState_setParams(&state->filter[3], ALfilterType_HighShelf, - sqrtf(slot->EffectProps.Equalizer.HighGain), - slot->EffectProps.Equalizer.HighCutoff/frequency, - 0.0f); + gain, freq_mult, calc_rcpQ_from_slope(gain, 0.75f) + ); } static ALvoid ALequalizerState_process(ALequalizerState *state, ALuint SamplesToDo, const ALfloat *restrict SamplesIn, ALfloat (*restrict SamplesOut)[BUFFERSIZE], ALuint NumChannels) diff --git a/Alc/effects/reverb.c b/Alc/effects/reverb.c index 6c3f2691..71e12b33 100644 --- a/Alc/effects/reverb.c +++ b/Alc/effects/reverb.c @@ -1112,6 +1112,7 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons const ALeffectProps *props = &Slot->EffectProps; ALuint frequency = Device->Frequency; ALfloat lfscale, hfscale, hfRatio; + ALfloat gainlf, gainhf; ALfloat cw, x, y; if(Slot->EffectType == AL_EFFECT_EAXREVERB && !EmulateEAXReverb) @@ -1121,11 +1122,13 @@ static ALvoid ALreverbState_update(ALreverbState *State, ALCdevice *Device, cons // Calculate the master filters hfscale = props->Reverb.HFReference / frequency; + gainhf = maxf(props->Reverb.GainHF, 0.0001f); ALfilterState_setParams(&State->LpFilter, ALfilterType_HighShelf, - props->Reverb.GainHF, hfscale, 0.0f); + gainhf, hfscale, calc_rcpQ_from_slope(gainhf, 0.75f)); lfscale = props->Reverb.LFReference / frequency; + gainlf = maxf(props->Reverb.GainLF, 0.0001f); ALfilterState_setParams(&State->HpFilter, ALfilterType_LowShelf, - props->Reverb.GainLF, lfscale, 0.0f); + gainlf, lfscale, calc_rcpQ_from_slope(gainlf, 0.75f)); // Update the modulator line. UpdateModulator(props->Reverb.ModulationTime, props->Reverb.ModulationDepth, diff --git a/OpenAL32/Include/alFilter.h b/OpenAL32/Include/alFilter.h index 9772f432..3c65fd9f 100644 --- a/OpenAL32/Include/alFilter.h +++ b/OpenAL32/Include/alFilter.h @@ -3,6 +3,8 @@ #include "alMain.h" +#include "math_defs.h" + #ifdef __cplusplus extern "C" { #endif @@ -11,23 +13,29 @@ extern "C" { #define HIGHPASSFREQREF (250.0f) -/* Filters implementation is based on the "Cookbook formulae for audio * - * EQ biquad filter coefficients" by Robert Bristow-Johnson * - * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt */ +/* Filters implementation is based on the "Cookbook formulae for audio + * EQ biquad filter coefficients" by Robert Bristow-Johnson + * http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt + */ +/* Implementation note: For the shelf filters, the specified gain is for the + * reference frequency, which is the centerpoint of the transition band. This + * better matches EFX filter design. To set the gain for the shelf itself, use + * the square root of the desired linear gain (or halve the dB gain). + */ typedef enum ALfilterType { /** EFX-style low-pass filter, specifying a gain and reference frequency. */ ALfilterType_HighShelf, /** EFX-style high-pass filter, specifying a gain and reference frequency. */ ALfilterType_LowShelf, - /** Peaking filter, specifying a gain, reference frequency, and bandwidth. */ + /** Peaking filter, specifying a gain and reference frequency. */ ALfilterType_Peaking, - /** Low-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ + /** Low-pass cut-off filter, specifying a cut-off frequency. */ ALfilterType_LowPass, - /** High-pass cut-off filter, specifying a cut-off frequency and bandwidth. */ + /** High-pass cut-off filter, specifying a cut-off frequency. */ ALfilterType_HighPass, - /** Band-pass filter, specifying a center frequency and bandwidth. */ + /** Band-pass filter, specifying a center frequency. */ ALfilterType_BandPass, } ALfilterType; @@ -41,8 +49,27 @@ typedef struct ALfilterState { } ALfilterState; #define ALfilterState_process(a, ...) ((a)->process((a), __VA_ARGS__)) +/* Calculates the rcpQ (i.e. 1/Q) coefficient for shelving filters, using the + * reference gain and shelf slope parameter. + * 0 < gain + * 0 < slope <= 1 + */ +inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope) +{ + return sqrtf((gain + 1.0f/gain)*(1.0f/slope - 1.0f) + 2.0f); +} +/* Calculates the rcpQ (i.e. 1/Q) coefficient for filters, using the frequency + * multiple (i.e. ref_freq / sampling_freq) and bandwidth. + * 0 < freq_mult < 0.5. + */ +inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth) +{ + ALfloat w0 = F_TAU * freq_mult; + return 2.0f*sinhf(logf(2.0f)/2.0f*bandwidth*w0/sinf(w0)); +} + void ALfilterState_clear(ALfilterState *filter); -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth); +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ); inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample) { diff --git a/OpenAL32/Include/alu.h b/OpenAL32/Include/alu.h index 126fffb5..27cf6713 100644 --- a/OpenAL32/Include/alu.h +++ b/OpenAL32/Include/alu.h @@ -16,18 +16,7 @@ #include "hrtf.h" #include "align.h" - - -#define F_PI (3.14159265358979323846f) -#define F_PI_2 (1.57079632679489661923f) -#define F_TAU (6.28318530717958647692f) - -#ifndef FLT_EPSILON -#define FLT_EPSILON (1.19209290e-07f) -#endif - -#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f)) -#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI)) +#include "math_defs.h" #define MAX_PITCH (255) diff --git a/OpenAL32/alFilter.c b/OpenAL32/alFilter.c index bced3a7f..3cf82c32 100644 --- a/OpenAL32/alFilter.c +++ b/OpenAL32/alFilter.c @@ -32,6 +32,8 @@ extern inline struct ALfilter *LookupFilter(ALCdevice *device, ALuint id); extern inline struct ALfilter *RemoveFilter(ALCdevice *device, ALuint id); extern inline ALfloat ALfilterState_processSingle(ALfilterState *filter, ALfloat sample); +extern inline ALfloat calc_rcpQ_from_slope(ALfloat gain, ALfloat slope); +extern inline ALfloat calc_rcpQ_from_bandwidth(ALfloat freq_mult, ALfloat bandwidth); static void InitFilterParams(ALfilter *filter, ALenum type); @@ -336,7 +338,7 @@ void ALfilterState_clear(ALfilterState *filter) filter->y[1] = 0.0f; } -void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat bandwidth) +void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat gain, ALfloat freq_mult, ALfloat rcpQ) { ALfloat alpha, sqrtgain_alpha_2; ALfloat w0, sin_w0, cos_w0; @@ -347,12 +349,12 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g w0 = F_TAU * freq_mult; sin_w0 = sinf(w0); cos_w0 = cosf(w0); + alpha = sin_w0/2.0f * rcpQ; /* Calculate filter coefficients depending on filter type */ switch(type) { case ALfilterType_HighShelf: - alpha = sin_w0/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f); sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; filter->b[0] = gain*((gain+1.0f) + (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); filter->b[1] = -2.0f*gain*((gain-1.0f) + (gain+1.0f)*cos_w0 ); @@ -362,7 +364,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->a[2] = (gain+1.0f) - (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_LowShelf: - alpha = sin_w0/2.0f*sqrtf((gain + 1.0f/gain)*(1.0f/0.75f - 1.0f) + 2.0f); sqrtgain_alpha_2 = 2.0f * sqrtf(gain) * alpha; filter->b[0] = gain*((gain+1.0f) - (gain-1.0f)*cos_w0 + sqrtgain_alpha_2); filter->b[1] = 2.0f*gain*((gain-1.0f) - (gain+1.0f)*cos_w0 ); @@ -372,7 +373,7 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->a[2] = (gain+1.0f) + (gain-1.0f)*cos_w0 - sqrtgain_alpha_2; break; case ALfilterType_Peaking: - alpha = sin_w0 * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sin_w0); + gain = sqrtf(gain); filter->b[0] = 1.0f + alpha * gain; filter->b[1] = -2.0f * cos_w0; filter->b[2] = 1.0f - alpha * gain; @@ -382,7 +383,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g break; case ALfilterType_LowPass: - alpha = sin_w0 * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sin_w0); filter->b[0] = (1.0f - cos_w0) / 2.0f; filter->b[1] = 1.0f - cos_w0; filter->b[2] = (1.0f - cos_w0) / 2.0f; @@ -391,7 +391,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->a[2] = 1.0f - alpha; break; case ALfilterType_HighPass: - alpha = sin_w0 * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sin_w0); filter->b[0] = (1.0f + cos_w0) / 2.0f; filter->b[1] = -(1.0f + cos_w0); filter->b[2] = (1.0f + cos_w0) / 2.0f; @@ -400,7 +399,6 @@ void ALfilterState_setParams(ALfilterState *filter, ALfilterType type, ALfloat g filter->a[2] = 1.0f - alpha; break; case ALfilterType_BandPass: - alpha = sin_w0 * sinhf(logf(2.0f) / 2.0f * bandwidth * w0 / sin_w0); filter->b[0] = alpha; filter->b[1] = 0; filter->b[2] = -alpha; diff --git a/include/math_defs.h b/include/math_defs.h new file mode 100644 index 00000000..d3c8b1b4 --- /dev/null +++ b/include/math_defs.h @@ -0,0 +1,15 @@ +#ifndef AL_MATH_DEFS_H +#define AL_MATH_DEFS_H + +#define F_PI (3.14159265358979323846f) +#define F_PI_2 (1.57079632679489661923f) +#define F_TAU (6.28318530717958647692f) + +#ifndef FLT_EPSILON +#define FLT_EPSILON (1.19209290e-07f) +#endif + +#define DEG2RAD(x) ((ALfloat)(x) * (F_PI/180.0f)) +#define RAD2DEG(x) ((ALfloat)(x) * (180.0f/F_PI)) + +#endif /* AL_MATH_DEFS_H */ |