Combine some HRTF loading code
[openal-soft.git] / Alc / hrtf.c
bloba086c1a3009c32a5a694b220710ddc9bf471dd85
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2011 by Chris Robinson
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <ctype.h>
26 #include "AL/al.h"
27 #include "AL/alc.h"
28 #include "alMain.h"
29 #include "alSource.h"
30 #include "alu.h"
31 #include "bformatdec.h"
32 #include "hrtf.h"
34 #include "compat.h"
35 #include "almalloc.h"
38 /* Current data set limits defined by the makehrtf utility. */
39 #define MIN_IR_SIZE (8)
40 #define MAX_IR_SIZE (128)
41 #define MOD_IR_SIZE (8)
43 #define MIN_EV_COUNT (5)
44 #define MAX_EV_COUNT (128)
46 #define MIN_AZ_COUNT (1)
47 #define MAX_AZ_COUNT (128)
49 static const ALchar magicMarker00[8] = "MinPHR00";
50 static const ALchar magicMarker01[8] = "MinPHR01";
52 /* First value for pass-through coefficients (remaining are 0), used for omni-
53 * directional sounds. */
54 static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/;
56 static struct Hrtf *LoadedHrtfs = NULL;
59 /* Calculate the elevation index given the polar elevation in radians. This
60 * will return an index between 0 and (evcount - 1). Assumes the FPU is in
61 * round-to-zero mode.
63 static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev)
65 ev = (F_PI_2 + ev) * (evcount-1) / F_PI;
66 return mini(fastf2i(ev + 0.5f), evcount-1);
69 /* Calculate the azimuth index given the polar azimuth in radians. This will
70 * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to-
71 * zero mode.
73 static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az)
75 az = (F_TAU + az) * azcount / F_TAU;
76 return fastf2i(az + 0.5f) % azcount;
79 /* Calculates static HRIR coefficients and delays for the given polar elevation
80 * and azimuth in radians. The coefficients are normalized.
82 void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays)
84 ALsizei evidx, azidx, lidx, ridx;
85 ALsizei azcount, evoffset;
86 ALfloat dirfact;
87 ALsizei i;
89 dirfact = 1.0f - (spread / F_TAU);
91 /* Claculate elevation index. */
92 evidx = CalcEvIndex(Hrtf->evCount, elevation);
93 azcount = Hrtf->azCount[evidx];
94 evoffset = Hrtf->evOffset[evidx];
96 /* Calculate azimuth index. */
97 azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth);
99 /* Calculate the HRIR indices for left and right channels. */
100 lidx = evoffset + azidx;
101 ridx = evoffset + ((azcount-azidx) % azcount);
103 /* Calculate the HRIR delays. */
104 delays[0] = fastf2i(Hrtf->delays[lidx]*dirfact + 0.5f);
105 delays[1] = fastf2i(Hrtf->delays[ridx]*dirfact + 0.5f);
107 /* Calculate the sample offsets for the HRIR indices. */
108 lidx *= Hrtf->irSize;
109 ridx *= Hrtf->irSize;
111 /* Calculate the normalized and attenuated HRIR coefficients. */
112 i = 0;
113 coeffs[i][0] = lerp(PassthruCoeff, Hrtf->coeffs[lidx+i], dirfact) * (1.0f/32767.0f);
114 coeffs[i][1] = lerp(PassthruCoeff, Hrtf->coeffs[ridx+i], dirfact) * (1.0f/32767.0f);
115 for(i = 1;i < Hrtf->irSize;i++)
117 coeffs[i][0] = Hrtf->coeffs[lidx+i]*(1.0f/32767.0f) * dirfact;
118 coeffs[i][1] = Hrtf->coeffs[ridx+i]*(1.0f/32767.0f) * dirfact;
123 ALsizei BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount)
125 /* Set this to 2 for dual-band HRTF processing. May require a higher quality
126 * band-splitter, or better calculation of the new IR length to deal with the
127 * tail generated by the filter.
129 #define NUM_BANDS 2
130 BandSplitter splitter;
131 ALsizei lidx[HRTF_AMBI_MAX_CHANNELS], ridx[HRTF_AMBI_MAX_CHANNELS];
132 ALsizei min_delay = HRTF_HISTORY_LENGTH;
133 ALfloat temps[3][HRIR_LENGTH];
134 ALsizei max_length = 0;
135 ALsizei i, j, c, b;
137 for(c = 0;c < AmbiCount;c++)
139 ALuint evidx, azidx;
140 ALuint evoffset;
141 ALuint azcount;
143 /* Calculate elevation index. */
144 evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) *
145 (Hrtf->evCount-1)/F_PI + 0.5f);
146 evidx = mini(evidx, Hrtf->evCount-1);
148 azcount = Hrtf->azCount[evidx];
149 evoffset = Hrtf->evOffset[evidx];
151 /* Calculate azimuth index for this elevation. */
152 azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) *
153 azcount/F_TAU + 0.5f) % azcount;
155 /* Calculate indices for left and right channels. */
156 lidx[c] = evoffset + azidx;
157 ridx[c] = evoffset + ((azcount-azidx) % azcount);
159 min_delay = mini(min_delay, mini(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[c]]));
162 memset(temps, 0, sizeof(temps));
163 bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate);
164 for(c = 0;c < AmbiCount;c++)
166 const ALshort *fir;
167 ALsizei delay;
169 /* Convert the left FIR from shorts to float */
170 fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize];
171 if(NUM_BANDS == 1)
173 for(i = 0;i < Hrtf->irSize;i++)
174 temps[0][i] = fir[i] / 32767.0f;
176 else
178 /* Band-split left HRIR into low and high frequency responses. */
179 bandsplit_clear(&splitter);
180 for(i = 0;i < Hrtf->irSize;i++)
181 temps[2][i] = fir[i] / 32767.0f;
182 bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
185 /* Add to the left output coefficients with the specified delay. */
186 delay = Hrtf->delays[lidx[c]] - min_delay;
187 for(i = 0;i < NumChannels;++i)
189 for(b = 0;b < NUM_BANDS;b++)
191 ALsizei k = 0;
192 for(j = delay;j < HRIR_LENGTH;++j)
193 state->Chan[i].Coeffs[j][0] += temps[b][k++] * AmbiMatrix[c][b][i];
196 max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH));
198 /* Convert the right FIR from shorts to float */
199 fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize];
200 if(NUM_BANDS == 1)
202 for(i = 0;i < Hrtf->irSize;i++)
203 temps[0][i] = fir[i] / 32767.0f;
205 else
207 /* Band-split right HRIR into low and high frequency responses. */
208 bandsplit_clear(&splitter);
209 for(i = 0;i < Hrtf->irSize;i++)
210 temps[2][i] = fir[i] / 32767.0f;
211 bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
214 /* Add to the right output coefficients with the specified delay. */
215 delay = Hrtf->delays[ridx[c]] - min_delay;
216 for(i = 0;i < NumChannels;++i)
218 for(b = 0;b < NUM_BANDS;b++)
220 ALuint k = 0;
221 for(j = delay;j < HRIR_LENGTH;++j)
222 state->Chan[i].Coeffs[j][1] += temps[b][k++] * AmbiMatrix[c][b][i];
225 max_length = maxi(max_length, mini(delay + Hrtf->irSize, HRIR_LENGTH));
227 TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
229 return max_length;
230 #undef NUM_BANDS
234 static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount,
235 const ALubyte *azCount, const ALushort *evOffset,
236 const ALshort *coeffs, const ALubyte *delays,
237 const_al_string filename)
239 struct Hrtf *Hrtf;
240 size_t total;
242 total = sizeof(struct Hrtf);
243 total += sizeof(Hrtf->azCount[0])*evCount;
244 total = RoundUp(total, 2); /* Align for (u)short fields */
245 total += sizeof(Hrtf->evOffset[0])*evCount;
246 total += sizeof(Hrtf->coeffs[0])*irSize*irCount;
247 total += sizeof(Hrtf->delays[0])*irCount;
248 total += al_string_length(filename)+1;
250 Hrtf = al_calloc(16, total);
251 if(Hrtf == NULL)
252 ERR("Out of memory.\n");
253 else
255 uintptr_t offset = sizeof(struct Hrtf);
256 char *base = (char*)Hrtf;
257 ALushort *_evOffset;
258 ALubyte *_azCount;
259 ALubyte *_delays;
260 ALshort *_coeffs;
261 char *_name;
262 ALsizei i;
264 Hrtf->sampleRate = rate;
265 Hrtf->irSize = irSize;
266 Hrtf->evCount = evCount;
268 /* Set up pointers to storage following the main HRTF struct. */
269 _azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount;
270 offset += sizeof(_azCount[0])*evCount;
272 offset = RoundUp(offset, 2); /* Align for (u)short fields */
273 _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset;
274 offset += sizeof(_evOffset[0])*evCount;
276 _coeffs = (ALshort*)(base + offset); Hrtf->coeffs = _coeffs;
277 offset += sizeof(_coeffs[0])*irSize*irCount;
279 _delays = (ALubyte*)(base + offset); Hrtf->delays = _delays;
280 offset += sizeof(_delays[0])*irCount;
282 _name = (char*)(base + offset); Hrtf->filename = _name;
283 offset += sizeof(_name[0])*(al_string_length(filename)+1);
285 Hrtf->next = NULL;
287 /* Copy input data to storage. */
288 for(i = 0;i < evCount;i++) _azCount[i] = azCount[i];
289 for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i];
290 for(i = 0;i < irSize*irCount;i++) _coeffs[i] = coeffs[i];
291 for(i = 0;i < irCount;i++) _delays[i] = delays[i];
292 for(i = 0;i < (ALsizei)al_string_length(filename);i++)
293 _name[i] = VECTOR_ELEM(filename, i);
294 _name[i] = '\0';
296 assert(offset == total);
299 return Hrtf;
302 static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename)
304 const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
305 struct Hrtf *Hrtf = NULL;
306 ALboolean failed = AL_FALSE;
307 ALuint rate = 0, irCount = 0;
308 ALushort irSize = 0;
309 ALubyte evCount = 0;
310 ALubyte *azCount = NULL;
311 ALushort *evOffset = NULL;
312 ALshort *coeffs = NULL;
313 const ALubyte *delays = NULL;
314 ALuint i, j;
316 if(datalen < 9)
318 ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
319 al_string_get_cstr(filename), 9, datalen);
320 return NULL;
323 rate = *(data++);
324 rate |= *(data++)<<8;
325 rate |= *(data++)<<16;
326 rate |= *(data++)<<24;
327 datalen -= 4;
329 irCount = *(data++);
330 irCount |= *(data++)<<8;
331 datalen -= 2;
333 irSize = *(data++);
334 irSize |= *(data++)<<8;
335 datalen -= 2;
337 evCount = *(data++);
338 datalen -= 1;
340 if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
342 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
343 irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
344 failed = AL_TRUE;
346 if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
348 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
349 evCount, MIN_EV_COUNT, MAX_EV_COUNT);
350 failed = AL_TRUE;
352 if(failed)
353 return NULL;
355 if(datalen < evCount*2)
357 ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
358 al_string_get_cstr(filename), evCount*2, datalen);
359 return NULL;
362 azCount = malloc(sizeof(azCount[0])*evCount);
363 evOffset = malloc(sizeof(evOffset[0])*evCount);
364 if(azCount == NULL || evOffset == NULL)
366 ERR("Out of memory.\n");
367 failed = AL_TRUE;
370 if(!failed)
372 evOffset[0] = *(data++);
373 evOffset[0] |= *(data++)<<8;
374 datalen -= 2;
375 for(i = 1;i < evCount;i++)
377 evOffset[i] = *(data++);
378 evOffset[i] |= *(data++)<<8;
379 datalen -= 2;
380 if(evOffset[i] <= evOffset[i-1])
382 ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
383 i, evOffset[i], evOffset[i-1]);
384 failed = AL_TRUE;
387 azCount[i-1] = evOffset[i] - evOffset[i-1];
388 if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
390 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
391 i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
392 failed = AL_TRUE;
395 if(irCount <= evOffset[i-1])
397 ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n",
398 i-1, evOffset[i-1], irCount);
399 failed = AL_TRUE;
402 azCount[i-1] = irCount - evOffset[i-1];
403 if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
405 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
406 i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
407 failed = AL_TRUE;
411 if(!failed)
413 coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
414 if(coeffs == NULL)
416 ERR("Out of memory.\n");
417 failed = AL_TRUE;
421 if(!failed)
423 size_t reqsize = 2*irSize*irCount + irCount;
424 if(datalen < reqsize)
426 ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n",
427 al_string_get_cstr(filename), reqsize, datalen);
428 failed = AL_TRUE;
432 if(!failed)
434 for(i = 0;i < irCount*irSize;i+=irSize)
436 for(j = 0;j < irSize;j++)
438 coeffs[i+j] = *(data++);
439 coeffs[i+j] |= *(data++)<<8;
440 datalen -= 2;
444 delays = data;
445 data += irCount;
446 datalen -= irCount;
447 for(i = 0;i < irCount;i++)
449 if(delays[i] > maxDelay)
451 ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay);
452 failed = AL_TRUE;
457 if(!failed)
458 Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
459 evOffset, coeffs, delays, filename);
461 free(azCount);
462 free(evOffset);
463 free(coeffs);
464 return Hrtf;
467 static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename)
469 const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
470 struct Hrtf *Hrtf = NULL;
471 ALboolean failed = AL_FALSE;
472 ALuint rate = 0, irCount = 0;
473 ALubyte irSize = 0, evCount = 0;
474 const ALubyte *azCount = NULL;
475 ALushort *evOffset = NULL;
476 ALshort *coeffs = NULL;
477 const ALubyte *delays = NULL;
478 ALuint i, j;
480 if(datalen < 6)
482 ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
483 al_string_get_cstr(filename), 6, datalen);
484 return NULL;
487 rate = *(data++);
488 rate |= *(data++)<<8;
489 rate |= *(data++)<<16;
490 rate |= *(data++)<<24;
491 datalen -= 4;
493 irSize = *(data++);
494 datalen -= 1;
496 evCount = *(data++);
497 datalen -= 1;
499 if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
501 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
502 irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
503 failed = AL_TRUE;
505 if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
507 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
508 evCount, MIN_EV_COUNT, MAX_EV_COUNT);
509 failed = AL_TRUE;
511 if(failed)
512 return NULL;
514 if(datalen < evCount)
516 ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
517 al_string_get_cstr(filename), evCount, datalen);
518 return NULL;
521 azCount = data;
522 data += evCount;
523 datalen -= evCount;
525 evOffset = malloc(sizeof(evOffset[0])*evCount);
526 if(azCount == NULL || evOffset == NULL)
528 ERR("Out of memory.\n");
529 failed = AL_TRUE;
532 if(!failed)
534 for(i = 0;i < evCount;i++)
536 if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT)
538 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
539 i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT);
540 failed = AL_TRUE;
545 if(!failed)
547 evOffset[0] = 0;
548 irCount = azCount[0];
549 for(i = 1;i < evCount;i++)
551 evOffset[i] = evOffset[i-1] + azCount[i-1];
552 irCount += azCount[i];
555 coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
556 if(coeffs == NULL)
558 ERR("Out of memory.\n");
559 failed = AL_TRUE;
563 if(!failed)
565 size_t reqsize = 2*irSize*irCount + irCount;
566 if(datalen < reqsize)
568 ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
569 al_string_get_cstr(filename), reqsize, datalen);
570 failed = AL_TRUE;
574 if(!failed)
576 for(i = 0;i < irCount*irSize;i+=irSize)
578 for(j = 0;j < irSize;j++)
580 ALshort coeff;
581 coeff = *(data++);
582 coeff |= *(data++)<<8;
583 datalen -= 2;
584 coeffs[i+j] = coeff;
588 delays = data;
589 data += irCount;
590 datalen -= irCount;
591 for(i = 0;i < irCount;i++)
593 if(delays[i] > maxDelay)
595 ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay);
596 failed = AL_TRUE;
601 if(!failed)
602 Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
603 evOffset, coeffs, delays, filename);
605 free(evOffset);
606 free(coeffs);
607 return Hrtf;
610 static void AddFileEntry(vector_HrtfEntry *list, al_string *filename)
612 HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL };
613 struct Hrtf *hrtf = NULL;
614 const HrtfEntry *iter;
615 struct FileMapping fmap;
616 const char *name;
617 const char *ext;
618 int i;
620 #define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0)
621 VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME);
622 if(iter != VECTOR_END(*list))
624 TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename));
625 goto done;
627 #undef MATCH_FNAME
629 entry.hrtf = LoadedHrtfs;
630 while(entry.hrtf)
632 if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0)
634 TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename));
635 goto skip_load;
637 entry.hrtf = entry.hrtf->next;
640 TRACE("Loading %s...\n", al_string_get_cstr(*filename));
641 fmap = MapFileToMem(al_string_get_cstr(*filename));
642 if(fmap.ptr == NULL)
644 ERR("Could not open %s\n", al_string_get_cstr(*filename));
645 goto done;
648 if(fmap.len < sizeof(magicMarker01))
649 ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), fmap.len);
650 else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0)
652 TRACE("Detected data set format v1\n");
653 hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01),
654 fmap.len-sizeof(magicMarker01), *filename
657 else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0)
659 TRACE("Detected data set format v0\n");
660 hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00),
661 fmap.len-sizeof(magicMarker00), *filename
664 else
665 ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), (const char*)fmap.ptr);
666 UnmapFileMem(&fmap);
668 if(!hrtf)
670 ERR("Failed to load %s\n", al_string_get_cstr(*filename));
671 goto done;
674 hrtf->next = LoadedHrtfs;
675 LoadedHrtfs = hrtf;
676 TRACE("Loaded HRTF support for format: %s %uhz\n",
677 DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
678 entry.hrtf = hrtf;
680 skip_load:
681 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
682 * format update). */
683 name = strrchr(al_string_get_cstr(*filename), '/');
684 if(!name) name = strrchr(al_string_get_cstr(*filename), '\\');
685 if(!name) name = al_string_get_cstr(*filename);
686 else ++name;
688 ext = strrchr(name, '.');
690 i = 0;
691 do {
692 if(!ext)
693 al_string_copy_cstr(&entry.name, name);
694 else
695 al_string_copy_range(&entry.name, name, ext);
696 if(i != 0)
698 char str[64];
699 snprintf(str, sizeof(str), " #%d", i+1);
700 al_string_append_cstr(&entry.name, str);
702 ++i;
704 #define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
705 VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME);
706 #undef MATCH_NAME
707 } while(iter != VECTOR_END(*list));
709 TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name),
710 al_string_get_cstr(*filename));
711 VECTOR_PUSH_BACK(*list, entry);
713 done:
714 al_string_deinit(filename);
717 /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
718 * for input instead of opening the given filename.
720 static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename)
722 HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL };
723 struct Hrtf *hrtf = NULL;
724 const HrtfEntry *iter;
725 int i;
727 #define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0)
728 VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME);
729 if(iter != VECTOR_END(*list))
731 TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename));
732 goto done;
734 #undef MATCH_FNAME
736 entry.hrtf = LoadedHrtfs;
737 while(entry.hrtf)
739 if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0)
741 TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename));
742 goto skip_load;
744 entry.hrtf = entry.hrtf->next;
747 TRACE("Loading %s...\n", al_string_get_cstr(*filename));
748 if(datalen < sizeof(magicMarker01))
750 ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), datalen);
751 goto done;
754 if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0)
756 TRACE("Detected data set format v1\n");
757 hrtf = LoadHrtf01(data+sizeof(magicMarker01),
758 datalen-sizeof(magicMarker01), *filename
761 else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0)
763 TRACE("Detected data set format v0\n");
764 hrtf = LoadHrtf00(data+sizeof(magicMarker00),
765 datalen-sizeof(magicMarker00), *filename
768 else
769 ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), data);
771 if(!hrtf)
773 ERR("Failed to load %s\n", al_string_get_cstr(*filename));
774 goto done;
777 hrtf->next = LoadedHrtfs;
778 LoadedHrtfs = hrtf;
779 TRACE("Loaded HRTF support for format: %s %uhz\n",
780 DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
781 entry.hrtf = hrtf;
783 skip_load:
784 i = 0;
785 do {
786 al_string_copy(&entry.name, *filename);
787 if(i != 0)
789 char str[64];
790 snprintf(str, sizeof(str), " #%d", i+1);
791 al_string_append_cstr(&entry.name, str);
793 ++i;
795 #define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
796 VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME);
797 #undef MATCH_NAME
798 } while(iter != VECTOR_END(*list));
800 TRACE("Adding built-in entry \"%s\"\n", al_string_get_cstr(entry.name));
801 VECTOR_PUSH_BACK(*list, entry);
803 done:
804 al_string_deinit(filename);
808 #ifndef ALSOFT_EMBED_HRTF_DATA
809 #define IDR_DEFAULT_44100_MHR 1
810 #define IDR_DEFAULT_48000_MHR 2
812 static const ALubyte *GetResource(int UNUSED(name), size_t *size)
814 *size = 0;
815 return NULL;
818 #else
819 #include "hrtf_res.h"
821 #ifdef _WIN32
822 static const ALubyte *GetResource(int name, size_t *size)
824 HMODULE handle;
825 HGLOBAL res;
826 HRSRC rc;
828 GetModuleHandleExW(
829 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
830 (LPCWSTR)GetResource, &handle
832 rc = FindResourceW(handle, MAKEINTRESOURCEW(name), MAKEINTRESOURCEW(MHRTYPE));
833 res = LoadResource(handle, rc);
835 *size = SizeofResource(handle, rc);
836 return LockResource(res);
839 #elif defined(__APPLE__)
841 #include <Availability.h>
842 #include <mach-o/getsect.h>
843 #include <mach-o/ldsyms.h>
845 static const ALubyte *GetResource(int name, size_t *size)
847 #if defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1070)
848 /* NOTE: OSX 10.7 and up need to call getsectiondata(&_mh_dylib_header, ...). However, that
849 * call requires 10.7.
851 if(name == IDR_DEFAULT_44100_MHR)
852 return getsectiondata(&_mh_dylib_header, "binary", "default_44100", size);
853 if(name == IDR_DEFAULT_48000_MHR)
854 return getsectiondata(&_mh_dylib_header, "binary", "default_48000", size);
855 #else
856 if(name == IDR_DEFAULT_44100_MHR)
857 return getsectdata("binary", "default_44100", size);
858 if(name == IDR_DEFAULT_48000_MHR)
859 return getsectdata("binary", "default_48000", size);
860 #endif
861 *size = 0;
862 return NULL;
865 #else
867 extern const ALubyte _binary_default_44100_mhr_start[] HIDDEN_DECL;
868 extern const ALubyte _binary_default_44100_mhr_end[] HIDDEN_DECL;
869 extern const ALubyte _binary_default_44100_mhr_size[] HIDDEN_DECL;
871 extern const ALubyte _binary_default_48000_mhr_start[] HIDDEN_DECL;
872 extern const ALubyte _binary_default_48000_mhr_end[] HIDDEN_DECL;
873 extern const ALubyte _binary_default_48000_mhr_size[] HIDDEN_DECL;
875 static const ALubyte *GetResource(int name, size_t *size)
877 if(name == IDR_DEFAULT_44100_MHR)
879 /* Make sure all symbols are referenced, to ensure the compiler won't
880 * ignore the declarations and lose the visibility attribute used to
881 * hide them (would be nice if ld or objcopy could automatically mark
882 * them as hidden when generating them, but apparently they can't).
884 const void *volatile ptr =_binary_default_44100_mhr_size;
885 (void)ptr;
886 *size = _binary_default_44100_mhr_end - _binary_default_44100_mhr_start;
887 return _binary_default_44100_mhr_start;
889 if(name == IDR_DEFAULT_48000_MHR)
891 const void *volatile ptr =_binary_default_48000_mhr_size;
892 (void)ptr;
893 *size = _binary_default_48000_mhr_end - _binary_default_48000_mhr_start;
894 return _binary_default_48000_mhr_start;
896 *size = 0;
897 return NULL;
899 #endif
900 #endif
902 vector_HrtfEntry EnumerateHrtf(const_al_string devname)
904 vector_HrtfEntry list = VECTOR_INIT_STATIC();
905 const char *defaulthrtf = "";
906 const char *pathlist = "";
907 bool usedefaults = true;
909 if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist))
911 while(pathlist && *pathlist)
913 const char *next, *end;
915 while(isspace(*pathlist) || *pathlist == ',')
916 pathlist++;
917 if(*pathlist == '\0')
918 continue;
920 next = strchr(pathlist, ',');
921 if(next)
922 end = next++;
923 else
925 end = pathlist + strlen(pathlist);
926 usedefaults = false;
929 while(end != pathlist && isspace(*(end-1)))
930 --end;
931 if(end != pathlist)
933 al_string pname = AL_STRING_INIT_STATIC();
934 vector_al_string flist;
936 al_string_append_range(&pname, pathlist, end);
938 flist = SearchDataFiles(".mhr", al_string_get_cstr(pname));
939 VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
940 VECTOR_DEINIT(flist);
942 al_string_deinit(&pname);
945 pathlist = next;
948 else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables"))
949 ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
951 if(usedefaults)
953 vector_al_string flist;
954 const ALubyte *rdata;
955 size_t rsize;
957 flist = SearchDataFiles(".mhr", "openal/hrtf");
958 VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
959 VECTOR_DEINIT(flist);
961 rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize);
962 if(rdata != NULL && rsize > 0)
964 al_string ename = AL_STRING_INIT_STATIC();
965 al_string_copy_cstr(&ename, "Built-In 44100hz");
966 AddBuiltInEntry(&list, rdata, rsize, &ename);
969 rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize);
970 if(rdata != NULL && rsize > 0)
972 al_string ename = AL_STRING_INIT_STATIC();
973 al_string_copy_cstr(&ename, "Built-In 48000hz");
974 AddBuiltInEntry(&list, rdata, rsize, &ename);
978 if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf))
980 const HrtfEntry *iter;
981 /* Find the preferred HRTF and move it to the front of the list. */
982 #define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0)
983 VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY);
984 #undef FIND_ENTRY
985 if(iter == VECTOR_END(list))
986 WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf);
987 else if(iter != VECTOR_BEGIN(list))
989 HrtfEntry entry = *iter;
990 memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0),
991 (iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry));
992 VECTOR_ELEM(list,0) = entry;
996 return list;
999 void FreeHrtfList(vector_HrtfEntry *list)
1001 #define CLEAR_ENTRY(i) do { \
1002 al_string_deinit(&(i)->name); \
1003 } while(0)
1004 VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY);
1005 VECTOR_DEINIT(*list);
1006 #undef CLEAR_ENTRY
1010 void FreeHrtfs(void)
1012 struct Hrtf *Hrtf = LoadedHrtfs;
1013 LoadedHrtfs = NULL;
1015 while(Hrtf != NULL)
1017 struct Hrtf *next = Hrtf->next;
1018 al_free(Hrtf);
1019 Hrtf = next;