Add a source radius property that determines the directionality of a sound

At 0 distance from the listener, the sound is omni-directional. As the source
and listener become 'radius' units apart, the sound becomes more directional.

With HRTF, an omni-directional sound is handled using 0-delay, pass-through
filter coefficients, which is blended with the real delay and coefficients as
needed to become more directional.
This commit is contained in:
Chris Robinson 2014-07-08 09:13:35 -07:00
parent c5af088b5f
commit f4cdecebcf
5 changed files with 74 additions and 43 deletions

View File

@ -425,7 +425,7 @@ ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
/* Get the static HRIR coefficients and delays for this /* Get the static HRIR coefficients and delays for this
* channel. */ * channel. */
GetLerpedHrtfCoeffs(Device->Hrtf, GetLerpedHrtfCoeffs(Device->Hrtf,
0.0f, chans[c].angle, DryGain, 0.0f, chans[c].angle, 1.0f, DryGain,
src->Direct.Mix.Hrtf.Params[c].Coeffs, src->Direct.Mix.Hrtf.Params[c].Coeffs,
src->Direct.Mix.Hrtf.Params[c].Delay); src->Direct.Mix.Hrtf.Params[c].Delay);
} }
@ -899,6 +899,8 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
{ {
/* Use a binaural HRTF algorithm for stereo headphone playback */ /* Use a binaural HRTF algorithm for stereo headphone playback */
ALfloat delta, ev = 0.0f, az = 0.0f; ALfloat delta, ev = 0.0f, az = 0.0f;
ALfloat radius = ALSource->Radius;
ALfloat dirfact = 1.0f;
if(Distance > FLT_EPSILON) if(Distance > FLT_EPSILON)
{ {
@ -914,6 +916,8 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
ev = asinf(clampf(Position[1], -1.0f, 1.0f)); ev = asinf(clampf(Position[1], -1.0f, 1.0f));
az = atan2f(Position[0], -Position[2]*ZScale); az = atan2f(Position[0], -Position[2]*ZScale);
} }
if(radius > Distance)
dirfact *= Distance / radius;
/* Check to see if the HRIR is already moving. */ /* Check to see if the HRIR is already moving. */
if(src->Direct.Moving) if(src->Direct.Moving)
@ -926,12 +930,10 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
if(delta > 0.001f) if(delta > 0.001f)
{ {
ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf, ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
ev, az, DryGain, delta, ev, az, dirfact, DryGain, delta, src->Direct.Counter,
src->Direct.Counter, src->Direct.Mix.Hrtf.Params[0].Coeffs, src->Direct.Mix.Hrtf.Params[0].Delay,
src->Direct.Mix.Hrtf.Params[0].Coeffs, src->Direct.Mix.Hrtf.Params[0].CoeffStep, src->Direct.Mix.Hrtf.Params[0].DelayStep
src->Direct.Mix.Hrtf.Params[0].Delay, );
src->Direct.Mix.Hrtf.Params[0].CoeffStep,
src->Direct.Mix.Hrtf.Params[0].DelayStep);
src->Direct.Counter = counter; src->Direct.Counter = counter;
src->Direct.Mix.Hrtf.Gain = DryGain; src->Direct.Mix.Hrtf.Gain = DryGain;
src->Direct.Mix.Hrtf.Dir[0] = Position[0]; src->Direct.Mix.Hrtf.Dir[0] = Position[0];
@ -942,7 +944,7 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
else else
{ {
/* Get the initial (static) HRIR coefficients and delays. */ /* Get the initial (static) HRIR coefficients and delays. */
GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain, GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
src->Direct.Mix.Hrtf.Params[0].Coeffs, src->Direct.Mix.Hrtf.Params[0].Coeffs,
src->Direct.Mix.Hrtf.Params[0].Delay); src->Direct.Mix.Hrtf.Params[0].Delay);
src->Direct.Counter = 0; src->Direct.Counter = 0;
@ -968,8 +970,9 @@ ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
/* Normalize the length, and compute panned gains. */ /* Normalize the length, and compute panned gains. */
if(Distance > FLT_EPSILON) if(Distance > FLT_EPSILON)
{ {
ALfloat radius = ALSource->Radius;
ALfloat Target[MaxChannels]; ALfloat Target[MaxChannels];
ALfloat invlen = 1.0f/Distance; ALfloat invlen = 1.0f/maxf(Distance, radius);
Position[0] *= invlen; Position[0] *= invlen;
Position[1] *= invlen; Position[1] *= invlen;
Position[2] *= invlen; Position[2] *= invlen;

View File

@ -123,7 +123,7 @@ ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3],
* increase the apparent resolution of the HRIR data set. The coefficients * increase the apparent resolution of the HRIR data set. The coefficients
* are also normalized and attenuated by the specified gain. * are also normalized and attenuated by the specified gain.
*/ */
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays) void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
{ {
ALuint evidx[2], azidx[2]; ALuint evidx[2], azidx[2];
ALuint lidx[4], ridx[4]; ALuint lidx[4], ridx[4];
@ -162,12 +162,12 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
blend[3] = ( mu[1]) * ( mu[2]); blend[3] = ( mu[1]) * ( mu[2]);
/* Calculate the HRIR delays using linear interpolation. */ /* Calculate the HRIR delays using linear interpolation. */
delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] + Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
0.5f) << HRTFDELAY_BITS; dirfact + 0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] + Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
0.5f) << HRTFDELAY_BITS; dirfact + 0.5f) << HRTFDELAY_BITS;
/* Calculate the sample offsets for the HRIR indices. */ /* Calculate the sample offsets for the HRIR indices. */
lidx[0] *= Hrtf->irSize; lidx[0] *= Hrtf->irSize;
@ -185,17 +185,26 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
*/ */
if(gain > 0.0001f) if(gain > 0.0001f)
{ {
ALfloat c;
gain *= 1.0f/32767.0f; gain *= 1.0f/32767.0f;
for(i = 0;i < Hrtf->irSize;i++)
i = 0;
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(1.0f, c, dirfact) * gain;
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(1.0f, c, dirfact) * gain;
for(i = 1;i < Hrtf->irSize;i++)
{ {
coeffs[i][0] = (Hrtf->coeffs[lidx[0]+i]*blend[0] + c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
Hrtf->coeffs[lidx[2]+i]*blend[2] + coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
Hrtf->coeffs[lidx[3]+i]*blend[3]) * gain; c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
coeffs[i][1] = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
Hrtf->coeffs[ridx[1]+i]*blend[1] + coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
Hrtf->coeffs[ridx[2]+i]*blend[2] +
Hrtf->coeffs[ridx[3]+i]*blend[3]) * gain;
} }
} }
else else
@ -215,7 +224,7 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
* specified gain. Stepping resolution and count is determined using the * specified gain. Stepping resolution and count is determined using the
* given delta factor between 0.0 and 1.0. * given delta factor between 0.0 and 1.0.
*/ */
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep) ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep)
{ {
ALuint evidx[2], azidx[2]; ALuint evidx[2], azidx[2];
ALuint lidx[4], ridx[4]; ALuint lidx[4], ridx[4];
@ -266,12 +275,12 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
left = (ALfloat)(delays[0] - (delayStep[0] * counter)); left = (ALfloat)(delays[0] - (delayStep[0] * counter));
right = (ALfloat)(delays[1] - (delayStep[1] * counter)); right = (ALfloat)(delays[1] - (delayStep[1] * counter));
delays[0] = fastf2u(Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] + delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3] + Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
0.5f) << HRTFDELAY_BITS; dirfact + 0.5f) << HRTFDELAY_BITS;
delays[1] = fastf2u(Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] + delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3] + Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
0.5f) << HRTFDELAY_BITS; dirfact + 0.5f) << HRTFDELAY_BITS;
delayStep[0] = fastf2i(step * (delays[0] - left)); delayStep[0] = fastf2i(step * (delays[0] - left));
delayStep[1] = fastf2i(step * (delays[1] - right)); delayStep[1] = fastf2i(step * (delays[1] - right));
@ -294,20 +303,35 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
*/ */
if(gain > 0.0001f) if(gain > 0.0001f)
{ {
ALfloat c;
gain *= 1.0f/32767.0f; gain *= 1.0f/32767.0f;
for(i = 0;i < Hrtf->irSize;i++)
i = 0;
left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter);
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain;
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain;
coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right);
for(i = 1;i < Hrtf->irSize;i++)
{ {
left = coeffs[i][0] - (coeffStep[i][0] * counter); left = coeffs[i][0] - (coeffStep[i][0] * counter);
right = coeffs[i][1] - (coeffStep[i][1] * counter); right = coeffs[i][1] - (coeffStep[i][1] * counter);
coeffs[i][0] = (Hrtf->coeffs[lidx[0]+i]*blend[0] + c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
Hrtf->coeffs[lidx[1]+i]*blend[1] + Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
Hrtf->coeffs[lidx[2]+i]*blend[2] + coeffs[i][0] = lerp(1.0f, c, dirfact) * gain;
Hrtf->coeffs[lidx[3]+i]*blend[3]) * gain; c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
coeffs[i][1] = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
Hrtf->coeffs[ridx[1]+i]*blend[1] + coeffs[i][1] = lerp(1.0f, c, dirfact) * gain;
Hrtf->coeffs[ridx[2]+i]*blend[2] +
Hrtf->coeffs[ridx[3]+i]*blend[3]) * gain;
coeffStep[i][0] = step * (coeffs[i][0] - left); coeffStep[i][0] = step * (coeffs[i][0] - left);
coeffStep[i][1] = step * (coeffs[i][1] - right); coeffStep[i][1] = step * (coeffs[i][1] - right);

View File

@ -22,7 +22,7 @@ void FreeHrtfs(void);
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf); ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]); ALfloat CalcHrtfDelta(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3]);
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays); void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep); ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat delta, ALint counter, ALfloat (*coeffs)[2], ALuint *delays, ALfloat (*coeffStep)[2], ALint *delayStep);
#endif /* ALC_HRTF_H */ #endif /* ALC_HRTF_H */

View File

@ -71,6 +71,8 @@ typedef struct ALsource {
volatile ALfloat RoomRolloffFactor; volatile ALfloat RoomRolloffFactor;
volatile ALfloat DopplerFactor; volatile ALfloat DopplerFactor;
volatile ALfloat Radius;
enum Resampler Resampler; enum Resampler Resampler;
/** /**

View File

@ -2407,6 +2407,8 @@ static ALvoid InitSourceParams(ALsource *Source)
Source->DopplerFactor = 1.0f; Source->DopplerFactor = 1.0f;
Source->DirectChannels = AL_FALSE; Source->DirectChannels = AL_FALSE;
Source->Radius = 0.0f;
Source->DistanceModel = DefaultDistanceModel; Source->DistanceModel = DefaultDistanceModel;
Source->Resampler = DefaultResampler; Source->Resampler = DefaultResampler;