Implement a lerped lookup of the HRTF coefficients/delays
Code supplied by Christopher Fitzgerald
This commit is contained in:
@@ -269,8 +269,6 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
|
||||
{
|
||||
for(c = 0;c < num_channels;c++)
|
||||
{
|
||||
const ALshort *hrtf_left, *hrtf_right;
|
||||
|
||||
if(chans[c] == LFE)
|
||||
{
|
||||
/* Skip LFE */
|
||||
@@ -284,17 +282,10 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
|
||||
continue;
|
||||
}
|
||||
|
||||
GetHrtfCoeffs(0.0, angles[c] * (M_PI/180.0),
|
||||
&hrtf_left, &hrtf_right,
|
||||
&ALSource->Params.HrtfDelay[c][0],
|
||||
&ALSource->Params.HrtfDelay[c][1]);
|
||||
for(i = 0;i < HRIR_LENGTH;i++)
|
||||
{
|
||||
ALSource->Params.HrtfCoeffs[c][i][0] =
|
||||
hrtf_left[i]*(1.0/32767.0)*DryGain*ListenerGain;
|
||||
ALSource->Params.HrtfCoeffs[c][i][1] =
|
||||
hrtf_right[i]*(1.0/32767.0)*DryGain*ListenerGain;
|
||||
}
|
||||
GetLerpedHrtfCoeffs(0.0, angles[c] * (M_PI/180.0),
|
||||
DryGain*ListenerGain,
|
||||
ALSource->Params.HrtfCoeffs[c],
|
||||
ALSource->Params.HrtfDelay[c]);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -692,11 +683,9 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
|
||||
BufferListItem = BufferListItem->next;
|
||||
}
|
||||
|
||||
// Use energy-preserving panning algorithm for multi-speaker playback
|
||||
if((Device->Flags&DEVICE_USE_HRTF))
|
||||
{
|
||||
const ALshort *hrtf_left, *hrtf_right;
|
||||
|
||||
// Use a binaural HRTF algorithm for stereo headphone playback
|
||||
if(Distance > 0.0f)
|
||||
{
|
||||
ALfloat invlen = 1.0f/Distance;
|
||||
@@ -705,18 +694,14 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
|
||||
Position[2] *= invlen;
|
||||
}
|
||||
|
||||
GetHrtfCoeffs(asin(Position[1]), atan2(Position[0], -Position[2]*ZScale),
|
||||
&hrtf_left, &hrtf_right,
|
||||
&ALSource->Params.HrtfDelay[0][0],
|
||||
&ALSource->Params.HrtfDelay[0][1]);
|
||||
for(i = 0;i < HRIR_LENGTH;i++)
|
||||
{
|
||||
ALSource->Params.HrtfCoeffs[0][i][0] = hrtf_left[i]*(1.0/32767.0) * DryGain;
|
||||
ALSource->Params.HrtfCoeffs[0][i][1] = hrtf_right[i]*(1.0/32767.0) * DryGain;
|
||||
}
|
||||
GetLerpedHrtfCoeffs(asin(Position[1]),
|
||||
atan2(Position[0], -Position[2]*ZScale), DryGain,
|
||||
ALSource->Params.HrtfCoeffs[0],
|
||||
ALSource->Params.HrtfDelay[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use energy-preserving panning algorithm for multi-speaker playback
|
||||
ALfloat DirGain, AmbientGain;
|
||||
const ALfloat *SpeakerGain;
|
||||
ALfloat length;
|
||||
|
||||
+79
-17
@@ -39,34 +39,96 @@ static struct HRTF {
|
||||
#include "hrtf_tables.inc"
|
||||
};
|
||||
|
||||
static ALuint CalcEvIndex(ALdouble ev)
|
||||
// Calculate the elevation indices given the polar elevation in radians.
|
||||
// This will return two indices between 0 and (evCount - 1) and an
|
||||
// interpolation factor between 0.0 and 1.0.
|
||||
static void CalcEvIndices (ALfloat ev, ALuint evidx [2], ALfloat * evmu)
|
||||
{
|
||||
ev = (M_PI/2.0 + ev) * (evCount-1) / M_PI;
|
||||
return (ALuint)(ev+0.5);
|
||||
ev = (M_PI/2.0f + ev) * (evCount-1) / M_PI;
|
||||
evidx[0] = (ALuint)ev;
|
||||
evidx[1] = __min(evidx[0] + 1, evCount - 1);
|
||||
*evmu = ev - evidx[0];
|
||||
}
|
||||
|
||||
static ALuint CalcAzIndex(ALint evidx, ALdouble az)
|
||||
// Calculate the azimuth indices given the polar azimuth in radians. This
|
||||
// will return two indices between 0 and (azCount [ei] - 1) and an
|
||||
// interpolation factor between 0.0 and 1.0.
|
||||
static void CalcAzIndices (ALuint evidx, ALfloat az, ALuint azidx [2], ALfloat * azmu)
|
||||
{
|
||||
az = (M_PI*2.0 + az) * azCount[evidx] / (M_PI*2.0);
|
||||
return (ALuint)(az+0.5) % azCount[evidx];
|
||||
az = (M_PI*2.0f + az) * azCount[evidx] / (M_PI*2.0f);
|
||||
azidx[0] = (ALuint)az % azCount[evidx];
|
||||
azidx[1] = (azidx[0] + 1) % azCount[evidx];
|
||||
*azmu = az - (ALuint)az;
|
||||
}
|
||||
|
||||
void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right, ALuint *ldelay, ALuint *rdelay)
|
||||
// Calculates static HRIR coefficients and delays for the given polar
|
||||
// elevation and azimuth in radians. Linear interpolation is used to
|
||||
// increase the apparent resolution of the HRIR dataset. The coefficients
|
||||
// are also normalized and attenuated by the specified gain.
|
||||
void GetLerpedHrtfCoeffs(ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
|
||||
{
|
||||
ALuint lidx, ridx;
|
||||
ALuint evidx, azidx;
|
||||
ALuint evidx[2], azidx[2];
|
||||
ALfloat mu[3];
|
||||
ALuint lidx[4], ridx[4];
|
||||
ALuint i;
|
||||
|
||||
evidx = CalcEvIndex(elevation);
|
||||
azidx = CalcAzIndex(evidx, angle);
|
||||
// Claculate elevation indices and interpolation factor.
|
||||
CalcEvIndices(elevation, evidx, &mu[2]);
|
||||
|
||||
lidx = evOffset[evidx] + azidx;
|
||||
ridx = evOffset[evidx] + ((azCount[evidx]-azidx) % azCount[evidx]);
|
||||
// Calculate azimuth indices and interpolation factor for the first
|
||||
// elevation.
|
||||
CalcAzIndices(evidx[0], azimuth, azidx, &mu[0]);
|
||||
|
||||
*ldelay = Hrtf.delays[lidx];
|
||||
*rdelay = Hrtf.delays[ridx];
|
||||
// Calculate the first set of linear HRIR indices for left and right
|
||||
// channels.
|
||||
lidx[0] = evOffset[evidx[0]] + azidx[0];
|
||||
lidx[1] = evOffset[evidx[0]] + azidx[1];
|
||||
ridx[0] = evOffset[evidx[0]] + ((azCount[evidx[0]]-azidx[0]) % azCount[evidx[0]]);
|
||||
ridx[1] = evOffset[evidx[0]] + ((azCount[evidx[0]]-azidx[1]) % azCount[evidx[0]]);
|
||||
|
||||
*left = Hrtf.coeffs[lidx];
|
||||
*right = Hrtf.coeffs[ridx];
|
||||
// Calculate azimuth indices and interpolation factor for the second
|
||||
// elevation.
|
||||
CalcAzIndices (evidx[1], azimuth, azidx, &mu[1]);
|
||||
|
||||
// Calculate the second set of linear HRIR indices for left and right
|
||||
// channels.
|
||||
lidx[2] = evOffset[evidx[1]] + azidx[0];
|
||||
lidx[3] = evOffset[evidx[1]] + azidx[1];
|
||||
ridx[2] = evOffset[evidx[1]] + ((azCount[evidx[1]]-azidx[0]) % azCount[evidx[1]]);
|
||||
ridx[3] = evOffset[evidx[1]] + ((azCount[evidx[1]]-azidx[1]) % azCount[evidx[1]]);
|
||||
|
||||
// Calculate the normalized and attenuated HRIR coefficients using linear
|
||||
// interpolation when there is enough gain to warrant it. Zero the
|
||||
// coefficients if gain is too low.
|
||||
if(gain > 0.0001f)
|
||||
{
|
||||
ALdouble scale = gain * (1.0/32767.0);
|
||||
for(i = 0;i < HRIR_LENGTH;i++)
|
||||
{
|
||||
coeffs[i][0] = lerp(lerp(Hrtf.coeffs[lidx[0]][i], Hrtf.coeffs[lidx[1]][i], mu[0]),
|
||||
lerp(Hrtf.coeffs[lidx[2]][i], Hrtf.coeffs[lidx[3]][i], mu[1]),
|
||||
mu[2]) * scale;
|
||||
coeffs[i][1] = lerp(lerp(Hrtf.coeffs[ridx[0]][i], Hrtf.coeffs[ridx[1]][i], mu[0]),
|
||||
lerp(Hrtf.coeffs[ridx[2]][i], Hrtf.coeffs[ridx[3]][i], mu[1]),
|
||||
mu[2]) * scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(i = 0;i < HRIR_LENGTH;i++)
|
||||
{
|
||||
coeffs[i][0] = 0.0f;
|
||||
coeffs[i][1] = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the HRIR delays using linear interpolation.
|
||||
delays[0] = (ALuint)(lerp(lerp(Hrtf.delays[lidx[0]], Hrtf.delays[lidx[1]], mu[0]),
|
||||
lerp(Hrtf.delays[lidx[2]], Hrtf.delays[lidx[3]], mu[1]),
|
||||
mu[2]) + 0.5f);
|
||||
delays[1] = (ALuint)(lerp(lerp(Hrtf.delays[ridx[0]], Hrtf.delays[ridx[1]], mu[0]),
|
||||
lerp(Hrtf.delays[ridx[2]], Hrtf.delays[ridx[3]], mu[1]),
|
||||
mu[2]) + 0.5f);
|
||||
}
|
||||
|
||||
ALCboolean IsHrtfCompatible(ALCdevice *device)
|
||||
|
||||
@@ -523,7 +523,7 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans);
|
||||
#define HRIR_MASK (HRIR_LENGTH-1)
|
||||
void InitHrtf(void);
|
||||
ALCboolean IsHrtfCompatible(ALCdevice *device);
|
||||
void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right, ALuint *ldelay, ALuint *rdelay);
|
||||
void GetLerpedHrtfCoeffs(ALfloat elevation, ALfloat azimuth, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
|
||||
|
||||
void al_print(const char *fname, unsigned int line, const char *fmt, ...)
|
||||
PRINTF_STYLE(3,4);
|
||||
|
||||
Reference in New Issue
Block a user