diff options
author | Chris Robinson <[email protected]> | 2017-03-11 18:04:06 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2017-03-11 18:04:06 -0800 |
commit | 96aaab93662be289d3b2c5312ae50502afa8d221 (patch) | |
tree | c270633e689c7a64edaea8a6c15305197b435ced /Alc/mixer.c | |
parent | feffe1e81a155ded0bcdb519a1a126fd8e908baa (diff) |
Rework HRTF coefficient fading
This improves fading between HRIRs as sources pan around. In particular, it
improves the issue with individual coefficients having various rounding errors
in the stepping values, as well as issues with interpolating delay values.
It does this by doing two mixing passes for each source. First using the last
coefficients that fade to silence, and then again using the new coefficients
that fade from silence. When added together, it creates a linear fade from one
to the other. Additionally, the gain is applied separately so the individual
coefficients don't step with rounding errors. Although this does increase CPU
cost since it's doing two mixes per source, each mix is a bit cheaper now since
the stepping is simplified to a single gain value, and the overall quality is
improved.
Diffstat (limited to 'Alc/mixer.c')
-rw-r--r-- | Alc/mixer.c | 87 |
1 files changed, 52 insertions, 35 deletions
diff --git a/Alc/mixer.c b/Alc/mixer.c index d8adb697..67e74396 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -380,7 +380,7 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei ALint64 DataSize64; ALsizei Counter; ALsizei IrSize; - ALsizei chan, j; + ALsizei chan; ALsizei send; /* Get source info */ @@ -605,46 +605,63 @@ ALboolean MixSource(ALvoice *voice, ALsource *Source, ALCdevice *Device, ALsizei MixHrtfParams hrtfparams; int lidx, ridx; + lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); + ridx = GetChannelIdxByName(Device->RealOut, FrontRight); + assert(lidx != -1 && ridx != -1); + if(!Counter) { - parms->Hrtf.Current = parms->Hrtf.Target; - for(j = 0;j < HRIR_LENGTH;j++) - { - hrtfparams.Steps.Coeffs[j][0] = 0.0f; - hrtfparams.Steps.Coeffs[j][1] = 0.0f; - } - hrtfparams.Steps.Delay[0] = 0; - hrtfparams.Steps.Delay[1] = 0; + parms->Hrtf.Old = parms->Hrtf.Target; + hrtfparams.Current = &parms->Hrtf.Target; + hrtfparams.Gain = parms->Hrtf.Target.Gain; + hrtfparams.GainStep = 0.0f; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf.State, DstBufferSize + ); } else { - ALfloat delta = 1.0f / (ALfloat)Counter; - ALfloat coeffdiff; - ALint delaydiff; - for(j = 0;j < IrSize;j++) - { - coeffdiff = parms->Hrtf.Target.Coeffs[j][0] - parms->Hrtf.Current.Coeffs[j][0]; - hrtfparams.Steps.Coeffs[j][0] = coeffdiff * delta; - coeffdiff = parms->Hrtf.Target.Coeffs[j][1] - parms->Hrtf.Current.Coeffs[j][1]; - hrtfparams.Steps.Coeffs[j][1] = coeffdiff * delta; - } - delaydiff = parms->Hrtf.Target.Delay[0] - parms->Hrtf.Current.Delay[0]; - hrtfparams.Steps.Delay[0] = fastf2i((ALfloat)delaydiff * delta); - delaydiff = parms->Hrtf.Target.Delay[1] - parms->Hrtf.Current.Delay[1]; - hrtfparams.Steps.Delay[1] = fastf2i((ALfloat)delaydiff * delta); - } - hrtfparams.Target = &parms->Hrtf.Target; - hrtfparams.Current = &parms->Hrtf.Current; - - lidx = GetChannelIdxByName(Device->RealOut, FrontLeft); - ridx = GetChannelIdxByName(Device->RealOut, FrontRight); - assert(lidx != -1 && ridx != -1); + HrtfState backupstate = parms->Hrtf.State; + ALfloat gain; + + /* The old coefficients need to fade to silence + * completely since they'll be replaced after the mix. + * So it needs to fade out over DstBufferSize instead + * of Counter. + */ + hrtfparams.Current = &parms->Hrtf.Old; + hrtfparams.Gain = parms->Hrtf.Old.Gain; + hrtfparams.GainStep = -hrtfparams.Gain / + (ALfloat)DstBufferSize; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &backupstate, DstBufferSize + ); - MixHrtfSamples( - voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], - samples, Counter, voice->Offset, OutPos, IrSize, &hrtfparams, - &parms->Hrtf.State, DstBufferSize - ); + /* The new coefficients need to fade in completely + * since they're replacing the old ones. To keep the + * source gain fading consistent, interpolate between + * the old and new target gain given how much of the + * fade time this mix handles. + */ + gain = lerp(parms->Hrtf.Old.Gain, parms->Hrtf.Target.Gain, + minf(1.0f, (ALfloat)Counter / (ALfloat)DstBufferSize)); + hrtfparams.Current = &parms->Hrtf.Target; + hrtfparams.Gain = 0.0f; + hrtfparams.GainStep = gain / (ALfloat)DstBufferSize; + MixHrtfSamples( + voice->Direct.Buffer[lidx], voice->Direct.Buffer[ridx], + samples, voice->Offset, OutPos, IrSize, &hrtfparams, + &parms->Hrtf.State, DstBufferSize + ); + /* Update the old parameters with the result. */ + parms->Hrtf.Old = parms->Hrtf.Target; + if(Counter > DstBufferSize) + parms->Hrtf.Old.Gain = hrtfparams.Gain; + } } } |