From 5148b60c7355b091ed646e22841aeff97e6706e2 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Jan 2019 14:43:15 -0800 Subject: [PATCH 1/7] Parameterize distance attenuation by reference distance (where gain = unity) --- assignment-client/src/audio/AudioMixerSlave.cpp | 11 +++++++---- libraries/audio-client/src/AudioClient.cpp | 5 +++-- libraries/audio/src/AudioHRTF.h | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 7a6ab9c3e2..bddadf6e26 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -727,9 +727,12 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // distance attenuation: approximate, ignore zone-specific attenuations glm::vec3 relativePosition = streamToAdd.getPosition() - listeningNodeStream.getPosition(); float distance = glm::length(relativePosition); - return gain / distance; + + float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN); + gain = gain / d; // avatar: skip master gain - it is constant for all streams + return gain; } float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, @@ -774,9 +777,9 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo 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); + // 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)); return gain; } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 9bad7e2f45..82674ddc72 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1952,8 +1952,9 @@ 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; return gain; } diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index eeef66e10c..952c4e4af6 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -30,6 +30,9 @@ 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 = 1.0f; // distance where attn is 0dB + class AudioHRTF { public: From 53dece5451d5380f8e43e2f0929910c33bf6766b Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Jan 2019 14:50:44 -0800 Subject: [PATCH 2/7] Clamp near-field distance attenuation to max gain --- assignment-client/src/audio/AudioMixerSlave.cpp | 2 ++ libraries/audio-client/src/AudioClient.cpp | 1 + libraries/audio/src/AudioHRTF.h | 1 + 3 files changed, 4 insertions(+) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index bddadf6e26..573dab030e 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -730,6 +730,7 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN); gain = gain / d; + gain = std::min(gain, ATTN_GAIN_MAX); // avatar: skip master gain - it is constant for all streams return gain; @@ -780,6 +781,7 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo // 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; } diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index 82674ddc72..990834fcb8 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -1955,6 +1955,7 @@ float AudioClient::gainForSource(float distance, float volume) { // 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; } diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index 952c4e4af6..de104db226 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -32,6 +32,7 @@ static const float HRTF_HEAD_RADIUS = 0.0875f; // average human head in meters // Distance attenuation static const float ATTN_DISTANCE_REF = 1.0f; // distance where attn is 0dB +static const float ATTN_GAIN_MAX = 8.0f; // max gain allowed by distance attn (+18dB) class AudioHRTF { From 83e1efd2f0219fbec408f1fb9cebc1a32a43df43 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Jan 2019 15:12:42 -0800 Subject: [PATCH 3/7] Improved reference distance = 2m --- libraries/audio/src/AudioHRTF.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.h b/libraries/audio/src/AudioHRTF.h index de104db226..7d23f4825a 100644 --- a/libraries/audio/src/AudioHRTF.h +++ b/libraries/audio/src/AudioHRTF.h @@ -31,8 +31,8 @@ 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 = 1.0f; // distance where attn is 0dB -static const float ATTN_GAIN_MAX = 8.0f; // max gain allowed by distance attn (+18dB) +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 { From 4c502cdbc9f3a6780272e45af337e2a1cb0042e1 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 3 Jan 2019 15:17:41 -0800 Subject: [PATCH 4/7] Revert to simpler approximation for stream sorting --- assignment-client/src/audio/AudioMixerSlave.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 573dab030e..b699970560 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -727,13 +727,9 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // distance attenuation: approximate, ignore zone-specific attenuations glm::vec3 relativePosition = streamToAdd.getPosition() - listeningNodeStream.getPosition(); float distance = glm::length(relativePosition); - - float d = (1.0f / ATTN_DISTANCE_REF) * std::max(distance, HRTF_NEARFIELD_MIN); - gain = gain / d; - gain = std::min(gain, ATTN_GAIN_MAX); + return gain / distance; // avatar: skip master gain - it is constant for all streams - return gain; } float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNodeStream, From 328809f008a14c410f382e130f413b83ab7843b3 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 16 Jan 2019 11:10:38 -0800 Subject: [PATCH 5/7] More robust approximation of distance attenuation at extreme settings. Fixes artifacts that occur when attenuation zone coef = 1.0 and distance > 32m. --- libraries/shared/src/AudioHelpers.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/AudioHelpers.h b/libraries/shared/src/AudioHelpers.h index 1dcc11af0c..8f7f5f7f33 100644 --- a/libraries/shared/src/AudioHelpers.h +++ b/libraries/shared/src/AudioHelpers.h @@ -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] From 7cade1e3543e01936edaaab1bb0eb173e676a539 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 16 Jan 2019 12:16:20 -0800 Subject: [PATCH 6/7] Clamp attenuation zone coefficients to a more reasonable limit of -60dB per doubling of distance --- assignment-client/src/audio/AudioMixerSlave.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index b699970560..3caa5584da 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -771,7 +771,8 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo } } // translate the zone setting to gain per log2(distance) - float g = glm::clamp(1.0f - attenuationPerDoublingInDistance, EPSILON, 1.0f); + 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 attenuation using the distance to this node // reference attenuation of 0dB at distance = ATTN_DISTANCE_REF From 3ffaced0f3588dd24568dfc930ce7be25656cf73 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 17 Jan 2019 13:59:33 -0800 Subject: [PATCH 7/7] Experimental attenuation curve: linear falloff, with prescribed propagation limit. A positive coefficient sets logarithmic falloff, as before. A negative coefficient sets linear falloff, where abs(coefficient) is the distance limit in meters. --- assignment-client/src/audio/AudioMixer.cpp | 2 +- .../src/audio/AudioMixerSlave.cpp | 30 ++++++++++++++----- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 77f416f31e..f80ce2f4c3 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -736,7 +736,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)) { diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index 3caa5584da..a7abea3704 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -770,15 +770,29 @@ float computeGain(float masterListenerGain, const AvatarAudioStream& listeningNo break; } } - // translate the 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 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); + 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; }