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 HrtfEntry
*entry
{nullptr};
50 static std::unique_ptr
<HrtfHandle
> Create(size_t fname_len
);
55 std::unique_ptr
<HrtfHandle
> HrtfHandle::Create(size_t fname_len
)
57 void *ptr
{al_calloc(DEF_ALIGN
, FAM_SIZE(HrtfHandle
, filename
, fname_len
))};
58 return std::unique_ptr
<HrtfHandle
>{new (ptr
) HrtfHandle
{}};
63 using HrtfHandlePtr
= std::unique_ptr
<HrtfHandle
>;
65 /* Current data set limits defined by the makehrtf utility. */
66 #define MIN_IR_SIZE (8)
67 #define MAX_IR_SIZE (512)
68 #define MOD_IR_SIZE (8)
70 #define MIN_FD_COUNT (1)
71 #define MAX_FD_COUNT (16)
73 #define MIN_FD_DISTANCE (50)
74 #define MAX_FD_DISTANCE (2500)
76 #define MIN_EV_COUNT (5)
77 #define MAX_EV_COUNT (128)
79 #define MIN_AZ_COUNT (1)
80 #define MAX_AZ_COUNT (128)
82 #define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1)
84 constexpr ALchar magicMarker00
[8]{'M','i','n','P','H','R','0','0'};
85 constexpr ALchar magicMarker01
[8]{'M','i','n','P','H','R','0','1'};
86 constexpr ALchar magicMarker02
[8]{'M','i','n','P','H','R','0','2'};
88 /* First value for pass-through coefficients (remaining are 0), used for omni-
89 * directional sounds. */
90 constexpr ALfloat PassthruCoeff
{0.707106781187f
/*sqrt(0.5)*/};
92 std::mutex LoadedHrtfLock
;
93 al::vector
<HrtfHandlePtr
> LoadedHrtfs
;
96 class databuf final
: public std::streambuf
{
97 int_type
underflow() override
98 { return traits_type::eof(); }
100 pos_type
seekoff(off_type offset
, std::ios_base::seekdir whence
, std::ios_base::openmode mode
) override
102 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
103 return traits_type::eof();
108 case std::ios_base::beg
:
109 if(offset
< 0 || offset
> egptr()-eback())
110 return traits_type::eof();
111 cur
= eback() + offset
;
114 case std::ios_base::cur
:
115 if((offset
>= 0 && offset
> egptr()-gptr()) ||
116 (offset
< 0 && -offset
> gptr()-eback()))
117 return traits_type::eof();
118 cur
= gptr() + offset
;
121 case std::ios_base::end
:
122 if(offset
> 0 || -offset
> egptr()-eback())
123 return traits_type::eof();
124 cur
= egptr() + offset
;
128 return traits_type::eof();
131 setg(eback(), cur
, egptr());
132 return cur
- eback();
135 pos_type
seekpos(pos_type pos
, std::ios_base::openmode mode
) override
137 // Simplified version of seekoff
138 if((mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
139 return traits_type::eof();
141 if(pos
< 0 || pos
> egptr()-eback())
142 return traits_type::eof();
144 setg(eback(), eback() + static_cast<size_t>(pos
), egptr());
149 databuf(const char_type
*start
, const char_type
*end
) noexcept
151 setg(const_cast<char_type
*>(start
), const_cast<char_type
*>(start
),
152 const_cast<char_type
*>(end
));
156 class idstream final
: public std::istream
{
160 idstream(const char *start
, const char *end
)
161 : std::istream
{nullptr}, mStreamBuf
{start
, end
}
162 { init(&mStreamBuf
); }
166 /* Calculate the elevation index given the polar elevation in radians. This
167 * will return an index between 0 and (evcount - 1).
169 ALsizei
CalcEvIndex(ALsizei evcount
, ALfloat ev
, ALfloat
*mu
)
171 ev
= (al::MathDefs
<float>::Pi()*0.5f
+ ev
) * (evcount
-1) / al::MathDefs
<float>::Pi();
172 ALsizei idx
{float2int(ev
)};
175 return mini(idx
, evcount
-1);
178 /* Calculate the azimuth index given the polar azimuth in radians. This will
179 * return an index between 0 and (azcount - 1).
181 ALsizei
CalcAzIndex(ALsizei azcount
, ALfloat az
, ALfloat
*mu
)
183 az
= (al::MathDefs
<float>::Tau()+az
) * azcount
/ al::MathDefs
<float>::Tau();
184 ALsizei idx
{float2int(az
)};
187 return idx
% azcount
;
193 /* Calculates static HRIR coefficients and delays for the given polar elevation
194 * and azimuth in radians. The coefficients are normalized.
196 void GetHrtfCoeffs(const HrtfEntry
*Hrtf
, ALfloat elevation
, ALfloat azimuth
, ALfloat spread
,
197 ALfloat (*RESTRICT coeffs
)[2], ALsizei
*delays
)
199 const ALfloat dirfact
{1.0f
- (spread
/ al::MathDefs
<float>::Tau())};
201 /* Claculate the lower elevation index. */
203 ALsizei evidx
{CalcEvIndex(Hrtf
->evCount
, elevation
, &emu
)};
204 ALsizei evoffset
{Hrtf
->evOffset
[evidx
]};
206 /* Calculate lower azimuth index. */
208 ALsizei azidx
{CalcAzIndex(Hrtf
->azCount
[evidx
], azimuth
, &amu
[0])};
210 /* Calculate the lower HRIR indices. */
213 evoffset
+ ((azidx
+1) % Hrtf
->azCount
[evidx
])
215 if(evidx
< Hrtf
->evCount
-1)
217 /* Increment elevation to the next (upper) index. */
219 evoffset
= Hrtf
->evOffset
[evidx
];
221 /* Calculate upper azimuth index. */
222 azidx
= CalcAzIndex(Hrtf
->azCount
[evidx
], azimuth
, &amu
[1]);
224 /* Calculate the upper HRIR indices. */
225 idx
[2] = evoffset
+ azidx
;
226 idx
[3] = evoffset
+ ((azidx
+1) % Hrtf
->azCount
[evidx
]);
230 /* If the lower elevation is the top index, the upper elevation is the
238 /* Calculate bilinear blending weights, attenuated according to the
239 * directional panning factor.
241 const ALfloat blend
[4]{
242 (1.0f
-emu
) * (1.0f
-amu
[0]) * dirfact
,
243 (1.0f
-emu
) * ( amu
[0]) * dirfact
,
244 ( emu
) * (1.0f
-amu
[1]) * dirfact
,
245 ( emu
) * ( amu
[1]) * dirfact
248 /* Calculate the blended HRIR delays. */
250 Hrtf
->delays
[idx
[0]][0]*blend
[0] + Hrtf
->delays
[idx
[1]][0]*blend
[1] +
251 Hrtf
->delays
[idx
[2]][0]*blend
[2] + Hrtf
->delays
[idx
[3]][0]*blend
[3]
254 Hrtf
->delays
[idx
[0]][1]*blend
[0] + Hrtf
->delays
[idx
[1]][1]*blend
[1] +
255 Hrtf
->delays
[idx
[2]][1]*blend
[2] + Hrtf
->delays
[idx
[3]][1]*blend
[3]
258 const ALsizei irSize
{Hrtf
->irSize
};
259 ASSUME(irSize
>= MIN_IR_SIZE
);
261 /* Calculate the sample offsets for the HRIR indices. */
267 /* Calculate the blended HRIR coefficients. */
268 ALfloat
*coeffout
{al::assume_aligned
<16>(coeffs
[0])};
269 coeffout
[0] = PassthruCoeff
* (1.0f
-dirfact
);
270 coeffout
[1] = PassthruCoeff
* (1.0f
-dirfact
);
271 std::fill(coeffout
+2, coeffout
+ irSize
*2, 0.0f
);
272 for(ALsizei c
{0};c
< 4;c
++)
274 const ALfloat
*srccoeffs
{al::assume_aligned
<16>(Hrtf
->coeffs
[idx
[c
]])};
275 const ALfloat mult
{blend
[c
]};
276 auto blend_coeffs
= [mult
](const ALfloat src
, const ALfloat coeff
) noexcept
-> ALfloat
277 { return src
*mult
+ coeff
; };
278 std::transform
<const ALfloat
*RESTRICT
>(srccoeffs
, srccoeffs
+ irSize
*2, coeffout
,
279 coeffout
, blend_coeffs
);
284 std::unique_ptr
<DirectHrtfState
> DirectHrtfState::Create(ALsizei num_chans
)
286 void *ptr
{al_calloc(16, FAM_SIZE(DirectHrtfState
, Chan
, num_chans
))};
287 return std::unique_ptr
<DirectHrtfState
>{new (ptr
) DirectHrtfState
{}};
290 void BuildBFormatHrtf(const HrtfEntry
*Hrtf
, DirectHrtfState
*state
, const ALsizei NumChannels
, const AngularPoint
*AmbiPoints
, const ALfloat (*RESTRICT AmbiMatrix
)[MAX_AMBI_COEFFS
], const ALsizei AmbiCount
, const ALfloat
*RESTRICT AmbiOrderHFGain
)
292 static constexpr int OrderFromChan
[MAX_AMBI_COEFFS
]{
293 0, 1,1,1, 2,2,2,2,2, 3,3,3,3,3,3,3,
295 /* Set this to true for dual-band HRTF processing. May require a higher
296 * quality filter, or better calculation of the new IR length to deal with
297 * the tail generated by the filter.
299 static constexpr bool DualBand
{true};
301 ASSUME(NumChannels
> 0);
302 ASSUME(AmbiCount
> 0);
304 ALsizei min_delay
{HRTF_HISTORY_LENGTH
};
305 ALsizei max_delay
{0};
306 al::vector
<ALsizei
> idx(AmbiCount
);
307 auto calc_idxs
= [Hrtf
,&max_delay
,&min_delay
](const AngularPoint
&pt
) noexcept
-> ALsizei
309 /* Calculate elevation index. */
310 const auto evidx
= clampi(
311 static_cast<ALsizei
>((90.0f
+pt
.Elev
)*(Hrtf
->evCount
-1)/180.0f
+ 0.5f
),
314 const ALsizei azcount
{Hrtf
->azCount
[evidx
]};
315 const ALsizei evoffset
{Hrtf
->evOffset
[evidx
]};
317 /* Calculate azimuth index for this elevation. */
318 const auto azidx
= static_cast<ALsizei
>((360.0f
+pt
.Azim
)*azcount
/360.0f
+ 0.5f
) % azcount
;
320 /* Calculate the index for the impulse response. */
321 ALsizei idx
{evoffset
+ azidx
};
323 min_delay
= mini(min_delay
, mini(Hrtf
->delays
[idx
][0], Hrtf
->delays
[idx
][1]));
324 max_delay
= maxi(max_delay
, maxi(Hrtf
->delays
[idx
][0], Hrtf
->delays
[idx
][1]));
328 std::transform(AmbiPoints
, AmbiPoints
+AmbiCount
, idx
.begin(), calc_idxs
);
330 const ALdouble xover_norm
{400.0 / Hrtf
->sampleRate
};
331 BandSplitterR
<double> splitter
;
332 splitter
.init(xover_norm
);
334 al::vector
<std::array
<std::array
<ALdouble
,2>,HRIR_LENGTH
>> tmpres(NumChannels
);
335 al::vector
<std::array
<ALdouble
,HRIR_LENGTH
>> tmpfilt(3);
336 for(ALsizei c
{0};c
< AmbiCount
;++c
)
338 const ALfloat (*fir
)[2]{&Hrtf
->coeffs
[idx
[c
] * Hrtf
->irSize
]};
339 const ALsizei ldelay
{Hrtf
->delays
[idx
[c
]][0] - min_delay
};
340 const ALsizei rdelay
{Hrtf
->delays
[idx
[c
]][1] - min_delay
};
344 /* For single-band decoding, apply the HF scale to the response. */
345 for(ALsizei i
{0};i
< NumChannels
;++i
)
347 const ALdouble mult
{ALdouble
{AmbiOrderHFGain
[OrderFromChan
[i
]]} *
349 const ALsizei numirs
{mini(Hrtf
->irSize
, HRIR_LENGTH
-maxi(ldelay
, rdelay
))};
350 ALsizei lidx
{ldelay
}, ridx
{rdelay
};
351 for(ALsizei j
{0};j
< numirs
;++j
)
353 tmpres
[i
][lidx
++][0] += fir
[j
][0] * mult
;
354 tmpres
[i
][ridx
++][1] += fir
[j
][1] * mult
;
360 /* Split the left HRIR into low and high frequency bands. */
361 auto tmpfilt_iter
= std::transform(fir
, fir
+Hrtf
->irSize
, tmpfilt
[2].begin(),
362 [](const ALfloat (&ir
)[2]) noexcept
{ return ir
[0]; });
363 std::fill(tmpfilt_iter
, tmpfilt
[2].end(), 0.0);
365 splitter
.process(tmpfilt
[0].data(), tmpfilt
[1].data(), tmpfilt
[2].data(), HRIR_LENGTH
);
367 /* Apply left ear response with delay and HF scale. */
368 for(ALsizei i
{0};i
< NumChannels
;++i
)
370 const ALdouble mult
{AmbiMatrix
[c
][i
]};
371 const ALdouble hfgain
{AmbiOrderHFGain
[OrderFromChan
[i
]]};
372 for(ALsizei lidx
{ldelay
},j
{0};lidx
< HRIR_LENGTH
;++lidx
,++j
)
373 tmpres
[i
][lidx
][0] += (tmpfilt
[0][j
]*hfgain
+ tmpfilt
[1][j
]) * mult
;
376 /* Split the right HRIR into low and high frequency bands. */
377 tmpfilt_iter
= std::transform(fir
, fir
+Hrtf
->irSize
, tmpfilt
[2].begin(),
378 [](const ALfloat (&ir
)[2]) noexcept
{ return ir
[1]; });
379 std::fill(tmpfilt_iter
, tmpfilt
[2].end(), 0.0);
381 splitter
.process(tmpfilt
[0].data(), tmpfilt
[1].data(), tmpfilt
[2].data(), HRIR_LENGTH
);
383 /* Apply right ear response with delay and HF scale. */
384 for(ALsizei i
{0};i
< NumChannels
;++i
)
386 const ALdouble mult
{AmbiMatrix
[c
][i
]};
387 const ALdouble hfgain
{AmbiOrderHFGain
[OrderFromChan
[i
]]};
388 for(ALsizei ridx
{rdelay
},j
{0};ridx
< HRIR_LENGTH
;++ridx
,++j
)
389 tmpres
[i
][ridx
][1] += (tmpfilt
[0][j
]*hfgain
+ tmpfilt
[1][j
]) * mult
;
394 for(ALsizei i
{0};i
< NumChannels
;++i
)
396 for(ALsizei idx
{0};idx
< HRIR_LENGTH
;idx
++)
398 state
->Chan
[i
].Coeffs
[idx
][0] = static_cast<ALfloat
>(tmpres
[i
][idx
][0]);
399 state
->Chan
[i
].Coeffs
[idx
][1] = static_cast<ALfloat
>(tmpres
[i
][idx
][1]);
407 max_length
= mini(max_delay
-min_delay
+ Hrtf
->irSize
, HRIR_LENGTH
);
410 /* Increase the IR size by 2/3rds to account for the tail generated by
413 const ALsizei irsize
= mini(Hrtf
->irSize
*5/3, HRIR_LENGTH
);
414 max_length
= mini(max_delay
-min_delay
+ irsize
, HRIR_LENGTH
);
416 /* Round up to the next IR size multiple. */
417 max_length
+= MOD_IR_SIZE
-1;
418 max_length
-= max_length
%MOD_IR_SIZE
;
420 TRACE("Skipped delay: %d, max delay: %d, new FIR length: %d\n",
421 min_delay
, max_delay
-min_delay
, max_length
);
422 state
->IrSize
= max_length
;
428 HrtfEntry
*CreateHrtfStore(ALuint rate
, ALsizei irSize
, ALfloat distance
, ALsizei evCount
,
429 ALsizei irCount
, const ALubyte
*azCount
, const ALushort
*evOffset
, const ALfloat (*coeffs
)[2],
430 const ALubyte (*delays
)[2], const char *filename
)
435 total
= sizeof(HrtfEntry
);
436 total
+= sizeof(Hrtf
->azCount
[0])*evCount
;
437 total
= RoundUp(total
, sizeof(ALushort
)); /* Align for ushort fields */
438 total
+= sizeof(Hrtf
->evOffset
[0])*evCount
;
439 total
= RoundUp(total
, 16); /* Align for coefficients using SIMD */
440 total
+= sizeof(Hrtf
->coeffs
[0])*irSize
*irCount
;
441 total
+= sizeof(Hrtf
->delays
[0])*irCount
;
443 Hrtf
= static_cast<HrtfEntry
*>(al_calloc(16, total
));
445 ERR("Out of memory allocating storage for %s.\n", filename
);
448 uintptr_t offset
= sizeof(HrtfEntry
);
449 char *base
= reinterpret_cast<char*>(Hrtf
);
452 ALubyte (*_delays
)[2];
453 ALfloat (*_coeffs
)[2];
456 InitRef(&Hrtf
->ref
, 0);
457 Hrtf
->sampleRate
= rate
;
458 Hrtf
->irSize
= irSize
;
459 Hrtf
->distance
= distance
;
460 Hrtf
->evCount
= evCount
;
462 /* Set up pointers to storage following the main HRTF struct. */
463 _azCount
= reinterpret_cast<ALubyte
*>(base
+ offset
);
464 offset
+= sizeof(_azCount
[0])*evCount
;
466 offset
= RoundUp(offset
, sizeof(ALushort
)); /* Align for ushort fields */
467 _evOffset
= reinterpret_cast<ALushort
*>(base
+ offset
);
468 offset
+= sizeof(_evOffset
[0])*evCount
;
470 offset
= RoundUp(offset
, 16); /* Align for coefficients using SIMD */
471 _coeffs
= reinterpret_cast<ALfloat(*)[2]>(base
+ offset
);
472 offset
+= sizeof(_coeffs
[0])*irSize
*irCount
;
474 _delays
= reinterpret_cast<ALubyte(*)[2]>(base
+ offset
);
475 offset
+= sizeof(_delays
[0])*irCount
;
477 assert(offset
== total
);
479 /* Copy input data to storage. */
480 for(i
= 0;i
< evCount
;i
++) _azCount
[i
] = azCount
[i
];
481 for(i
= 0;i
< evCount
;i
++) _evOffset
[i
] = evOffset
[i
];
482 for(i
= 0;i
< irSize
*irCount
;i
++)
484 _coeffs
[i
][0] = coeffs
[i
][0];
485 _coeffs
[i
][1] = coeffs
[i
][1];
487 for(i
= 0;i
< irCount
;i
++)
489 _delays
[i
][0] = delays
[i
][0];
490 _delays
[i
][1] = delays
[i
][1];
493 /* Finally, assign the storage pointers. */
494 Hrtf
->azCount
= _azCount
;
495 Hrtf
->evOffset
= _evOffset
;
496 Hrtf
->coeffs
= _coeffs
;
497 Hrtf
->delays
= _delays
;
503 ALubyte
GetLE_ALubyte(std::istream
&data
)
505 return static_cast<ALubyte
>(data
.get());
508 ALshort
GetLE_ALshort(std::istream
&data
)
510 int ret
= data
.get();
511 ret
|= data
.get() << 8;
512 return static_cast<ALshort
>((ret
^32768) - 32768);
515 ALushort
GetLE_ALushort(std::istream
&data
)
517 int ret
= data
.get();
518 ret
|= data
.get() << 8;
519 return static_cast<ALushort
>(ret
);
522 ALint
GetLE_ALint24(std::istream
&data
)
524 int ret
= data
.get();
525 ret
|= data
.get() << 8;
526 ret
|= data
.get() << 16;
527 return (ret
^8388608) - 8388608;
530 ALuint
GetLE_ALuint(std::istream
&data
)
532 int ret
= data
.get();
533 ret
|= data
.get() << 8;
534 ret
|= data
.get() << 16;
535 ret
|= data
.get() << 24;
539 HrtfEntry
*LoadHrtf00(std::istream
&data
, const char *filename
)
541 ALuint rate
{GetLE_ALuint(data
)};
542 ALushort irCount
{GetLE_ALushort(data
)};
543 ALushort irSize
{GetLE_ALushort(data
)};
544 ALubyte evCount
{GetLE_ALubyte(data
)};
545 if(!data
|| data
.eof())
547 ERR("Failed reading %s\n", filename
);
551 ALboolean failed
{AL_FALSE
};
552 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
554 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
555 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
558 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
560 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
561 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
567 al::vector
<ALushort
> evOffset(evCount
);
568 for(auto &val
: evOffset
)
569 val
= GetLE_ALushort(data
);
570 if(!data
|| data
.eof())
572 ERR("Failed reading %s\n", filename
);
575 for(ALsizei i
{1};i
< evCount
;i
++)
577 if(evOffset
[i
] <= evOffset
[i
-1])
579 ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
580 i
, evOffset
[i
], evOffset
[i
-1]);
584 if(irCount
<= evOffset
.back())
586 ERR("Invalid evOffset: evOffset[" SZFMT
"]=%d (irCount=%d)\n",
587 evOffset
.size()-1, evOffset
.back(), irCount
);
593 al::vector
<ALubyte
> azCount(evCount
);
594 for(ALsizei i
{1};i
< evCount
;i
++)
596 azCount
[i
-1] = evOffset
[i
] - evOffset
[i
-1];
597 if(azCount
[i
-1] < MIN_AZ_COUNT
|| azCount
[i
-1] > MAX_AZ_COUNT
)
599 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
600 i
-1, azCount
[i
-1], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
604 azCount
.back() = irCount
- evOffset
.back();
605 if(azCount
.back() < MIN_AZ_COUNT
|| azCount
.back() > MAX_AZ_COUNT
)
607 ERR("Unsupported azimuth count: azCount[" SZFMT
"]=%d (%d to %d)\n",
608 azCount
.size()-1, azCount
.back(), MIN_AZ_COUNT
, MAX_AZ_COUNT
);
614 al::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
615 al::vector
<std::array
<ALubyte
,2>> delays(irCount
);
616 for(auto &val
: coeffs
)
617 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
618 for(auto &val
: delays
)
619 val
[0] = GetLE_ALubyte(data
);
620 if(!data
|| data
.eof())
622 ERR("Failed reading %s\n", filename
);
625 for(ALsizei i
{0};i
< irCount
;i
++)
627 if(delays
[i
][0] > MAX_HRIR_DELAY
)
629 ERR("Invalid delays[%d]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
636 /* Mirror the left ear responses to the right ear. */
637 for(ALsizei i
{0};i
< evCount
;i
++)
639 ALushort evoffset
= evOffset
[i
];
640 ALubyte azcount
= azCount
[i
];
641 for(ALsizei j
{0};j
< azcount
;j
++)
643 ALsizei lidx
= evoffset
+ j
;
644 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
646 for(ALsizei k
{0};k
< irSize
;k
++)
647 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
648 delays
[ridx
][1] = delays
[lidx
][0];
652 return CreateHrtfStore(rate
, irSize
, 0.0f
, evCount
, irCount
, azCount
.data(),
653 evOffset
.data(), &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
654 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
657 HrtfEntry
*LoadHrtf01(std::istream
&data
, const char *filename
)
659 ALuint rate
{GetLE_ALuint(data
)};
660 ALushort irSize
{GetLE_ALubyte(data
)};
661 ALubyte evCount
{GetLE_ALubyte(data
)};
662 if(!data
|| data
.eof())
664 ERR("Failed reading %s\n", filename
);
668 ALboolean failed
{AL_FALSE
};
669 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
671 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
672 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
675 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
677 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
678 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
684 al::vector
<ALubyte
> azCount(evCount
);
685 data
.read(reinterpret_cast<char*>(azCount
.data()), evCount
);
686 if(!data
|| data
.eof() || data
.gcount() < evCount
)
688 ERR("Failed reading %s\n", filename
);
691 for(ALsizei i
{0};i
< evCount
;++i
)
693 if(azCount
[i
] < MIN_AZ_COUNT
|| azCount
[i
] > MAX_AZ_COUNT
)
695 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
696 i
, azCount
[i
], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
703 al::vector
<ALushort
> evOffset(evCount
);
705 ALushort irCount
{azCount
[0]};
706 for(ALsizei i
{1};i
< evCount
;i
++)
708 evOffset
[i
] = evOffset
[i
-1] + azCount
[i
-1];
709 irCount
+= azCount
[i
];
712 al::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
713 al::vector
<std::array
<ALubyte
,2>> delays(irCount
);
714 for(auto &val
: coeffs
)
715 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
716 for(auto &val
: delays
)
717 val
[0] = GetLE_ALubyte(data
);
718 if(!data
|| data
.eof())
720 ERR("Failed reading %s\n", filename
);
723 for(ALsizei i
{0};i
< irCount
;i
++)
725 if(delays
[i
][0] > MAX_HRIR_DELAY
)
727 ERR("Invalid delays[%d]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
734 /* Mirror the left ear responses to the right ear. */
735 for(ALsizei i
{0};i
< evCount
;i
++)
737 ALushort evoffset
= evOffset
[i
];
738 ALubyte azcount
= azCount
[i
];
739 for(ALsizei j
{0};j
< azcount
;j
++)
741 ALsizei lidx
= evoffset
+ j
;
742 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
744 for(ALsizei k
{0};k
< irSize
;k
++)
745 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
746 delays
[ridx
][1] = delays
[lidx
][0];
750 return CreateHrtfStore(rate
, irSize
, 0.0f
, evCount
, irCount
, azCount
.data(),
751 evOffset
.data(), &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
752 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
);
755 #define SAMPLETYPE_S16 0
756 #define SAMPLETYPE_S24 1
758 #define CHANTYPE_LEFTONLY 0
759 #define CHANTYPE_LEFTRIGHT 1
761 HrtfEntry
*LoadHrtf02(std::istream
&data
, const char *filename
)
763 ALuint rate
{GetLE_ALuint(data
)};
764 ALubyte sampleType
{GetLE_ALubyte(data
)};
765 ALubyte channelType
{GetLE_ALubyte(data
)};
766 ALushort irSize
{GetLE_ALubyte(data
)};
767 ALubyte fdCount
{GetLE_ALubyte(data
)};
768 if(!data
|| data
.eof())
770 ERR("Failed reading %s\n", filename
);
774 ALboolean failed
{AL_FALSE
};
775 if(sampleType
> SAMPLETYPE_S24
)
777 ERR("Unsupported sample type: %d\n", sampleType
);
780 if(channelType
> CHANTYPE_LEFTRIGHT
)
782 ERR("Unsupported channel type: %d\n", channelType
);
786 if(irSize
< MIN_IR_SIZE
|| irSize
> MAX_IR_SIZE
|| (irSize
%MOD_IR_SIZE
))
788 ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
789 irSize
, MIN_IR_SIZE
, MAX_IR_SIZE
, MOD_IR_SIZE
);
794 ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n",
795 fdCount
, MIN_FD_COUNT
, MAX_FD_COUNT
);
803 al::vector
<ALubyte
> azCount
;
804 for(ALsizei i
{0};i
< fdCount
;i
++)
806 distance
= GetLE_ALushort(data
);
807 evCount
= GetLE_ALubyte(data
);
808 if(!data
|| data
.eof())
810 ERR("Failed reading %s\n", filename
);
814 if(distance
< MIN_FD_DISTANCE
|| distance
> MAX_FD_DISTANCE
)
816 ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n",
817 distance
, MIN_FD_DISTANCE
, MAX_FD_DISTANCE
);
820 if(evCount
< MIN_EV_COUNT
|| evCount
> MAX_EV_COUNT
)
822 ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
823 evCount
, MIN_EV_COUNT
, MAX_EV_COUNT
);
829 azCount
.resize(evCount
);
830 data
.read(reinterpret_cast<char*>(azCount
.data()), evCount
);
831 if(!data
|| data
.eof() || data
.gcount() < evCount
)
833 ERR("Failed reading %s\n", filename
);
837 for(ALsizei j
{0};j
< evCount
;j
++)
839 if(azCount
[j
] < MIN_AZ_COUNT
|| azCount
[j
] > MAX_AZ_COUNT
)
841 ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
842 j
, azCount
[j
], MIN_AZ_COUNT
, MAX_AZ_COUNT
);
850 al::vector
<ALushort
> evOffset(evCount
);
852 ALushort irCount
{azCount
[0]};
853 for(ALsizei i
{1};i
< evCount
;++i
)
855 evOffset
[i
] = evOffset
[i
-1] + azCount
[i
-1];
856 irCount
+= azCount
[i
];
859 al::vector
<std::array
<ALfloat
,2>> coeffs(irSize
*irCount
);
860 al::vector
<std::array
<ALubyte
,2>> delays(irCount
);
861 if(channelType
== CHANTYPE_LEFTONLY
)
863 if(sampleType
== SAMPLETYPE_S16
)
865 for(auto &val
: coeffs
)
866 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
868 else if(sampleType
== SAMPLETYPE_S24
)
870 for(auto &val
: coeffs
)
871 val
[0] = GetLE_ALint24(data
) / 8388608.0f
;
873 for(auto &val
: delays
)
874 val
[0] = GetLE_ALubyte(data
);
875 if(!data
|| data
.eof())
877 ERR("Failed reading %s\n", filename
);
880 for(ALsizei i
{0};i
< irCount
;++i
)
882 if(delays
[i
][0] > MAX_HRIR_DELAY
)
884 ERR("Invalid delays[%d][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
889 else if(channelType
== CHANTYPE_LEFTRIGHT
)
891 if(sampleType
== SAMPLETYPE_S16
)
893 for(auto &val
: coeffs
)
895 val
[0] = GetLE_ALshort(data
) / 32768.0f
;
896 val
[1] = GetLE_ALshort(data
) / 32768.0f
;
899 else if(sampleType
== SAMPLETYPE_S24
)
901 for(auto &val
: coeffs
)
903 val
[0] = GetLE_ALint24(data
) / 8388608.0f
;
904 val
[1] = GetLE_ALint24(data
) / 8388608.0f
;
907 for(auto &val
: delays
)
909 val
[0] = GetLE_ALubyte(data
);
910 val
[1] = GetLE_ALubyte(data
);
912 if(!data
|| data
.eof())
914 ERR("Failed reading %s\n", filename
);
918 for(ALsizei i
{0};i
< irCount
;++i
)
920 if(delays
[i
][0] > MAX_HRIR_DELAY
)
922 ERR("Invalid delays[%d][0]: %d (%d)\n", i
, delays
[i
][0], MAX_HRIR_DELAY
);
925 if(delays
[i
][1] > MAX_HRIR_DELAY
)
927 ERR("Invalid delays[%d][1]: %d (%d)\n", i
, delays
[i
][1], MAX_HRIR_DELAY
);
935 if(channelType
== CHANTYPE_LEFTONLY
)
937 /* Mirror the left ear responses to the right ear. */
938 for(ALsizei i
{0};i
< evCount
;i
++)
940 ALushort evoffset
= evOffset
[i
];
941 ALubyte azcount
= azCount
[i
];
942 for(ALsizei j
{0};j
< azcount
;j
++)
944 ALsizei lidx
= evoffset
+ j
;
945 ALsizei ridx
= evoffset
+ ((azcount
-j
) % azcount
);
947 for(ALsizei k
{0};k
< irSize
;k
++)
948 coeffs
[ridx
*irSize
+ k
][1] = coeffs
[lidx
*irSize
+ k
][0];
949 delays
[ridx
][1] = delays
[lidx
][0];
954 return CreateHrtfStore(rate
, irSize
,
955 static_cast<ALfloat
>(distance
) / 1000.0f
, evCount
, irCount
, azCount
.data(), evOffset
.data(),
956 &reinterpret_cast<ALfloat(&)[2]>(coeffs
[0]),
957 &reinterpret_cast<ALubyte(&)[2]>(delays
[0]), filename
962 bool checkName(al::vector
<EnumeratedHrtf
> &list
, const std::string
&name
)
964 return std::find_if(list
.cbegin(), list
.cend(),
965 [&name
](const EnumeratedHrtf
&entry
)
966 { return name
== entry
.name
; }
970 void AddFileEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
)
972 /* Check if this file has already been loaded globally. */
973 auto loaded_entry
= LoadedHrtfs
.begin();
974 for(;loaded_entry
!= LoadedHrtfs
.end();++loaded_entry
)
976 if(filename
!= (*loaded_entry
)->filename
)
979 /* Check if this entry has already been added to the list. */
980 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
981 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
982 { return loaded_entry
->get() == entry
.hrtf
; }
984 if(iter
!= list
.cend())
986 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
993 if(loaded_entry
== LoadedHrtfs
.end())
995 TRACE("Got new file \"%s\"\n", filename
.c_str());
997 LoadedHrtfs
.emplace_back(HrtfHandle::Create(filename
.length()+1));
998 loaded_entry
= LoadedHrtfs
.end()-1;
999 strcpy((*loaded_entry
)->filename
, filename
.c_str());
1002 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
1003 * format update). */
1004 size_t namepos
= filename
.find_last_of('/')+1;
1005 if(!namepos
) namepos
= filename
.find_last_of('\\')+1;
1007 size_t extpos
{filename
.find_last_of('.')};
1008 if(extpos
<= namepos
) extpos
= std::string::npos
;
1010 const std::string basename
{(extpos
== std::string::npos
) ?
1011 filename
.substr(namepos
) : filename
.substr(namepos
, extpos
-namepos
)};
1012 std::string newname
{basename
};
1014 while(checkName(list
, newname
))
1018 newname
+= std::to_string(++count
);
1020 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
->get()});
1021 const EnumeratedHrtf
&entry
= list
.back();
1023 TRACE("Adding file entry \"%s\"\n", entry
.name
.c_str());
1026 /* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
1027 * for input instead of opening the given filename.
1029 void AddBuiltInEntry(al::vector
<EnumeratedHrtf
> &list
, const std::string
&filename
, ALuint residx
)
1031 auto loaded_entry
= LoadedHrtfs
.begin();
1032 for(;loaded_entry
!= LoadedHrtfs
.end();++loaded_entry
)
1034 if(filename
!= (*loaded_entry
)->filename
)
1037 /* Check if this entry has already been added to the list. */
1038 auto iter
= std::find_if(list
.cbegin(), list
.cend(),
1039 [loaded_entry
](const EnumeratedHrtf
&entry
) -> bool
1040 { return loaded_entry
->get() == entry
.hrtf
; }
1042 if(iter
!= list
.cend())
1044 TRACE("Skipping duplicate file entry %s\n", filename
.c_str());
1051 if(loaded_entry
== LoadedHrtfs
.end())
1053 const size_t namelen
{filename
.length()+32};
1055 TRACE("Got new file \"%s\"\n", filename
.c_str());
1057 LoadedHrtfs
.emplace_back(HrtfHandle::Create(namelen
));
1058 loaded_entry
= LoadedHrtfs
.end()-1;
1059 snprintf((*loaded_entry
)->filename
, namelen
, "!%u_%s",
1060 residx
, filename
.c_str());
1063 /* TODO: Get a human-readable name from the HRTF data (possibly coming in a
1064 * format update). */
1066 std::string newname
{filename
};
1068 while(checkName(list
, newname
))
1072 newname
+= std::to_string(++count
);
1074 list
.emplace_back(EnumeratedHrtf
{newname
, loaded_entry
->get()});
1075 const EnumeratedHrtf
&entry
= list
.back();
1077 TRACE("Adding built-in entry \"%s\"\n", entry
.name
.c_str());
1081 #define IDR_DEFAULT_44100_MHR 1
1082 #define IDR_DEFAULT_48000_MHR 2
1084 struct ResData
{ const char *data
; size_t size
; };
1085 #ifndef ALSOFT_EMBED_HRTF_DATA
1087 ResData
GetResource(int UNUSED(name
))
1088 { return {nullptr, 0u}; }
1092 #include "default-44100.mhr.h"
1093 #include "default-48000.mhr.h"
1095 ResData
GetResource(int name
)
1097 if(name
== IDR_DEFAULT_44100_MHR
)
1098 return {reinterpret_cast<const char*>(hrtf_default_44100
), sizeof(hrtf_default_44100
)};
1099 if(name
== IDR_DEFAULT_48000_MHR
)
1100 return {reinterpret_cast<const char*>(hrtf_default_48000
), sizeof(hrtf_default_48000
)};
1101 return {nullptr, 0u};
1108 al::vector
<EnumeratedHrtf
> EnumerateHrtf(const char *devname
)
1110 al::vector
<EnumeratedHrtf
> list
;
1112 bool usedefaults
{true};
1113 const char *pathlist
{""};
1114 if(ConfigValueStr(devname
, nullptr, "hrtf-paths", &pathlist
))
1116 while(pathlist
&& *pathlist
)
1118 const char *next
, *end
;
1120 while(isspace(*pathlist
) || *pathlist
== ',')
1122 if(*pathlist
== '\0')
1125 next
= strchr(pathlist
, ',');
1130 end
= pathlist
+ strlen(pathlist
);
1131 usedefaults
= false;
1134 while(end
!= pathlist
&& isspace(*(end
-1)))
1138 const std::string pname
{pathlist
, end
};
1139 for(const auto &fname
: SearchDataFiles(".mhr", pname
.c_str()))
1140 AddFileEntry(list
, fname
);
1146 else if(ConfigValueExists(devname
, nullptr, "hrtf_tables"))
1147 ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
1151 for(const auto &fname
: SearchDataFiles(".mhr", "openal/hrtf"))
1152 AddFileEntry(list
, fname
);
1154 ResData res
{GetResource(IDR_DEFAULT_44100_MHR
)};
1155 if(res
.data
!= nullptr && res
.size
> 0)
1156 AddBuiltInEntry(list
, "Built-In 44100hz", IDR_DEFAULT_44100_MHR
);
1158 res
= GetResource(IDR_DEFAULT_48000_MHR
);
1159 if(res
.data
!= nullptr && res
.size
> 0)
1160 AddBuiltInEntry(list
, "Built-In 48000hz", IDR_DEFAULT_48000_MHR
);
1163 const char *defaulthrtf
{""};
1164 if(!list
.empty() && ConfigValueStr(devname
, nullptr, "default-hrtf", &defaulthrtf
))
1166 auto iter
= std::find_if(list
.begin(), list
.end(),
1167 [defaulthrtf
](const EnumeratedHrtf
&entry
) -> bool
1168 { return entry
.name
== defaulthrtf
; }
1170 if(iter
== list
.end())
1171 WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf
);
1172 else if(iter
!= list
.begin())
1174 EnumeratedHrtf entry
{*iter
};
1176 list
.insert(list
.begin(), entry
);
1183 HrtfEntry
*GetLoadedHrtf(HrtfHandle
*handle
)
1185 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1189 HrtfEntry
*hrtf
{handle
->entry
};
1194 std::unique_ptr
<std::istream
> stream
;
1195 const char *name
{""};
1198 if(sscanf(handle
->filename
, "!%u%c", &residx
, &ch
) == 2 && ch
== '_')
1200 name
= strchr(handle
->filename
, ch
)+1;
1202 TRACE("Loading %s...\n", name
);
1203 ResData res
{GetResource(residx
)};
1204 if(!res
.data
|| res
.size
== 0)
1206 ERR("Could not get resource %u, %s\n", residx
, name
);
1209 stream
= al::make_unique
<idstream
>(res
.data
, res
.data
+res
.size
);
1213 name
= handle
->filename
;
1215 TRACE("Loading %s...\n", handle
->filename
);
1216 auto fstr
= al::make_unique
<al::ifstream
>(handle
->filename
, std::ios::binary
);
1217 if(!fstr
->is_open())
1219 ERR("Could not open %s\n", handle
->filename
);
1222 stream
= std::move(fstr
);
1225 HrtfEntry
*hrtf
{nullptr};
1226 char magic
[sizeof(magicMarker02
)];
1227 stream
->read(magic
, sizeof(magic
));
1228 if(stream
->gcount() < static_cast<std::streamsize
>(sizeof(magicMarker02
)))
1229 ERR("%s data is too short (" SZFMT
" bytes)\n", name
, stream
->gcount());
1230 else if(memcmp(magic
, magicMarker02
, sizeof(magicMarker02
)) == 0)
1232 TRACE("Detected data set format v2\n");
1233 hrtf
= LoadHrtf02(*stream
, name
);
1235 else if(memcmp(magic
, magicMarker01
, sizeof(magicMarker01
)) == 0)
1237 TRACE("Detected data set format v1\n");
1238 hrtf
= LoadHrtf01(*stream
, name
);
1240 else if(memcmp(magic
, magicMarker00
, sizeof(magicMarker00
)) == 0)
1242 TRACE("Detected data set format v0\n");
1243 hrtf
= LoadHrtf00(*stream
, name
);
1246 ERR("Invalid header in %s: \"%.8s\"\n", name
, magic
);
1250 ERR("Failed to load %s\n", name
);
1253 handle
->entry
= hrtf
;
1255 TRACE("Loaded HRTF support for format: %s %uhz\n",
1256 DevFmtChannelsString(DevFmtStereo
), hrtf
->sampleRate
);
1263 void Hrtf_IncRef(HrtfEntry
*hrtf
)
1265 auto ref
= IncrementRef(&hrtf
->ref
);
1266 TRACEREF("%p increasing refcount to %u\n", hrtf
, ref
);
1269 void Hrtf_DecRef(HrtfEntry
*hrtf
)
1271 auto ref
= DecrementRef(&hrtf
->ref
);
1272 TRACEREF("%p decreasing refcount to %u\n", hrtf
, ref
);
1275 std::lock_guard
<std::mutex
> _
{LoadedHrtfLock
};
1277 /* Need to double-check that it's still unused, as another device
1278 * could've reacquired this HRTF after its reference went to 0 and
1279 * before the lock was taken.
1281 auto iter
= std::find_if(LoadedHrtfs
.begin(), LoadedHrtfs
.end(),
1282 [hrtf
](const HrtfHandlePtr
&entry
) noexcept
-> bool
1283 { return hrtf
== entry
->entry
; }
1285 if(iter
!= LoadedHrtfs
.end() && ReadRef(&hrtf
->ref
) == 0)
1287 al_free((*iter
)->entry
);
1288 (*iter
)->entry
= nullptr;
1289 TRACE("Unloaded unused HRTF %s\n", (*iter
)->filename
);