aboutsummaryrefslogtreecommitdiffstats
path: root/alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2022-03-01 15:38:04 -0800
committerChris Robinson <[email protected]>2022-03-01 15:38:04 -0800
commitfbac67a6a0f297ca69c9b61da85e90f5c13663ae (patch)
treeeb8ddca54554b2b2e3df855b0cb5fb9343e0e702 /alc
parentd86f1ab4768ce9fdb3480a9d2a81d8f8e9293e0e (diff)
Rework the initial reverb decay
The idea here is that the initial reverb decay can't become less than the dry path distance attenuation, as the dry attenuation represents the audio that has not yet had a chance to start reflecting in the environment. As well, the reference distance indicates where there is no distance attenuation, with any initial attenuation set by the environment itself. So what we do is use the dry path attenuation as the baseline for what's mixed to the reverb, with the decay rate indicating how much of the remaining room (non-direct) energy attenuates with distance. This may be over-complicating it. Other sources hint at a more typical XdB per doubling of distance, with X varying depending on environment properties (room size, absorbancy, etc). This could be handled by applying a normal inverse distance attenuation model, with a rolloff factor generated from the reverb properties (density, decay rate, etc). Will need more testing and research.
Diffstat (limited to 'alc')
-rw-r--r--alc/alu.cpp73
1 files changed, 32 insertions, 41 deletions
diff --git a/alc/alu.cpp b/alc/alu.cpp
index a263960c..f0667f73 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -1308,14 +1308,12 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
alu::Vector ToSource{Position[0], Position[1], Position[2], 0.0f};
const float Distance{ToSource.normalize()};
- /* Initial source gain */
- GainTriplet DryGain{props->Gain, 1.0f, 1.0f};
- GainTriplet WetGain[MAX_SENDS];
- for(uint i{0};i < NumSends;i++)
- WetGain[i] = DryGain;
-
/* Calculate distance attenuation */
float ClampedDist{Distance};
+ float DryAttenuation{1.0f};
+ float WetAttenuation[MAX_SENDS];
+ for(uint i{0};i < NumSends;i++)
+ WetAttenuation[i] = DryAttenuation;
switch(context->mParams.SourceDistanceModel ? props->mDistanceModel
: context->mParams.mDistanceModel)
@@ -1330,11 +1328,11 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
else
{
float dist{lerp(props->RefDistance, ClampedDist, props->RolloffFactor)};
- if(dist > 0.0f) DryGain.Base *= props->RefDistance / dist;
+ 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) WetGain[i].Base *= props->RefDistance / dist;
+ if(dist > 0.0f) WetAttenuation[i] = props->RefDistance / dist;
}
}
break;
@@ -1350,12 +1348,12 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
{
float attn{props->RolloffFactor * (ClampedDist-props->RefDistance) /
(props->MaxDistance-props->RefDistance)};
- DryGain.Base *= maxf(1.0f - attn, 0.0f);
+ DryAttenuation = maxf(1.0f - attn, 0.0f);
for(uint i{0};i < NumSends;i++)
{
attn = RoomRolloff[i] * (ClampedDist-props->RefDistance) /
(props->MaxDistance-props->RefDistance);
- WetGain[i].Base *= maxf(1.0f - attn, 0.0f);
+ WetAttenuation[i] = maxf(1.0f - attn, 0.0f);
}
}
break;
@@ -1370,9 +1368,9 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
else
{
const float dist_ratio{ClampedDist/props->RefDistance};
- DryGain.Base *= std::pow(dist_ratio, -props->RolloffFactor);
+ DryAttenuation = std::pow(dist_ratio, -props->RolloffFactor);
for(uint i{0};i < NumSends;i++)
- WetGain[i].Base *= std::pow(dist_ratio, -RoomRolloff[i]);
+ WetAttenuation[i] = std::pow(dist_ratio, -RoomRolloff[i]);
}
break;
@@ -1381,51 +1379,44 @@ 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};
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, ConeHF;
- if(!(Angle > props->InnerAngle))
+ if(Angle >= props->OuterAngle)
{
- ConeGain = 1.0f;
- ConeHF = 1.0f;
+ ConeGain = props->OuterGain;
+ ConeHF = lerp(1.0f, props->OuterGainHF, props->DryGainHFAuto);
}
- else if(Angle < props->OuterAngle)
+ else if(Angle >= props->InnerAngle)
{
const float scale{(Angle-props->InnerAngle) / (props->OuterAngle-props->InnerAngle)};
ConeGain = lerp(1.0f, props->OuterGain, scale);
- ConeHF = lerp(1.0f, props->OuterGainHF, scale);
- }
- else
- {
- ConeGain = props->OuterGain;
- ConeHF = props->OuterGainHF;
+ ConeHF = lerp(1.0f, props->OuterGainHF, scale * props->DryGainHFAuto);
}
- DryGain.Base *= ConeGain;
- if(props->DryGainHFAuto)
- DryGain.HF *= ConeHF;
- if(props->WetGainAuto)
- std::for_each(std::begin(WetGain), std::begin(WetGain)+NumSends,
- [ConeGain](GainTriplet &gain) noexcept -> void { gain.Base *= ConeGain; });
- if(props->WetGainHFAuto)
- std::for_each(std::begin(WetGain), std::begin(WetGain)+NumSends,
- [ConeHF](GainTriplet &gain) noexcept -> void { gain.HF *= ConeHF; });
+ WetConeGain = lerp(1.0f, ConeGain, props->WetGainAuto);
+ WetConeHF = lerp(1.0f, ConeHF, props->WetGainHFAuto);
}
/* Apply gain and frequency filters */
+ 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.HF *= props->Direct.GainHF;
- DryGain.LF *= props->Direct.GainLF;
+ DryGain.HF = ConeHF * props->Direct.GainHF;
+ DryGain.LF = props->Direct.GainLF;
+ GainTriplet WetGain[MAX_SENDS]{};
for(uint i{0};i < NumSends;i++)
{
- WetGain[i].Base = minf(clampf(WetGain[i].Base, props->MinGain, props->MaxGain) *
- props->Send[i].Gain * context->mParams.Gain, GainMixMax);
- WetGain[i].HF *= props->Send[i].GainHF;
- WetGain[i].LF *= props->Send[i].GainLF;
+ 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;
+ WetGain[i].LF = props->Send[i].GainLF;
}
/* Distance-based air absorption and initial send decay. */
@@ -1454,16 +1445,16 @@ void CalcAttnSourceParams(Voice *voice, const VoiceProps *props, const ContextBa
continue;
const float gain{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].Base)};
- WetGain[i].Base *= gain;
+ WetGain[i].Base *= (1.0f-DryAttenuation)*gain + DryAttenuation;
/* Yes, the wet path's air absorption is applied with
* WetGainAuto on, rather than WetGainHFAuto.
*/
if(gain > 0.0f)
{
float gainhf{std::pow(ReverbDecayGain, meters_base/DecayDistance[i].HF)};
- WetGain[i].HF *= minf(gainhf / gain, 1.0f);
+ 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 *= minf(gainlf / gain, 1.0f);
+ WetGain[i].LF *= (1.0f-DryAttenuation)*minf(gainlf/gain, 1.0f) + DryAttenuation;
}
}
}