Merge pull request #14732 from kencooke/audio-distattn-improvements

Bug fixes and improvements to audio distance attenuation
This commit is contained in:
Antonina Savinova 2019-01-29 14:02:29 -08:00 committed by GitHub
commit 5d49a3f6df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 11 deletions

View file

@ -743,7 +743,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) {
float coefficient = coefficientObject.value(COEFFICIENT).toString().toFloat(&ok);
if (ok && coefficient >= 0.0f && coefficient <= 1.0f &&
if (ok && coefficient <= 1.0f &&
itSource != end(_audioZones) &&
itListener != end(_audioZones)) {

View file

@ -770,13 +770,29 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo
break;
}
}
// translate the zone setting to gain per log2(distance)
float g = glm::clamp(1.0f - attenuationPerDoublingInDistance, EPSILON, 1.0f);
// calculate the attenuation using the distance to this node
// reference attenuation of 0dB at distance = 1.0m
gain *= fastExp2f(fastLog2f(g) * fastLog2f(std::max(distance, HRTF_NEARFIELD_MIN)));
gain = std::min(gain, 1.0f / HRTF_NEARFIELD_MIN);
if (attenuationPerDoublingInDistance < 0.0f) {
// translate a negative zone setting to distance limit
const float MIN_DISTANCE_LIMIT = ATTN_DISTANCE_REF + 1.0f; // silent after 1m
float distanceLimit = std::max(-attenuationPerDoublingInDistance, MIN_DISTANCE_LIMIT);
// calculate the LINEAR attenuation using the distance to this node
// reference attenuation of 0dB at distance = ATTN_DISTANCE_REF
float d = distance - ATTN_DISTANCE_REF;
gain *= std::max(1.0f - d / (distanceLimit - ATTN_DISTANCE_REF), 0.0f);
gain = std::min(gain, ATTN_GAIN_MAX);
} else {
// translate a positive zone setting to gain per log2(distance)
const float MIN_ATTENUATION_COEFFICIENT = 0.001f; // -60dB per log2(distance)
float g = glm::clamp(1.0f - attenuationPerDoublingInDistance, MIN_ATTENUATION_COEFFICIENT, 1.0f);
// calculate the LOGARITHMIC attenuation using the distance to this node
// reference attenuation of 0dB at distance = ATTN_DISTANCE_REF
float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN);
gain *= fastExp2f(fastLog2f(g) * fastLog2f(d));
gain = std::min(gain, ATTN_GAIN_MAX);
}
return gain;
}

View file

@ -1979,8 +1979,10 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) {
float AudioClient::gainForSource(float distance, float volume) {
// attenuation = -6dB * log2(distance)
// reference attenuation of 0dB at distance = 1.0m
float gain = volume / std::max(distance, HRTF_NEARFIELD_MIN);
// reference attenuation of 0dB at distance = ATTN_DISTANCE_REF
float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN);
float gain = volume / d;
gain = std::min(gain, ATTN_GAIN_MAX);
return gain;
}

View file

@ -30,6 +30,10 @@ static const float HRTF_NEARFIELD_MAX = 1.0f; // distance in meters
static const float HRTF_NEARFIELD_MIN = 0.125f; // distance in meters
static const float HRTF_HEAD_RADIUS = 0.0875f; // average human head in meters
// Distance attenuation
static const float ATTN_DISTANCE_REF = 2.0f; // distance where attn is 0dB
static const float ATTN_GAIN_MAX = 16.0f; // max gain allowed by distance attn (+24dB)
class AudioHRTF {
public:

View file

@ -43,8 +43,9 @@ static inline float fastLog2f(float x) {
}
//
// for -127 <= x < 128, returns exp2(x)
// otherwise, returns undefined
// for -126 <= x < 128, returns exp2(x)
// for x < -126, returns 0
// for x >= 128, returns undefined
//
// rel |error| < 9e-6, smooth (exact for x=N)
//
@ -60,6 +61,7 @@ static inline float fastExp2f(float x) {
x -= xi.i;
// construct exp2(xi) as a float
xi.i &= ~(xi.i >> 31); // MAX(xi.i, 0)
xi.i <<= IEEE754_MANT_BITS;
// polynomial for exp2(x) over x=[0,1]