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
39 #include <type_traits>
46 #include "alfstream.h"
48 #include "alnumeric.h"
49 #include "aloptional.h"
51 #include "filters/splitter.h"
53 #include "math_defs.h"
54 #include "opthelpers.h"
58 std::unique_ptr
<HrtfEntry
> entry
;
59 al::FlexArray
<char> filename
;
61 HrtfHandle(size_t fname_len
) : filename
{fname_len
} { }
62 HrtfHandle(const HrtfHandle
&) = delete;
63 HrtfHandle
& operator=(const HrtfHandle
&) = delete;
65 static std::unique_ptr
<HrtfHandle
> Create(size_t fname_len
)
66 { return std::unique_ptr
<HrtfHandle
>{new (FamCount
{fname_len
}) HrtfHandle
{fname_len
}}; }
68 DEF_FAM_NEWDEL(HrtfHandle
, filename
)
73 using namespace std::placeholders
;
75 using HrtfHandlePtr
= std::unique_ptr
<HrtfHandle
>;
77 /* Data set limits must be the same as or more flexible than those defined in
78 * the makemhr utility.
80 #define MIN_IR_SIZE (8)
81 #define MAX_IR_SIZE (512)
82 #define MOD_IR_SIZE (2)
84 #define MIN_FD_COUNT (1)
85 #define MAX_FD_COUNT (16)
87 #define MIN_FD_DISTANCE (0.05f)
88 #define MAX_FD_DISTANCE (2.5f)
90 #define MIN_EV_COUNT (5)
91 #define MAX_EV_COUNT (128)
93 #define MIN_AZ_COUNT (1)
94 #define MAX_AZ_COUNT (128)
96 #define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1)
98 constexpr ALchar magicMarker00
[8]{'M','i','n','P','H','R','0','0'};
99 constexpr ALchar magicMarker01
[8]{'M','i','n','P','H','R','0','1'};
100 constexpr ALchar magicMarker02
[8]{'M','i','n','P','H','R','0','2'};
102 /* First value for pass-through coefficients (remaining are 0), used for omni-
103 * directional sounds. */
104 constexpr ALfloat PassthruCoeff
{0.707106781187f
/*sqrt(0.5)*/};
106 std::mutex LoadedHrtfLock
;
107 al::vector
<HrtfHandlePtr
> LoadedHrtfs
;
110 class databuf final
: public std::streambuf
{
111 int_type
underflow() override
112 { return traits_type::eof(); }
114 pos_type
seekoff(off_type offset
, std::ios_base::seekdir whence
, std::ios_base::openmode mode
) override
116 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
117 return traits_type::eof();
122 case std::ios_base::beg
:
123 if(offset
< 0 || offset
> egptr()-eback())
124 return traits_type::eof();
125 cur
= eback() + offset
;
128 case std::ios_base::cur
:
129 if((offset
>= 0 && offset
> egptr()-gptr()) ||
130 (offset
< 0 && -offset
> gptr()-eback()))
131 return traits_type::eof();
132 cur
= gptr() + offset
;
135 case std::ios_base::end
:
136 if(offset
> 0 || -offset
> egptr()-eback())
137 return traits_type::eof();
138 cur
= egptr() + offset
;
142 return traits_type::eof();
145 setg(eback(), cur
, egptr());
146 return cur
- eback();
149 pos_type
seekpos(pos_type pos
, std::ios_base::openmode mode
) override
151 // Simplified version of seekoff
152 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
153 return traits_type::eof();
155 if(pos
< 0 || pos
> egptr()-eback())
156 return traits_type::eof();
158 setg(eback(), eback() + static_cast<size_t>(pos
), egptr());
163 databuf(const char_type
*start_
, const char_type
*end_
) noexcept
165 setg(const_cast<char_type
*>(start_
), const_cast<char_type
*>(start_
),
166 const_cast<char_type
*>(end_
));
170 class idstream final
: public std::istream
{
174 idstream(const char *start_
, const char *end_
)
175 : std::istream
{nullptr}, mStreamBuf
{start_
, end_
}
176 { init(&mStreamBuf
); }
180 struct IdxBlend
{ ALsizei idx
; ALfloat blend
; };
181 /* Calculate the elevation index given the polar elevation in radians. This
182 * will return an index between 0 and (evcount - 1).
184 IdxBlend
CalcEvIndex(ALsizei evcount
, ALfloat ev
)
186 ev
= (al::MathDefs
<float>::Pi()*0.5f
+ ev
) * static_cast<float>(evcount
-1) /
187 al::MathDefs
<float>::Pi();
188 ALsizei idx
{float2int(ev
)};
190 return IdxBlend
{mini(idx
, evcount
-1), ev
-static_cast<float>(idx
)};
193 /* Calculate the azimuth index given the polar azimuth in radians. This will
194 * return an index between 0 and (azcount - 1).
196 IdxBlend
CalcAzIndex(ALsizei azcount
, ALfloat az
)
198 az
= (al::MathDefs
<float>::Tau()+az
) * static_cast<float>(azcount
) /
199 al::MathDefs
<float>::Tau();
200 ALsizei idx
{float2int(az
)};
202 return IdxBlend
{idx
%azcount
, az
-static_cast<float>(idx
)};
208 /* Calculates static HRIR coefficients and delays for the given polar elevation
209 * and azimuth in radians. The coefficients are normalized.
211 void GetHrtfCoeffs(const HrtfEntry
*Hrtf
, ALfloat elevation
, ALfloat azimuth
, ALfloat distance
,
212 ALfloat spread
, HrirArray
&coeffs
, ALsizei (&delays
)[2])
214 const ALfloat dirfact
{1.0f
- (spread
/ al::MathDefs
<float>::Tau())};
216 const auto *field
= Hrtf
->field
;
217 const auto *field_end
= field
+ Hrtf
->fdCount
-1;
219 while(distance
< field
->distance
&& field
!= field_end
)
221 ebase
+= field
->evCount
;
225 /* Claculate the elevation indinces. */
226 const auto elev0
= CalcEvIndex(field
->evCount
, elevation
);
227 const ALsizei elev1_idx
{mini(elev0
.idx
+1, field
->evCount
-1)};
228 const ALsizei ir0offset
{Hrtf
->elev
[ebase
+ elev0
.idx
].irOffset
};
229 const ALsizei ir1offset
{Hrtf
->elev
[ebase
+ elev1_idx
].irOffset
};
231 /* Calculate azimuth indices. */
232 const auto az0
= CalcAzIndex(Hrtf
->elev
[ebase
+ elev0
.idx
].azCount
, azimuth
);
233 const auto az1
= CalcAzIndex(Hrtf
->elev
[ebase
+ elev1_idx
].azCount
, azimuth
);
235 /* Calculate the HRIR indices to blend. */
238 ir0offset
+ ((az0
.idx
+1) % Hrtf
->elev
[ebase
+ elev0
.idx
].azCount
),
240 ir1offset
+ ((az1
.idx
+1) % Hrtf
->elev
[ebase
+ elev1_idx
].azCount
)
243 /* Calculate bilinear blending weights, attenuated according to the
244 * directional panning factor.
246 const ALfloat blend
[4]{
247 (1.0f
-elev0
.blend
) * (1.0f
-az0
.blend
) * dirfact
,
248 (1.0f
-elev0
.blend
) * ( az0
.blend
) * dirfact
,
249 ( elev0
.blend
) * (1.0f
-az1
.blend
) * dirfact
,
250 ( elev0
.blend
) * ( az1
.blend
) * dirfact
253 /* Calculate the blended HRIR delays. */
255 Hrtf
->delays
[idx
[0]][0]*blend
[0] + Hrtf
->delays
[idx
[1]][0]*blend
[1] +
256 Hrtf
->delays
[idx
[2]][0]*blend
[2] + Hrtf
->delays
[idx
[3]][0]*blend
[3]
259 Hrtf
->delays
[idx
[0]][1]*blend
[0] + Hrtf
->delays
[idx
[1]][1]*blend
[1] +
260 Hrtf
->delays
[idx
[2]][1]*blend
[2] + Hrtf
->delays
[idx
[3]][1]*blend
[3]
263 const ALuint irSize
{Hrtf
->irSize
};
264 ASSUME(irSize
>= MIN_IR_SIZE
);
266 /* Calculate the sample offsets for the HRIR indices. */
272 /* Calculate the blended HRIR coefficients. */
273 ALfloat
*coeffout
{al::assume_aligned
<16>(&coeffs
[0][0])};
274 coeffout
[0] = PassthruCoeff
* (1.0f
-dirfact
);
275 coeffout
[1] = PassthruCoeff
* (1.0f
-dirfact
);
276 std::fill(coeffout
+2, coeffout
+ irSize
*2, 0.0f
);
277 for(ALsizei c
{0};c
< 4;c
++)
279 const ALfloat
*srccoeffs
{al::assume_aligned
<16>(Hrtf
->coeffs
[idx
[c
]])};
280 const ALfloat mult
{blend
[c
]};
281 auto blend_coeffs
= [mult
](const ALfloat src
, const ALfloat coeff
) noexcept
-> ALfloat
282 { return src
*mult
+ coeff
; };
283 std::transform(srccoeffs
, srccoeffs
+ irSize
*2, coeffout
, coeffout
, blend_coeffs
);
288 std::unique_ptr
<DirectHrtfState
> DirectHrtfState::Create(size_t num_chans
)
290 return std::unique_ptr
<DirectHrtfState
>{new (FamCount
{num_chans
}) DirectHrtfState
{num_chans
}};
293 void BuildBFormatHrtf(const HrtfEntry
*Hrtf
, DirectHrtfState
*state
,
294 const al::span
<const AngularPoint
> AmbiPoints
, const ALfloat (*AmbiMatrix
)[MAX_AMBI_CHANNELS
],
295 const ALfloat
*AmbiOrderHFGain
)
297 using double2
= std::array
<double,2>;
298 struct ImpulseResponse
{
299 alignas(16) std::array
<double2
,HRIR_LENGTH
> hrir
;
300 ALuint ldelay
, rdelay
;
303 static constexpr int OrderFromChan
[MAX_AMBI_CHANNELS
]{
304 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,
306 /* Set this to true for dual-band HRTF processing. May require better
307 * calculation of the new IR length to deal with the head and tail
308 * generated by the HF scaling.
310 static constexpr bool DualBand
{true};
312 ALuint min_delay
{HRTF_HISTORY_LENGTH
};
314 al::vector
<ImpulseResponse
> impres
; impres
.reserve(AmbiPoints
.size());
315 auto calc_res
= [Hrtf
,&max_delay
,&min_delay
](const AngularPoint
&pt
) -> ImpulseResponse
319 auto &field
= Hrtf
->field
[0];
321 /* Calculate the elevation indices. */
322 const auto elev0
= CalcEvIndex(field
.evCount
, pt
.Elev
);
323 const ALsizei elev1_idx
{mini(elev0
.idx
+1, field
.evCount
-1)};
324 const ALsizei ir0offset
{Hrtf
->elev
[elev0
.idx
].irOffset
};
325 const ALsizei ir1offset
{Hrtf
->elev
[elev1_idx
].irOffset
};
327 /* Calculate azimuth indices. */
328 const auto az0
= CalcAzIndex(Hrtf
->elev
[elev0
.idx
].azCount
, pt
.Azim
);
329 const auto az1
= CalcAzIndex(Hrtf
->elev
[elev1_idx
].azCount
, pt
.Azim
);
331 /* Calculate the HRIR indices to blend. */
333 static_cast<ALuint
>(ir0offset
+ az0
.idx
),
334 static_cast<ALuint
>(ir0offset
+ ((az0
.idx
+1) % Hrtf
->elev
[elev0
.idx
].azCount
)),
335 static_cast<ALuint
>(ir1offset
+ az1
.idx
),
336 static_cast<ALuint
>(ir1offset
+ ((az1
.idx
+1) % Hrtf
->elev
[elev1_idx
].azCount
))};
338 /* Calculate bilinear blending weights. */
339 const ALfloat blend
[4]{
340 (1.0f
-elev0
.blend
) * (1.0f
-az0
.blend
),
341 (1.0f
-elev0
.blend
) * ( az0
.blend
),
342 ( elev0
.blend
) * (1.0f
-az1
.blend
),
343 ( elev0
.blend
) * ( az1
.blend
)};
345 /* Calculate the blended HRIR delays. */
346 res
.ldelay
= fastf2u(
347 Hrtf
->delays
[idx
[0]][0]*blend
[0] + Hrtf
->delays
[idx
[1]][0]*blend
[1] +
348 Hrtf
->delays
[idx
[2]][0]*blend
[2] + Hrtf
->delays
[idx
[3]][0]*blend
[3]);
349 res
.rdelay
= fastf2u(
350 Hrtf
->delays
[idx
[0]][1]*blend
[0] + Hrtf
->delays
[idx
[1]][1]*blend
[1] +
351 Hrtf
->delays
[idx
[2]][1]*blend
[2] + Hrtf
->delays
[idx
[3]][1]*blend
[3]);
353 const size_t irSize
{Hrtf
->irSize
};
354 ASSUME(irSize
>= MIN_IR_SIZE
);
356 /* Calculate the blended HRIR coefficients. */
357 double *coeffout
{al::assume_aligned
<16>(&res
.hrir
[0][0])};
358 std::fill(coeffout
, coeffout
+ irSize
*2, 0.0);
359 for(ALsizei c
{0};c
< 4;c
++)
361 const ALfloat
*srccoeffs
{al::assume_aligned
<16>(Hrtf
->coeffs
[idx
[c
]*irSize
])};
362 const ALfloat mult
{blend
[c
]};
363 auto blend_coeffs
= [mult
](const float src
, const double coeff
) noexcept
-> double
364 { return src
*mult
+ coeff
; };
365 std::transform(srccoeffs
, srccoeffs
+ irSize
*2, coeffout
, coeffout
, blend_coeffs
);
368 min_delay
= minu(min_delay
, minu(res
.ldelay
, res
.rdelay
));
369 max_delay
= maxu(max_delay
, maxu(res
.ldelay
, res
.rdelay
));
373 std::transform(AmbiPoints
.begin(), AmbiPoints
.end(), std::back_inserter(impres
), calc_res
);
375 /* For dual-band processing, add a 16-sample delay to compensate for the HF
376 * scale on the minimum-phase response.
378 static constexpr ALsizei base_delay
{DualBand
? 16 : 0};
379 const ALdouble xover_norm
{400.0 / Hrtf
->sampleRate
};
380 BandSplitterR
<double> splitter
{xover_norm
};
382 auto tmpres
= al::vector
<std::array
<double2
,HRIR_LENGTH
>>(state
->Coeffs
.size());
383 auto tmpflt
= al::vector
<std::array
<double,HRIR_LENGTH
*4>>(3);
384 for(size_t c
{0u};c
< AmbiPoints
.size();++c
)
386 const al::span
<const double2
,HRIR_LENGTH
> hrir
{impres
[c
].hrir
};
387 const ALuint ldelay
{impres
[c
].ldelay
- min_delay
+ base_delay
};
388 const ALuint rdelay
{impres
[c
].rdelay
- min_delay
+ base_delay
};
390 if /*constexpr*/(!DualBand
)
392 /* For single-band decoding, apply the HF scale to the response. */
393 for(size_t i
{0u};i
< state
->Coeffs
.size();++i
)
395 const double mult
{double{AmbiOrderHFGain
[OrderFromChan
[i
]]} * AmbiMatrix
[c
][i
]};
396 const ALuint numirs
{minu(Hrtf
->irSize
, HRIR_LENGTH
-maxu(ldelay
, rdelay
))};
397 ALuint lidx
{ldelay
}, ridx
{rdelay
};
398 for(ALuint j
{0};j
< numirs
;++j
)
400 tmpres
[i
][lidx
++][0] += hrir
[j
][0] * mult
;
401 tmpres
[i
][ridx
++][1] += hrir
[j
][1] * mult
;
407 /* For dual-band processing, the HRIR needs to be split into low and
408 * high frequency responses. The band-splitter alone creates frequency-
409 * dependent phase-shifts, which is not ideal. To counteract it,
410 * combine it with a backwards phase-shift.
413 /* Load the (left) HRIR backwards, into a temp buffer with padding. */
414 std::fill(tmpflt
[2].begin(), tmpflt
[2].end(), 0.0);
415 std::transform(hrir
.begin(), hrir
.begin()+Hrtf
->irSize
, tmpflt
[2].rbegin() + HRIR_LENGTH
*3,
416 [](const double2
&ir
) noexcept
-> double { return ir
[0]; });
418 /* Apply the all-pass on the reversed signal and reverse the resulting
419 * sample array. This produces the forward response with a backwards
420 * phase-shift (+n degrees becomes -n degrees).
422 splitter
.applyAllpass(tmpflt
[2].data(), tmpflt
[2].size());
423 std::reverse(tmpflt
[2].begin(), tmpflt
[2].end());
425 /* Now apply the band-splitter. This applies the normal phase-shift,
426 * which cancels out with the backwards phase-shift to get the original
427 * phase on the split signal.
430 splitter
.process(tmpflt
[0].data(), tmpflt
[1].data(), tmpflt
[2].data(), tmpflt
[2].size());
432 /* Apply left ear response with delay and HF scale. */
433 for(size_t i
{0u};i
< state
->Coeffs
.size();++i
)
435 const ALdouble mult
{AmbiMatrix
[c
][i
]};
436 const ALdouble hfgain
{AmbiOrderHFGain
[OrderFromChan
[i
]]};
437 ALuint j
{HRIR_LENGTH
*3 - ldelay
};
438 for(ALuint lidx
{0};lidx
< HRIR_LENGTH
;++lidx
,++j
)
439 tmpres
[i
][lidx
][0] += (tmpflt
[0][j
]*hfgain
+ tmpflt
[1][j
]) * mult
;
442 /* Now run the same process on the right HRIR. */
443 std::fill(tmpflt
[2].begin(), tmpflt
[2].end(), 0.0);
444 std::transform(hrir
.begin(), hrir
.begin()+Hrtf
->irSize
, tmpflt
[2].rbegin() + HRIR_LENGTH
*3,
445 [](const double2
&ir
) noexcept
-> double { return ir
[1]; });
447 splitter
.applyAllpass(tmpflt
[2].data(), tmpflt
[2].size());
448 std::reverse(tmpflt
[2].begin(), tmpflt
[2].end());
451 splitter
.process(tmpflt
[0].data(), tmpflt
[1].data(), tmpflt
[2].data(), tmpflt
[2].size());
453 for(size_t i
{0u};i
< state
->Coeffs
.size();++i
)
455 const ALdouble mult
{AmbiMatrix
[c
][i
]};
456 const ALdouble hfgain
{AmbiOrderHFGain
[OrderFromChan
[i
]]};
457 ALuint j
{HRIR_LENGTH
*3 - rdelay
};
458 for(ALuint ridx
{0};ridx
< HRIR_LENGTH
;++ridx
,++j
)
459 tmpres
[i
][ridx
][1] += (tmpflt
[0][j
]*hfgain
+ tmpflt
[1][j
]) * mult
;
465 for(size_t i
{0u};i
< state
->Coeffs
.size();++i
)
467 auto copy_arr
= [](const double2
&in
) noexcept
-> float2
468 { return float2
{{static_cast<float>(in
[0]), static_cast<float>(in
[1])}}; };
469 std::transform(tmpres
[i
].begin(), tmpres
[i
].end(), state
->Coeffs
[i
].begin(),
474 ALuint max_length
{HRIR_LENGTH
};
475 /* Increase the IR size by double the base delay with dual-band processing
476 * to account for the head and tail from the HF response scale.
478 const ALuint irsize
{minu(Hrtf
->irSize
+ base_delay
*2, max_length
)};
479 max_length
= minu(max_delay
-min_delay
+ irsize
, max_length
);
481 /* Round up to the next IR size multiple. */
482 max_length
+= MOD_IR_SIZE
-1;
483 max_length
-= max_length
%MOD_IR_SIZE
;
485 TRACE("Skipped delay: %u, max delay: %u, new FIR length: %u\n", min_delay
, max_delay
-min_delay
,
487 state
->IrSize
= max_length
;
493 std::unique_ptr
<HrtfEntry
> CreateHrtfStore(ALuint rate
, ALushort irSize
, const ALuint fdCount
,
494 const ALubyte
*evCount
, const ALfloat
*distance
, const ALushort
*azCount
,
495 const ALushort
*irOffset
, ALushort irCount
, const ALfloat (*coeffs
)[2],
496 const ALubyte (*delays
)[2], const char *filename
)
498 std::unique_ptr
<HrtfEntry
> Hrtf
;
500 ALuint evTotal
{std::accumulate(evCount
, evCount
+fdCount
, 0u)};
501 size_t total
{sizeof(HrtfEntry
)};
502 total
= RoundUp(total
, alignof(HrtfEntry::Field
)); /* Align for field infos */
503 total
+= sizeof(HrtfEntry::Field
)*fdCount
;
504 total
= RoundUp(total
, alignof(HrtfEntry::Elevation
)); /* Align for elevation infos */
505 total
+= sizeof(Hrtf
->elev
[0])*evTotal
;
506 total
= RoundUp(total
, 16); /* Align for coefficients using SIMD */
507 total
+= sizeof(Hrtf
->coeffs
[0])*irSize
*irCount
;
508 total
+= sizeof(Hrtf
->delays
[0])*irCount
;
510 Hrtf
.reset(new (al_calloc(16, total
)) HrtfEntry
{});
512 ERR("Out of memory allocating storage for %s.\n", filename
);
515 InitRef(Hrtf
->mRef
, 1u);
516 Hrtf
->sampleRate
= rate
;
517 Hrtf
->irSize
= irSize
;
518 Hrtf
->fdCount
= fdCount
;
520 /* Set up pointers to storage following the main HRTF struct. */
521 char *base
= reinterpret_cast<char*>(Hrtf
.get());
522 uintptr_t offset
= sizeof(HrtfEntry
);
524 offset
= RoundUp(offset
, alignof(HrtfEntry::Field
)); /* Align for field infos */
525 auto field_
= reinterpret_cast<HrtfEntry::Field
*>(base
+ offset
);
526 offset
+= sizeof(field_
[0])*fdCount
;
528 offset
= RoundUp(offset
, alignof(HrtfEntry::Elevation
)); /* Align for elevation infos */
529 auto elev_
= reinterpret_cast<HrtfEntry::Elevation
*>(base
+ offset
);
530 offset
+= sizeof(elev_
[0])*evTotal
;
532 offset
= RoundUp(offset
, 16); /* Align for coefficients using SIMD */
533 auto coeffs_
= reinterpret_cast<ALfloat(*)[2]>(base
+ offset
);
534 offset
+= sizeof(coeffs_
[0])*irSize
*irCount
;
536 auto delays_
= reinterpret_cast<ALubyte(*)[2]>(base
+ offset
);
537 offset
+= sizeof(delays_
[0])*irCount
;
539 assert(offset
== total
);
541 /* Copy input data to storage. */
542 for(ALuint i
{0};i
< fdCount
;i
++)
544 field_
[i
].distance
= distance
[i
];
545 field_
[i
].evCount
= evCount
[i
];
547 for(ALuint i
{0};i
< evTotal
;i
++)
549 elev_
[i
].azCount
= azCount
[i
];
550 elev_
[i
].irOffset
= irOffset
[i
];
552 for(ALuint i
{0};i
< ALuint
{irSize
}*irCount
;i
++)
554 coeffs_
[i
][0] = coeffs
[i
][0];
555 coeffs_
[i
][1] = coeffs
[i
][1];
557 for(ALuint i
{0};i
< irCount
;i
++)
559 delays_
[i
][0] = delays
[i
][0];
560 delays_
[i
][1] = delays
[i
][1];
563 /* Finally, assign the storage pointers. */
564 Hrtf
->field
= field_
;
566 Hrtf
->coeffs
= coeffs_
;
567 Hrtf
->delays
= delays_
;
573 ALubyte
GetLE_ALubyte(std::istream
&data
)
575 return static_cast<ALubyte
>(data
.get());
578 ALshort
GetLE_ALshort(std::istream
&data
)
580 int ret
= data
.get();
581 ret
|= data
.get() << 8;
582 return static_cast<ALshort
>((ret
^32768) - 32768);
585 ALushort
GetLE_ALushort(std::istream
&data
)
587 int ret
= data
.get();
588 ret
|= data
.get() << 8;
589 return static_cast<ALushort
>(ret
);
592 ALint
GetLE_ALint24(std::istream
&data
)
594 int ret
= data
.get();
595 ret
|= data
.get() << 8;
596 ret
|= data
.get() << 16;
597 return (ret
^8388608) - 8388608;
600 ALuint
GetLE_ALuint(std::istream
&data
)
602 int ret
= data
.get();
603 ret
|= data
.get() << 8;
604 ret
|= data
.get() << 16;
605 ret
|= data
.get() << 24;
606 return static_cast<ALuint
>(ret
);
609 std::unique_ptr
<HrtfEntry
> LoadHrtf00(std::istream
&data
, const char *filename
)
611 ALuint rate
{GetLE_ALuint(data
)};
612 ALushort irCount
{GetLE_ALushort(data
)};
613 ALushort irSize
{GetLE_ALushort(data
)};
614 ALubyte evCount
{GetLE_ALubyte(data
)};
615 if(!data
|| data
.eof())
617 ERR("Failed reading %s\n", filename
);
621 ALboolean failed
{AL_FALSE
};
622 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
624 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
625 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
628 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
630 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
631 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
637 auto evOffset
= al::vector
<ALushort
>(evCount
);
638 for(auto &val
: evOffset
)
639 val
= GetLE_ALushort(data
);
640 if(!data
|| data
.eof())
642 ERR("Failed reading %s\n", filename
);
645 for(size_t i
{1};i
< evCount
;i
++)
647 if(evOffset
[i
] <= evOffset
[i
-1])
649 ERR("Invalid evOffset: evOffset[%zu]=%d (last=%d)\n", i
, evOffset
[i
], evOffset
[i
-1]);
653 if(irCount
<= evOffset
.back())
655 ERR("Invalid evOffset: evOffset[%zu]=%d (irCount=%d)\n",
656 evOffset
.size()-1, evOffset
.back(), irCount
);
662 auto azCount
= al::vector
<ALushort
>(evCount
);
663 for(size_t i
{1};i
< evCount
;i
++)
665 azCount
[i
-1] = static_cast<ALushort
>(evOffset
[i
] - evOffset
[i
-1]);
666 if(azCount
[i
-1] < MIN_AZ_COUNT
|| azCount
[i
-1] > MAX_AZ_COUNT
)
668 ERR("Unsupported azimuth count: azCount[%zd]=%d (%d to %d)\n",
669 i
-1, azCount
[i
-1], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
673 azCount
.back() = static_cast<ALushort
>(irCount
- evOffset
.back());
674 if(azCount
.back() < MIN_AZ_COUNT
|| azCount
.back() > MAX_AZ_COUNT
)
676 ERR("Unsupported azimuth count: azCount[%zu]=%d (%d to %d)\n",
677 azCount
.size()-1, azCount
.back(), MIN_AZ_COUNT
, MAX_AZ_COUNT
);
683 auto coeffs
= al::vector
<std::array
<ALfloat
,2>>(irSize
*irCount
);
684 auto delays
= al::vector
<std::array
<ALubyte
,2>>(irCount
);
685 for(auto &val
: coeffs
)
686 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
687 for(auto &val
: delays
)
688 val
[0] = GetLE_ALubyte(data
);
689 if(!data
|| data
.eof())
691 ERR("Failed reading %s\n", filename
);
694 for(size_t i
{0};i
< irCount
;i
++)
696 if(delays
[i
][0] > MAX_HRIR_DELAY
)
698 ERR("Invalid delays[%zd]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
705 /* Mirror the left ear responses to the right ear. */
706 for(size_t i
{0};i
< evCount
;i
++)
708 const ALushort evoffset
{evOffset
[i
]};
709 const ALushort azcount
{azCount
[i
]};
710 for(size_t j
{0};j
< azcount
;j
++)
712 const size_t lidx
{evoffset
+ j
};
713 const size_t ridx
{evoffset
+ ((azcount
-j
) % azcount
)};
715 for(size_t k
{0};k
< irSize
;k
++)
716 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
717 delays
[ridx
][1] = delays
[lidx
][0];
721 static constexpr ALfloat distance
{0.0f
};
722 return CreateHrtfStore(rate
, irSize
, 1, &evCount
, &distance
, azCount
.data(), evOffset
.data(),
723 irCount
, &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
724 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
727 std::unique_ptr
<HrtfEntry
> LoadHrtf01(std::istream
&data
, const char *filename
)
729 ALuint rate
{GetLE_ALuint(data
)};
730 ALushort irSize
{GetLE_ALubyte(data
)};
731 ALubyte evCount
{GetLE_ALubyte(data
)};
732 if(!data
|| data
.eof())
734 ERR("Failed reading %s\n", filename
);
738 ALboolean failed
{AL_FALSE
};
739 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
741 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
742 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
745 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
747 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
748 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
754 auto azCount
= al::vector
<ALushort
>(evCount
);
755 std::generate(azCount
.begin(), azCount
.end(), std::bind(GetLE_ALubyte
, std::ref(data
)));
756 if(!data
|| data
.eof())
758 ERR("Failed reading %s\n", filename
);
761 for(size_t i
{0};i
< evCount
;++i
)
763 if(azCount
[i
] < MIN_AZ_COUNT
|| azCount
[i
] > MAX_AZ_COUNT
)
765 ERR("Unsupported azimuth count: azCount[%zd]=%d (%d to %d)\n", i
, azCount
[i
],
766 MIN_AZ_COUNT
, MAX_AZ_COUNT
);
773 auto evOffset
= al::vector
<ALushort
>(evCount
);
775 ALushort irCount
{azCount
[0]};
776 for(size_t i
{1};i
< evCount
;i
++)
778 evOffset
[i
] = static_cast<ALushort
>(evOffset
[i
-1] + azCount
[i
-1]);
779 irCount
= static_cast<ALushort
>(irCount
+ azCount
[i
]);
782 auto coeffs
= al::vector
<std::array
<ALfloat
,2>>(irSize
*irCount
);
783 auto delays
= al::vector
<std::array
<ALubyte
,2>>(irCount
);
784 for(auto &val
: coeffs
)
785 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
786 for(auto &val
: delays
)
787 val
[0] = GetLE_ALubyte(data
);
788 if(!data
|| data
.eof())
790 ERR("Failed reading %s\n", filename
);
793 for(size_t i
{0};i
< irCount
;i
++)
795 if(delays
[i
][0] > MAX_HRIR_DELAY
)
797 ERR("Invalid delays[%zd]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
804 /* Mirror the left ear responses to the right ear. */
805 for(size_t i
{0};i
< evCount
;i
++)
807 const ALushort evoffset
{evOffset
[i
]};
808 const ALushort azcount
{azCount
[i
]};
809 for(size_t j
{0};j
< azcount
;j
++)
811 const size_t lidx
{evoffset
+ j
};
812 const size_t ridx
{evoffset
+ ((azcount
-j
) % azcount
)};
814 for(size_t k
{0};k
< irSize
;k
++)
815 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
816 delays
[ridx
][1] = delays
[lidx
][0];
820 static constexpr ALfloat distance
{0.0f
};
821 return CreateHrtfStore(rate
, irSize
, 1, &evCount
, &distance
, azCount
.data(), evOffset
.data(),
822 irCount
, &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
823 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
826 #define SAMPLETYPE_S16 0
827 #define SAMPLETYPE_S24 1
829 #define CHANTYPE_LEFTONLY 0
830 #define CHANTYPE_LEFTRIGHT 1
832 std::unique_ptr
<HrtfEntry
> LoadHrtf02(std::istream
&data
, const char *filename
)
834 ALuint rate
{GetLE_ALuint(data
)};
835 ALubyte sampleType
{GetLE_ALubyte(data
)};
836 ALubyte channelType
{GetLE_ALubyte(data
)};
837 ALushort irSize
{GetLE_ALubyte(data
)};
838 ALubyte fdCount
{GetLE_ALubyte(data
)};
839 if(!data
|| data
.eof())
841 ERR("Failed reading %s\n", filename
);
845 ALboolean failed
{AL_FALSE
};
846 if(sampleType
> SAMPLETYPE_S24
)
848 ERR("Unsupported sample type: %d\n", sampleType
);
851 if(channelType
> CHANTYPE_LEFTRIGHT
)
853 ERR("Unsupported channel type: %d\n", channelType
);
857 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
859 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
860 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
863 if(fdCount
< 1 || fdCount
> MAX_FD_COUNT
)
865 ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n",
866 fdCount
, MIN_FD_COUNT
, MAX_FD_COUNT
);
872 auto distance
= al::vector
<ALfloat
>(fdCount
);
873 auto evCount
= al::vector
<ALubyte
>(fdCount
);
874 auto azCount
= al::vector
<ALushort
>{};
875 for(size_t f
{0};f
< fdCount
;f
++)
877 distance
[f
] = GetLE_ALushort(data
) / 1000.0f
;
878 evCount
[f
] = GetLE_ALubyte(data
);
879 if(!data
|| data
.eof())
881 ERR("Failed reading %s\n", filename
);
885 if(distance
[f
] < MIN_FD_DISTANCE
|| distance
[f
] > MAX_FD_DISTANCE
)
887 ERR("Unsupported field distance[%zu]=%f (%f to %f meters)\n", f
, distance
[f
],
888 MIN_FD_DISTANCE
, MAX_FD_DISTANCE
);
891 if(f
> 0 && distance
[f
] <= distance
[f
-1])
893 ERR("Field distance[%zu] is not after previous (%f > %f)\n", f
, distance
[f
],
897 if(evCount
[f
] < MIN_EV_COUNT
|| evCount
[f
] > MAX_EV_COUNT
)
899 ERR("Unsupported elevation count: evCount[%zu]=%d (%d to %d)\n", f
, evCount
[f
],
900 MIN_EV_COUNT
, MAX_EV_COUNT
);
906 const size_t ebase
{azCount
.size()};
907 azCount
.resize(ebase
+ evCount
[f
]);
908 std::generate(azCount
.begin()+static_cast<ptrdiff_t>(ebase
), azCount
.end(),
909 std::bind(GetLE_ALubyte
, std::ref(data
)));
910 if(!data
|| data
.eof())
912 ERR("Failed reading %s\n", filename
);
916 for(size_t e
{0};e
< evCount
[f
];e
++)
918 if(azCount
[ebase
+e
] < MIN_AZ_COUNT
|| azCount
[ebase
+e
] > MAX_AZ_COUNT
)
920 ERR("Unsupported azimuth count: azCount[%zu][%zu]=%d (%d to %d)\n", f
, e
,
921 azCount
[ebase
+e
], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
929 auto evOffset
= al::vector
<ALushort
>(azCount
.size());
931 std::partial_sum(azCount
.cbegin(), azCount
.cend()-1, evOffset
.begin()+1);
932 const auto irTotal
= static_cast<ALushort
>(evOffset
.back() + azCount
.back());
934 auto coeffs
= al::vector
<std::array
<ALfloat
,2>>(irSize
*irTotal
);
935 auto delays
= al::vector
<std::array
<ALubyte
,2>>(irTotal
);
936 if(channelType
== CHANTYPE_LEFTONLY
)
938 if(sampleType
== SAMPLETYPE_S16
)
940 for(auto &val
: coeffs
)
941 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
943 else if(sampleType
== SAMPLETYPE_S24
)
945 for(auto &val
: coeffs
)
946 val
[0] = static_cast<float>(GetLE_ALint24(data
)) / 8388608.0f
;
948 for(auto &val
: delays
)
949 val
[0] = GetLE_ALubyte(data
);
950 if(!data
|| data
.eof())
952 ERR("Failed reading %s\n", filename
);
955 for(size_t i
{0};i
< irTotal
;++i
)
957 if(delays
[i
][0] > MAX_HRIR_DELAY
)
959 ERR("Invalid delays[%zu][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
964 else if(channelType
== CHANTYPE_LEFTRIGHT
)
966 if(sampleType
== SAMPLETYPE_S16
)
968 for(auto &val
: coeffs
)
970 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
971 val
[1] = GetLE_ALshort(data
) / 32768.0f
;
974 else if(sampleType
== SAMPLETYPE_S24
)
976 for(auto &val
: coeffs
)
978 val
[0] = static_cast<float>(GetLE_ALint24(data
)) / 8388608.0f
;
979 val
[1] = static_cast<float>(GetLE_ALint24(data
)) / 8388608.0f
;
982 for(auto &val
: delays
)
984 val
[0] = GetLE_ALubyte(data
);
985 val
[1] = GetLE_ALubyte(data
);
987 if(!data
|| data
.eof())
989 ERR("Failed reading %s\n", filename
);
993 for(size_t i
{0};i
< irTotal
;++i
)
995 if(delays
[i
][0] > MAX_HRIR_DELAY
)
997 ERR("Invalid delays[%zu][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
1000 if(delays
[i
][1] > MAX_HRIR_DELAY
)
1002 ERR("Invalid delays[%zu][1]: %d (%d)\n", i
, delays
[i
][1], MAX_HRIR_DELAY
);
1010 if(channelType
== CHANTYPE_LEFTONLY
)
1012 /* Mirror the left ear responses to the right ear. */
1014 for(size_t f
{0};f
< fdCount
;f
++)
1016 for(size_t e
{0};e
< evCount
[f
];e
++)
1018 const ALushort evoffset
{evOffset
[ebase
+e
]};
1019 const ALushort azcount
{azCount
[ebase
+e
]};
1020 for(size_t a
{0};a
< azcount
;a
++)
1022 const size_t lidx
{evoffset
+ a
};
1023 const size_t ridx
{evoffset
+ ((azcount
-a
) % azcount
)};
1025 for(size_t k
{0};k
< irSize
;k
++)
1026 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
1027 delays
[ridx
][1] = delays
[lidx
][0];
1030 ebase
+= evCount
[f
];
1036 auto distance_
= al::vector
<ALfloat
>(distance
.size());
1037 auto evCount_
= al::vector
<ALubyte
>(evCount
.size());
1038 auto azCount_
= al::vector
<ALushort
>(azCount
.size());
1039 auto evOffset_
= al::vector
<ALushort
>(evOffset
.size());
1040 auto coeffs_
= al::vector
<float2
>(coeffs
.size());
1041 auto delays_
= al::vector
<std::array
<ALubyte
,2>>(delays
.size());
1043 /* Simple reverse for the per-field elements. */
1044 std::reverse_copy(distance
.cbegin(), distance
.cend(), distance_
.begin());
1045 std::reverse_copy(evCount
.cbegin(), evCount
.cend(), evCount_
.begin());
1047 /* Each field has a group of elevations, which each have an azimuth
1048 * count. Reverse the order of the groups, keeping the relative order
1049 * of per-group azimuth counts.
1051 auto azcnt_end
= azCount_
.end();
1052 auto copy_azs
= [&azCount
,&azcnt_end
](const ptrdiff_t ebase
, const ALubyte num_evs
) -> ptrdiff_t
1054 auto azcnt_src
= azCount
.begin()+ebase
;
1055 azcnt_end
= std::copy_backward(azcnt_src
, azcnt_src
+num_evs
, azcnt_end
);
1056 return ebase
+ num_evs
;
1058 std::accumulate(evCount
.cbegin(), evCount
.cend(), ptrdiff_t{0}, copy_azs
);
1059 assert(azCount_
.begin() == azcnt_end
);
1061 /* Reestablish the IR offset for each elevation index, given the new
1062 * ordering of elevations.
1065 std::partial_sum(azCount_
.cbegin(), azCount_
.cend()-1, evOffset_
.begin()+1);
1067 /* Reverse the order of each field's group of IRs. */
1068 auto coeffs_end
= coeffs_
.end();
1069 auto delays_end
= delays_
.end();
1070 auto copy_irs
= [irSize
,&azCount
,&coeffs
,&delays
,&coeffs_end
,&delays_end
](const ptrdiff_t ebase
, const ALubyte num_evs
) -> ptrdiff_t
1072 const ALsizei abase
{std::accumulate(azCount
.cbegin(), azCount
.cbegin()+ebase
, 0)};
1073 const ALsizei num_azs
{std::accumulate(azCount
.cbegin()+ebase
,
1074 azCount
.cbegin() + (ebase
+num_evs
), 0)};
1076 coeffs_end
= std::copy_backward(coeffs
.cbegin() + abase
*irSize
,
1077 coeffs
.cbegin() + (abase
+num_azs
)*irSize
, coeffs_end
);
1078 delays_end
= std::copy_backward(delays
.cbegin() + abase
,
1079 delays
.cbegin() + (abase
+num_azs
), delays_end
);
1081 return ebase
+ num_evs
;
1083 std::accumulate(evCount
.cbegin(), evCount
.cend(), ptrdiff_t{0}, copy_irs
);
1084 assert(coeffs_
.begin() == coeffs_end
);
1085 assert(delays_
.begin() == delays_end
);
1087 distance
= std::move(distance_
);
1088 evCount
= std::move(evCount_
);
1089 azCount
= std::move(azCount_
);
1090 evOffset
= std::move(evOffset_
);
1091 coeffs
= std::move(coeffs_
);
1092 delays
= std::move(delays_
);
1095 return CreateHrtfStore(rate
, irSize
, fdCount
, evCount
.data(), distance
.data(), azCount
.data(),
1096 evOffset
.data(), irTotal
, &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
1097 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
1101 bool checkName(al::vector
<EnumeratedHrtf
> &list
, const std::string
&name
)
1103 return std::find_if(list
.cbegin(), list
.cend(),
1104 [&name
](const EnumeratedHrtf
&entry
)
1105 { return name
== entry
.name
; }
1109 void AddFileEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
)
1111 /* Check if this file has already been loaded globally. */
1112 auto loaded_entry
= LoadedHrtfs
.begin();
1113 for(;loaded_entry
!= LoadedHrtfs
.end();++loaded_entry
)
1115 if(filename
!= (*loaded_entry
)->filename
.data())
1118 /* Check if this entry has already been added to the list. */
1119 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
1120 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
1121 { return loaded_entry
->get() == entry
.hrtf
; }
1123 if(iter
!= list
.cend())
1125 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
1132 if(loaded_entry
== LoadedHrtfs
.end())
1134 TRACE("Got new file \"%s\"\n", filename
.c_str());
1136 LoadedHrtfs
.emplace_back(HrtfHandle::Create(filename
.length()+1));
1137 loaded_entry
= LoadedHrtfs
.end()-1;
1138 std::copy(filename
.begin(), filename
.end(), (*loaded_entry
)->filename
.begin());
1139 (*loaded_entry
)->filename
.back() = '\0';
1142 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
1143 * format update). */
1144 size_t namepos
= filename
.find_last_of('/')+1;
1145 if(!namepos
) namepos
= filename
.find_last_of('\\')+1;
1147 size_t extpos
{filename
.find_last_of('.')};
1148 if(extpos
<= namepos
) extpos
= std::string::npos
;
1150 const std::string basename
{(extpos
== std::string::npos
) ?
1151 filename
.substr(namepos
) : filename
.substr(namepos
, extpos
-namepos
)};
1152 std::string newname
{basename
};
1154 while(checkName(list
, newname
))
1158 newname
+= std::to_string(++count
);
1160 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
->get()});
1161 const EnumeratedHrtf
&entry
= list
.back();
1163 TRACE("Adding file entry \"%s\"\n", entry
.name
.c_str());
1166 /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
1167 * for input instead of opening the given filename.
1169 void AddBuiltInEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
, ALuint residx
)
1171 auto loaded_entry
= LoadedHrtfs
.begin();
1172 for(;loaded_entry
!= LoadedHrtfs
.end();++loaded_entry
)
1174 if(filename
!= (*loaded_entry
)->filename
.data())
1177 /* Check if this entry has already been added to the list. */
1178 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
1179 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
1180 { return loaded_entry
->get() == entry
.hrtf
; }
1182 if(iter
!= list
.cend())
1184 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
1191 if(loaded_entry
== LoadedHrtfs
.end())
1193 TRACE("Got new file \"%s\"\n", filename
.c_str());
1195 LoadedHrtfs
.emplace_back(HrtfHandle::Create(filename
.length()+32));
1196 loaded_entry
= LoadedHrtfs
.end()-1;
1197 snprintf((*loaded_entry
)->filename
.data(), (*loaded_entry
)->filename
.size(), "!%u_%s",
1198 residx
, filename
.c_str());
1201 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
1202 * format update). */
1204 std::string newname
{filename
};
1206 while(checkName(list
, newname
))
1210 newname
+= std::to_string(++count
);
1212 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
->get()});
1213 const EnumeratedHrtf
&entry
= list
.back();
1215 TRACE("Adding built-in entry \"%s\"\n", entry
.name
.c_str());
1219 #define IDR_DEFAULT_44100_MHR 1
1220 #define IDR_DEFAULT_48000_MHR 2
1222 using ResData
= al::span
<const char>;
1223 #ifndef ALSOFT_EMBED_HRTF_DATA
1225 ResData
GetResource(int /*name*/)
1226 { return ResData
{}; }
1230 #include "default-44100.mhr.h"
1231 #include "default-48000.mhr.h"
1233 ResData
GetResource(int name
)
1235 if(name
== IDR_DEFAULT_44100_MHR
)
1236 return {reinterpret_cast<const char*>(hrtf_default_44100
), sizeof(hrtf_default_44100
)};
1237 if(name
== IDR_DEFAULT_48000_MHR
)
1238 return {reinterpret_cast<const char*>(hrtf_default_48000
), sizeof(hrtf_default_48000
)};
1246 al::vector
<EnumeratedHrtf
> EnumerateHrtf(const char *devname
)
1248 al::vector
<EnumeratedHrtf
> list
;
1250 bool usedefaults
{true};
1251 if(auto pathopt
= ConfigValueStr(devname
, nullptr, "hrtf-paths"))
1253 const char *pathlist
{pathopt
->c_str()};
1254 while(pathlist
&& *pathlist
)
1256 const char *next
, *end
;
1258 while(isspace(*pathlist
) || *pathlist
== ',')
1260 if(*pathlist
== '\0')
1263 next
= strchr(pathlist
, ',');
1268 end
= pathlist
+ strlen(pathlist
);
1269 usedefaults
= false;
1272 while(end
!= pathlist
&& isspace(*(end
-1)))
1276 const std::string pname
{pathlist
, end
};
1277 for(const auto &fname
: SearchDataFiles(".mhr", pname
.c_str()))
1278 AddFileEntry(list
, fname
);
1284 else if(ConfigValueExists(devname
, nullptr, "hrtf_tables"))
1285 ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
1289 for(const auto &fname
: SearchDataFiles(".mhr", "openal/hrtf"))
1290 AddFileEntry(list
, fname
);
1292 if(!GetResource(IDR_DEFAULT_44100_MHR
).empty())
1293 AddBuiltInEntry(list
, "Built-In 44100hz", IDR_DEFAULT_44100_MHR
);
1295 if(!GetResource(IDR_DEFAULT_48000_MHR
).empty())
1296 AddBuiltInEntry(list
, "Built-In 48000hz", IDR_DEFAULT_48000_MHR
);
1301 if(auto defhrtfopt
= ConfigValueStr(devname
, nullptr, "default-hrtf"))
1303 auto iter
= std::find_if(list
.begin(), list
.end(),
1304 [&defhrtfopt
](const EnumeratedHrtf
&entry
) -> bool
1305 { return entry
.name
== *defhrtfopt
; }
1307 if(iter
== list
.end())
1308 WARN("Failed to find default HRTF \"%s\"\n", defhrtfopt
->c_str());
1309 else if(iter
!= list
.begin())
1311 EnumeratedHrtf entry
{std::move(*iter
)};
1313 list
.insert(list
.begin(), std::move(entry
));
1321 HrtfEntry
*GetLoadedHrtf(HrtfHandle
*handle
)
1323 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1327 HrtfEntry
*hrtf
{handle
->entry
.get()};
1332 std::unique_ptr
<std::istream
> stream
;
1333 const char *name
{""};
1336 if(sscanf(handle
->filename
.data(), "!%d%c", &residx
, &ch
) == 2 && ch
== '_')
1338 name
= strchr(handle
->filename
.data(), ch
)+1;
1340 TRACE("Loading %s...\n", name
);
1341 ResData res
{GetResource(residx
)};
1344 ERR("Could not get resource %u, %s\n", residx
, name
);
1347 stream
= al::make_unique
<idstream
>(res
.begin(), res
.end());
1351 name
= handle
->filename
.data();
1353 TRACE("Loading %s...\n", handle
->filename
.data());
1354 auto fstr
= al::make_unique
<al::ifstream
>(handle
->filename
.data(), std::ios::binary
);
1355 if(!fstr
->is_open())
1357 ERR("Could not open %s\n", handle
->filename
.data());
1360 stream
= std::move(fstr
);
1363 std::unique_ptr
<HrtfEntry
> hrtf
;
1364 char magic
[sizeof(magicMarker02
)];
1365 stream
->read(magic
, sizeof(magic
));
1366 if(stream
->gcount() < static_cast<std::streamsize
>(sizeof(magicMarker02
)))
1367 ERR("%s data is too short (%zu bytes)\n", name
, stream
->gcount());
1368 else if(memcmp(magic
, magicMarker02
, sizeof(magicMarker02
)) == 0)
1370 TRACE("Detected data set format v2\n");
1371 hrtf
= LoadHrtf02(*stream
, name
);
1373 else if(memcmp(magic
, magicMarker01
, sizeof(magicMarker01
)) == 0)
1375 TRACE("Detected data set format v1\n");
1376 hrtf
= LoadHrtf01(*stream
, name
);
1378 else if(memcmp(magic
, magicMarker00
, sizeof(magicMarker00
)) == 0)
1380 TRACE("Detected data set format v0\n");
1381 hrtf
= LoadHrtf00(*stream
, name
);
1384 ERR("Invalid header in %s: \"%.8s\"\n", name
, magic
);
1389 ERR("Failed to load %s\n", name
);
1393 TRACE("Loaded HRTF support for sample rate: %uhz\n", hrtf
->sampleRate
);
1394 handle
->entry
= std::move(hrtf
);
1396 return handle
->entry
.get();
1400 void HrtfEntry::IncRef()
1402 auto ref
= IncrementRef(mRef
);
1403 TRACE("HrtfEntry %p increasing refcount to %u\n", decltype(std::declval
<void*>()){this}, ref
);
1406 void HrtfEntry::DecRef()
1408 auto ref
= DecrementRef(mRef
);
1409 TRACE("HrtfEntry %p decreasing refcount to %u\n", decltype(std::declval
<void*>()){this}, ref
);
1412 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1414 /* Go through and clear all unused HRTFs. */
1415 auto delete_unused
= [](HrtfHandlePtr
&handle
) -> void
1417 HrtfEntry
*entry
{handle
->entry
.get()};
1418 if(entry
&& ReadRef(entry
->mRef
) == 0)
1420 TRACE("Unloading unused HRTF %s\n", handle
->filename
.data());
1421 handle
->entry
= nullptr;
1424 std::for_each(LoadedHrtfs
.begin(), LoadedHrtfs
.end(), delete_unused
);