From 51adcd45e61553fc14bd7129c56e837d95377876 Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Wed, 25 Nov 2020 06:48:41 -0800 Subject: [PATCH] Simplify manual sound rolloff handling --- src/common/audio/sound/oalsound.cpp | 95 ++++++++++------------------- 1 file changed, 33 insertions(+), 62 deletions(-) diff --git a/src/common/audio/sound/oalsound.cpp b/src/common/audio/sound/oalsound.cpp index d97c9d5a68e..252688572b8 100644 --- a/src/common/audio/sound/oalsound.cpp +++ b/src/common/audio/sound/oalsound.cpp @@ -1304,7 +1304,7 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); alSourcef(source, AL_REFERENCE_DISTANCE, rolloff->MinDistance/distscale); - alSourcef(source, AL_MAX_DISTANCE, (1000.f+rolloff->MinDistance)/distscale); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); alSourcef(source, AL_ROLLOFF_FACTOR, rolloff->RolloffFactor); manualRolloff = false; } @@ -1324,77 +1324,49 @@ FISoundChannel *OpenALSoundRenderer::StartSound3D(SoundHandle sfx, SoundListener // when AL_EXT_source_distance_model is not supported, we have to play // around a bit to get appropriate distance attenation. What we do is // calculate the attenuation that should be applied, then given an - // Inverse Distance rolloff model with OpenAL, reverse the calculation - // to get the distance needed for that much attenuation. The Inverse - // Distance calculation is: + // Inverse Distance rolloff model with OpenAL, calculate the reference + // distance that will achieve that much attenuation with the current + // distance. The Inverse Distance calculation is: // // Gain = MinDist / (MinDist + RolloffFactor*(Distance - MinDist)) // - // Thus, the reverse is: + // Simplifying for RolloffFactor=1, it can be broken down by: // - // Distance = (MinDist/Gain - MinDist)/RolloffFactor + MinDist + // Gain = MinDist / (MinDist + (Distance - MinDist)) + // Gain = MinDist / Distance + // Gain * Distance = MinDist // - // This can be simplified by using a MinDist and RolloffFactor of 1, - // which makes it: - // - // Distance = 1.0f/Gain; - // - // The source position is then set that many units away from the - // listener position, and OpenAL takes care of the rest. + // The source's reference distance is then set according to the desired + // gain and effective distance from the listener, and OpenAL takes care + // of the rest. if(AL.EXT_source_distance_model) alSourcei(source, AL_DISTANCE_MODEL, AL_INVERSE_DISTANCE); - alSourcef(source, AL_REFERENCE_DISTANCE, 1.f); - alSourcef(source, AL_MAX_DISTANCE, 100000.f); - alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); - if(AL.EXT_SOURCE_RADIUS) - { - /* Since the OpenAL distance is decoupled from the sound's distance, get the OpenAL - * distance that corresponds to the area radius. */ - float gain = GetRolloff(rolloff, AREA_SOUND_RADIUS); - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? - // Clamp in case the max distance is <= the area radius - ((gain > 0.00001f) ? 1.f/gain : 100000.f) : 0.f - ); - } - - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - float gain = GetRolloff(rolloff, sqrtf(dist_sqr) * distscale); - FVector3 dir = pos - listener->position; - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); - dir += listener->position; + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(rolloff, dist * distscale); + // Don't let the ref distance go to 0, or else distance attenuation is + // lost with the inverse distance model. + alSourcef(source, AL_REFERENCE_DISTANCE, std::max(gain*dist, 0.0004f)); + alSourcef(source, AL_MAX_DISTANCE, std::numeric_limits::max()); + alSourcef(source, AL_ROLLOFF_FACTOR, 1.f); + } - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); - } + if(dist_sqr < (0.0004f*0.0004f)) + { + // Head relative + alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); + alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); } else { - if(AL.EXT_SOURCE_RADIUS) - alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); - - if(dist_sqr < (0.0004f*0.0004f)) - { - // Head relative - alSourcei(source, AL_SOURCE_RELATIVE, AL_TRUE); - alSource3f(source, AL_POSITION, 0.f, 0.f, 0.f); - } - else - { - alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); - } + alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); alSource3f(source, AL_DIRECTION, 0.f, 0.f, 0.f); alSourcef(source, AL_DOPPLER_FACTOR, 0.f); + if(AL.EXT_SOURCE_RADIUS) + alSourcef(source, AL_SOURCE_RADIUS, (chanflags&SNDF_AREA) ? AREA_SOUND_RADIUS : 0.f); alSourcei(source, AL_LOOPING, (chanflags&SNDF_LOOP) ? AL_TRUE : AL_FALSE); @@ -1633,8 +1605,7 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh if(chan == NULL || chan->SysChannel == NULL) return; - FVector3 dir = pos - listener->position; - float dist_sqr = (float)dir.LengthSquared(); + float dist_sqr = (float)(pos - listener->position).LengthSquared(); chan->DistanceSqr = dist_sqr; alDeferUpdatesSOFT(); @@ -1649,13 +1620,13 @@ void OpenALSoundRenderer::UpdateSoundParams3D(SoundListener *listener, FISoundCh { if(chan->ManualRolloff) { - float gain = GetRolloff(&chan->Rolloff, sqrtf(dist_sqr)*chan->DistanceScale); - dir.MakeResize((gain > 0.00001f) ? 1.f/gain : 100000.f); + float dist = sqrtf(dist_sqr); + float gain = GetRolloff(&chan->Rolloff, dist * chan->DistanceScale); + alSourcef(source, AL_REFERENCE_DISTANCE, std::max(gain*dist, 0.0004f)); } - dir += listener->position; alSourcei(source, AL_SOURCE_RELATIVE, AL_FALSE); - alSource3f(source, AL_POSITION, dir[0], dir[1], -dir[2]); + alSource3f(source, AL_POSITION, pos[0], pos[1], -pos[2]); } alSource3f(source, AL_VELOCITY, vel[0], vel[1], -vel[2]); getALError();