Load HRTF files as needed
Currently only applies to external files, rather than embedded datasets. Also, HRTFs aren't unloaded after being loaded, until library shutdown.
This commit is contained in:
@@ -2049,6 +2049,7 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
|
||||
if(hrtf_userreq == Hrtf_Enable || (hrtf_userreq != Hrtf_Disable && hrtf_appreq == Hrtf_Enable))
|
||||
{
|
||||
const struct Hrtf *hrtf = NULL;
|
||||
if(VECTOR_SIZE(device->HrtfList) == 0)
|
||||
{
|
||||
VECTOR_DEINIT(device->HrtfList);
|
||||
@@ -2056,9 +2057,14 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
}
|
||||
if(VECTOR_SIZE(device->HrtfList) > 0)
|
||||
{
|
||||
const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, 0).hrtf->handle;
|
||||
if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList))
|
||||
hrtf = VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf->handle;
|
||||
hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, hrtf_id).hrtf);
|
||||
else
|
||||
hrtf = GetLoadedHrtf(VECTOR_ELEM(device->HrtfList, 0).hrtf);
|
||||
}
|
||||
|
||||
if(hrtf)
|
||||
{
|
||||
device->FmtChans = DevFmtStereo;
|
||||
device->Frequency = hrtf->sampleRate;
|
||||
device->Flags |= DEVICE_CHANNELS_REQUEST | DEVICE_FREQUENCY_REQUEST;
|
||||
@@ -2071,36 +2077,6 @@ static ALCenum UpdateDeviceParams(ALCdevice *device, const ALCint *attrList)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(hrtf_appreq == Hrtf_Enable)
|
||||
{
|
||||
size_t i = VECTOR_SIZE(device->HrtfList);
|
||||
/* Loopback device. We don't need to match to a specific HRTF entry
|
||||
* here. If the requested ID matches, we'll pick that later, if not,
|
||||
* we'll try to auto-select one anyway. Just make sure one exists
|
||||
* that'll work.
|
||||
*/
|
||||
if(device->FmtChans == DevFmtStereo)
|
||||
{
|
||||
if(VECTOR_SIZE(device->HrtfList) == 0)
|
||||
{
|
||||
VECTOR_DEINIT(device->HrtfList);
|
||||
device->HrtfList = EnumerateHrtf(device->DeviceName);
|
||||
}
|
||||
for(i = 0;i < VECTOR_SIZE(device->HrtfList);i++)
|
||||
{
|
||||
const struct Hrtf *hrtf = VECTOR_ELEM(device->HrtfList, i).hrtf->handle;
|
||||
if(hrtf->sampleRate == device->Frequency)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i == VECTOR_SIZE(device->HrtfList))
|
||||
{
|
||||
ERR("Requested format not HRTF compatible: %s, %uhz\n",
|
||||
DevFmtChannelsString(device->FmtChans), device->Frequency);
|
||||
hrtf_appreq = Hrtf_Disable;
|
||||
device->HrtfStatus = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
|
||||
}
|
||||
}
|
||||
|
||||
oldFreq = device->Frequency;
|
||||
oldChans = device->FmtChans;
|
||||
|
||||
+81
-59
@@ -46,6 +46,12 @@
|
||||
#define MIN_AZ_COUNT (1)
|
||||
#define MAX_AZ_COUNT (128)
|
||||
|
||||
struct HrtfEntry {
|
||||
struct HrtfEntry *next;
|
||||
struct Hrtf *handle;
|
||||
char filename[];
|
||||
};
|
||||
|
||||
static const ALchar magicMarker00[8] = "MinPHR00";
|
||||
static const ALchar magicMarker01[8] = "MinPHR01";
|
||||
|
||||
@@ -240,7 +246,7 @@ ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsize
|
||||
static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount,
|
||||
const ALubyte *azCount, const ALushort *evOffset,
|
||||
const ALshort *coeffs, const ALubyte *delays,
|
||||
const_al_string filename)
|
||||
const char *filename)
|
||||
{
|
||||
struct Hrtf *Hrtf;
|
||||
size_t total;
|
||||
@@ -255,7 +261,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount
|
||||
|
||||
Hrtf = al_calloc(16, total);
|
||||
if(Hrtf == NULL)
|
||||
ERR("Out of memory allocating storage for %s.\n", alstr_get_cstr(filename));
|
||||
ERR("Out of memory allocating storage for %s.\n", filename);
|
||||
else
|
||||
{
|
||||
uintptr_t offset = sizeof(struct Hrtf);
|
||||
@@ -298,7 +304,7 @@ static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount
|
||||
return Hrtf;
|
||||
}
|
||||
|
||||
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename)
|
||||
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename)
|
||||
{
|
||||
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
||||
struct Hrtf *Hrtf = NULL;
|
||||
@@ -314,8 +320,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
|
||||
|
||||
if(datalen < 9)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
|
||||
alstr_get_cstr(filename), 9, datalen);
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, 9, datalen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -353,8 +358,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
|
||||
|
||||
if(datalen < evCount*2)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
|
||||
alstr_get_cstr(filename), evCount*2, datalen);
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -423,7 +427,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
|
||||
if(datalen < reqsize)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n",
|
||||
alstr_get_cstr(filename), reqsize, datalen);
|
||||
filename, reqsize, datalen);
|
||||
failed = AL_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -463,7 +467,7 @@ static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_str
|
||||
return Hrtf;
|
||||
}
|
||||
|
||||
static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename)
|
||||
static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename)
|
||||
{
|
||||
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
||||
struct Hrtf *Hrtf = NULL;
|
||||
@@ -478,8 +482,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str
|
||||
|
||||
if(datalen < 6)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
|
||||
alstr_get_cstr(filename), 6, datalen);
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 6, datalen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -512,8 +515,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str
|
||||
|
||||
if(datalen < evCount)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
|
||||
alstr_get_cstr(filename), evCount, datalen);
|
||||
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -565,7 +567,7 @@ static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_str
|
||||
if(datalen < reqsize)
|
||||
{
|
||||
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
|
||||
alstr_get_cstr(filename), reqsize, datalen);
|
||||
filename, reqsize, datalen);
|
||||
failed = AL_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -610,9 +612,7 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename)
|
||||
{
|
||||
EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
|
||||
struct HrtfEntry *loaded_entry;
|
||||
struct Hrtf *hrtf = NULL;
|
||||
const EnumeratedHrtf *iter;
|
||||
struct FileMapping fmap;
|
||||
const char *name;
|
||||
const char *ext;
|
||||
int i;
|
||||
@@ -639,51 +639,14 @@ static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename)
|
||||
loaded_entry = loaded_entry->next;
|
||||
}
|
||||
|
||||
TRACE("Loading %s...\n", alstr_get_cstr(filename));
|
||||
fmap = MapFileToMem(alstr_get_cstr(filename));
|
||||
if(fmap.ptr == NULL)
|
||||
{
|
||||
ERR("Could not open %s\n", alstr_get_cstr(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
if(fmap.len < sizeof(magicMarker01))
|
||||
ERR("%s data is too short ("SZFMT" bytes)\n", alstr_get_cstr(filename), fmap.len);
|
||||
else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v1\n");
|
||||
hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01),
|
||||
fmap.len-sizeof(magicMarker01), filename
|
||||
);
|
||||
}
|
||||
else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v0\n");
|
||||
hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00),
|
||||
fmap.len-sizeof(magicMarker00), filename
|
||||
);
|
||||
}
|
||||
else
|
||||
ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)fmap.ptr);
|
||||
UnmapFileMem(&fmap);
|
||||
|
||||
if(!hrtf)
|
||||
{
|
||||
ERR("Failed to load %s\n", alstr_get_cstr(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
loaded_entry = al_calloc(DEF_ALIGN,
|
||||
offsetof(struct HrtfEntry, filename[alstr_length(filename)+1])
|
||||
);
|
||||
loaded_entry->next = LoadedHrtfs;
|
||||
loaded_entry->handle = hrtf;
|
||||
loaded_entry->handle = NULL;
|
||||
strcpy(loaded_entry->filename, alstr_get_cstr(filename));
|
||||
LoadedHrtfs = loaded_entry;
|
||||
|
||||
TRACE("Loaded HRTF support for format: %s %uhz\n",
|
||||
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
|
||||
|
||||
skip_load:
|
||||
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
|
||||
* format update). */
|
||||
@@ -762,19 +725,19 @@ static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const ALubyte *data, si
|
||||
if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v1\n");
|
||||
hrtf = LoadHrtf01(data+sizeof(magicMarker01),
|
||||
datalen-sizeof(magicMarker01), filename
|
||||
hrtf = LoadHrtf01((const ALubyte*)data+sizeof(magicMarker01),
|
||||
datalen-sizeof(magicMarker01), alstr_get_cstr(filename)
|
||||
);
|
||||
}
|
||||
else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v0\n");
|
||||
hrtf = LoadHrtf00(data+sizeof(magicMarker00),
|
||||
datalen-sizeof(magicMarker00), filename
|
||||
hrtf = LoadHrtf00((const ALubyte*)data+sizeof(magicMarker00),
|
||||
datalen-sizeof(magicMarker00), alstr_get_cstr(filename)
|
||||
);
|
||||
}
|
||||
else
|
||||
ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), data);
|
||||
ERR("Invalid header in %s: \"%.8s\"\n", alstr_get_cstr(filename), (const char*)data);
|
||||
|
||||
if(!hrtf)
|
||||
{
|
||||
@@ -1032,6 +995,65 @@ void FreeHrtfList(vector_EnumeratedHrtf *list)
|
||||
#undef CLEAR_ENTRY
|
||||
}
|
||||
|
||||
struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
|
||||
{
|
||||
static ATOMIC_FLAG LoadLock = ATOMIC_FLAG_INIT;
|
||||
struct Hrtf *hrtf = NULL;
|
||||
struct FileMapping fmap;
|
||||
|
||||
while(ATOMIC_FLAG_TEST_AND_SET(&LoadLock, almemory_order_seq_cst))
|
||||
althrd_yield();
|
||||
|
||||
if(entry->handle)
|
||||
{
|
||||
hrtf = entry->handle;
|
||||
goto done;
|
||||
}
|
||||
|
||||
TRACE("Loading %s...\n", entry->filename);
|
||||
fmap = MapFileToMem(entry->filename);
|
||||
if(fmap.ptr == NULL)
|
||||
{
|
||||
ERR("Could not open %s\n", entry->filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if(fmap.len < sizeof(magicMarker01))
|
||||
ERR("%s data is too short ("SZFMT" bytes)\n", entry->filename, fmap.len);
|
||||
else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v1\n");
|
||||
hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01),
|
||||
fmap.len-sizeof(magicMarker01), entry->filename
|
||||
);
|
||||
}
|
||||
else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0)
|
||||
{
|
||||
TRACE("Detected data set format v0\n");
|
||||
hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00),
|
||||
fmap.len-sizeof(magicMarker00), entry->filename
|
||||
);
|
||||
}
|
||||
else
|
||||
ERR("Invalid header in %s: \"%.8s\"\n", entry->filename, (const char*)fmap.ptr);
|
||||
UnmapFileMem(&fmap);
|
||||
|
||||
if(!hrtf)
|
||||
{
|
||||
ERR("Failed to load %s\n", entry->filename);
|
||||
goto done;
|
||||
}
|
||||
|
||||
TRACE("Loaded HRTF support for format: %s %uhz\n",
|
||||
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
|
||||
|
||||
entry->handle = hrtf;
|
||||
|
||||
done:
|
||||
ATOMIC_FLAG_CLEAR(&LoadLock, almemory_order_seq_cst);
|
||||
return hrtf;
|
||||
}
|
||||
|
||||
|
||||
void FreeHrtfs(void)
|
||||
{
|
||||
|
||||
+3
-6
@@ -18,6 +18,8 @@
|
||||
#define HRTF_AMBI_MAX_CHANNELS 16
|
||||
|
||||
|
||||
struct HrtfEntry;
|
||||
|
||||
struct Hrtf {
|
||||
ALuint sampleRate;
|
||||
ALsizei irSize;
|
||||
@@ -29,17 +31,12 @@ struct Hrtf {
|
||||
const ALubyte *delays;
|
||||
};
|
||||
|
||||
struct HrtfEntry {
|
||||
struct HrtfEntry *next;
|
||||
struct Hrtf *handle;
|
||||
char filename[];
|
||||
};
|
||||
|
||||
|
||||
void FreeHrtfs(void);
|
||||
|
||||
vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname);
|
||||
void FreeHrtfList(vector_EnumeratedHrtf *list);
|
||||
struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry);
|
||||
|
||||
void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays);
|
||||
|
||||
|
||||
+4
-4
@@ -1151,8 +1151,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
|
||||
if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->HrtfList))
|
||||
{
|
||||
const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, hrtf_id);
|
||||
const struct Hrtf *hrtf = entry->hrtf->handle;
|
||||
if(hrtf->sampleRate == device->Frequency)
|
||||
const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf);
|
||||
if(hrtf && hrtf->sampleRate == device->Frequency)
|
||||
{
|
||||
device->HrtfHandle = hrtf;
|
||||
alstr_copy(&device->HrtfName, entry->name);
|
||||
@@ -1162,8 +1162,8 @@ void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf
|
||||
for(i = 0;!device->HrtfHandle && i < VECTOR_SIZE(device->HrtfList);i++)
|
||||
{
|
||||
const EnumeratedHrtf *entry = &VECTOR_ELEM(device->HrtfList, i);
|
||||
const struct Hrtf *hrtf = entry->hrtf->handle;
|
||||
if(hrtf->sampleRate == device->Frequency)
|
||||
const struct Hrtf *hrtf = GetLoadedHrtf(entry->hrtf);
|
||||
if(hrtf && hrtf->sampleRate == device->Frequency)
|
||||
{
|
||||
device->HrtfHandle = hrtf;
|
||||
alstr_copy(&device->HrtfName, entry->name);
|
||||
|
||||
@@ -637,7 +637,7 @@ typedef struct DirectHrtfState {
|
||||
typedef struct EnumeratedHrtf {
|
||||
al_string name;
|
||||
|
||||
const struct HrtfEntry *hrtf;
|
||||
struct HrtfEntry *hrtf;
|
||||
} EnumeratedHrtf;
|
||||
TYPEDEF_VECTOR(EnumeratedHrtf, vector_EnumeratedHrtf)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user