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
40 #include "filters/splitter.h"
47 struct HrtfEntry
*next
;
54 /* Current data set limits defined by the makehrtf utility. */
55 #define MIN_IR_SIZE (8)
56 #define MAX_IR_SIZE (512)
57 #define MOD_IR_SIZE (8)
59 #define MIN_FD_COUNT (1)
60 #define MAX_FD_COUNT (16)
62 #define MIN_FD_DISTANCE (50)
63 #define MAX_FD_DISTANCE (2500)
65 #define MIN_EV_COUNT (5)
66 #define MAX_EV_COUNT (128)
68 #define MIN_AZ_COUNT (1)
69 #define MAX_AZ_COUNT (128)
71 #define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1)
73 constexpr ALchar magicMarker00
[8]{'M','i','n','P','H','R','0','0'};
74 constexpr ALchar magicMarker01
[8]{'M','i','n','P','H','R','0','1'};
75 constexpr ALchar magicMarker02
[8]{'M','i','n','P','H','R','0','2'};
77 /* First value for pass-through coefficients (remaining are 0), used for omni-
78 * directional sounds. */
79 constexpr ALfloat PassthruCoeff
{0.707106781187f
/*sqrt(0.5)*/};
81 std::mutex LoadedHrtfLock
;
82 HrtfEntry
*LoadedHrtfs
{nullptr};
85 class databuf final
: public std::streambuf
{
86 int_type
underflow() override
87 { return traits_type::eof(); }
89 pos_type
seekoff(off_type offset
, std::ios_base::seekdir whence
, std::ios_base::openmode mode
) override
91 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
92 return traits_type::eof();
97 case std::ios_base::beg
:
98 if(offset
< 0 || offset
> egptr()-eback())
99 return traits_type::eof();
100 cur
= eback() + offset
;
103 case std::ios_base::cur
:
104 if((offset
>= 0 && offset
> egptr()-gptr()) ||
105 (offset
< 0 && -offset
> gptr()-eback()))
106 return traits_type::eof();
107 cur
= gptr() + offset
;
110 case std::ios_base::end
:
111 if(offset
> 0 || -offset
> egptr()-eback())
112 return traits_type::eof();
113 cur
= egptr() + offset
;
117 return traits_type::eof();
120 setg(eback(), cur
, egptr());
121 return cur
- eback();
124 pos_type
seekpos(pos_type pos
, std::ios_base::openmode mode
) override
126 // Simplified version of seekoff
127 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
128 return traits_type::eof();
130 if(pos
< 0 || pos
> egptr()-eback())
131 return traits_type::eof();
133 setg(eback(), eback() + pos
, egptr());
138 databuf(const char_type
*start
, const char_type
*end
) noexcept
140 setg(const_cast<char_type
*>(start
), const_cast<char_type
*>(start
),
141 const_cast<char_type
*>(end
));
145 class idstream final
: public std::istream
{
149 idstream(const char *start
, const char *end
)
150 : std::istream
{nullptr}, mStreamBuf
{start
, end
}
151 { init(&mStreamBuf
); }
155 /* Calculate the elevation index given the polar elevation in radians. This
156 * will return an index between 0 and (evcount - 1).
158 ALsizei
CalcEvIndex(ALsizei evcount
, ALfloat ev
, ALfloat
*mu
)
160 ev
= (F_PI_2
+ev
) * (evcount
-1) / F_PI
;
161 ALsizei idx
{float2int(ev
)};
164 return mini(idx
, evcount
-1);
167 /* Calculate the azimuth index given the polar azimuth in radians. This will
168 * return an index between 0 and (azcount - 1).
170 ALsizei
CalcAzIndex(ALsizei azcount
, ALfloat az
, ALfloat
*mu
)
172 az
= (F_TAU
+az
) * azcount
/ F_TAU
;
173 ALsizei idx
{float2int(az
)};
176 return idx
% azcount
;
182 /* Calculates static HRIR coefficients and delays for the given polar elevation
183 * and azimuth in radians. The coefficients are normalized.
185 void GetHrtfCoeffs(const struct Hrtf
*Hrtf
, ALfloat elevation
, ALfloat azimuth
, ALfloat spread
,
186 ALfloat (*RESTRICT coeffs
)[2], ALsizei
*delays
)
188 ALfloat dirfact
{1.0f
- (spread
/ F_TAU
)};
190 /* Claculate the lower elevation index. */
192 ALsizei evidx
{CalcEvIndex(Hrtf
->evCount
, elevation
, &emu
)};
193 ALsizei evoffset
{Hrtf
->evOffset
[evidx
]};
195 /* Calculate lower azimuth index. */
197 ALsizei azidx
{CalcAzIndex(Hrtf
->azCount
[evidx
], azimuth
, &amu
[0])};
199 /* Calculate the lower HRIR indices. */
202 evoffset
+ ((azidx
+1) % Hrtf
->azCount
[evidx
])
204 if(evidx
< Hrtf
->evCount
-1)
206 /* Increment elevation to the next (upper) index. */
208 evoffset
= Hrtf
->evOffset
[evidx
];
210 /* Calculate upper azimuth index. */
211 azidx
= CalcAzIndex(Hrtf
->azCount
[evidx
], azimuth
, &amu
[1]);
213 /* Calculate the upper HRIR indices. */
214 idx
[2] = evoffset
+ azidx
;
215 idx
[3] = evoffset
+ ((azidx
+1) % Hrtf
->azCount
[evidx
]);
219 /* If the lower elevation is the top index, the upper elevation is the
227 /* Calculate bilinear blending weights, attenuated according to the
228 * directional panning factor.
231 (1.0f
-emu
) * (1.0f
-amu
[0]) * dirfact
,
232 (1.0f
-emu
) * ( amu
[0]) * dirfact
,
233 ( emu
) * (1.0f
-amu
[1]) * dirfact
,
234 ( emu
) * ( amu
[1]) * dirfact
237 /* Calculate the blended HRIR delays. */
239 Hrtf
->delays
[idx
[0]][0]*blend
[0] + Hrtf
->delays
[idx
[1]][0]*blend
[1] +
240 Hrtf
->delays
[idx
[2]][0]*blend
[2] + Hrtf
->delays
[idx
[3]][0]*blend
[3]
243 Hrtf
->delays
[idx
[0]][1]*blend
[0] + Hrtf
->delays
[idx
[1]][1]*blend
[1] +
244 Hrtf
->delays
[idx
[2]][1]*blend
[2] + Hrtf
->delays
[idx
[3]][1]*blend
[3]
247 /* Calculate the sample offsets for the HRIR indices. */
248 idx
[0] *= Hrtf
->irSize
;
249 idx
[1] *= Hrtf
->irSize
;
250 idx
[2] *= Hrtf
->irSize
;
251 idx
[3] *= Hrtf
->irSize
;
253 ASSUME(Hrtf
->irSize
>= MIN_IR_SIZE
&& (Hrtf
->irSize
%MOD_IR_SIZE
) == 0);
255 /* Calculate the blended HRIR coefficients. */
256 coeffs
[0][0] = PassthruCoeff
* (1.0f
-dirfact
);
257 coeffs
[0][1] = PassthruCoeff
* (1.0f
-dirfact
);
258 for(ALsizei i
{1};i
< Hrtf
->irSize
;i
++)
263 for(ALsizei c
{0};c
< 4;c
++)
265 const ALfloat (*RESTRICT srccoeffs
)[2] = Hrtf
->coeffs
+ idx
[c
];
266 for(ALsizei i
{0};i
< Hrtf
->irSize
;i
++)
268 coeffs
[i
][0] += srccoeffs
[i
][0] * blend
[c
];
269 coeffs
[i
][1] += srccoeffs
[i
][1] * blend
[c
];
275 void BuildBFormatHrtf(const struct Hrtf
*Hrtf
, DirectHrtfState
*state
, ALsizei NumChannels
, const struct AngularPoint
*AmbiPoints
, const ALfloat (*RESTRICT AmbiMatrix
)[MAX_AMBI_COEFFS
], ALsizei AmbiCount
, const ALfloat
*RESTRICT AmbiOrderHFGain
)
277 /* Set this to 2 for dual-band HRTF processing. May require a higher quality
278 * band-splitter, or better calculation of the new IR length to deal with the
279 * tail generated by the filter.
282 ALsizei min_delay
{HRTF_HISTORY_LENGTH
};
283 ALsizei max_delay
{0};
284 std::vector
<ALsizei
> idx(AmbiCount
);
285 for(ALsizei c
{0};c
< AmbiCount
;c
++)
291 /* Calculate elevation index. */
292 evidx
= (ALsizei
)((F_PI_2
+AmbiPoints
[c
].Elev
) * (Hrtf
->evCount
-1) / F_PI
+ 0.5f
);
293 evidx
= clampi(evidx
, 0, Hrtf
->evCount
-1);
295 azcount
= Hrtf
->azCount
[evidx
];
296 evoffset
= Hrtf
->evOffset
[evidx
];
298 /* Calculate azimuth index for this elevation. */
299 azidx
= (ALsizei
)((F_TAU
+AmbiPoints
[c
].Azim
) * azcount
/ F_TAU
+ 0.5f
) % azcount
;
301 /* Calculate indices for left and right channels. */
302 idx
[c
] = evoffset
+ azidx
;
304 min_delay
= mini(min_delay
, mini(Hrtf
->delays
[idx
[c
]][0], Hrtf
->delays
[idx
[c
]][1]));
305 max_delay
= maxi(max_delay
, maxi(Hrtf
->delays
[idx
[c
]][0], Hrtf
->delays
[idx
[c
]][1]));
308 std::vector
<std::array
<std::array
<ALdouble
,2>,HRIR_LENGTH
>> tmpres(NumChannels
);
309 ALfloat temps
[3][HRIR_LENGTH
]{};
311 BandSplitter splitter
;
312 bandsplit_init(&splitter
, 400.0f
/ (ALfloat
)Hrtf
->sampleRate
);
313 for(ALsizei c
{0};c
< AmbiCount
;++c
)
315 const ALfloat (*fir
)[2] = &Hrtf
->coeffs
[idx
[c
] * Hrtf
->irSize
];
316 ALsizei ldelay
= Hrtf
->delays
[idx
[c
]][0] - min_delay
;
317 ALsizei rdelay
= Hrtf
->delays
[idx
[c
]][1] - min_delay
;
321 for(ALsizei i
{0};i
< NumChannels
;++i
)
323 ALdouble mult
= (ALdouble
)AmbiOrderHFGain
[(ALsizei
)sqrt(i
)] * AmbiMatrix
[c
][i
];
324 ALsizei lidx
= ldelay
, ridx
= rdelay
;
326 while(lidx
< HRIR_LENGTH
&& ridx
< HRIR_LENGTH
&& j
< Hrtf
->irSize
)
328 tmpres
[i
][lidx
++][0] += fir
[j
][0] * mult
;
329 tmpres
[i
][ridx
++][1] += fir
[j
][1] * mult
;
336 /* Band-split left HRIR into low and high frequency responses. */
337 bandsplit_clear(&splitter
);
338 for(ALsizei i
{0};i
< Hrtf
->irSize
;++i
)
339 temps
[2][i
] = fir
[i
][0];
340 bandsplit_process(&splitter
, temps
[0], temps
[1], temps
[2], HRIR_LENGTH
);
342 /* Apply left ear response with delay. */
343 for(ALsizei i
{0};i
< NumChannels
;++i
)
345 ALdouble hfgain
= AmbiOrderHFGain
[(ALsizei
)sqrt(i
)];
346 for(ALsizei b
{0};b
< NUM_BANDS
;++b
)
348 ALdouble mult
= AmbiMatrix
[c
][i
] * ((b
==0) ? hfgain
: 1.0);
349 ALsizei lidx
= ldelay
;
351 while(lidx
< HRIR_LENGTH
)
352 tmpres
[i
][lidx
++][0] += temps
[b
][j
++] * mult
;
356 /* Band-split right HRIR into low and high frequency responses. */
357 bandsplit_clear(&splitter
);
358 for(ALsizei i
{0};i
< Hrtf
->irSize
;++i
)
359 temps
[2][i
] = fir
[i
][1];
360 bandsplit_process(&splitter
, temps
[0], temps
[1], temps
[2], HRIR_LENGTH
);
362 /* Apply right ear response with delay. */
363 for(ALsizei i
{0};i
< NumChannels
;++i
)
365 ALdouble hfgain
= AmbiOrderHFGain
[(ALsizei
)sqrt(i
)];
366 for(ALsizei b
{0};b
< NUM_BANDS
;++b
)
368 ALdouble mult
= AmbiMatrix
[c
][i
] * ((b
==0) ? hfgain
: 1.0);
369 ALsizei ridx
= rdelay
;
371 while(ridx
< HRIR_LENGTH
)
372 tmpres
[i
][ridx
++][1] += temps
[b
][j
++] * mult
;
378 for(ALsizei i
{0};i
< NumChannels
;++i
)
380 for(ALsizei idx
{0};idx
< HRIR_LENGTH
;idx
++)
382 state
->Chan
[i
].Coeffs
[idx
][0] = (ALfloat
)tmpres
[i
][idx
][0];
383 state
->Chan
[i
].Coeffs
[idx
][1] = (ALfloat
)tmpres
[i
][idx
][1];
391 max_length
= mini(max_delay
-min_delay
+ Hrtf
->irSize
, HRIR_LENGTH
);
394 /* Increase the IR size by 2/3rds to account for the tail generated by
395 * the band-split filter.
397 const ALsizei irsize
= mini(Hrtf
->irSize
*5/3, HRIR_LENGTH
);
398 max_length
= mini(max_delay
-min_delay
+ irsize
, HRIR_LENGTH
);
400 /* Round up to the next IR size multiple. */
401 max_length
+= MOD_IR_SIZE
-1;
402 max_length
-= max_length
%MOD_IR_SIZE
;
404 TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n",
405 min_delay
, max_delay
-min_delay
, max_length
);
406 state
->IrSize
= max_length
;
413 struct Hrtf
*CreateHrtfStore(ALuint rate
, ALsizei irSize
, ALfloat distance
, ALsizei evCount
,
414 ALsizei irCount
, const ALubyte
*azCount
, const ALushort
*evOffset
, const ALfloat (*coeffs
)[2],
415 const ALubyte (*delays
)[2], const char *filename
)
420 total
= sizeof(struct Hrtf
);
421 total
+= sizeof(Hrtf
->azCount
[0])*evCount
;
422 total
= RoundUp(total
, sizeof(ALushort
)); /* Align for ushort fields */
423 total
+= sizeof(Hrtf
->evOffset
[0])*evCount
;
424 total
= RoundUp(total
, 16); /* Align for coefficients using SIMD */
425 total
+= sizeof(Hrtf
->coeffs
[0])*irSize
*irCount
;
426 total
+= sizeof(Hrtf
->delays
[0])*irCount
;
428 Hrtf
= static_cast<struct Hrtf
*>(al_calloc(16, total
));
430 ERR("Out of memory allocating storage for %s.\n", filename
);
433 uintptr_t offset
= sizeof(struct Hrtf
);
434 char *base
= (char*)Hrtf
;
437 ALubyte (*_delays
)[2];
438 ALfloat (*_coeffs
)[2];
441 InitRef(&Hrtf
->ref
, 0);
442 Hrtf
->sampleRate
= rate
;
443 Hrtf
->irSize
= irSize
;
444 Hrtf
->distance
= distance
;
445 Hrtf
->evCount
= evCount
;
447 /* Set up pointers to storage following the main HRTF struct. */
448 _azCount
= reinterpret_cast<ALubyte
*>(base
+ offset
);
449 offset
+= sizeof(_azCount
[0])*evCount
;
451 offset
= RoundUp(offset
, sizeof(ALushort
)); /* Align for ushort fields */
452 _evOffset
= reinterpret_cast<ALushort
*>(base
+ offset
);
453 offset
+= sizeof(_evOffset
[0])*evCount
;
455 offset
= RoundUp(offset
, 16); /* Align for coefficients using SIMD */
456 _coeffs
= reinterpret_cast<ALfloat(*)[2]>(base
+ offset
);
457 offset
+= sizeof(_coeffs
[0])*irSize
*irCount
;
459 _delays
= reinterpret_cast<ALubyte(*)[2]>(base
+ offset
);
460 offset
+= sizeof(_delays
[0])*irCount
;
462 assert(offset
== total
);
464 /* Copy input data to storage. */
465 for(i
= 0;i
< evCount
;i
++) _azCount
[i
] = azCount
[i
];
466 for(i
= 0;i
< evCount
;i
++) _evOffset
[i
] = evOffset
[i
];
467 for(i
= 0;i
< irSize
*irCount
;i
++)
469 _coeffs
[i
][0] = coeffs
[i
][0];
470 _coeffs
[i
][1] = coeffs
[i
][1];
472 for(i
= 0;i
< irCount
;i
++)
474 _delays
[i
][0] = delays
[i
][0];
475 _delays
[i
][1] = delays
[i
][1];
478 /* Finally, assign the storage pointers. */
479 Hrtf
->azCount
= _azCount
;
480 Hrtf
->evOffset
= _evOffset
;
481 Hrtf
->coeffs
= _coeffs
;
482 Hrtf
->delays
= _delays
;
488 ALubyte
GetLE_ALubyte(std::istream
&data
)
490 return static_cast<ALubyte
>(data
.get());
493 ALshort
GetLE_ALshort(std::istream
&data
)
495 int ret
= data
.get();
496 ret
|= data
.get() << 8;
497 return static_cast<ALshort
>((ret
^32768) - 32768);
500 ALushort
GetLE_ALushort(std::istream
&data
)
502 int ret
= data
.get();
503 ret
|= data
.get() << 8;
504 return static_cast<ALushort
>(ret
);
507 ALint
GetLE_ALint24(std::istream
&data
)
509 int ret
= data
.get();
510 ret
|= data
.get() << 8;
511 ret
|= data
.get() << 16;
512 return (ret
^8388608) - 8388608;
515 ALuint
GetLE_ALuint(std::istream
&data
)
517 int ret
= data
.get();
518 ret
|= data
.get() << 8;
519 ret
|= data
.get() << 16;
520 ret
|= data
.get() << 24;
524 struct Hrtf
*LoadHrtf00(std::istream
&data
, const char *filename
)
526 ALuint rate
{GetLE_ALuint(data
)};
527 ALushort irCount
{GetLE_ALushort(data
)};
528 ALushort irSize
{GetLE_ALushort(data
)};
529 ALubyte evCount
{GetLE_ALubyte(data
)};
530 if(!data
|| data
.eof())
532 ERR("Failed reading %s\n", filename
);
536 ALboolean failed
{AL_FALSE
};
537 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
539 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
540 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
543 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
545 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
546 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
552 std::vector
<ALushort
> evOffset(evCount
);
553 for(auto &val
: evOffset
)
554 val
= GetLE_ALushort(data
);
555 if(!data
|| data
.eof())
557 ERR("Failed reading %s\n", filename
);
560 for(ALsizei i
{1};i
< evCount
;i
++)
562 if(evOffset
[i
] <= evOffset
[i
-1])
564 ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
565 i
, evOffset
[i
], evOffset
[i
-1]);
569 if(irCount
<= evOffset
.back())
571 ERR("Invalid evOffset: evOffset[" SZFMT
"]=%d (irCount=%d)\n",
572 evOffset
.size()-1, evOffset
.back(), irCount
);
578 std::vector
<ALubyte
> azCount(evCount
);
579 for(ALsizei i
{1};i
< evCount
;i
++)
581 azCount
[i
-1] = evOffset
[i
] - evOffset
[i
-1];
582 if(azCount
[i
-1] < MIN_AZ_COUNT
|| azCount
[i
-1] > MAX_AZ_COUNT
)
584 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
585 i
-1, azCount
[i
-1], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
589 azCount
.back() = irCount
- evOffset
.back();
590 if(azCount
.back() < MIN_AZ_COUNT
|| azCount
.back() > MAX_AZ_COUNT
)
592 ERR("Unsupported azimuth count: azCount[" SZFMT
"]=%d (%d to %d)\n",
593 azCount
.size()-1, azCount
.back(), MIN_AZ_COUNT
, MAX_AZ_COUNT
);
599 std::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
600 std::vector
<std::array
<ALubyte
,2>> delays(irCount
);
601 for(auto &val
: coeffs
)
602 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
603 for(auto &val
: delays
)
604 val
[0] = GetLE_ALubyte(data
);
605 if(!data
|| data
.eof())
607 ERR("Failed reading %s\n", filename
);
610 for(ALsizei i
{0};i
< irCount
;i
++)
612 if(delays
[i
][0] > MAX_HRIR_DELAY
)
614 ERR("Invalid delays[%d]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
621 /* Mirror the left ear responses to the right ear. */
622 for(ALsizei i
{0};i
< evCount
;i
++)
624 ALushort evoffset
= evOffset
[i
];
625 ALubyte azcount
= azCount
[i
];
626 for(ALsizei j
{0};j
< azcount
;j
++)
628 ALsizei lidx
= evoffset
+ j
;
629 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
631 for(ALsizei k
{0};k
< irSize
;k
++)
632 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
633 delays
[ridx
][1] = delays
[lidx
][0];
637 return CreateHrtfStore(rate
, irSize
, 0.0f
, evCount
, irCount
, azCount
.data(),
638 evOffset
.data(), &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
639 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
642 struct Hrtf
*LoadHrtf01(std::istream
&data
, const char *filename
)
644 ALuint rate
{GetLE_ALuint(data
)};
645 ALushort irSize
{GetLE_ALubyte(data
)};
646 ALubyte evCount
{GetLE_ALubyte(data
)};
647 if(!data
|| data
.eof())
649 ERR("Failed reading %s\n", filename
);
653 ALboolean failed
{AL_FALSE
};
654 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
656 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
657 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
660 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
662 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
663 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
669 std::vector
<ALubyte
> azCount(evCount
);
670 data
.read(reinterpret_cast<char*>(azCount
.data()), evCount
);
671 if(!data
|| data
.eof() || data
.gcount() < evCount
)
673 ERR("Failed reading %s\n", filename
);
676 for(ALsizei i
{0};i
< evCount
;++i
)
678 if(azCount
[i
] < MIN_AZ_COUNT
|| azCount
[i
] > MAX_AZ_COUNT
)
680 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
681 i
, azCount
[i
], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
688 std::vector
<ALushort
> evOffset(evCount
);
690 ALushort irCount
{azCount
[0]};
691 for(ALsizei i
{1};i
< evCount
;i
++)
693 evOffset
[i
] = evOffset
[i
-1] + azCount
[i
-1];
694 irCount
+= azCount
[i
];
697 std::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
698 std::vector
<std::array
<ALubyte
,2>> delays(irCount
);
699 for(auto &val
: coeffs
)
700 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
701 for(auto &val
: delays
)
702 val
[0] = GetLE_ALubyte(data
);
703 if(!data
|| data
.eof())
705 ERR("Failed reading %s\n", filename
);
708 for(ALsizei i
{0};i
< irCount
;i
++)
710 if(delays
[i
][0] > MAX_HRIR_DELAY
)
712 ERR("Invalid delays[%d]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
719 /* Mirror the left ear responses to the right ear. */
720 for(ALsizei i
{0};i
< evCount
;i
++)
722 ALushort evoffset
= evOffset
[i
];
723 ALubyte azcount
= azCount
[i
];
724 for(ALsizei j
{0};j
< azcount
;j
++)
726 ALsizei lidx
= evoffset
+ j
;
727 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
729 for(ALsizei k
{0};k
< irSize
;k
++)
730 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
731 delays
[ridx
][1] = delays
[lidx
][0];
735 return CreateHrtfStore(rate
, irSize
, 0.0f
, evCount
, irCount
, azCount
.data(),
736 evOffset
.data(), &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
737 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
740 #define SAMPLETYPE_S16 0
741 #define SAMPLETYPE_S24 1
743 #define CHANTYPE_LEFTONLY 0
744 #define CHANTYPE_LEFTRIGHT 1
746 struct Hrtf
*LoadHrtf02(std::istream
&data
, const char *filename
)
748 ALuint rate
{GetLE_ALuint(data
)};
749 ALubyte sampleType
{GetLE_ALubyte(data
)};
750 ALubyte channelType
{GetLE_ALubyte(data
)};
751 ALushort irSize
{GetLE_ALubyte(data
)};
752 ALubyte fdCount
{GetLE_ALubyte(data
)};
753 if(!data
|| data
.eof())
755 ERR("Failed reading %s\n", filename
);
759 ALboolean failed
{AL_FALSE
};
760 if(sampleType
> SAMPLETYPE_S24
)
762 ERR("Unsupported sample type: %d\n", sampleType
);
765 if(channelType
> CHANTYPE_LEFTRIGHT
)
767 ERR("Unsupported channel type: %d\n", channelType
);
771 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
773 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
774 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
779 ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n",
780 fdCount
, MIN_FD_COUNT
, MAX_FD_COUNT
);
788 std::vector
<ALubyte
> azCount
;
789 for(ALsizei i
{0};i
< fdCount
;i
++)
791 distance
= GetLE_ALushort(data
);
792 evCount
= GetLE_ALubyte(data
);
793 if(!data
|| data
.eof())
795 ERR("Failed reading %s\n", filename
);
799 if(distance
< MIN_FD_DISTANCE
|| distance
> MAX_FD_DISTANCE
)
801 ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n",
802 distance
, MIN_FD_DISTANCE
, MAX_FD_DISTANCE
);
805 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
807 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
808 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
814 azCount
.resize(evCount
);
815 data
.read(reinterpret_cast<char*>(azCount
.data()), evCount
);
816 if(!data
|| data
.eof() || data
.gcount() < evCount
)
818 ERR("Failed reading %s\n", filename
);
822 for(ALsizei j
{0};j
< evCount
;j
++)
824 if(azCount
[j
] < MIN_AZ_COUNT
|| azCount
[j
] > MAX_AZ_COUNT
)
826 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
827 j
, azCount
[j
], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
835 std::vector
<ALushort
> evOffset(evCount
);
837 ALushort irCount
{azCount
[0]};
838 for(ALsizei i
{1};i
< evCount
;++i
)
840 evOffset
[i
] = evOffset
[i
-1] + azCount
[i
-1];
841 irCount
+= azCount
[i
];
844 std::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
845 std::vector
<std::array
<ALubyte
,2>> delays(irCount
);
846 if(channelType
== CHANTYPE_LEFTONLY
)
848 if(sampleType
== SAMPLETYPE_S16
)
850 for(auto &val
: coeffs
)
851 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
853 else if(sampleType
== SAMPLETYPE_S24
)
855 for(auto &val
: coeffs
)
856 val
[0] = GetLE_ALint24(data
) / 8388608.0f
;
858 for(auto &val
: delays
)
859 val
[0] = GetLE_ALubyte(data
);
860 if(!data
|| data
.eof())
862 ERR("Failed reading %s\n", filename
);
865 for(ALsizei i
{0};i
< irCount
;++i
)
867 if(delays
[i
][0] > MAX_HRIR_DELAY
)
869 ERR("Invalid delays[%d][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
874 else if(channelType
== CHANTYPE_LEFTRIGHT
)
876 if(sampleType
== SAMPLETYPE_S16
)
878 for(auto &val
: coeffs
)
880 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
881 val
[1] = GetLE_ALshort(data
) / 32768.0f
;
884 else if(sampleType
== SAMPLETYPE_S24
)
886 for(auto &val
: coeffs
)
888 val
[0] = GetLE_ALint24(data
) / 8388608.0f
;
889 val
[1] = GetLE_ALint24(data
) / 8388608.0f
;
892 for(auto &val
: delays
)
894 val
[0] = GetLE_ALubyte(data
);
895 val
[1] = GetLE_ALubyte(data
);
897 if(!data
|| data
.eof())
899 ERR("Failed reading %s\n", filename
);
903 for(ALsizei i
{0};i
< irCount
;++i
)
905 if(delays
[i
][0] > MAX_HRIR_DELAY
)
907 ERR("Invalid delays[%d][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
910 if(delays
[i
][1] > MAX_HRIR_DELAY
)
912 ERR("Invalid delays[%d][1]: %d (%d)\n", i
, delays
[i
][1], MAX_HRIR_DELAY
);
920 if(channelType
== CHANTYPE_LEFTONLY
)
922 /* Mirror the left ear responses to the right ear. */
923 for(ALsizei i
{0};i
< evCount
;i
++)
925 ALushort evoffset
= evOffset
[i
];
926 ALubyte azcount
= azCount
[i
];
927 for(ALsizei j
{0};j
< azcount
;j
++)
929 ALsizei lidx
= evoffset
+ j
;
930 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
932 for(ALsizei k
{0};k
< irSize
;k
++)
933 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
934 delays
[ridx
][1] = delays
[lidx
][0];
939 return CreateHrtfStore(rate
, irSize
,
940 (ALfloat
)distance
/ 1000.0f
, evCount
, irCount
, azCount
.data(), evOffset
.data(),
941 &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
942 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
947 bool checkName(al::vector
<EnumeratedHrtf
> &list
, const std::string
&name
)
949 return std::find_if(list
.cbegin(), list
.cend(),
950 [&name
](const EnumeratedHrtf
&entry
)
951 { return name
== entry
.name
; }
955 void AddFileEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
)
957 /* Check if this file has already been loaded globally. */
958 HrtfEntry
*loaded_entry
{LoadedHrtfs
};
961 if(filename
== loaded_entry
->filename
)
963 /* Check if this entry has already been added to the list. */
964 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
965 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
966 { return loaded_entry
== entry
.hrtf
; }
968 if(iter
!= list
.cend())
970 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
976 loaded_entry
= loaded_entry
->next
;
981 TRACE("Got new file \"%s\"\n", filename
.c_str());
983 loaded_entry
= static_cast<HrtfEntry
*>(al_calloc(DEF_ALIGN
,
984 FAM_SIZE(struct HrtfEntry
, filename
, filename
.length()+1)
986 loaded_entry
->next
= LoadedHrtfs
;
987 loaded_entry
->handle
= nullptr;
988 strcpy(loaded_entry
->filename
, filename
.c_str());
989 LoadedHrtfs
= loaded_entry
;
992 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
994 size_t namepos
= filename
.find_last_of('/')+1;
995 if(!namepos
) namepos
= filename
.find_last_of('\\')+1;
997 size_t extpos
{filename
.find_last_of('.')};
998 if(extpos
<= namepos
) extpos
= std::string::npos
;
1000 const std::string basename
{(extpos
== std::string::npos
) ?
1001 filename
.substr(namepos
) : filename
.substr(namepos
, extpos
-namepos
)};
1002 std::string newname
{basename
};
1004 while(checkName(list
, newname
))
1008 newname
+= std::to_string(++count
);
1010 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
});
1011 const EnumeratedHrtf
&entry
= list
.back();
1013 TRACE("Adding file entry \"%s\"\n", entry
.name
.c_str());
1016 /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
1017 * for input instead of opening the given filename.
1019 void AddBuiltInEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
, ALuint residx
)
1021 HrtfEntry
*loaded_entry
{LoadedHrtfs
};
1024 if(filename
== loaded_entry
->filename
)
1026 /* Check if this entry has already been added to the list. */
1027 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
1028 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
1029 { return loaded_entry
== entry
.hrtf
; }
1031 if(iter
!= list
.cend())
1033 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
1039 loaded_entry
= loaded_entry
->next
;
1044 size_t namelen
= filename
.length()+32;
1046 TRACE("Got new file \"%s\"\n", filename
.c_str());
1048 loaded_entry
= static_cast<HrtfEntry
*>(al_calloc(DEF_ALIGN
,
1049 FAM_SIZE(struct HrtfEntry
, filename
, namelen
)
1051 loaded_entry
->next
= LoadedHrtfs
;
1052 loaded_entry
->handle
= nullptr;
1053 snprintf(loaded_entry
->filename
, namelen
, "!%u_%s",
1054 residx
, filename
.c_str());
1055 LoadedHrtfs
= loaded_entry
;
1058 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
1059 * format update). */
1061 std::string newname
{filename
};
1063 while(checkName(list
, newname
))
1067 newname
+= std::to_string(++count
);
1069 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
});
1070 const EnumeratedHrtf
&entry
= list
.back();
1072 TRACE("Adding built-in entry \"%s\"\n", entry
.name
.c_str());
1076 #define IDR_DEFAULT_44100_MHR 1
1077 #define IDR_DEFAULT_48000_MHR 2
1079 struct ResData
{ const char *data
; size_t size
; };
1080 #ifndef ALSOFT_EMBED_HRTF_DATA
1082 ResData
GetResource(int UNUSED(name
))
1083 { return {nullptr, 0u}; }
1087 #include "default-44100.mhr.h"
1088 #include "default-48000.mhr.h"
1090 ResData
GetResource(int name
)
1092 if(name
== IDR_DEFAULT_44100_MHR
)
1093 return {reinterpret_cast<const char*>(hrtf_default_44100
), sizeof(hrtf_default_44100
)};
1094 if(name
== IDR_DEFAULT_48000_MHR
)
1095 return {reinterpret_cast<const char*>(hrtf_default_48000
), sizeof(hrtf_default_48000
)};
1096 return {nullptr, 0u};
1103 al::vector
<EnumeratedHrtf
> EnumerateHrtf(const char *devname
)
1105 al::vector
<EnumeratedHrtf
> list
;
1107 bool usedefaults
{true};
1108 const char *pathlist
{""};
1109 if(ConfigValueStr(devname
, nullptr, "hrtf-paths", &pathlist
))
1111 while(pathlist
&& *pathlist
)
1113 const char *next
, *end
;
1115 while(isspace(*pathlist
) || *pathlist
== ',')
1117 if(*pathlist
== '\0')
1120 next
= strchr(pathlist
, ',');
1125 end
= pathlist
+ strlen(pathlist
);
1126 usedefaults
= false;
1129 while(end
!= pathlist
&& isspace(*(end
-1)))
1133 const std::string pname
{pathlist
, end
};
1134 for(const auto &fname
: SearchDataFiles(".mhr", pname
.c_str()))
1135 AddFileEntry(list
, fname
);
1141 else if(ConfigValueExists(devname
, nullptr, "hrtf_tables"))
1142 ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
1146 for(const auto &fname
: SearchDataFiles(".mhr", "openal/hrtf"))
1147 AddFileEntry(list
, fname
);
1149 ResData res
{GetResource(IDR_DEFAULT_44100_MHR
)};
1150 if(res
.data
!= nullptr && res
.size
> 0)
1151 AddBuiltInEntry(list
, "Built-In 44100hz", IDR_DEFAULT_44100_MHR
);
1153 res
= GetResource(IDR_DEFAULT_48000_MHR
);
1154 if(res
.data
!= nullptr && res
.size
> 0)
1155 AddBuiltInEntry(list
, "Built-In 48000hz", IDR_DEFAULT_48000_MHR
);
1158 const char *defaulthrtf
{""};
1159 if(!list
.empty() && ConfigValueStr(devname
, nullptr, "default-hrtf", &defaulthrtf
))
1161 auto iter
= std::find_if(list
.begin(), list
.end(),
1162 [defaulthrtf
](const EnumeratedHrtf
&entry
) -> bool
1163 { return entry
.name
== defaulthrtf
; }
1165 if(iter
== list
.end())
1166 WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf
);
1167 else if(iter
!= list
.begin())
1169 EnumeratedHrtf entry
{*iter
};
1171 list
.insert(list
.begin(), entry
);
1178 struct Hrtf
*GetLoadedHrtf(struct HrtfEntry
*entry
)
1180 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1184 Hrtf
*hrtf
{entry
->handle
};
1189 std::unique_ptr
<std::istream
> stream
;
1190 const char *name
{""};
1193 if(sscanf(entry
->filename
, "!%u%c", &residx
, &ch
) == 2 && ch
== '_')
1195 name
= strchr(entry
->filename
, ch
)+1;
1197 TRACE("Loading %s...\n", name
);
1198 ResData res
{GetResource(residx
)};
1199 if(!res
.data
|| res
.size
== 0)
1201 ERR("Could not get resource %u, %s\n", residx
, name
);
1204 stream
.reset(new idstream
{res
.data
, res
.data
+res
.size
});
1208 name
= entry
->filename
;
1210 TRACE("Loading %s...\n", entry
->filename
);
1211 std::unique_ptr
<al::ifstream
> fstr
{new al::ifstream
{entry
->filename
, std::ios::binary
}};
1212 if(!fstr
->is_open())
1214 ERR("Could not open %s\n", entry
->filename
);
1217 stream
= std::move(fstr
);
1221 char magic
[sizeof(magicMarker02
)];
1222 stream
->read(magic
, sizeof(magic
));
1223 if(stream
->gcount() < static_cast<std::streamsize
>(sizeof(magicMarker02
)))
1224 ERR("%s data is too short (" SZFMT
" bytes)\n", name
, stream
->gcount());
1225 else if(memcmp(magic
, magicMarker02
, sizeof(magicMarker02
)) == 0)
1227 TRACE("Detected data set format v2\n");
1228 hrtf
= LoadHrtf02(*stream
, name
);
1230 else if(memcmp(magic
, magicMarker01
, sizeof(magicMarker01
)) == 0)
1232 TRACE("Detected data set format v1\n");
1233 hrtf
= LoadHrtf01(*stream
, name
);
1235 else if(memcmp(magic
, magicMarker00
, sizeof(magicMarker00
)) == 0)
1237 TRACE("Detected data set format v0\n");
1238 hrtf
= LoadHrtf00(*stream
, name
);
1241 ERR("Invalid header in %s: \"%.8s\"\n", name
, magic
);
1245 ERR("Failed to load %s\n", name
);
1248 entry
->handle
= hrtf
;
1250 TRACE("Loaded HRTF support for format: %s %uhz\n",
1251 DevFmtChannelsString(DevFmtStereo
), hrtf
->sampleRate
);
1258 void Hrtf_IncRef(struct Hrtf
*hrtf
)
1260 auto ref
= IncrementRef(&hrtf
->ref
);
1261 TRACEREF("%p increasing refcount to %u\n", hrtf
, ref
);
1264 void Hrtf_DecRef(struct Hrtf
*hrtf
)
1266 auto ref
= DecrementRef(&hrtf
->ref
);
1267 TRACEREF("%p decreasing refcount to %u\n", hrtf
, ref
);
1270 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1272 struct HrtfEntry
*Hrtf
{LoadedHrtfs
};
1273 while(Hrtf
!= nullptr)
1275 /* Need to double-check that it's still unused, as another device
1276 * could've reacquired this HRTF after its reference went to 0 and
1277 * before the lock was taken.
1279 if(hrtf
== Hrtf
->handle
&& ReadRef(&hrtf
->ref
) == 0)
1281 al_free(Hrtf
->handle
);
1282 Hrtf
->handle
= nullptr;
1283 TRACE("Unloaded unused HRTF %s\n", Hrtf
->filename
);
1291 void FreeHrtfs(void)
1293 struct HrtfEntry
*Hrtf
{LoadedHrtfs
};
1294 LoadedHrtfs
= nullptr;
1296 while(Hrtf
!= nullptr)
1298 struct HrtfEntry
*next
{Hrtf
->next
};
1299 al_free(Hrtf
->handle
);