Round the B-Format HRTF response where the multiple is defined
[openal-soft.git] / Alc / hrtf.c
blob9e401573397be328d562e40475d3ca0756bf8e3f
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 struct HrtfEntry {
50 struct HrtfEntry *next;
51 struct Hrtf *handle;
52 char filename[];
55 static const ALchar magicMarker00[8] = "MinPHR00";
56 static const ALchar magicMarker01[8] = "MinPHR01";
58 /* First value for pass-through coefficients (remaining are 0), used for omni-
59 * directional sounds. */
60 static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/;
62 static ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT;
63 static struct HrtfEntry *LoadedHrtfs = NULL;
66 /* Calculate the elevation index given the polar elevation in radians. This
67 * will return an index between 0 and (evcount - 1). Assumes the FPU is in
68 * round-to-zero mode.
70 static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu)
72 ALsizei idx;
73 ev = (F_PI_2+ev) * (evcount-1) / F_PI;
74 idx = mini(fastf2i(ev), evcount-1);
76 *mu = ev - idx;
77 return idx;
80 /* Calculate the azimuth index given the polar azimuth in radians. This will
81 * return an index between 0 and (azcount - 1). Assumes the FPU is in round-to-
82 * zero mode.
84 static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu)
86 ALsizei idx;
87 az = (F_TAU+az) * azcount / F_TAU;
89 idx = fastf2i(az) % azcount;
90 *mu = az - floorf(az);
91 return idx;
94 /* Calculates static HRIR coefficients and delays for the given polar elevation
95 * and azimuth in radians. The coefficients are normalized.
97 void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat (*coeffs)[2], ALsizei *delays)
99 ALsizei evidx, azidx, idx[4];
100 ALsizei evoffset;
101 ALfloat emu, amu[2];
102 ALfloat blend[4];
103 ALfloat dirfact;
104 ALsizei i, c;
106 dirfact = 1.0f - (spread / F_TAU);
108 /* Claculate the lower elevation index. */
109 evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu);
110 evoffset = Hrtf->evOffset[evidx];
112 /* Calculate lower azimuth index. */
113 azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]);
115 /* Calculate the lower HRIR indices. */
116 idx[0] = evoffset + azidx;
117 idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]);
118 if(evidx < Hrtf->evCount-1)
120 /* Increment elevation to the next (upper) index. */
121 evidx++;
122 evoffset = Hrtf->evOffset[evidx];
124 /* Calculate upper azimuth index. */
125 azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[1]);
127 /* Calculate the upper HRIR indices. */
128 idx[2] = evoffset + azidx;
129 idx[3] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]);
131 else
133 /* If the lower elevation is the top index, the upper elevation is the
134 * same as the lower.
136 amu[1] = amu[0];
137 idx[2] = idx[0];
138 idx[3] = idx[1];
141 /* Calculate bilinear blending weights, attenuated according to the
142 * directional panning factor.
144 blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact;
145 blend[1] = (1.0f-emu) * ( amu[0]) * dirfact;
146 blend[2] = ( emu) * (1.0f-amu[1]) * dirfact;
147 blend[3] = ( emu) * ( amu[1]) * dirfact;
149 /* Calculate the blended HRIR delays. */
150 delays[0] = fastf2i(
151 Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] +
152 Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + 0.5f
154 delays[1] = fastf2i(
155 Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] +
156 Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f
159 /* Calculate the sample offsets for the HRIR indices. */
160 idx[0] *= Hrtf->irSize;
161 idx[1] *= Hrtf->irSize;
162 idx[2] *= Hrtf->irSize;
163 idx[3] *= Hrtf->irSize;
165 /* Calculate the blended HRIR coefficients. */
166 coeffs[0][0] = PassthruCoeff * (1.0f-dirfact);
167 coeffs[0][1] = PassthruCoeff * (1.0f-dirfact);
168 for(i = 1;i < Hrtf->irSize;i++)
170 coeffs[i][0] = 0.0f;
171 coeffs[i][1] = 0.0f;
173 for(c = 0;c < 4;c++)
175 for(i = 0;i < Hrtf->irSize;i++)
177 coeffs[i][0] += Hrtf->coeffs[idx[c]+i][0] * blend[c];
178 coeffs[i][1] += Hrtf->coeffs[idx[c]+i][1] * blend[c];
184 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)
186 /* Set this to 2 for dual-band HRTF processing. May require a higher quality
187 * band-splitter, or better calculation of the new IR length to deal with the
188 * tail generated by the filter.
190 #define NUM_BANDS 2
191 BandSplitter splitter;
192 ALsizei idx[HRTF_AMBI_MAX_CHANNELS];
193 ALsizei min_delay = HRTF_HISTORY_LENGTH;
194 ALfloat temps[3][HRIR_LENGTH];
195 ALsizei max_length = 0;
196 ALsizei i, c, b;
198 for(c = 0;c < AmbiCount;c++)
200 ALuint evidx, azidx;
201 ALuint evoffset;
202 ALuint azcount;
204 /* Calculate elevation index. */
205 evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) *
206 (Hrtf->evCount-1)/F_PI + 0.5f);
207 evidx = mini(evidx, Hrtf->evCount-1);
209 azcount = Hrtf->azCount[evidx];
210 evoffset = Hrtf->evOffset[evidx];
212 /* Calculate azimuth index for this elevation. */
213 azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) *
214 azcount/F_TAU + 0.5f) % azcount;
216 /* Calculate indices for left and right channels. */
217 idx[c] = evoffset + azidx;
219 min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1]));
222 memset(temps, 0, sizeof(temps));
223 bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate);
224 for(c = 0;c < AmbiCount;c++)
226 const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize];
227 ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay;
228 ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay;
230 max_length = maxi(max_length,
231 mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH)
234 if(NUM_BANDS == 1)
236 for(i = 0;i < NumChannels;++i)
238 ALsizei lidx = ldelay, ridx = rdelay;
239 ALsizei j = 0;
240 while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize)
242 state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][0][i];
243 state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][0][i];
244 j++;
248 else
250 /* Band-split left HRIR into low and high frequency responses. */
251 bandsplit_clear(&splitter);
252 for(i = 0;i < Hrtf->irSize;i++)
253 temps[2][i] = fir[i][0];
254 bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
256 /* Apply left ear response with delay. */
257 for(i = 0;i < NumChannels;++i)
259 for(b = 0;b < NUM_BANDS;b++)
261 ALsizei lidx = ldelay;
262 ALsizei j = 0;
263 while(lidx < HRIR_LENGTH)
264 state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][b][i];
268 /* Band-split right HRIR into low and high frequency responses. */
269 bandsplit_clear(&splitter);
270 for(i = 0;i < Hrtf->irSize;i++)
271 temps[2][i] = fir[i][1];
272 bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
274 /* Apply right ear response with delay. */
275 for(i = 0;i < NumChannels;++i)
277 for(b = 0;b < NUM_BANDS;b++)
279 ALsizei ridx = rdelay;
280 ALsizei j = 0;
281 while(ridx < HRIR_LENGTH)
282 state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][b][i];
287 /* Round up to the next IR size multiple. */
288 max_length = RoundUp(max_length, MOD_IR_SIZE);
290 TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
291 return max_length;
292 #undef NUM_BANDS
296 static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize, ALsizei evCount, ALsizei irCount,
297 const ALubyte *azCount, const ALushort *evOffset,
298 const ALfloat (*coeffs)[2], const ALubyte (*delays)[2],
299 const char *filename)
301 struct Hrtf *Hrtf;
302 size_t total;
304 total = sizeof(struct Hrtf);
305 total += sizeof(Hrtf->azCount[0])*evCount;
306 total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */
307 total += sizeof(Hrtf->evOffset[0])*evCount;
308 total = RoundUp(total, 16); /* Align for coefficients using SIMD */
309 total += sizeof(Hrtf->coeffs[0])*irSize*irCount;
310 total += sizeof(Hrtf->delays[0])*irCount;
312 Hrtf = al_calloc(16, total);
313 if(Hrtf == NULL)
314 ERR("Out of memory allocating storage for %s.\n", filename);
315 else
317 uintptr_t offset = sizeof(struct Hrtf);
318 char *base = (char*)Hrtf;
319 ALushort *_evOffset;
320 ALubyte *_azCount;
321 ALubyte (*_delays)[2];
322 ALfloat (*_coeffs)[2];
323 ALsizei i;
325 InitRef(&Hrtf->ref, 0);
326 Hrtf->sampleRate = rate;
327 Hrtf->irSize = irSize;
328 Hrtf->evCount = evCount;
330 /* Set up pointers to storage following the main HRTF struct. */
331 _azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount;
332 offset += sizeof(_azCount[0])*evCount;
334 offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */
335 _evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset;
336 offset += sizeof(_evOffset[0])*evCount;
338 offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */
339 _coeffs = (ALfloat(*)[2])(base + offset); Hrtf->coeffs = _coeffs;
340 offset += sizeof(_coeffs[0])*irSize*irCount;
342 _delays = (ALubyte(*)[2])(base + offset); Hrtf->delays = _delays;
343 offset += sizeof(_delays[0])*irCount;
345 /* Copy input data to storage. */
346 for(i = 0;i < evCount;i++) _azCount[i] = azCount[i];
347 for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i];
348 for(i = 0;i < irSize*irCount;i++)
350 _coeffs[i][0] = coeffs[i][0];
351 _coeffs[i][1] = coeffs[i][1];
353 for(i = 0;i < irCount;i++)
355 _delays[i][0] = delays[i][0];
356 _delays[i][1] = delays[i][1];
359 assert(offset == total);
362 return Hrtf;
365 static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename)
367 const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
368 struct Hrtf *Hrtf = NULL;
369 ALboolean failed = AL_FALSE;
370 ALuint rate = 0;
371 ALushort irCount = 0;
372 ALushort irSize = 0;
373 ALubyte evCount = 0;
374 ALubyte *azCount = NULL;
375 ALushort *evOffset = NULL;
376 ALfloat (*coeffs)[2] = NULL;
377 ALubyte (*delays)[2] = NULL;
378 ALsizei i, j;
380 if(datalen < 9)
382 ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, 9, datalen);
383 return NULL;
386 rate = *(data++);
387 rate |= *(data++)<<8;
388 rate |= *(data++)<<16;
389 rate |= *(data++)<<24;
390 datalen -= 4;
392 irCount = *(data++);
393 irCount |= *(data++)<<8;
394 datalen -= 2;
396 irSize = *(data++);
397 irSize |= *(data++)<<8;
398 datalen -= 2;
400 evCount = *(data++);
401 datalen -= 1;
403 if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
405 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
406 irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
407 failed = AL_TRUE;
409 if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
411 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
412 evCount, MIN_EV_COUNT, MAX_EV_COUNT);
413 failed = AL_TRUE;
415 if(failed)
416 return NULL;
418 if(datalen < evCount*2u)
420 ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen);
421 return NULL;
424 azCount = malloc(sizeof(azCount[0])*evCount);
425 evOffset = malloc(sizeof(evOffset[0])*evCount);
426 if(azCount == NULL || evOffset == NULL)
428 ERR("Out of memory.\n");
429 failed = AL_TRUE;
432 if(!failed)
434 evOffset[0] = *(data++);
435 evOffset[0] |= *(data++)<<8;
436 datalen -= 2;
437 for(i = 1;i < evCount;i++)
439 evOffset[i] = *(data++);
440 evOffset[i] |= *(data++)<<8;
441 datalen -= 2;
442 if(evOffset[i] <= evOffset[i-1])
444 ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
445 i, evOffset[i], evOffset[i-1]);
446 failed = AL_TRUE;
449 azCount[i-1] = evOffset[i] - evOffset[i-1];
450 if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
452 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
453 i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
454 failed = AL_TRUE;
457 if(irCount <= evOffset[i-1])
459 ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n",
460 i-1, evOffset[i-1], irCount);
461 failed = AL_TRUE;
464 azCount[i-1] = irCount - evOffset[i-1];
465 if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
467 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
468 i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
469 failed = AL_TRUE;
473 if(!failed)
475 coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
476 delays = malloc(sizeof(delays[0])*irCount);
477 if(coeffs == NULL || delays == NULL)
479 ERR("Out of memory.\n");
480 failed = AL_TRUE;
484 if(!failed)
486 size_t reqsize = 2*irSize*irCount + irCount;
487 if(datalen < reqsize)
489 ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n",
490 filename, reqsize, datalen);
491 failed = AL_TRUE;
495 if(!failed)
497 for(i = 0;i < irCount*irSize;i+=irSize)
499 for(j = 0;j < irSize;j++)
501 ALshort coeff;
502 coeff = *(data++);
503 coeff |= *(data++)<<8;
504 datalen -= 2;
505 coeffs[i+j][0] = coeff / 32768.0f;
509 for(i = 0;i < irCount;i++)
511 delays[i][0] = *(data++);
512 datalen -= 1;
513 if(delays[i][0] > maxDelay)
515 ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
516 failed = AL_TRUE;
521 if(!failed)
523 /* Mirror the left ear responses to the right ear. */
524 for(i = 0;i < evCount;i++)
526 ALushort evoffset = evOffset[i];
527 ALubyte azcount = azCount[i];
528 for(j = 0;j < azcount;j++)
530 ALsizei lidx = evoffset + j;
531 ALsizei ridx = evoffset + ((azcount-j) % azcount);
532 ALsizei k;
534 for(k = 0;k < irSize;k++)
535 coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0];
536 delays[ridx][1] = delays[lidx][0];
540 Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
541 evOffset, coeffs, delays, filename);
544 free(azCount);
545 free(evOffset);
546 free(coeffs);
547 free(delays);
548 return Hrtf;
551 static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename)
553 const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
554 struct Hrtf *Hrtf = NULL;
555 ALboolean failed = AL_FALSE;
556 ALuint rate = 0;
557 ALushort irCount = 0;
558 ALushort irSize = 0;
559 ALubyte evCount = 0;
560 const ALubyte *azCount = NULL;
561 ALushort *evOffset = NULL;
562 ALfloat (*coeffs)[2] = NULL;
563 ALubyte (*delays)[2] = NULL;
564 ALsizei i, j;
566 if(datalen < 6)
568 ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 6, datalen);
569 return NULL;
572 rate = *(data++);
573 rate |= *(data++)<<8;
574 rate |= *(data++)<<16;
575 rate |= *(data++)<<24;
576 datalen -= 4;
578 irSize = *(data++);
579 datalen -= 1;
581 evCount = *(data++);
582 datalen -= 1;
584 if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
586 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
587 irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
588 failed = AL_TRUE;
590 if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
592 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
593 evCount, MIN_EV_COUNT, MAX_EV_COUNT);
594 failed = AL_TRUE;
596 if(failed)
597 return NULL;
599 if(datalen < evCount)
601 ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen);
602 return NULL;
605 azCount = data;
606 data += evCount;
607 datalen -= evCount;
609 evOffset = malloc(sizeof(evOffset[0])*evCount);
610 if(azCount == NULL || evOffset == NULL)
612 ERR("Out of memory.\n");
613 failed = AL_TRUE;
616 if(!failed)
618 for(i = 0;i < evCount;i++)
620 if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT)
622 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
623 i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT);
624 failed = AL_TRUE;
629 if(!failed)
631 evOffset[0] = 0;
632 irCount = azCount[0];
633 for(i = 1;i < evCount;i++)
635 evOffset[i] = evOffset[i-1] + azCount[i-1];
636 irCount += azCount[i];
639 coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
640 delays = malloc(sizeof(delays[0])*irCount);
641 if(coeffs == NULL || delays == NULL)
643 ERR("Out of memory.\n");
644 failed = AL_TRUE;
648 if(!failed)
650 size_t reqsize = 2*irSize*irCount + irCount;
651 if(datalen < reqsize)
653 ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
654 filename, reqsize, datalen);
655 failed = AL_TRUE;
659 if(!failed)
661 for(i = 0;i < irCount*irSize;i+=irSize)
663 for(j = 0;j < irSize;j++)
665 ALshort coeff;
666 coeff = *(data++);
667 coeff |= *(data++)<<8;
668 datalen -= 2;
669 coeffs[i+j][0] = coeff / 32768.0f;
673 for(i = 0;i < irCount;i++)
675 delays[i][0] = *(data++);
676 datalen -= 1;
677 if(delays[i][0] > maxDelay)
679 ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], maxDelay);
680 failed = AL_TRUE;
685 if(!failed)
687 /* Mirror the left ear responses to the right ear. */
688 for(i = 0;i < evCount;i++)
690 ALushort evoffset = evOffset[i];
691 ALubyte azcount = azCount[i];
692 for(j = 0;j < azcount;j++)
694 ALsizei lidx = evoffset + j;
695 ALsizei ridx = evoffset + ((azcount-j) % azcount);
696 ALsizei k;
698 for(k = 0;k < irSize;k++)
699 coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0];
700 delays[ridx][1] = delays[lidx][0];
704 Hrtf = CreateHrtfStore(rate, irSize, evCount, irCount, azCount,
705 evOffset, coeffs, delays, filename);
708 free(evOffset);
709 free(coeffs);
710 free(delays);
711 return Hrtf;
715 static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename)
717 EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
718 struct HrtfEntry *loaded_entry;
719 const EnumeratedHrtf *iter;
720 const char *name;
721 const char *ext;
722 int i;
724 /* Check if this file has already been loaded globally. */
725 loaded_entry = LoadedHrtfs;
726 while(loaded_entry)
728 if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0)
730 /* Check if this entry has already been added to the list. */
731 #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf)
732 VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY);
733 if(iter != VECTOR_END(*list))
735 TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename));
736 return;
738 #undef MATCH_FNAME
740 break;
742 loaded_entry = loaded_entry->next;
745 if(!loaded_entry)
747 TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename));
749 loaded_entry = al_calloc(DEF_ALIGN,
750 FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1)
752 loaded_entry->next = LoadedHrtfs;
753 loaded_entry->handle = NULL;
754 strcpy(loaded_entry->filename, alstr_get_cstr(filename));
755 LoadedHrtfs = loaded_entry;
758 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
759 * format update). */
760 name = strrchr(alstr_get_cstr(filename), '/');
761 if(!name) name = strrchr(alstr_get_cstr(filename), '\\');
762 if(!name) name = alstr_get_cstr(filename);
763 else ++name;
765 ext = strrchr(name, '.');
767 i = 0;
768 do {
769 if(!ext)
770 alstr_copy_cstr(&entry.name, name);
771 else
772 alstr_copy_range(&entry.name, name, ext);
773 if(i != 0)
775 char str[64];
776 snprintf(str, sizeof(str), " #%d", i+1);
777 alstr_append_cstr(&entry.name, str);
779 ++i;
781 #define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0)
782 VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME);
783 #undef MATCH_NAME
784 } while(iter != VECTOR_END(*list));
785 entry.hrtf = loaded_entry;
787 TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name),
788 alstr_get_cstr(filename));
789 VECTOR_PUSH_BACK(*list, entry);
792 /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
793 * for input instead of opening the given filename.
795 static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, size_t residx)
797 EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
798 struct HrtfEntry *loaded_entry;
799 struct Hrtf *hrtf = NULL;
800 const EnumeratedHrtf *iter;
801 const char *name;
802 const char *ext;
803 int i;
805 loaded_entry = LoadedHrtfs;
806 while(loaded_entry)
808 if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0)
810 #define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf)
811 VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY);
812 if(iter != VECTOR_END(*list))
814 TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename));
815 return;
817 #undef MATCH_FNAME
819 break;
821 loaded_entry = loaded_entry->next;
824 if(!loaded_entry)
826 size_t namelen = alstr_length(filename)+32;
828 TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename));
830 loaded_entry = al_calloc(DEF_ALIGN,
831 FAM_SIZE(struct HrtfEntry, filename, namelen)
833 loaded_entry->next = LoadedHrtfs;
834 loaded_entry->handle = hrtf;
835 snprintf(loaded_entry->filename, namelen, "!"SZFMT"_%s",
836 residx, alstr_get_cstr(filename));
837 LoadedHrtfs = loaded_entry;
840 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
841 * format update). */
842 name = strrchr(alstr_get_cstr(filename), '/');
843 if(!name) name = strrchr(alstr_get_cstr(filename), '\\');
844 if(!name) name = alstr_get_cstr(filename);
845 else ++name;
847 ext = strrchr(name, '.');
849 i = 0;
850 do {
851 if(!ext)
852 alstr_copy_cstr(&entry.name, name);
853 else
854 alstr_copy_range(&entry.name, name, ext);
855 if(i != 0)
857 char str[64];
858 snprintf(str, sizeof(str), " #%d", i+1);
859 alstr_append_cstr(&entry.name, str);
861 ++i;
863 #define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0)
864 VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME);
865 #undef MATCH_NAME
866 } while(iter != VECTOR_END(*list));
867 entry.hrtf = loaded_entry;
869 TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name));
870 VECTOR_PUSH_BACK(*list, entry);
874 #define IDR_DEFAULT_44100_MHR 1
875 #define IDR_DEFAULT_48000_MHR 2
877 #ifndef ALSOFT_EMBED_HRTF_DATA
879 static const ALubyte *GetResource(int UNUSED(name), size_t *size)
881 *size = 0;
882 return NULL;
885 #else
887 #include "default-44100.mhr.h"
888 #include "default-48000.mhr.h"
890 static const ALubyte *GetResource(int name, size_t *size)
892 if(name == IDR_DEFAULT_44100_MHR)
894 *size = sizeof(hrtf_default_44100);
895 return hrtf_default_44100;
897 if(name == IDR_DEFAULT_48000_MHR)
899 *size = sizeof(hrtf_default_48000);
900 return hrtf_default_48000;
902 *size = 0;
903 return NULL;
905 #endif
907 vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname)
909 vector_EnumeratedHrtf list = VECTOR_INIT_STATIC();
910 const char *defaulthrtf = "";
911 const char *pathlist = "";
912 bool usedefaults = true;
914 if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist))
916 al_string pname = AL_STRING_INIT_STATIC();
917 while(pathlist && *pathlist)
919 const char *next, *end;
921 while(isspace(*pathlist) || *pathlist == ',')
922 pathlist++;
923 if(*pathlist == '\0')
924 continue;
926 next = strchr(pathlist, ',');
927 if(next)
928 end = next++;
929 else
931 end = pathlist + strlen(pathlist);
932 usedefaults = false;
935 while(end != pathlist && isspace(*(end-1)))
936 --end;
937 if(end != pathlist)
939 vector_al_string flist;
940 size_t i;
942 alstr_copy_range(&pname, pathlist, end);
944 flist = SearchDataFiles(".mhr", alstr_get_cstr(pname));
945 for(i = 0;i < VECTOR_SIZE(flist);i++)
946 AddFileEntry(&list, VECTOR_ELEM(flist, i));
947 VECTOR_FOR_EACH(al_string, flist, alstr_reset);
948 VECTOR_DEINIT(flist);
951 pathlist = next;
954 alstr_reset(&pname);
956 else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables"))
957 ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
959 if(usedefaults)
961 al_string ename = AL_STRING_INIT_STATIC();
962 vector_al_string flist;
963 const ALubyte *rdata;
964 size_t rsize, i;
966 flist = SearchDataFiles(".mhr", "openal/hrtf");
967 for(i = 0;i < VECTOR_SIZE(flist);i++)
968 AddFileEntry(&list, VECTOR_ELEM(flist, i));
969 VECTOR_FOR_EACH(al_string, flist, alstr_reset);
970 VECTOR_DEINIT(flist);
972 rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize);
973 if(rdata != NULL && rsize > 0)
975 alstr_copy_cstr(&ename, "Built-In 44100hz");
976 AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR);
979 rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize);
980 if(rdata != NULL && rsize > 0)
982 alstr_copy_cstr(&ename, "Built-In 48000hz");
983 AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR);
985 alstr_reset(&ename);
988 if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf))
990 const EnumeratedHrtf *iter;
991 /* Find the preferred HRTF and move it to the front of the list. */
992 #define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0)
993 VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY);
994 #undef FIND_ENTRY
995 if(iter == VECTOR_END(list))
996 WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf);
997 else if(iter != VECTOR_BEGIN(list))
999 EnumeratedHrtf entry = *iter;
1000 memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0),
1001 (iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf));
1002 VECTOR_ELEM(list,0) = entry;
1006 return list;
1009 void FreeHrtfList(vector_EnumeratedHrtf *list)
1011 #define CLEAR_ENTRY(i) alstr_reset(&(i)->name)
1012 VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY);
1013 VECTOR_DEINIT(*list);
1014 #undef CLEAR_ENTRY
1017 struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
1019 struct Hrtf *hrtf = NULL;
1020 struct FileMapping fmap;
1021 const ALubyte *rdata;
1022 const char *name;
1023 size_t residx;
1024 size_t rsize;
1025 char ch;
1027 while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst))
1028 althrd_yield();
1030 if(entry->handle)
1032 hrtf = entry->handle;
1033 Hrtf_IncRef(hrtf);
1034 goto done;
1037 fmap.ptr = NULL;
1038 fmap.len = 0;
1039 if(sscanf(entry->filename, "!"SZFMT"%c", &residx, &ch) == 2 && ch == '_')
1041 name = strchr(entry->filename, ch)+1;
1043 TRACE("Loading %s...\n", name);
1044 rdata = GetResource(residx, &rsize);
1045 if(rdata == NULL || rsize == 0)
1047 ERR("Could not get resource "SZFMT", %s\n", residx, name);
1048 goto done;
1051 else
1053 name = entry->filename;
1055 TRACE("Loading %s...\n", entry->filename);
1056 fmap = MapFileToMem(entry->filename);
1057 if(fmap.ptr == NULL)
1059 ERR("Could not open %s\n", entry->filename);
1060 goto done;
1063 rdata = fmap.ptr;
1064 rsize = fmap.len;
1067 if(rsize < sizeof(magicMarker01))
1068 ERR("%s data is too short ("SZFMT" bytes)\n", name, rsize);
1069 else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0)
1071 TRACE("Detected data set format v1\n");
1072 hrtf = LoadHrtf01(rdata+sizeof(magicMarker01),
1073 rsize-sizeof(magicMarker01), name
1076 else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0)
1078 TRACE("Detected data set format v0\n");
1079 hrtf = LoadHrtf00(rdata+sizeof(magicMarker00),
1080 rsize-sizeof(magicMarker00), name
1083 else
1084 ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata);
1085 if(fmap.ptr)
1086 UnmapFileMem(&fmap);
1088 if(!hrtf)
1090 ERR("Failed to load %s\n", name);
1091 goto done;
1093 entry->handle = hrtf;
1094 Hrtf_IncRef(hrtf);
1096 TRACE("Loaded HRTF support for format: %s %uhz\n",
1097 DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
1099 done:
1100 ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst);
1101 return hrtf;
1105 void Hrtf_IncRef(struct Hrtf *hrtf)
1107 uint ref = IncrementRef(&hrtf->ref);
1108 TRACEREF("%p increasing refcount to %u\n", hrtf, ref);
1111 void Hrtf_DecRef(struct Hrtf *hrtf)
1113 struct HrtfEntry *Hrtf;
1114 uint ref = DecrementRef(&hrtf->ref);
1115 TRACEREF("%p decreasing refcount to %u\n", hrtf, ref);
1116 if(ref == 0)
1118 while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst))
1119 althrd_yield();
1121 Hrtf = LoadedHrtfs;
1122 while(Hrtf != NULL)
1124 /* Need to double-check that it's still unused, as another device
1125 * could've reacquired this HRTF after its reference went to 0 and
1126 * before the lock was taken.
1128 if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0)
1130 al_free(Hrtf->handle);
1131 Hrtf->handle = NULL;
1132 TRACE("Unloaded unused HRTF %s\n", Hrtf->filename);
1134 Hrtf = Hrtf->next;
1137 ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst);
1142 void FreeHrtfs(void)
1144 struct HrtfEntry *Hrtf = LoadedHrtfs;
1145 LoadedHrtfs = NULL;
1147 while(Hrtf != NULL)
1149 struct HrtfEntry *next = Hrtf->next;
1150 al_free(Hrtf->handle);
1151 al_free(Hrtf);
1152 Hrtf = next;