Use an 8-channel cube for HRTF's virtual format.

There were phase issues caused by applying HRTF directly to the B-Format
channels, since the HRIR delays were all averaged which removed the inter-aural
time-delay, which in turn removed significant spatial information.
This commit is contained in:
Chris Robinson
2016-02-20 00:53:01 -08:00
parent e90cdbcf98
commit e1ce7f9180
5 changed files with 55 additions and 122 deletions
+7 -7
View File
@@ -100,14 +100,14 @@ extern inline void aluMatrixdSet(aluMatrixd *matrix,
ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
/* NOTE: HRTF is set up a bit special in the device. By default, the device's
* DryBuffer, NumChannels, ChannelName, and Channel fields correspond to the
* output mixing format, and the DryBuffer is then converted and written to the
* backend's audio buffer.
/* NOTE: HRTF is set up a bit special in the device. By default, without HRTF,
* the device's DryBuffer, NumChannels, ChannelName, and Channel fields
* correspond to the output format, and the DryBuffer is then converted and
* written to the backend's audio buffer.
*
* With HRTF, these fields correspond to a virtual format (typically B-Format),
* and the actual output is stored in DryBuffer[NumChannels] for the left
* channel and DryBuffer[NumChannels+1] for the right. As a final output step,
* With HRTF, these fields correspond to a virtual format, and the actual
* output is stored in DryBuffer[NumChannels] for the left channel and
* DryBuffer[NumChannels+1] for the right. As a final output step,
* the virtual channels will have HRTF applied and written to the actual
* output. Things like effects and B-Format decoding will want to write to the
* virtual channels so that they can be mixed with HRTF in full 3D.
-102
View File
@@ -181,108 +181,6 @@ void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azi
}
}
/* Calculates HRTF coefficients for B-Format channels (only up to first-order).
* Note that these will decode a B-Format output mix, which uses FuMa ordering
* and scaling, not N3D!
*/
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat (*coeffs_list[4])[2], ALuint *delay_list[4])
{
ALuint elev_idx, azi_idx;
ALfloat scale;
ALuint i, c;
for(c = 0;c < 4;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] = 0.0f;
coeffs[i][1] = 0.0f;
}
delay[0] = 0;
delay[1] = 0;
}
/* NOTE: HRTF coefficients are generated by combining all the HRIRs in the
* dataset, with each entry scaled according to how much it contributes to
* the given B-Format channel based on its direction (including negative
* contributions!).
*/
scale = 0.0f;
for(elev_idx = 0;elev_idx < Hrtf->evCount;elev_idx++)
{
ALfloat elev = (ALfloat)elev_idx/(ALfloat)(Hrtf->evCount-1)*F_PI - F_PI_2;
ALuint evoffset = Hrtf->evOffset[elev_idx];
ALuint azcount = Hrtf->azCount[elev_idx];
scale += (ALfloat)azcount;
for(azi_idx = 0;azi_idx < azcount;azi_idx++)
{
ALuint lidx, ridx;
ALfloat ambi_coeffs[4];
ALfloat az, gain;
ALfloat x, y, z;
lidx = evoffset + azi_idx;
ridx = evoffset + ((azcount-azi_idx) % azcount);
az = (ALfloat)azi_idx / (ALfloat)azcount * F_TAU;
if(az > F_PI) az -= F_TAU;
x = cosf(-az) * cosf(elev);
y = sinf(-az) * cosf(elev);
z = sinf(elev);
ambi_coeffs[0] = 1.414213562f;
ambi_coeffs[1] = x;
ambi_coeffs[2] = y;
ambi_coeffs[3] = z;
for(c = 0;c < 4;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
/* NOTE: Always include the total delay average since the
* channels need to have matching delays. */
delay[0] += Hrtf->delays[lidx];
delay[1] += Hrtf->delays[ridx];
gain = ambi_coeffs[c];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] += Hrtf->coeffs[lidx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
coeffs[i][1] += Hrtf->coeffs[ridx*Hrtf->irSize + i]*(1.0f/32767.0f) * gain;
}
}
}
}
scale = 1.0f/scale;
for(c = 0;c < 4;c++)
{
ALfloat (*coeffs)[2] = coeffs_list[c];
ALuint *delay = delay_list[c];
for(i = 0;i < Hrtf->irSize;i++)
{
coeffs[i][0] *= scale;
coeffs[i][1] *= scale;
}
delay[0] = minu((ALuint)((ALfloat)delay[0] * scale), HRTF_HISTORY_LENGTH-1);
delay[0] <<= HRTFDELAY_BITS;
delay[1] = minu((ALuint)((ALfloat)delay[1] * scale), HRTF_HISTORY_LENGTH-1);
delay[1] <<= HRTFDELAY_BITS;
}
}
static struct Hrtf *LoadHrtf00(FILE *f)
{
-1
View File
@@ -34,6 +34,5 @@ ALuint GetHrtfSampleRate(const struct Hrtf *Hrtf);
ALuint GetHrtfIrSize(const struct Hrtf *Hrtf);
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat dirfact, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays);
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat (*coeffs_list[4])[2], ALuint *delay_list[4]);
#endif /* ALC_HRTF_H */
+39 -12
View File
@@ -184,6 +184,15 @@ DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
case SideLeft: return "side-left";
case SideRight: return "side-right";
case UpperFrontLeft: return "upper-front-left";
case UpperFrontRight: return "upper-front-right";
case UpperBackLeft: return "upper-back-left";
case UpperBackRight: return "upper-back-right";
case LowerFrontLeft: return "lower-front-left";
case LowerFrontRight: return "lower-front-right";
case LowerBackLeft: return "lower-back-left";
case LowerBackRight: return "lower-back-right";
case BFormatW: return "bformat-w";
case BFormatX: return "bformat-x";
case BFormatY: return "bformat-y";
@@ -466,6 +475,15 @@ ALvoid aluInitPanning(ALCdevice *device)
{ BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } },
{ SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } },
{ SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } },
}, Cube8Cfg[8] = {
{ UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } },
{ UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } },
{ UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } },
{ UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } },
{ LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } },
{ LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } },
{ LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } },
{ LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } },
}, BFormat3D[4] = {
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
@@ -482,13 +500,25 @@ ALvoid aluInitPanning(ALCdevice *device)
if(device->Hrtf)
{
ALfloat (*coeffs_list[4])[2];
ALuint *delay_list[4];
static const struct {
enum Channel Channel;
ALfloat Angle;
ALfloat Elevation;
} CubeInfo[8] = {
{ UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) },
{ UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) },
{ UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) },
{ UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) },
{ LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) },
{ LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) },
{ LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) },
{ LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) },
};
ALuint i;
count = COUNTOF(BFormat3D);
chanmap = BFormat3D;
ambiscale = 1.0f;
count = COUNTOF(Cube8Cfg);
chanmap = Cube8Cfg;
ambiscale = FIRST_ORDER_SCALE;
for(i = 0;i < count;i++)
device->ChannelName[i] = chanmap[i].ChanName;
@@ -498,15 +528,12 @@ ALvoid aluInitPanning(ALCdevice *device)
&device->NumChannels, AL_TRUE);
device->AmbiScale = ambiscale;
for(i = 0;i < 4;++i)
for(i = 0;i < device->NumChannels;i++)
{
static const enum Channel inputs[4] = { BFormatW, BFormatX, BFormatY, BFormatZ };
int chan = GetChannelIdxByName(device, inputs[i]);
coeffs_list[i] = device->Hrtf_Params[chan].Coeffs;
delay_list[i] = device->Hrtf_Params[chan].Delay;
int chan = GetChannelIdxByName(device, CubeInfo[i].Channel);
GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f,
device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay);
}
GetBFormatHrtfCoeffs(device->Hrtf, coeffs_list, delay_list);
return;
}
+9
View File
@@ -317,6 +317,15 @@ enum Channel {
SideLeft,
SideRight,
UpperFrontLeft,
UpperFrontRight,
UpperBackLeft,
UpperBackRight,
LowerFrontLeft,
LowerFrontRight,
LowerBackLeft,
LowerBackRight,
BFormatW,
BFormatX,
BFormatY,