aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-03-02 11:14:59 -0800
committerChris Robinson <[email protected]>2022-03-02 11:14:59 -0800
commit43682a8c3ece8c2b01fa552390cc64b67e4d8b1e (patch)
tree7c25660bce1477e2f33421317e26de35f3710272
parentfbac67a6a0f297ca69c9b61da85e90f5c13663ae (diff)
Rework source send distance attenuation handling
Specifically, AL_[EAX]REVERB_ROOM_ROLLOFF_FACTOR always applies to an inverse distance rolloff model, where the source's AL_ROOM_ROLLOFF_FACTOR applies to the selected distance model. Consequently, the normal distance and cone attenuation only needs to be calculated once for all sends, with the effect's room rolloff calculated and applied separately.
-rw-r--r--alc/alu.cpp138
1 files changed, 77 insertions, 61 deletions
diff --git a/alc/alu.cpp b/alc/alu.cpp
index f0667f73..d3cc74ca 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -1235,6 +1235,7 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
EffectSlot *SendSlots[MAX_SENDS];
float RoomRolloff[MAX_SENDS];
GainTriplet DecayDistance[MAX_SENDS];
+ uint UseDryAttnForRoom{0};
for(uint i{0};i < NumSends;i++)
{
SendSlots[i] = props->Send[i].Slot;
@@ -1246,9 +1247,20 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
DecayDistance[i].LF = 0.0f;
DecayDistance[i].HF = 0.0f;
}
- else if(SendSlots[i]->AuxSendAuto)
+ else if(!SendSlots[i]->AuxSendAuto)
{
- RoomRolloff[i] = SendSlots[i]->RoomRolloff + props->RoomRolloffFactor;
+ /* If the slot's auxiliary send auto is off, the data sent to the
+ * effect slot is the same as the dry path, sans filter effects.
+ */
+ RoomRolloff[i] = 0.0f;
+ DecayDistance[i].Base = 0.0f;
+ DecayDistance[i].LF = 0.0f;
+ DecayDistance[i].HF = 0.0f;
+ UseDryAttnForRoom |= 1u<<i;
+ }
+ else
+ {
+ RoomRolloff[i] = SendSlots[i]->RoomRolloff;
/* Calculate the distances to where this effect's decay reaches
* -60dB.
*/
@@ -1271,15 +1283,6 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
}
}
}
- else
- {
- /* If the slot's auxiliary send auto is off, the data sent to the
- * effect slot is the same as the dry path, sans filter effects */
- RoomRolloff[i] = props->RolloffFactor;
- DecayDistance[i].Base = 0.0f;
- DecayDistance[i].LF = 0.0f;
- DecayDistance[i].HF = 0.0f;
- }
if(!SendSlots[i])
voice->mSend[i].Buffer = {};
@@ -1310,10 +1313,8 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
/* Calculate distance attenuation */
float ClampedDist{Distance};
- float DryAttenuation{1.0f};
- float WetAttenuation[MAX_SENDS];
- for(uint i{0};i < NumSends;i++)
- WetAttenuation[i] = DryAttenuation;
+ float DryGainBase{props->Gain};
+ float WetGainBase{props->Gain};
switch(context->mParams.SourceDistanceModel ? props->mDistanceModel
: context->mParams.mDistanceModel)
@@ -1328,12 +1329,10 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
else
{
float dist{lerp(props->RefDistance, ClampedDist, props->RolloffFactor)};
- if(dist > 0.0f) DryAttenuation = props->RefDistance / dist;
- for(uint i{0};i < NumSends;i++)
- {
- dist = lerp(props->RefDistance, ClampedDist, RoomRolloff[i]);
- if(dist > 0.0f) WetAttenuation[i] = props->RefDistance / dist;
- }
+ if(dist > 0.0f) DryGainBase *= props->RefDistance / dist;
+
+ dist = lerp(props->RefDistance, ClampedDist, props->RoomRolloffFactor);
+ if(dist > 0.0f) WetGainBase *= props->RefDistance / dist;
}
break;
@@ -1346,15 +1345,13 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
ClampedDist = props->RefDistance;
else
{
- float attn{props->RolloffFactor * (ClampedDist-props->RefDistance) /
- (props->MaxDistance-props->RefDistance)};
- DryAttenuation = maxf(1.0f - attn, 0.0f);
- for(uint i{0};i < NumSends;i++)
- {
- attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) /
- (props->MaxDistance-props->RefDistance);
- WetAttenuation[i] = maxf(1.0f - attn, 0.0f);
- }
+ float attn{(ClampedDist-props->RefDistance) /
+ (props->MaxDistance-props->RefDistance) * props->RolloffFactor};
+ DryGainBase *= maxf(1.0f - attn, 0.0f);
+
+ attn = (ClampedDist-props->RefDistance) /
+ (props->MaxDistance-props->RefDistance) * props->RoomRolloffFactor;
+ WetGainBase *= maxf(1.0f - attn, 0.0f);
}
break;
@@ -1368,9 +1365,8 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
else
{
const float dist_ratio{ClampedDist/props->RefDistance};
- DryAttenuation = std::pow(dist_ratio, -props->RolloffFactor);
- for(uint i{0};i < NumSends;i++)
- WetAttenuation[i] = std::pow(dist_ratio, -RoomRolloff[i]);
+ DryGainBase *= std::pow(dist_ratio, -props->RolloffFactor);
+ WetGainBase *= std::pow(dist_ratio, -props->RoomRolloffFactor);
}
break;
@@ -1379,13 +1375,13 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
}
/* Calculate directional soundcones */
- float ConeGain{1.0f}, ConeHF{1.0f};
- float WetConeGain{1.0f}, WetConeHF{1.0f};
+ float ConeHF{1.0f}, WetConeHF{1.0f};
if(directional && props->InnerAngle < 360.0f)
{
static constexpr float Rad2Deg{static_cast<float>(180.0 / al::numbers::pi)};
const float Angle{Rad2Deg*2.0f * std::acos(-Direction.dot_product(ToSource)) * ConeScale};
+ float ConeGain{1.0f};
if(Angle >= props->OuterAngle)
{
ConeGain = props->OuterGain;
@@ -1398,43 +1394,62 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
ConeHF = lerp(1.0f, props->OuterGainHF, scale * props->DryGainHFAuto);
}
- WetConeGain = lerp(1.0f, ConeGain, props->WetGainAuto);
+ DryGainBase *= ConeGain;
+ WetGainBase *= lerp(1.0f, ConeGain, props->WetGainAuto);
+
WetConeHF = lerp(1.0f, ConeHF, props->WetGainHFAuto);
}
/* Apply gain and frequency filters */
+ DryGainBase = clampf(DryGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
+ WetGainBase = clampf(WetGainBase, props->MinGain, props->MaxGain) * context->mParams.Gain;
+
GainTriplet DryGain{};
- DryGain.Base = props->Gain * DryAttenuation * ConeGain;
- DryGain.Base = minf(clampf(DryGain.Base, props->MinGain, props->MaxGain) * props->Direct.Gain *
- context->mParams.Gain, GainMixMax);
+ DryGain.Base = minf(DryGainBase * props->Direct.Gain, GainMixMax);
DryGain.HF = ConeHF * props->Direct.GainHF;
DryGain.LF = props->Direct.GainLF;
GainTriplet WetGain[MAX_SENDS]{};
for(uint i{0};i < NumSends;i++)
{
- const float gain{props->Gain * WetConeGain * WetAttenuation[i]};
- WetGain[i].Base = minf(clampf(gain, props->MinGain, props->MaxGain) * props->Send[i].Gain *
- context->mParams.Gain, GainMixMax);
- WetGain[i].HF = WetConeHF * props->Send[i].GainHF;
+ const auto wet_switch = static_cast<float>(!(UseDryAttnForRoom&(1u<<i)));
+ const float gain{lerp(DryGainBase, WetGainBase, wet_switch)};
+ WetGain[i].Base = minf(gain * props->Send[i].Gain, GainMixMax);
+ WetGain[i].HF = lerp(ConeHF, WetConeHF, wet_switch) * props->Send[i].GainHF;
WetGain[i].LF = props->Send[i].GainLF;
}
/* Distance-based air absorption and initial send decay. */
- if(ClampedDist > props->RefDistance && props->RolloffFactor > 0.0f)
+ if(likely(ClampedDist > props->RefDistance))
{
- const float meters_base{(ClampedDist-props->RefDistance) * props->RolloffFactor *
- context->mParams.MetersPerUnit};
- if(props->AirAbsorptionFactor > 0.0f)
+ const float meters_base{(ClampedDist-props->RefDistance) * props->RolloffFactor};
+ const float absorption{meters_base * context->mParams.MetersPerUnit *
+ props->AirAbsorptionFactor};
+ if(absorption > std::numeric_limits<float>::epsilon())
{
- const float hfattn{std::pow(context->mParams.AirAbsorptionGainHF,
- meters_base*props->AirAbsorptionFactor)};
- DryGain.HF *= hfattn;
- std::for_each(std::begin(WetGain), std::begin(WetGain)+NumSends,
- [hfattn](GainTriplet &gain) noexcept -> void { gain.HF *= hfattn; });
+ const float hfattn{std::pow(context->mParams.AirAbsorptionGainHF, absorption)};
+ ConeHF *= hfattn;
+ WetConeHF *= hfattn;
}
+ auto calc_attenuation = [](float distance, float refdist, float rolloff)
+ {
+ const float dist{lerp(refdist, distance, rolloff)};
+ if(dist > 0.0f) return refdist / dist;
+ return 1.0f;
+ };
+
+ /* The reverb effect's room rolloff factor always applies to an inverse
+ * distance rolloff model.
+ */
+ for(uint i{0};i < NumSends;i++)
+ WetGain[i].Base *= calc_attenuation(ClampedDist, props->RefDistance,
+ RoomRolloff[i]);
+
if(props->WetGainAuto)
{
+ const float baseAttn = calc_attenuation(ClampedDist, props->RefDistance,
+ props->RolloffFactor);
+
/* Apply a decay-time transformation to the wet path, based on the
* source distance in meters. The initial decay of the reverb
* effect is calculated and applied to the wet path.
@@ -1444,17 +1459,18 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
if(!(DecayDistance[i].Base > 0.0f))
continue;
- const float gain{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].Base)};
- WetGain[i].Base *= (1.0f-DryAttenuation)*gain + DryAttenuation;
- /* Yes, the wet path's air absorption is applied with
- * WetGainAuto on, rather than WetGainHFAuto.
- */
+ const float gain{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].Base)*
+ (1.0f-baseAttn) + baseAttn};
+ WetGain[i].Base *= gain;
+
if(gain > 0.0f)
{
- float gainhf{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].HF)};
- WetGain[i].HF *= (1.0f-DryAttenuation)*minf(gainhf/gain, 1.0f) + DryAttenuation;
- float gainlf{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].LF)};
- WetGain[i].LF *= (1.0f-DryAttenuation)*minf(gainlf/gain, 1.0f) + DryAttenuation;
+ float gainhf{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].HF)*
+ (1.0f-baseAttn) + baseAttn};
+ WetGain[i].HF *= minf(gainhf/gain, 1.0f);
+ float gainlf{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].LF)*
+ (1.0f-baseAttn) + baseAttn};
+ WetGain[i].LF *= minf(gainlf/gain, 1.0f);
}
}
}