Calculate HRTF coefficients for all B-Format channels at once

It's possible to calculate HRTF coefficients for full third-order ambisonics
now, but it's still not possible to use them here without upmixing first-order
content.
This commit is contained in:
Chris Robinson 2015-02-10 11:22:28 -08:00
parent 3ed79cc229
commit a6e574ba9e
3 changed files with 71 additions and 33 deletions

View File

@ -312,20 +312,28 @@ ALuint GetMovingHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat a
}
/* Calculates HRTF coefficients for a B-Format channel (first order only). */
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint chan_num, ALfloat (*coeffs)[2], ALuint *delays)
/* Calculates HRTF coefficients for B-Format channels. */
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list)
{
ALuint elev_idx, azi_idx;
ALfloat scale;
ALuint i;
ALuint i, c;
for(i = 0;i < Hrtf->irSize;i++)
assert(num_chans <= MAX_AMBI_COEFFS);
for(c = 0;c < num_chans;c++)
{
coeffs[i][0] = 0.0f;
coeffs[i][1] = 0.0f;
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;
}
delays[0] = 0;
delays[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
@ -345,18 +353,13 @@ void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint chan_num, ALfloa
{
ALuint lidx, ridx;
ALfloat az;
ALfloat ambi_coeffs[4];
ALfloat ambi_coeffs[MAX_AMBI_COEFFS];
ALfloat x, y, z;
ALfloat gain;
lidx = evoffset + azi_idx;
ridx = evoffset + ((azcount-azi_idx) % azcount);
/* NOTE: Always include the total delay average since the channels
* need to have matching delays. */
delays[0] += Hrtf->delays[lidx];
delays[1] += Hrtf->delays[ridx];
az = (ALfloat)azi_idx / (ALfloat)azcount * F_2PI;
if(az > F_PI) az -= F_2PI;
@ -368,29 +371,58 @@ void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint chan_num, ALfloa
ambi_coeffs[1] = x; /* X */
ambi_coeffs[2] = y; /* Y */
ambi_coeffs[3] = z; /* Z */
ambi_coeffs[4] = 0.5f * (3.0f*z*z - 1.0f); /* 0.5 * (3*Z*Z - 1) */
ambi_coeffs[5] = 2.0f * z * x; /* 2*Z*X */
ambi_coeffs[6] = 2.0f * y * z; /* 2*Y*Z */
ambi_coeffs[7] = x*x - y*y; /* X*X - Y*Y */
ambi_coeffs[8] = 2.0f * x * y; /* 2*X*Y */
ambi_coeffs[9] = 0.5f * z * (5.0f*z*z - 3.0f); /* 0.5 * Z * (5*Z*Z - 3) */
ambi_coeffs[10] = 0.7262f * x * (5.0f*z*z - 1.0f); /* sqrt(135.0 / 256.0) * X * (5*Z*Z - 1) */
ambi_coeffs[11] = 0.7262f * y * (5.0f*z*z - 1.0f); /* sqrt(135.0 / 256.0) * Y * (5*Z*Z - 1) */
ambi_coeffs[12] = 2.5981f * z * (x*x - y*y); /* sqrt(27.0 / 4.0) * Z * (X*X - Y*Y) */
ambi_coeffs[13] = 5.1962f * x * y * z; /* sqrt(27) * X * Y * Z */
ambi_coeffs[14] = x * (x*x - 3.0f*y*y); /* X * (X*X - 3*Y*Y) */
ambi_coeffs[15] = y * (3.0f*x*x - y*y); /* Y * (3*X*X - Y*Y) */
gain = ambi_coeffs[chan_num];
if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD))
continue;
lidx *= Hrtf->irSize;
ridx *= Hrtf->irSize;
for(i = 0;i < Hrtf->irSize;i++)
for(c = 0;c < num_chans;c++)
{
coeffs[i][0] += Hrtf->coeffs[lidx + i]*(1.0f/32767.0f) * gain;
coeffs[i][1] += Hrtf->coeffs[ridx + i]*(1.0f/32767.0f) * gain;
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;
delays[0] = minu((ALuint)((ALfloat)delays[0] * scale), HRTF_HISTORY_LENGTH-1)<<HRTFDELAY_BITS;
delays[1] = minu((ALuint)((ALfloat)delays[1] * scale), HRTF_HISTORY_LENGTH-1)<<HRTFDELAY_BITS;
for(i = 0;i < Hrtf->irSize;i++)
for(c = 0;c < num_chans;c++)
{
coeffs[i][0] *= scale;
coeffs[i][1] *= scale;
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;
}
}

View File

@ -23,6 +23,6 @@ void FreeHrtfs(void);
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);
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);
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint chan_num, ALfloat (*coeffs)[2], ALuint *delays);
void GetBFormatHrtfCoeffs(const struct Hrtf *Hrtf, const ALuint num_chans, ALfloat (**coeffs_list)[2], ALuint **delay_list);
#endif /* ALC_HRTF_H */

View File

@ -362,12 +362,18 @@ ALvoid aluInitPanning(ALCdevice *device)
device->ChannelName[i] = chanmap[i].ChanName;
for(;i < MAX_OUTPUT_CHANNELS;i++)
device->ChannelName[i] = InvalidChannel;
SetChannelMap(device, chanmap, count);
for(i = 0;i < count;i++)
{
GetBFormatHrtfCoeffs(device->Hrtf, i, device->Hrtf_Params[i].Coeffs,
device->Hrtf_Params[i].Delay);
ALfloat (*coeffs_list[4])[2] = {
device->Hrtf_Params[0].Coeffs, device->Hrtf_Params[1].Coeffs,
device->Hrtf_Params[2].Coeffs, device->Hrtf_Params[3].Coeffs
};
ALuint *delay_list[4] = {
device->Hrtf_Params[0].Delay, device->Hrtf_Params[1].Delay,
device->Hrtf_Params[2].Delay, device->Hrtf_Params[3].Delay
};
GetBFormatHrtfCoeffs(device->Hrtf, 4, coeffs_list, delay_list);
}
return;