diff options
author | Chris Robinson <[email protected]> | 2011-06-03 01:06:00 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2011-06-03 01:06:00 -0700 |
commit | 7ddfacb58f941b21da26b2749d3204307e3a0bbd (patch) | |
tree | 2cb41f7de025705f38a634781e6413c7c004829e | |
parent | c7a80418d9291cad29dc293b95a5c328f4408b08 (diff) |
Use a minimum phase HRTF data set
This reduces the coefficient size from 128 down to 32, with a set of delays
-rw-r--r-- | Alc/ALc.c | 2 | ||||
-rw-r--r-- | Alc/ALu.c | 20 | ||||
-rw-r--r-- | Alc/hrtf.c | 131 | ||||
-rw-r--r-- | Alc/mixer.c | 72 | ||||
-rw-r--r-- | OpenAL32/Include/alMain.h | 9 | ||||
-rw-r--r-- | OpenAL32/Include/alSource.h | 14 | ||||
-rw-r--r-- | OpenAL32/alSource.c | 7 |
7 files changed, 162 insertions, 93 deletions
@@ -496,6 +496,8 @@ static void alc_init(void) ALTHUNK_INIT(); ReadALConfig(); + InitHrtf(); + tls_create(&LocalContext); RTPrioLevel = GetConfigValueInt(NULL, "rt-prio", 0); @@ -245,7 +245,9 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) if(c == lfe_chan) { /* Skip LFE */ - for(i = 0;i < HRTF_LENGTH;i++) + ALSource->Params.HrtfDelay[c][0] = 0; + ALSource->Params.HrtfDelay[c][1] = 0; + for(i = 0;i < HRIR_LENGTH;i++) { ALSource->Params.HrtfCoeffs[c][i][0] = 0.0f; ALSource->Params.HrtfCoeffs[c][i][1] = 0.0f; @@ -253,8 +255,11 @@ ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext) continue; } - GetHrtfCoeffs(0.0, angles[c], &hrtf_left, &hrtf_right); - for(i = 0;i < HRTF_LENGTH;i++) + 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; @@ -676,10 +681,11 @@ ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext) Position[2] *= invlen; } - GetHrtfCoeffs(asin(Position[1]) * (180.0/M_PI), - atan2(Position[0], -Position[2]*ZScale) * (180.0/M_PI), - &hrtf_left, &hrtf_right); - for(i = 0;i < HRTF_LENGTH;i++) + 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; @@ -23,56 +23,99 @@ #include "AL/al.h" #include "AL/alc.h" #include "alMain.h" +#include "alSource.h" +#define HRIR_COUNT 828 -typedef struct { - ALsizei num_angles; - ALsizei max_angle; - ALshort coeffs[][2][HRTF_LENGTH]; -} HrtfFilterCoeffs; +static const ALubyte evCount = 19; +static const ALushort evOffset[19] = { 0, 1, 13, 37, 73, 118, 174, 234, 306, 378, 450, 522, 594, 654, 710, 755, 791, 815, 827 }; +static const ALubyte azCount[19] = { 1, 12, 24, 36, 45, 56, 60, 72, 72, 72, 72, 72, 60, 56, 45, 36, 24, 12, 1 }; -#include "hrtf_tables.inc" +static struct HRTF { + ALshort coeffs[HRIR_COUNT][HRIR_LENGTH]; + ALubyte delays[HRIR_COUNT]; +} Hrtf; -static void get_angle_coeffs(const HrtfFilterCoeffs *elev, ALfloat angle, const ALshort **left, const ALshort **right) +static ALuint CalcEvIndex(ALdouble ev) { - if(angle < 0) - { - int idx = ((angle > -elev->max_angle) ? - (int)(angle*(elev->num_angles-1)/-elev->max_angle + 0.5) : - (elev->num_angles-1)); - *left = elev->coeffs[idx][1]; - *right = elev->coeffs[idx][0]; - } - else - { - int idx = ((angle < elev->max_angle) ? - (int)(angle*(elev->num_angles-1)/elev->max_angle + 0.5) : - (elev->num_angles-1)); - *left = elev->coeffs[idx][0]; - *right = elev->coeffs[idx][1]; - } + ev = (M_PI/2.0 + ev) * (evCount-1) / M_PI; + return (ALuint)(ev+0.5); +} + +static ALuint CalcAzIndex(ALint evidx, ALdouble az) +{ + az = (M_PI*2.0 + az) * azCount[evidx] / (M_PI*2.0); + return (ALuint)(az+0.5) % azCount[evidx]; } -void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right) +void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right, ALuint *ldelay, ALuint *rdelay) { - int idx; - - if(elevation > 90.f) elevation = 90.f - (elevation - 90.f); - else if(elevation < -90.f) elevation = -90.f - (elevation - -90.f); - - idx = (int)(elevation/10.0 + 0.5); - if(idx >= 9) return get_angle_coeffs(&Elev90, angle, left, right); - if(idx >= 8) return get_angle_coeffs(&Elev80, angle, left, right); - if(idx >= 7) return get_angle_coeffs(&Elev70, angle, left, right); - if(idx >= 6) return get_angle_coeffs(&Elev60, angle, left, right); - if(idx >= 5) return get_angle_coeffs(&Elev50, angle, left, right); - if(idx >= 4) return get_angle_coeffs(&Elev40, angle, left, right); - if(idx >= 3) return get_angle_coeffs(&Elev30, angle, left, right); - if(idx >= 2) return get_angle_coeffs(&Elev20, angle, left, right); - if(idx >= 1) return get_angle_coeffs(&Elev10, angle, left, right); - if(idx >= 0) return get_angle_coeffs(&Elev0, angle, left, right); - if(idx >= -1) return get_angle_coeffs(&Elev10n, angle, left, right); - if(idx >= -2) return get_angle_coeffs(&Elev20n, angle, left, right); - if(idx >= -3) return get_angle_coeffs(&Elev30n, angle, left, right); - return get_angle_coeffs(&Elev40n, angle, left, right); + ALuint lidx, ridx; + ALuint evidx, azidx; + + evidx = CalcEvIndex(elevation); + azidx = CalcAzIndex(evidx, angle); + + lidx = evOffset[evidx] + azidx; + ridx = evOffset[evidx] + ((azCount[evidx]-azidx) % azCount[evidx]); + + *ldelay = Hrtf.delays[lidx]; + *rdelay = Hrtf.delays[ridx]; + + *left = Hrtf.coeffs[lidx]; + *right = Hrtf.coeffs[ridx]; +} + +void InitHrtf(void) +{ + const char *str; + FILE *f = NULL; + + str = GetConfigValue(NULL, "hrtf_tables", ""); + if(str[0] != '\0') + f = fopen(str, "rb"); + if(f != NULL) + { + const ALubyte maxDelay = SRC_HISTORY_LENGTH - HRIR_LENGTH; + struct HRTF newdata; + size_t i, j; + union { + ALfloat f; + ALubyte ub[4]; + } val; + + for(i = 0;i < HRIR_COUNT;i++) + { + for(j = 0;j < HRIR_LENGTH;j++) + { + val.ub[0] = fgetc(f); + val.ub[1] = fgetc(f); + val.ub[2] = fgetc(f); + val.ub[3] = fgetc(f); + if(val.f > 1.0f) newdata.coeffs[i][j] = 32767; + else if(val.f < -1.0f) newdata.coeffs[i][j] = -32768; + else newdata.coeffs[i][j] = (ALshort)(val.f*32767.0f); + } + } + val.ub[0] = fgetc(f); + val.ub[1] = fgetc(f); + val.ub[2] = fgetc(f); + val.ub[3] = fgetc(f); + /* skip maxHrtd */ + for(i = 0;i < HRIR_COUNT;i++) + { + val.ub[0] = fgetc(f); + val.ub[1] = fgetc(f); + val.ub[2] = fgetc(f); + val.ub[3] = fgetc(f); + val.f *= 44100.0f; + if(val.f >= maxDelay) newdata.delays[i] = maxDelay; + else newdata.delays[i] = (ALubyte)val.f; + } + if(!feof(f)) + Hrtf = newdata; + + fclose(f); + f = NULL; + } } diff --git a/Alc/mixer.c b/Alc/mixer.c index 33181890..9a746ff9 100644 --- a/Alc/mixer.c +++ b/Alc/mixer.c @@ -79,9 +79,6 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \ const T *RESTRICT data = srcdata; \ ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS]; \ ALfloat *RESTRICT ClickRemoval, *RESTRICT PendingClicks; \ - ALfloat (*RESTRICT HrtfCoeffs)[HRTF_LENGTH][2]; \ - ALfloat (*RESTRICT HrtfHistory)[HRTF_LENGTH]; \ - ALuint HrtfOffset; \ ALuint pos, frac; \ FILTER *DryFilter; \ ALuint BufferIdx; \ @@ -96,15 +93,17 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \ PendingClicks = Device->PendingClicks; \ DryFilter = &Source->Params.iirFilter; \ \ - HrtfCoeffs = Source->Params.HrtfCoeffs; \ - HrtfHistory = Source->HrtfHistory; \ - HrtfOffset = Source->HrtfOffset + OutPos; \ - \ pos = 0; \ frac = *DataPosFrac; \ \ for(i = 0;i < NumChannels;i++) \ { \ + static const ALuint MaxDelay = SRC_HISTORY_LENGTH - HRIR_LENGTH; \ + ALfloat (*RESTRICT Coeffs)[2] = Source->Params.HrtfCoeffs[i]; \ + const ALuint *RESTRICT Delay = Source->Params.HrtfDelay[i]; \ + ALfloat (*RESTRICT History)[2] = Source->HrtfHistory[i]; \ + ALuint Offset = Source->HrtfOffset + OutPos; \ + \ pos = 0; \ frac = *DataPosFrac; \ \ @@ -113,15 +112,18 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \ value = sampler(data + pos*NumChannels + i, NumChannels, frac); \ value = lpFilter2PC(DryFilter, i, value); \ \ - HrtfHistory[i][HrtfOffset&HRTF_LENGTH_MASK] = value; \ - for(c = 0;c < HRTF_LENGTH;c++) \ + History[Offset&SRC_HISTORY_MASK][0] = value; \ + History[Offset&SRC_HISTORY_MASK][1] = value; \ + \ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][0] = \ + History[(Offset-Delay[0])&SRC_HISTORY_MASK][0];\ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][1] = \ + History[(Offset-Delay[1])&SRC_HISTORY_MASK][1];\ + for(c = 0;c < HRIR_LENGTH;c++) \ { \ - ClickRemoval[FRONT_LEFT] -= \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][0]; \ - ClickRemoval[FRONT_RIGHT] -= \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][1]; \ + const ALuint off = (Offset-MaxDelay-c)&SRC_HISTORY_MASK; \ + ClickRemoval[FRONT_LEFT] -= History[off][0] * Coeffs[c][0]; \ + ClickRemoval[FRONT_RIGHT] -= History[off][1] * Coeffs[c][1]; \ } \ } \ for(BufferIdx = 0;BufferIdx < BufferSize;BufferIdx++) \ @@ -129,17 +131,20 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \ value = sampler(data + pos*NumChannels + i, NumChannels, frac); \ value = lpFilter2P(DryFilter, i, value); \ \ - HrtfHistory[i][HrtfOffset&HRTF_LENGTH_MASK] = value; \ - for(c = 0;c < HRTF_LENGTH;c++) \ + History[Offset&SRC_HISTORY_MASK][0] = value; \ + History[Offset&SRC_HISTORY_MASK][1] = value; \ + \ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][0] = \ + History[(Offset-Delay[0])&SRC_HISTORY_MASK][0];\ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][1] = \ + History[(Offset-Delay[1])&SRC_HISTORY_MASK][1];\ + for(c = 0;c < HRIR_LENGTH;c++) \ { \ - DryBuffer[OutPos][FRONT_LEFT] += \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][0]; \ - DryBuffer[OutPos][FRONT_RIGHT] += \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][1]; \ + const ALuint off = (Offset-MaxDelay-c)&SRC_HISTORY_MASK; \ + DryBuffer[OutPos][FRONT_LEFT] += History[off][0] * Coeffs[c][0];\ + DryBuffer[OutPos][FRONT_RIGHT] += History[off][1] * Coeffs[c][1];\ } \ - HrtfOffset++; \ + Offset++; \ \ frac += increment; \ pos += frac>>FRACTIONBITS; \ @@ -151,15 +156,18 @@ static void Mix_Hrtf_##T##_##sampler(ALsource *Source, ALCdevice *Device, \ value = sampler(data + pos*NumChannels + i, NumChannels, frac); \ value = lpFilter2PC(DryFilter, i, value); \ \ - HrtfHistory[i][HrtfOffset&HRTF_LENGTH_MASK] = value; \ - for(c = 0;c < HRTF_LENGTH;c++) \ + History[Offset&SRC_HISTORY_MASK][0] = value; \ + History[Offset&SRC_HISTORY_MASK][1] = value; \ + \ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][0] = \ + History[(Offset-Delay[0])&SRC_HISTORY_MASK][0];\ + History[(Offset-MaxDelay)&SRC_HISTORY_MASK][1] = \ + History[(Offset-Delay[1])&SRC_HISTORY_MASK][1];\ + for(c = 0;c < HRIR_LENGTH;c++) \ { \ - PendingClicks[FRONT_LEFT] += \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][0]; \ - PendingClicks[FRONT_RIGHT] += \ - HrtfHistory[i][(HrtfOffset-c)&HRTF_LENGTH_MASK] * \ - HrtfCoeffs[i][c][1]; \ + const ALuint off = (Offset-MaxDelay-c)&SRC_HISTORY_MASK; \ + PendingClicks[FRONT_LEFT] += History[off][0] * Coeffs[c][0]; \ + PendingClicks[FRONT_RIGHT] += History[off][1] * Coeffs[c][1]; \ } \ } \ OutPos -= BufferSize; \ diff --git a/OpenAL32/Include/alMain.h b/OpenAL32/Include/alMain.h index b6986a07..8df5a4b9 100644 --- a/OpenAL32/Include/alMain.h +++ b/OpenAL32/Include/alMain.h @@ -567,10 +567,11 @@ const ALCchar *DevFmtChannelsString(enum DevFmtChannels chans); ALboolean IsValidType(ALenum type); ALboolean IsValidChannels(ALenum type); -#define HRTF_BITS (7) -#define HRTF_LENGTH (1<<HRTF_BITS) -#define HRTF_LENGTH_MASK (HRTF_LENGTH-1) -void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right); +#define HRIR_BITS (5) +#define HRIR_LENGTH (1<<HRIR_BITS) +#define HRIR_LENGTH_MASK (HRIR_LENGTH-1) +void InitHrtf(void); +void GetHrtfCoeffs(ALfloat elevation, ALfloat angle, const ALshort **left, const ALshort **right, ALuint *ldelay, ALuint *rdelay); void al_print(const char *fname, unsigned int line, const char *fmt, ...) PRINTF_STYLE(3,4); diff --git a/OpenAL32/Include/alSource.h b/OpenAL32/Include/alSource.h index 53d7f53c..0572cbc1 100644 --- a/OpenAL32/Include/alSource.h +++ b/OpenAL32/Include/alSource.h @@ -11,6 +11,10 @@ extern "C" { #endif +#define SRC_HISTORY_BITS (7) +#define SRC_HISTORY_LENGTH (1<<SRC_HISTORY_BITS) +#define SRC_HISTORY_MASK (SRC_HISTORY_LENGTH-1) + typedef enum { POINT_RESAMPLER = 0, LINEAR_RESAMPLER, @@ -90,20 +94,21 @@ typedef struct ALsource ALuint SampleSize; /* HRTF info */ - ALfloat HrtfHistory[MAXCHANNELS][HRTF_LENGTH]; + ALfloat HrtfHistory[MAXCHANNELS][SRC_HISTORY_LENGTH][2]; ALuint HrtfOffset; - // Current target parameters used for mixing - ALboolean NeedsUpdate; + /* Current target parameters used for mixing */ struct { ALint Step; - ALfloat HrtfCoeffs[MAXCHANNELS][HRTF_LENGTH][2]; + ALfloat HrtfCoeffs[MAXCHANNELS][HRIR_LENGTH][2]; + ALuint HrtfDelay[MAXCHANNELS][2]; /* A mixing matrix. First subscript is the channel number of the input * data (regardless of channel configuration) and the second is the * channel target (eg. FRONT_LEFT) */ ALfloat DryGains[MAXCHANNELS][MAXCHANNELS]; + FILTER iirFilter; ALfloat history[MAXCHANNELS*2]; @@ -113,6 +118,7 @@ typedef struct ALsource ALfloat history[MAXCHANNELS]; } Send[MAX_SENDS]; } Params; + ALboolean NeedsUpdate; ALvoid (*Update)(struct ALsource *self, const ALCcontext *context); ALvoid (*DoMix)(struct ALsource *self, ALCdevice *Device, diff --git a/OpenAL32/alSource.c b/OpenAL32/alSource.c index 6c6bf44b..7dc4a2a9 100644 --- a/OpenAL32/alSource.c +++ b/OpenAL32/alSource.c @@ -1355,8 +1355,11 @@ AL_API ALvoid AL_APIENTRY alSourcePlayv(ALsizei n, const ALuint *sources) for(j = 0;j < MAXCHANNELS;j++) { ALuint k; - for(k = 0;k < HRTF_LENGTH;k++) - Source->HrtfHistory[j][k] = 0.0f; + for(k = 0;k < SRC_HISTORY_LENGTH;k++) + { + Source->HrtfHistory[j][k][0] = 0.0f; + Source->HrtfHistory[j][k][1] = 0.0f; + } } Source->HrtfOffset = 0; } |