aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2016-02-20 00:53:01 -0800
committerChris Robinson <[email protected]>2016-02-20 00:53:01 -0800
commite1ce7f9180d8127397faebf36eb815a5a575d7c8 (patch)
treede56927ad814a6a41a893cdc5332332bc27aeaf0
parente90cdbcf98662a86326b5b3f84f3b46534d7766e (diff)
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.
-rw-r--r--Alc/ALu.c14
-rw-r--r--Alc/hrtf.c102
-rw-r--r--Alc/hrtf.h1
-rw-r--r--Alc/panning.c51
-rw-r--r--OpenAL32/Include/alMain.h9
5 files changed, 55 insertions, 122 deletions
diff --git a/Alc/ALu.c b/Alc/ALu.c
index b36e2248..d4dac1ab 100644
--- a/Alc/ALu.c
+++ b/Alc/ALu.c
@@ -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.
diff --git a/Alc/hrtf.c b/Alc/hrtf.c
index c4cacf87..e4052f52 100644
--- a/Alc/hrtf.c
+++ b/Alc/hrtf.c
@@ -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)
{
diff --git a/Alc/hrtf.h b/Alc/hrtf.h
index 794d6abc..86016ae6 100644
--- a/Alc/hrtf.h
+++ b/Alc/hrtf.h
@@ -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 */
diff --git a/Alc/panning.c b/Alc/panning.c
index 5013ec16..9f1e87d7 100644
--- a/Alc/panning.c
+++ b/Alc/panning.c
@@ -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;
}
diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h
index 89936f85..4c0e9213 100644
--- a/OpenAL32/Include/alMain.h
+++ b/OpenAL32/Include/alMain.h
@@ -317,6 +317,15 @@ enum Channel {
SideLeft,
SideRight,
+ UpperFrontLeft,
+ UpperFrontRight,
+ UpperBackLeft,
+ UpperBackRight,
+ LowerFrontLeft,
+ LowerFrontRight,
+ LowerBackLeft,
+ LowerBackRight,
+
BFormatW,
BFormatX,
BFormatY,