diff options
author | Chris Robinson <[email protected]> | 2015-02-09 15:59:29 -0800 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2015-02-09 15:59:29 -0800 |
commit | a1d4847d078f4f807f5697f299eea834797f4287 (patch) | |
tree | 376b457d1655bd0db7747913cdf77be262a831f5 | |
parent | 8933e21ef21c2084570eb9cb998a47053b686ed1 (diff) |
Use B-Format for HRTF's virtual output format
This adds the ability to directly decode B-Format with HRTF, though only first-
order (WXYZ) for now. Second- and third-order would be easilly doable, however
we'd need to be able to up-mix first-order content (from the BFORMAT2D and
BFORMAT3D buffer formats) since it would be inappropriate to decode lower-order
content with a higher-order decoder.
-rw-r--r-- | Alc/ALu.c | 8 | ||||
-rw-r--r-- | Alc/hrtf.c | 84 | ||||
-rw-r--r-- | Alc/hrtf.h | 1 | ||||
-rw-r--r-- | Alc/panning.c | 37 |
4 files changed, 97 insertions, 33 deletions
@@ -98,10 +98,10 @@ extern inline void aluMatrixSet(aluMatrix *restrict matrix, ALfloat m00, ALfloat * output mixing 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 8-channel - * cube), 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 + * 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, + * 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. * @@ -82,7 +82,7 @@ static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *ev */ static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu) { - az = (F_2PI + az) * azcount / (F_2PI); + az = (F_2PI + az) * azcount / F_2PI; azidx[0] = fastf2u(az) % azcount; azidx[1] = (azidx[0] + 1) % azcount; *azmu = az - floorf(az); @@ -312,6 +312,88 @@ 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 ALfloat ambi_coeffs[4], ALfloat (*coeffs)[2], ALuint *delays) +{ + ALuint elev_idx, azi_idx; + ALfloat scale; + ALuint i; + + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] = 0.0f; + coeffs[i][1] = 0.0f; + } + 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 + * 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 az; + 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; + + x = cosf(az) * cosf(elev); + y = -sinf(az) * cosf(elev); + z = sinf(elev); + + gain = 0.0f; + gain += ambi_coeffs[0]*0.7071f; /* sqrt(1.0 / 2.0) */ + gain += ambi_coeffs[1]*x; /* X */ + gain += ambi_coeffs[2]*y; /* Y */ + gain += ambi_coeffs[3]*z; /* Z */ + + if(!(fabsf(gain) > GAIN_SILENCE_THRESHOLD)) + continue; + + lidx *= Hrtf->irSize; + ridx *= Hrtf->irSize; + for(i = 0;i < Hrtf->irSize;i++) + { + coeffs[i][0] += Hrtf->coeffs[lidx + i]*(1.0f/32767.0f) * gain; + coeffs[i][1] += Hrtf->coeffs[ridx + 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++) + { + coeffs[i][0] *= scale; + coeffs[i][1] *= scale; + } +} + + static struct Hrtf *LoadHrtf00(FILE *f, ALuint deviceRate) { const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1; @@ -23,5 +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 ALfloat ambi_coeffs[4], ALfloat (*coeffs)[2], ALuint *delays); #endif /* ALC_HRTF_H */ diff --git a/Alc/panning.c b/Alc/panning.c index 4a3541c2..b7b8a0c7 100644 --- a/Alc/panning.c +++ b/Alc/panning.c @@ -339,15 +339,6 @@ 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 }, { 0.224752f, -0.225790f, -0.130361f, 0.0f } } }, { SideLeft, { { 0.224739f, 0.000002f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f }, { 0.224739f, 0.000000f, 0.260717f, 0.0f } } }, { SideRight, { { 0.224739f, 0.000002f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f }, { 0.224739f, 0.000000f, -0.260717f, 0.0f } } }, - }, Cube8[8] = { - { TopFrontLeft, { { 0.176777f, 0.125000f, 0.125000f, 0.125000f }, { 0.176777f, 0.125000f, 0.125000f, 0.125000f } } }, - { TopFrontRight, { { 0.176777f, 0.125000f, -0.125000f, 0.125000f }, { 0.176777f, 0.125000f, -0.125000f, 0.125000f } } }, - { TopBackLeft, { { 0.176777f, -0.125000f, 0.125000f, 0.125000f }, { 0.176777f, -0.125000f, 0.125000f, 0.125000f } } }, - { TopBackRight, { { 0.176777f, -0.125000f, -0.125000f, 0.125000f }, { 0.176777f, -0.125000f, -0.125000f, 0.125000f } } }, - { BottomFrontLeft, { { 0.176777f, 0.125000f, 0.125000f, -0.125000f }, { 0.176777f, 0.125000f, 0.125000f, -0.125000f } } }, - { BottomFrontRight, { { 0.176777f, 0.125000f, -0.125000f, -0.125000f }, { 0.176777f, 0.125000f, -0.125000f, -0.125000f } } }, - { BottomBackLeft, { { 0.176777f, -0.125000f, 0.125000f, -0.125000f }, { 0.176777f, -0.125000f, 0.125000f, -0.125000f } } }, - { BottomBackRight, { { 0.176777f, -0.125000f, -0.125000f, -0.125000f }, { 0.176777f, -0.125000f, -0.125000f, -0.125000f } } }, }, BFormat3D[4] = { { Aux0, { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } } }, { Aux1, { { 0.0f, 1.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f, 0.0f } } }, @@ -362,33 +353,23 @@ ALvoid aluInitPanning(ALCdevice *device) if(device->Hrtf) { - static const struct { - enum Channel channel; - ALfloat elevation; - ALfloat angle; - } VirtualChans[8] = { - { TopFrontLeft, DEG2RAD( 45.0f), DEG2RAD( -45.0f) }, - { TopFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) }, - { TopBackLeft, DEG2RAD( 45.0f), DEG2RAD(-135.0f) }, - { TopBackRight, DEG2RAD( 45.0f), DEG2RAD( 135.0f) }, - { BottomFrontLeft, DEG2RAD(-45.0f), DEG2RAD( -45.0f) }, - { BottomFrontRight, DEG2RAD(-45.0f), DEG2RAD( 45.0f) }, - { BottomBackLeft, DEG2RAD(-45.0f), DEG2RAD(-135.0f) }, - { BottomBackRight, DEG2RAD(-45.0f), DEG2RAD( 135.0f) }, - }; ALuint i; - count = COUNTOF(Cube8); - chanmap = Cube8; + count = COUNTOF(BFormat3D); + chanmap = BFormat3D; for(i = 0;i < count;i++) - device->ChannelName[i] = VirtualChans[i].channel; + 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++) - GetLerpedHrtfCoeffs( - device->Hrtf, VirtualChans[i].elevation, VirtualChans[i].angle, 1.0f, 1.0f, + { + GetBFormatHrtfCoeffs(device->Hrtf, chanmap[i].Config.FOACoeff, device->Hrtf_Params[i].Coeffs, device->Hrtf_Params[i].Delay ); + } return; } |