2014-02-23 21:11:01 -08:00
|
|
|
#ifndef ALC_HRTF_H
|
|
|
|
#define ALC_HRTF_H
|
|
|
|
|
2019-02-07 08:38:49 -08:00
|
|
|
#include <array>
|
2019-01-08 23:44:08 -08:00
|
|
|
#include <memory>
|
2018-12-25 11:09:41 -08:00
|
|
|
#include <string>
|
|
|
|
|
2014-02-23 21:11:01 -08:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
|
2018-11-18 19:19:35 -08:00
|
|
|
#include "vector.h"
|
2018-11-22 07:54:29 -08:00
|
|
|
#include "almalloc.h"
|
2015-09-20 04:10:21 -07:00
|
|
|
|
2016-07-07 10:26:42 -07:00
|
|
|
|
2018-01-11 03:53:25 -08:00
|
|
|
#define HRTF_HISTORY_BITS (6)
|
|
|
|
#define HRTF_HISTORY_LENGTH (1<<HRTF_HISTORY_BITS)
|
|
|
|
#define HRTF_HISTORY_MASK (HRTF_HISTORY_LENGTH-1)
|
|
|
|
|
|
|
|
#define HRIR_BITS (7)
|
|
|
|
#define HRIR_LENGTH (1<<HRIR_BITS)
|
|
|
|
#define HRIR_MASK (HRIR_LENGTH-1)
|
|
|
|
|
|
|
|
|
2018-12-22 09:20:50 -08:00
|
|
|
struct HrtfHandle;
|
2017-04-05 12:27:30 -07:00
|
|
|
|
2018-12-22 09:20:50 -08:00
|
|
|
struct HrtfEntry {
|
2017-04-06 13:00:29 -07:00
|
|
|
RefCount ref;
|
|
|
|
|
2016-07-07 10:26:42 -07:00
|
|
|
ALuint sampleRate;
|
2017-01-16 07:45:07 -08:00
|
|
|
ALsizei irSize;
|
2017-10-23 13:26:35 -07:00
|
|
|
|
2019-02-27 23:13:40 -08:00
|
|
|
/* Base elevation index for the farthest field. */
|
|
|
|
ALsizei evFarBase;
|
2019-01-28 20:31:58 -08:00
|
|
|
struct Field {
|
|
|
|
ALubyte evCount;
|
2019-02-27 23:13:40 -08:00
|
|
|
ALfloat distance;
|
2019-01-28 20:31:58 -08:00
|
|
|
};
|
2019-02-27 23:13:40 -08:00
|
|
|
/* NOTE: Fields are stored *backwards*. field[0] is the farthest field, and
|
|
|
|
* field[fdCount-1] is the nearest.
|
|
|
|
*/
|
2019-01-28 20:31:58 -08:00
|
|
|
ALsizei fdCount;
|
|
|
|
Field *field;
|
2016-07-07 10:26:42 -07:00
|
|
|
|
|
|
|
const ALubyte *azCount;
|
|
|
|
const ALushort *evOffset;
|
2017-04-07 08:46:50 -07:00
|
|
|
const ALfloat (*coeffs)[2];
|
|
|
|
const ALubyte (*delays)[2];
|
2019-01-24 10:05:37 -08:00
|
|
|
|
|
|
|
void IncRef();
|
|
|
|
void DecRef();
|
|
|
|
|
|
|
|
static constexpr inline const char *CurrentPrefix() noexcept { return "HrtfEntry::"; }
|
|
|
|
DEF_PLACE_NEWDEL()
|
2016-07-07 10:26:42 -07:00
|
|
|
};
|
2014-02-23 21:11:01 -08:00
|
|
|
|
2018-12-25 11:09:41 -08:00
|
|
|
struct EnumeratedHrtf {
|
|
|
|
std::string name;
|
|
|
|
|
|
|
|
HrtfHandle *hrtf;
|
|
|
|
};
|
|
|
|
|
2017-01-18 19:16:24 -08:00
|
|
|
|
2019-03-29 11:28:38 -07:00
|
|
|
using float2 = std::array<float,2>;
|
|
|
|
|
2019-02-07 08:38:49 -08:00
|
|
|
template<typename T>
|
|
|
|
using HrirArray = std::array<std::array<T,2>,HRIR_LENGTH>;
|
|
|
|
|
2018-11-22 06:59:32 -08:00
|
|
|
struct HrtfState {
|
2019-02-07 08:38:49 -08:00
|
|
|
alignas(16) std::array<ALfloat,HRTF_HISTORY_LENGTH> History;
|
|
|
|
alignas(16) HrirArray<ALfloat> Values;
|
2018-11-22 06:59:32 -08:00
|
|
|
};
|
2018-01-11 03:53:25 -08:00
|
|
|
|
2018-11-22 06:59:32 -08:00
|
|
|
struct HrtfParams {
|
2019-02-07 08:38:49 -08:00
|
|
|
alignas(16) HrirArray<ALfloat> Coeffs;
|
2018-01-11 03:53:25 -08:00
|
|
|
ALsizei Delay[2];
|
|
|
|
ALfloat Gain;
|
2018-11-22 06:59:32 -08:00
|
|
|
};
|
2018-01-11 03:53:25 -08:00
|
|
|
|
2018-11-22 06:59:32 -08:00
|
|
|
struct DirectHrtfState {
|
2018-01-11 03:53:25 -08:00
|
|
|
/* HRTF filter state for dry buffer content */
|
2018-11-22 14:36:37 -08:00
|
|
|
ALsizei IrSize{0};
|
2019-01-12 01:25:33 -08:00
|
|
|
struct ChanData {
|
2019-02-07 08:38:49 -08:00
|
|
|
alignas(16) HrirArray<ALfloat> Values;
|
|
|
|
alignas(16) HrirArray<ALfloat> Coeffs;
|
2019-01-12 01:25:33 -08:00
|
|
|
};
|
|
|
|
al::FlexArray<ChanData> Chan;
|
2018-11-22 07:54:29 -08:00
|
|
|
|
2019-01-12 01:25:33 -08:00
|
|
|
DirectHrtfState(size_t numchans) : Chan{numchans} { }
|
|
|
|
DirectHrtfState(const DirectHrtfState&) = delete;
|
|
|
|
DirectHrtfState& operator=(const DirectHrtfState&) = delete;
|
|
|
|
|
|
|
|
static std::unique_ptr<DirectHrtfState> Create(size_t num_chans);
|
|
|
|
static constexpr size_t Sizeof(size_t numchans) noexcept
|
|
|
|
{ return al::FlexArray<ChanData>::Sizeof(numchans, offsetof(DirectHrtfState, Chan)); }
|
2018-11-22 14:36:37 -08:00
|
|
|
|
2018-11-22 07:54:29 -08:00
|
|
|
DEF_PLACE_NEWDEL()
|
2018-11-22 06:59:32 -08:00
|
|
|
};
|
2018-01-11 03:53:25 -08:00
|
|
|
|
2018-02-17 22:12:54 -08:00
|
|
|
struct AngularPoint {
|
|
|
|
ALfloat Elev;
|
|
|
|
ALfloat Azim;
|
|
|
|
};
|
|
|
|
|
2018-01-11 03:53:25 -08:00
|
|
|
|
2018-11-18 19:19:35 -08:00
|
|
|
al::vector<EnumeratedHrtf> EnumerateHrtf(const char *devname);
|
2018-12-22 09:20:50 -08:00
|
|
|
HrtfEntry *GetLoadedHrtf(HrtfHandle *handle);
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2019-02-07 08:38:49 -08:00
|
|
|
void GetHrtfCoeffs(const HrtfEntry *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat distance,
|
2019-03-14 22:26:19 -07:00
|
|
|
ALfloat spread, HrirArray<ALfloat> &coeffs, ALsizei (&delays)[2]);
|
2014-02-23 21:11:01 -08:00
|
|
|
|
2017-01-18 19:16:24 -08:00
|
|
|
/**
|
|
|
|
* Produces HRTF filter coefficients for decoding B-Format, given a set of
|
2018-05-15 22:11:10 -07:00
|
|
|
* virtual speaker positions, a matching decoding matrix, and per-order high-
|
|
|
|
* frequency gains for the decoder. The calculated impulse responses are
|
2018-12-21 08:55:22 -08:00
|
|
|
* ordered and scaled according to the matrix input. Note the specified virtual
|
|
|
|
* positions should be in degrees, not radians!
|
Decode directly from B-Format to HRTF instead of a cube
Last time this attempted to average the HRIRs according to their contribution
to a given B-Format channel as if they were loudspeakers, as well as averaging
the HRIR delays. The latter part resulted in the loss of the ITD (inter-aural
time delay), a key component of HRTF.
This time, the HRIRs are averaged similar to above, except instead of averaging
the delays, they're applied to the resulting coefficients (for example, a delay
of 8 would apply the HRIR starting at the 8th sample of the target HRIR). This
does roughly double the IR length, as the largest delay is about 35 samples
while the filter is normally 32 samples. However, this is still smaller the
original data set IR (which was 256 samples), it also only needs to be applied
to 4 channels for first-order ambisonics, rather than the 8-channel cube. So
it's doing twice as much work per sample, but only working on half the number
of samples.
Additionally, since the resulting HRIRs no longer rely on an extra delay line,
a more efficient HRTF mixing function can be made that doesn't use one. Such a
function can also avoid the per-sample stepping parameters the original uses.
2016-08-11 23:20:35 -07:00
|
|
|
*/
|
2019-04-12 19:19:24 -07:00
|
|
|
void BuildBFormatHrtf(const HrtfEntry *Hrtf, DirectHrtfState *state, const ALsizei NumChannels, const AngularPoint *AmbiPoints, const ALfloat (*RESTRICT AmbiMatrix)[MAX_AMBI_CHANNELS], const size_t AmbiCount, const ALfloat *RESTRICT AmbiOrderHFGain);
|
Decode directly from B-Format to HRTF instead of a cube
Last time this attempted to average the HRIRs according to their contribution
to a given B-Format channel as if they were loudspeakers, as well as averaging
the HRIR delays. The latter part resulted in the loss of the ITD (inter-aural
time delay), a key component of HRTF.
This time, the HRIRs are averaged similar to above, except instead of averaging
the delays, they're applied to the resulting coefficients (for example, a delay
of 8 would apply the HRIR starting at the 8th sample of the target HRIR). This
does roughly double the IR length, as the largest delay is about 35 samples
while the filter is normally 32 samples. However, this is still smaller the
original data set IR (which was 256 samples), it also only needs to be applied
to 4 channels for first-order ambisonics, rather than the 8-channel cube. So
it's doing twice as much work per sample, but only working on half the number
of samples.
Additionally, since the resulting HRIRs no longer rely on an extra delay line,
a more efficient HRTF mixing function can be made that doesn't use one. Such a
function can also avoid the per-sample stepping parameters the original uses.
2016-08-11 23:20:35 -07:00
|
|
|
|
2014-02-23 21:11:01 -08:00
|
|
|
#endif /* ALC_HRTF_H */
|