2011-05-01 20:59:44 +00:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 2011 by Chris Robinson
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public
|
|
|
|
* License along with this library; if not, write to the
|
2014-08-18 12:11:03 +00:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2011-05-01 20:59:44 +00:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2011-09-18 17:09:32 +00:00
|
|
|
#include <stdlib.h>
|
2011-09-18 18:10:32 +00:00
|
|
|
#include <ctype.h>
|
2011-09-18 17:09:32 +00:00
|
|
|
|
2011-05-01 20:59:44 +00:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
#include "alMain.h"
|
2011-06-03 08:06:00 +00:00
|
|
|
#include "alSource.h"
|
2012-09-11 08:59:42 +00:00
|
|
|
#include "alu.h"
|
2016-08-21 10:05:42 +00:00
|
|
|
#include "bformatdec.h"
|
2014-02-24 05:11:01 +00:00
|
|
|
#include "hrtf.h"
|
2018-01-11 15:56:54 +00:00
|
|
|
#include "alconfig.h"
|
2011-05-01 20:59:44 +00:00
|
|
|
|
2015-10-06 11:01:53 +00:00
|
|
|
#include "compat.h"
|
2016-07-07 17:31:43 +00:00
|
|
|
#include "almalloc.h"
|
2015-10-06 11:01:53 +00:00
|
|
|
|
2012-09-12 10:45:26 +00:00
|
|
|
|
2012-09-11 08:59:42 +00:00
|
|
|
/* Current data set limits defined by the makehrtf utility. */
|
|
|
|
#define MIN_IR_SIZE (8)
|
2017-07-25 23:17:46 +00:00
|
|
|
#define MAX_IR_SIZE (512)
|
2012-09-11 08:59:42 +00:00
|
|
|
#define MOD_IR_SIZE (8)
|
2011-07-16 07:22:01 +00:00
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
#define MIN_FD_COUNT (1)
|
|
|
|
#define MAX_FD_COUNT (16)
|
|
|
|
|
|
|
|
#define MIN_FD_DISTANCE (50)
|
|
|
|
#define MAX_FD_DISTANCE (2500)
|
|
|
|
|
2012-09-11 08:59:42 +00:00
|
|
|
#define MIN_EV_COUNT (5)
|
|
|
|
#define MAX_EV_COUNT (128)
|
2011-07-16 07:22:01 +00:00
|
|
|
|
2012-09-11 08:59:42 +00:00
|
|
|
#define MIN_AZ_COUNT (1)
|
|
|
|
#define MAX_AZ_COUNT (128)
|
2011-05-01 20:59:44 +00:00
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
#define MAX_HRIR_DELAY (HRTF_HISTORY_LENGTH-1)
|
|
|
|
|
2017-04-05 19:27:30 +00:00
|
|
|
struct HrtfEntry {
|
|
|
|
struct HrtfEntry *next;
|
|
|
|
struct Hrtf *handle;
|
|
|
|
char filename[];
|
|
|
|
};
|
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
static const ALchar magicMarker00[8] = "MinPHR00";
|
|
|
|
static const ALchar magicMarker01[8] = "MinPHR01";
|
2017-10-22 22:36:42 +00:00
|
|
|
static const ALchar magicMarker02[8] = "MinPHR02";
|
2012-09-11 08:59:42 +00:00
|
|
|
|
2014-11-23 18:49:54 +00:00
|
|
|
/* First value for pass-through coefficients (remaining are 0), used for omni-
|
|
|
|
* directional sounds. */
|
2017-03-31 11:25:22 +00:00
|
|
|
static const ALfloat PassthruCoeff = 0.707106781187f/*sqrt(0.5)*/;
|
2014-11-23 18:49:54 +00:00
|
|
|
|
2017-04-06 20:00:29 +00:00
|
|
|
static ATOMIC_FLAG LoadedHrtfLock = ATOMIC_FLAG_INIT;
|
2017-04-05 18:29:58 +00:00
|
|
|
static struct HrtfEntry *LoadedHrtfs = NULL;
|
2011-09-18 17:09:32 +00:00
|
|
|
|
2016-10-09 07:37:47 +00:00
|
|
|
|
|
|
|
/* Calculate the elevation index given the polar elevation in radians. This
|
|
|
|
* will return an index between 0 and (evcount - 1). Assumes the FPU is in
|
|
|
|
* round-to-zero mode.
|
2012-09-11 08:59:42 +00:00
|
|
|
*/
|
2017-05-01 22:46:25 +00:00
|
|
|
static ALsizei CalcEvIndex(ALsizei evcount, ALfloat ev, ALfloat *mu)
|
2011-05-01 20:59:44 +00:00
|
|
|
{
|
2017-05-01 22:46:25 +00:00
|
|
|
ALsizei idx;
|
|
|
|
ev = (F_PI_2+ev) * (evcount-1) / F_PI;
|
|
|
|
idx = mini(fastf2i(ev), evcount-1);
|
|
|
|
|
|
|
|
*mu = ev - idx;
|
|
|
|
return idx;
|
2011-06-03 08:06:00 +00:00
|
|
|
}
|
|
|
|
|
2016-10-09 07:37:47 +00:00
|
|
|
/* Calculate the azimuth index given the polar azimuth in radians. This will
|
|
|
|
* return an index between 0 and (azcount - 1). Assumes the FPU is in round-to-
|
|
|
|
* zero mode.
|
2012-09-11 08:59:42 +00:00
|
|
|
*/
|
2017-05-01 22:46:25 +00:00
|
|
|
static ALsizei CalcAzIndex(ALsizei azcount, ALfloat az, ALfloat *mu)
|
2011-06-03 08:06:00 +00:00
|
|
|
{
|
2017-05-01 22:46:25 +00:00
|
|
|
ALsizei idx;
|
|
|
|
az = (F_TAU+az) * azcount / F_TAU;
|
|
|
|
|
|
|
|
idx = fastf2i(az) % azcount;
|
|
|
|
*mu = az - floorf(az);
|
|
|
|
return idx;
|
2011-05-01 20:59:44 +00:00
|
|
|
}
|
|
|
|
|
2016-10-09 07:37:47 +00:00
|
|
|
/* Calculates static HRIR coefficients and delays for the given polar elevation
|
2017-03-12 02:04:06 +00:00
|
|
|
* and azimuth in radians. The coefficients are normalized.
|
2012-09-11 08:59:42 +00:00
|
|
|
*/
|
2017-08-09 21:57:01 +00:00
|
|
|
void GetHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread,
|
|
|
|
ALfloat (*restrict coeffs)[2], ALsizei *delays)
|
2011-05-01 20:59:44 +00:00
|
|
|
{
|
2017-05-01 22:46:25 +00:00
|
|
|
ALsizei evidx, azidx, idx[4];
|
2017-04-07 15:46:50 +00:00
|
|
|
ALsizei evoffset;
|
2017-05-01 22:46:25 +00:00
|
|
|
ALfloat emu, amu[2];
|
|
|
|
ALfloat blend[4];
|
2016-04-25 04:42:59 +00:00
|
|
|
ALfloat dirfact;
|
2017-05-01 22:46:25 +00:00
|
|
|
ALsizei i, c;
|
2011-06-03 08:06:00 +00:00
|
|
|
|
2016-04-25 04:42:59 +00:00
|
|
|
dirfact = 1.0f - (spread / F_TAU);
|
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Claculate the lower elevation index. */
|
|
|
|
evidx = CalcEvIndex(Hrtf->evCount, elevation, &emu);
|
2016-10-09 07:37:47 +00:00
|
|
|
evoffset = Hrtf->evOffset[evidx];
|
2011-06-03 08:06:00 +00:00
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate lower azimuth index. */
|
|
|
|
azidx= CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[0]);
|
2011-07-04 14:14:45 +00:00
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate the lower HRIR indices. */
|
|
|
|
idx[0] = evoffset + azidx;
|
|
|
|
idx[1] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]);
|
|
|
|
if(evidx < Hrtf->evCount-1)
|
|
|
|
{
|
|
|
|
/* Increment elevation to the next (upper) index. */
|
|
|
|
evidx++;
|
|
|
|
evoffset = Hrtf->evOffset[evidx];
|
2012-08-11 09:16:34 +00:00
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate upper azimuth index. */
|
|
|
|
azidx = CalcAzIndex(Hrtf->azCount[evidx], azimuth, &amu[1]);
|
2012-09-11 08:59:42 +00:00
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate the upper HRIR indices. */
|
|
|
|
idx[2] = evoffset + azidx;
|
|
|
|
idx[3] = evoffset + ((azidx+1) % Hrtf->azCount[evidx]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the lower elevation is the top index, the upper elevation is the
|
|
|
|
* same as the lower.
|
|
|
|
*/
|
|
|
|
amu[1] = amu[0];
|
|
|
|
idx[2] = idx[0];
|
|
|
|
idx[3] = idx[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Calculate bilinear blending weights, attenuated according to the
|
|
|
|
* directional panning factor.
|
|
|
|
*/
|
|
|
|
blend[0] = (1.0f-emu) * (1.0f-amu[0]) * dirfact;
|
|
|
|
blend[1] = (1.0f-emu) * ( amu[0]) * dirfact;
|
|
|
|
blend[2] = ( emu) * (1.0f-amu[1]) * dirfact;
|
|
|
|
blend[3] = ( emu) * ( amu[1]) * dirfact;
|
|
|
|
|
|
|
|
/* Calculate the blended HRIR delays. */
|
|
|
|
delays[0] = fastf2i(
|
|
|
|
Hrtf->delays[idx[0]][0]*blend[0] + Hrtf->delays[idx[1]][0]*blend[1] +
|
|
|
|
Hrtf->delays[idx[2]][0]*blend[2] + Hrtf->delays[idx[3]][0]*blend[3] + 0.5f
|
|
|
|
);
|
|
|
|
delays[1] = fastf2i(
|
|
|
|
Hrtf->delays[idx[0]][1]*blend[0] + Hrtf->delays[idx[1]][1]*blend[1] +
|
|
|
|
Hrtf->delays[idx[2]][1]*blend[2] + Hrtf->delays[idx[3]][1]*blend[3] + 0.5f
|
|
|
|
);
|
2016-10-09 07:37:47 +00:00
|
|
|
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate the sample offsets for the HRIR indices. */
|
|
|
|
idx[0] *= Hrtf->irSize;
|
|
|
|
idx[1] *= Hrtf->irSize;
|
|
|
|
idx[2] *= Hrtf->irSize;
|
|
|
|
idx[3] *= Hrtf->irSize;
|
|
|
|
|
2017-08-09 21:57:01 +00:00
|
|
|
coeffs = ASSUME_ALIGNED(coeffs, 16);
|
2017-05-01 22:46:25 +00:00
|
|
|
/* Calculate the blended HRIR coefficients. */
|
|
|
|
coeffs[0][0] = PassthruCoeff * (1.0f-dirfact);
|
|
|
|
coeffs[0][1] = PassthruCoeff * (1.0f-dirfact);
|
2017-03-12 02:04:06 +00:00
|
|
|
for(i = 1;i < Hrtf->irSize;i++)
|
2011-07-04 14:14:45 +00:00
|
|
|
{
|
2017-05-01 22:46:25 +00:00
|
|
|
coeffs[i][0] = 0.0f;
|
|
|
|
coeffs[i][1] = 0.0f;
|
|
|
|
}
|
|
|
|
for(c = 0;c < 4;c++)
|
|
|
|
{
|
2017-08-09 21:57:01 +00:00
|
|
|
const ALfloat (*restrict srccoeffs)[2] = ASSUME_ALIGNED(Hrtf->coeffs+idx[c], 16);
|
2017-05-01 22:46:25 +00:00
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
{
|
2017-08-09 21:57:01 +00:00
|
|
|
coeffs[i][0] += srccoeffs[i][0] * blend[c];
|
|
|
|
coeffs[i][1] += srccoeffs[i][1] * blend[c];
|
2017-05-01 22:46:25 +00:00
|
|
|
}
|
2014-11-23 18:49:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-09 23:59:29 +00:00
|
|
|
|
2017-07-31 08:20:42 +00:00
|
|
|
void BuildBFormatHrtf(const struct Hrtf *Hrtf, DirectHrtfState *state, ALsizei NumChannels, const ALfloat (*restrict AmbiPoints)[2], const ALfloat (*restrict AmbiMatrix)[2][MAX_AMBI_COEFFS], ALsizei AmbiCount)
|
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-12 06:20:35 +00:00
|
|
|
{
|
2017-01-15 21:57:22 +00:00
|
|
|
/* Set this to 2 for dual-band HRTF processing. May require a higher quality
|
2016-08-31 05:33:33 +00:00
|
|
|
* band-splitter, or better calculation of the new IR length to deal with the
|
|
|
|
* tail generated by the filter.
|
|
|
|
*/
|
2016-09-26 18:18:26 +00:00
|
|
|
#define NUM_BANDS 2
|
2016-08-21 10:05:42 +00:00
|
|
|
BandSplitter splitter;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALsizei idx[HRTF_AMBI_MAX_CHANNELS];
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei min_delay = HRTF_HISTORY_LENGTH;
|
2017-01-16 17:04:58 +00:00
|
|
|
ALfloat temps[3][HRIR_LENGTH];
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei max_length = 0;
|
2017-03-31 11:25:22 +00:00
|
|
|
ALsizei i, c, b;
|
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-12 06:20:35 +00:00
|
|
|
|
2017-01-19 03:16:24 +00:00
|
|
|
for(c = 0;c < AmbiCount;c++)
|
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-12 06:20:35 +00:00
|
|
|
{
|
2016-08-19 06:33:08 +00:00
|
|
|
ALuint evidx, azidx;
|
2016-08-17 12:34:09 +00:00
|
|
|
ALuint evoffset;
|
|
|
|
ALuint azcount;
|
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-12 06:20:35 +00:00
|
|
|
|
2016-08-17 12:34:09 +00:00
|
|
|
/* Calculate elevation index. */
|
2017-01-19 03:16:24 +00:00
|
|
|
evidx = (ALsizei)floorf((F_PI_2 + AmbiPoints[c][0]) *
|
2017-01-16 15:45:07 +00:00
|
|
|
(Hrtf->evCount-1)/F_PI + 0.5f);
|
|
|
|
evidx = mini(evidx, Hrtf->evCount-1);
|
2016-08-17 12:34:09 +00:00
|
|
|
|
2016-08-19 06:33:08 +00:00
|
|
|
azcount = Hrtf->azCount[evidx];
|
|
|
|
evoffset = Hrtf->evOffset[evidx];
|
2016-08-17 12:34:09 +00:00
|
|
|
|
|
|
|
/* Calculate azimuth index for this elevation. */
|
2017-01-19 03:16:24 +00:00
|
|
|
azidx = (ALsizei)floorf((F_TAU+AmbiPoints[c][1]) *
|
2017-01-16 15:45:07 +00:00
|
|
|
azcount/F_TAU + 0.5f) % azcount;
|
2016-08-17 12:34:09 +00:00
|
|
|
|
|
|
|
/* Calculate indices for left and right channels. */
|
2017-04-07 15:46:50 +00:00
|
|
|
idx[c] = evoffset + azidx;
|
2016-08-17 12:34:09 +00:00
|
|
|
|
2017-04-07 15:46:50 +00:00
|
|
|
min_delay = mini(min_delay, mini(Hrtf->delays[idx[c]][0], Hrtf->delays[idx[c]][1]));
|
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-12 06:20:35 +00:00
|
|
|
}
|
|
|
|
|
2016-08-21 10:05:42 +00:00
|
|
|
memset(temps, 0, sizeof(temps));
|
|
|
|
bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate);
|
2017-01-19 03:16:24 +00:00
|
|
|
for(c = 0;c < AmbiCount;c++)
|
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-12 06:20:35 +00:00
|
|
|
{
|
2017-04-07 15:46:50 +00:00
|
|
|
const ALfloat (*fir)[2] = &Hrtf->coeffs[idx[c] * Hrtf->irSize];
|
2017-04-07 18:49:24 +00:00
|
|
|
ALsizei ldelay = Hrtf->delays[idx[c]][0] - min_delay;
|
|
|
|
ALsizei rdelay = Hrtf->delays[idx[c]][1] - min_delay;
|
|
|
|
|
|
|
|
max_length = maxi(max_length,
|
|
|
|
mini(maxi(ldelay, rdelay) + Hrtf->irSize, HRIR_LENGTH)
|
|
|
|
);
|
2016-08-17 12:34:09 +00:00
|
|
|
|
2016-08-31 05:33:33 +00:00
|
|
|
if(NUM_BANDS == 1)
|
|
|
|
{
|
2017-03-31 11:25:22 +00:00
|
|
|
for(i = 0;i < NumChannels;++i)
|
|
|
|
{
|
2017-04-07 18:49:24 +00:00
|
|
|
ALsizei lidx = ldelay, ridx = rdelay;
|
|
|
|
ALsizei j = 0;
|
|
|
|
while(lidx < HRIR_LENGTH && ridx < HRIR_LENGTH && j < Hrtf->irSize)
|
|
|
|
{
|
|
|
|
state->Chan[i].Coeffs[lidx++][0] += fir[j][0] * AmbiMatrix[c][0][i];
|
|
|
|
state->Chan[i].Coeffs[ridx++][1] += fir[j][1] * AmbiMatrix[c][0][i];
|
|
|
|
j++;
|
|
|
|
}
|
2017-03-31 11:25:22 +00:00
|
|
|
}
|
2016-08-31 05:33:33 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Band-split left HRIR into low and high frequency responses. */
|
|
|
|
bandsplit_clear(&splitter);
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
2017-04-07 15:46:50 +00:00
|
|
|
temps[2][i] = fir[i][0];
|
2016-08-31 05:33:33 +00:00
|
|
|
bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
|
2016-08-21 10:05:42 +00:00
|
|
|
|
2017-04-07 18:49:24 +00:00
|
|
|
/* Apply left ear response with delay. */
|
2017-03-31 11:25:22 +00:00
|
|
|
for(i = 0;i < NumChannels;++i)
|
2016-08-21 10:05:42 +00:00
|
|
|
{
|
2017-03-31 11:25:22 +00:00
|
|
|
for(b = 0;b < NUM_BANDS;b++)
|
|
|
|
{
|
2017-04-07 18:49:24 +00:00
|
|
|
ALsizei lidx = ldelay;
|
|
|
|
ALsizei j = 0;
|
|
|
|
while(lidx < HRIR_LENGTH)
|
|
|
|
state->Chan[i].Coeffs[lidx++][0] += temps[b][j++] * AmbiMatrix[c][b][i];
|
2017-03-31 11:25:22 +00:00
|
|
|
}
|
2016-08-21 10:05:42 +00:00
|
|
|
}
|
2016-08-17 12:34:09 +00:00
|
|
|
|
2016-08-31 05:33:33 +00:00
|
|
|
/* Band-split right HRIR into low and high frequency responses. */
|
|
|
|
bandsplit_clear(&splitter);
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
2017-04-07 15:46:50 +00:00
|
|
|
temps[2][i] = fir[i][1];
|
2016-08-31 05:33:33 +00:00
|
|
|
bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
|
2016-08-21 10:05:42 +00:00
|
|
|
|
2017-04-07 18:49:24 +00:00
|
|
|
/* Apply right ear response with delay. */
|
2017-03-31 11:25:22 +00:00
|
|
|
for(i = 0;i < NumChannels;++i)
|
2016-08-21 10:05:42 +00:00
|
|
|
{
|
2017-03-31 11:25:22 +00:00
|
|
|
for(b = 0;b < NUM_BANDS;b++)
|
|
|
|
{
|
2017-04-07 18:49:24 +00:00
|
|
|
ALsizei ridx = rdelay;
|
|
|
|
ALsizei j = 0;
|
|
|
|
while(ridx < HRIR_LENGTH)
|
|
|
|
state->Chan[i].Coeffs[ridx++][1] += temps[b][j++] * AmbiMatrix[c][b][i];
|
2017-03-31 11:25:22 +00:00
|
|
|
}
|
2016-08-21 10:05:42 +00:00
|
|
|
}
|
2016-08-17 12:34:09 +00:00
|
|
|
}
|
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-12 06:20:35 +00:00
|
|
|
}
|
2017-06-17 02:00:00 +00:00
|
|
|
/* Round up to the next IR size multiple. */
|
2018-01-11 18:55:35 +00:00
|
|
|
max_length += MOD_IR_SIZE-1;
|
|
|
|
max_length -= max_length%MOD_IR_SIZE;
|
2016-08-17 12:34:09 +00:00
|
|
|
|
2017-06-17 02:00:00 +00:00
|
|
|
TRACE("Skipped min delay: %d, new combined length: %d\n", min_delay, max_length);
|
2017-07-31 08:20:42 +00:00
|
|
|
state->IrSize = max_length;
|
2017-01-19 03:16:24 +00:00
|
|
|
#undef NUM_BANDS
|
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-12 06:20:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-23 20:26:35 +00:00
|
|
|
static struct Hrtf *CreateHrtfStore(ALuint rate, ALsizei irSize,
|
|
|
|
ALfloat distance, ALsizei evCount, ALsizei irCount, const ALubyte *azCount,
|
|
|
|
const ALushort *evOffset, const ALfloat (*coeffs)[2], const ALubyte (*delays)[2],
|
|
|
|
const char *filename)
|
2017-03-31 10:45:26 +00:00
|
|
|
{
|
|
|
|
struct Hrtf *Hrtf;
|
|
|
|
size_t total;
|
|
|
|
|
|
|
|
total = sizeof(struct Hrtf);
|
|
|
|
total += sizeof(Hrtf->azCount[0])*evCount;
|
2017-03-31 11:25:22 +00:00
|
|
|
total = RoundUp(total, sizeof(ALushort)); /* Align for ushort fields */
|
2017-03-31 10:45:26 +00:00
|
|
|
total += sizeof(Hrtf->evOffset[0])*evCount;
|
2017-04-07 15:46:50 +00:00
|
|
|
total = RoundUp(total, 16); /* Align for coefficients using SIMD */
|
2017-03-31 10:45:26 +00:00
|
|
|
total += sizeof(Hrtf->coeffs[0])*irSize*irCount;
|
|
|
|
total += sizeof(Hrtf->delays[0])*irCount;
|
|
|
|
|
|
|
|
Hrtf = al_calloc(16, total);
|
|
|
|
if(Hrtf == NULL)
|
2017-04-05 19:27:30 +00:00
|
|
|
ERR("Out of memory allocating storage for %s.\n", filename);
|
2017-03-31 10:45:26 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
uintptr_t offset = sizeof(struct Hrtf);
|
|
|
|
char *base = (char*)Hrtf;
|
|
|
|
ALushort *_evOffset;
|
|
|
|
ALubyte *_azCount;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALubyte (*_delays)[2];
|
|
|
|
ALfloat (*_coeffs)[2];
|
2017-03-31 10:45:26 +00:00
|
|
|
ALsizei i;
|
|
|
|
|
2017-04-06 20:00:29 +00:00
|
|
|
InitRef(&Hrtf->ref, 0);
|
2017-03-31 10:45:26 +00:00
|
|
|
Hrtf->sampleRate = rate;
|
|
|
|
Hrtf->irSize = irSize;
|
2017-10-23 20:26:35 +00:00
|
|
|
Hrtf->distance = distance;
|
2017-03-31 10:45:26 +00:00
|
|
|
Hrtf->evCount = evCount;
|
|
|
|
|
|
|
|
/* Set up pointers to storage following the main HRTF struct. */
|
|
|
|
_azCount = (ALubyte*)(base + offset); Hrtf->azCount = _azCount;
|
|
|
|
offset += sizeof(_azCount[0])*evCount;
|
|
|
|
|
2017-03-31 11:25:22 +00:00
|
|
|
offset = RoundUp(offset, sizeof(ALushort)); /* Align for ushort fields */
|
2017-03-31 10:45:26 +00:00
|
|
|
_evOffset = (ALushort*)(base + offset); Hrtf->evOffset = _evOffset;
|
|
|
|
offset += sizeof(_evOffset[0])*evCount;
|
|
|
|
|
2017-04-07 15:46:50 +00:00
|
|
|
offset = RoundUp(offset, 16); /* Align for coefficients using SIMD */
|
|
|
|
_coeffs = (ALfloat(*)[2])(base + offset); Hrtf->coeffs = _coeffs;
|
2017-03-31 10:45:26 +00:00
|
|
|
offset += sizeof(_coeffs[0])*irSize*irCount;
|
|
|
|
|
2017-04-07 15:46:50 +00:00
|
|
|
_delays = (ALubyte(*)[2])(base + offset); Hrtf->delays = _delays;
|
2017-03-31 10:45:26 +00:00
|
|
|
offset += sizeof(_delays[0])*irCount;
|
|
|
|
|
|
|
|
/* Copy input data to storage. */
|
|
|
|
for(i = 0;i < evCount;i++) _azCount[i] = azCount[i];
|
|
|
|
for(i = 0;i < evCount;i++) _evOffset[i] = evOffset[i];
|
2017-03-31 11:25:22 +00:00
|
|
|
for(i = 0;i < irSize*irCount;i++)
|
2017-04-07 15:46:50 +00:00
|
|
|
{
|
|
|
|
_coeffs[i][0] = coeffs[i][0];
|
|
|
|
_coeffs[i][1] = coeffs[i][1];
|
|
|
|
}
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
_delays[i][0] = delays[i][0];
|
|
|
|
_delays[i][1] = delays[i][1];
|
|
|
|
}
|
2017-03-31 10:45:26 +00:00
|
|
|
|
|
|
|
assert(offset == total);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Hrtf;
|
|
|
|
}
|
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
static ALubyte GetLE_ALubyte(const ALubyte **data, size_t *len)
|
|
|
|
{
|
|
|
|
ALubyte ret = (*data)[0];
|
|
|
|
*data += 1; *len -= 1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALshort GetLE_ALshort(const ALubyte **data, size_t *len)
|
|
|
|
{
|
|
|
|
ALshort ret = (*data)[0] | ((*data)[1]<<8);
|
|
|
|
*data += 2; *len -= 2;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALushort GetLE_ALushort(const ALubyte **data, size_t *len)
|
|
|
|
{
|
|
|
|
ALushort ret = (*data)[0] | ((*data)[1]<<8);
|
|
|
|
*data += 2; *len -= 2;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-08-09 03:25:31 +00:00
|
|
|
static ALint GetLE_ALint24(const ALubyte **data, size_t *len)
|
2017-06-17 05:58:13 +00:00
|
|
|
{
|
2017-08-09 03:25:31 +00:00
|
|
|
ALint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16);
|
|
|
|
*data += 3; *len -= 3;
|
|
|
|
return (ret^0x800000) - 0x800000;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ALuint GetLE_ALuint(const ALubyte **data, size_t *len)
|
|
|
|
{
|
|
|
|
ALuint ret = (*data)[0] | ((*data)[1]<<8) | ((*data)[2]<<16) | ((*data)[3]<<24);
|
2017-06-17 05:58:13 +00:00
|
|
|
*data += 4; *len -= 4;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const ALubyte *Get_ALubytePtr(const ALubyte **data, size_t *len, size_t size)
|
|
|
|
{
|
|
|
|
const ALubyte *ret = *data;
|
|
|
|
*data += size; *len -= size;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-05 19:27:30 +00:00
|
|
|
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const char *filename)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
struct Hrtf *Hrtf = NULL;
|
|
|
|
ALboolean failed = AL_FALSE;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALuint rate = 0;
|
|
|
|
ALushort irCount = 0;
|
2012-10-07 15:19:09 +00:00
|
|
|
ALushort irSize = 0;
|
|
|
|
ALubyte evCount = 0;
|
2012-09-12 14:25:05 +00:00
|
|
|
ALubyte *azCount = NULL;
|
|
|
|
ALushort *evOffset = NULL;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALfloat (*coeffs)[2] = NULL;
|
|
|
|
ALubyte (*delays)[2] = NULL;
|
|
|
|
ALsizei i, j;
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
if(datalen < 9)
|
|
|
|
{
|
2017-04-05 19:27:30 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, 9, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
rate = GetLE_ALuint(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
irCount = GetLE_ALushort(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
irSize = GetLE_ALushort(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
evCount = GetLE_ALubyte(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
|
|
|
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
|
|
|
|
{
|
|
|
|
ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
|
|
|
|
irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
|
|
|
|
evCount, MIN_EV_COUNT, MAX_EV_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(failed)
|
|
|
|
return NULL;
|
|
|
|
|
2017-04-19 22:17:55 +00:00
|
|
|
if(datalen < evCount*2u)
|
2016-08-31 15:16:49 +00:00
|
|
|
{
|
2017-04-05 19:27:30 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n", filename, evCount*2, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
azCount = malloc(sizeof(azCount[0])*evCount);
|
|
|
|
evOffset = malloc(sizeof(evOffset[0])*evCount);
|
|
|
|
if(azCount == NULL || evOffset == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
evOffset[0] = GetLE_ALushort(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
for(i = 1;i < evCount;i++)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
evOffset[i] = GetLE_ALushort(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
if(evOffset[i] <= evOffset[i-1])
|
|
|
|
{
|
|
|
|
ERR("Invalid evOffset: evOffset[%d]=%d (last=%d)\n",
|
|
|
|
i, evOffset[i], evOffset[i-1]);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
azCount[i-1] = evOffset[i] - evOffset[i-1];
|
|
|
|
if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
|
|
|
|
i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(irCount <= evOffset[i-1])
|
|
|
|
{
|
|
|
|
ERR("Invalid evOffset: evOffset[%d]=%d (irCount=%d)\n",
|
|
|
|
i-1, evOffset[i-1], irCount);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
azCount[i-1] = irCount - evOffset[i-1];
|
|
|
|
if(azCount[i-1] < MIN_AZ_COUNT || azCount[i-1] > MAX_AZ_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
|
|
|
|
i-1, azCount[i-1], MIN_AZ_COUNT, MAX_AZ_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
|
2017-04-07 13:40:42 +00:00
|
|
|
delays = malloc(sizeof(delays[0])*irCount);
|
2017-04-07 16:49:06 +00:00
|
|
|
if(coeffs == NULL || delays == NULL)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
size_t reqsize = 2*irSize*irCount + irCount;
|
|
|
|
if(datalen < reqsize)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n",
|
2017-04-05 19:27:30 +00:00
|
|
|
filename, reqsize, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
if(!failed)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
for(i = 0;i < irCount;i++)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
2017-06-17 05:58:13 +00:00
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
|
2012-09-12 14:25:05 +00:00
|
|
|
}
|
2016-08-31 15:16:49 +00:00
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
delays[i][0] = GetLE_ALubyte(&data, &datalen);
|
2017-10-22 22:36:42 +00:00
|
|
|
if(delays[i][0] > MAX_HRIR_DELAY)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
|
2012-09-12 14:25:05 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
2017-04-07 15:46:50 +00:00
|
|
|
{
|
|
|
|
/* Mirror the left ear responses to the right ear. */
|
|
|
|
for(i = 0;i < evCount;i++)
|
|
|
|
{
|
|
|
|
ALushort evoffset = evOffset[i];
|
|
|
|
ALubyte azcount = azCount[i];
|
|
|
|
for(j = 0;j < azcount;j++)
|
|
|
|
{
|
|
|
|
ALsizei lidx = evoffset + j;
|
|
|
|
ALsizei ridx = evoffset + ((azcount-j) % azcount);
|
|
|
|
ALsizei k;
|
|
|
|
|
|
|
|
for(k = 0;k < irSize;k++)
|
|
|
|
coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0];
|
|
|
|
delays[ridx][1] = delays[lidx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:26:35 +00:00
|
|
|
Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount,
|
2017-03-31 10:45:26 +00:00
|
|
|
evOffset, coeffs, delays, filename);
|
2017-04-07 15:46:50 +00:00
|
|
|
}
|
2012-09-12 14:25:05 +00:00
|
|
|
|
|
|
|
free(azCount);
|
|
|
|
free(evOffset);
|
|
|
|
free(coeffs);
|
2017-04-07 13:40:42 +00:00
|
|
|
free(delays);
|
2016-02-17 03:56:44 +00:00
|
|
|
return Hrtf;
|
2012-09-12 14:25:05 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 19:27:30 +00:00
|
|
|
static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const char *filename)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
struct Hrtf *Hrtf = NULL;
|
|
|
|
ALboolean failed = AL_FALSE;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALuint rate = 0;
|
|
|
|
ALushort irCount = 0;
|
|
|
|
ALushort irSize = 0;
|
|
|
|
ALubyte evCount = 0;
|
2016-08-31 15:16:49 +00:00
|
|
|
const ALubyte *azCount = NULL;
|
2012-09-12 14:25:05 +00:00
|
|
|
ALushort *evOffset = NULL;
|
2017-04-07 15:46:50 +00:00
|
|
|
ALfloat (*coeffs)[2] = NULL;
|
|
|
|
ALubyte (*delays)[2] = NULL;
|
|
|
|
ALsizei i, j;
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
if(datalen < 6)
|
|
|
|
{
|
2017-04-05 19:27:30 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 6, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
rate = GetLE_ALuint(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
irSize = GetLE_ALubyte(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
evCount = GetLE_ALubyte(&data, &datalen);
|
2012-09-12 14:25:05 +00:00
|
|
|
|
|
|
|
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
|
|
|
|
{
|
|
|
|
ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
|
|
|
|
irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
|
|
|
|
evCount, MIN_EV_COUNT, MAX_EV_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(failed)
|
|
|
|
return NULL;
|
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
if(datalen < evCount)
|
|
|
|
{
|
2017-04-05 19:27:30 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-06-17 05:58:13 +00:00
|
|
|
azCount = Get_ALubytePtr(&data, &datalen, evCount);
|
2016-08-31 15:16:49 +00:00
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
evOffset = malloc(sizeof(evOffset[0])*evCount);
|
|
|
|
if(azCount == NULL || evOffset == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
for(i = 0;i < evCount;i++)
|
|
|
|
{
|
|
|
|
if(azCount[i] < MIN_AZ_COUNT || azCount[i] > MAX_AZ_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
|
|
|
|
i, azCount[i], MIN_AZ_COUNT, MAX_AZ_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
evOffset[0] = 0;
|
|
|
|
irCount = azCount[0];
|
|
|
|
for(i = 1;i < evCount;i++)
|
|
|
|
{
|
|
|
|
evOffset[i] = evOffset[i-1] + azCount[i-1];
|
|
|
|
irCount += azCount[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
|
2017-04-07 13:40:42 +00:00
|
|
|
delays = malloc(sizeof(delays[0])*irCount);
|
2017-04-07 16:49:06 +00:00
|
|
|
if(coeffs == NULL || delays == NULL)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
size_t reqsize = 2*irSize*irCount + irCount;
|
|
|
|
if(datalen < reqsize)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
|
2017-04-05 19:27:30 +00:00
|
|
|
filename, reqsize, datalen);
|
2016-08-31 15:16:49 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
if(!failed)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
for(i = 0;i < irCount;i++)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
2017-06-17 05:58:13 +00:00
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
|
2012-09-12 14:25:05 +00:00
|
|
|
}
|
2016-08-31 15:16:49 +00:00
|
|
|
|
2012-09-12 14:25:05 +00:00
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
2017-06-17 05:58:13 +00:00
|
|
|
delays[i][0] = GetLE_ALubyte(&data, &datalen);
|
2017-10-22 22:36:42 +00:00
|
|
|
if(delays[i][0] > MAX_HRIR_DELAY)
|
2012-09-12 14:25:05 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
|
2012-09-12 14:25:05 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
2017-04-07 15:46:50 +00:00
|
|
|
{
|
|
|
|
/* Mirror the left ear responses to the right ear. */
|
|
|
|
for(i = 0;i < evCount;i++)
|
|
|
|
{
|
|
|
|
ALushort evoffset = evOffset[i];
|
|
|
|
ALubyte azcount = azCount[i];
|
|
|
|
for(j = 0;j < azcount;j++)
|
|
|
|
{
|
|
|
|
ALsizei lidx = evoffset + j;
|
|
|
|
ALsizei ridx = evoffset + ((azcount-j) % azcount);
|
|
|
|
ALsizei k;
|
|
|
|
|
|
|
|
for(k = 0;k < irSize;k++)
|
|
|
|
coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0];
|
|
|
|
delays[ridx][1] = delays[lidx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:26:35 +00:00
|
|
|
Hrtf = CreateHrtfStore(rate, irSize, 0.0f, evCount, irCount, azCount,
|
2017-03-31 10:45:26 +00:00
|
|
|
evOffset, coeffs, delays, filename);
|
2017-04-07 15:46:50 +00:00
|
|
|
}
|
2012-09-12 14:25:05 +00:00
|
|
|
|
|
|
|
free(evOffset);
|
|
|
|
free(coeffs);
|
2017-04-07 13:40:42 +00:00
|
|
|
free(delays);
|
2016-02-17 03:56:44 +00:00
|
|
|
return Hrtf;
|
2012-09-12 14:25:05 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 03:25:31 +00:00
|
|
|
#define SAMPLETYPE_S16 0
|
|
|
|
#define SAMPLETYPE_S24 1
|
|
|
|
|
|
|
|
#define CHANTYPE_LEFTONLY 0
|
|
|
|
#define CHANTYPE_LEFTRIGHT 1
|
|
|
|
|
|
|
|
static struct Hrtf *LoadHrtf02(const ALubyte *data, size_t datalen, const char *filename)
|
|
|
|
{
|
|
|
|
struct Hrtf *Hrtf = NULL;
|
|
|
|
ALboolean failed = AL_FALSE;
|
|
|
|
ALuint rate = 0;
|
|
|
|
ALubyte sampleType;
|
|
|
|
ALubyte channelType;
|
|
|
|
ALushort irCount = 0;
|
|
|
|
ALushort irSize = 0;
|
2017-10-22 22:36:42 +00:00
|
|
|
ALubyte fdCount = 0;
|
|
|
|
ALushort distance = 0;
|
2017-08-09 03:25:31 +00:00
|
|
|
ALubyte evCount = 0;
|
|
|
|
const ALubyte *azCount = NULL;
|
|
|
|
ALushort *evOffset = NULL;
|
|
|
|
ALfloat (*coeffs)[2] = NULL;
|
|
|
|
ALubyte (*delays)[2] = NULL;
|
|
|
|
ALsizei i, j;
|
|
|
|
|
2017-08-10 03:42:22 +00:00
|
|
|
if(datalen < 8)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-08-10 03:42:22 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 8, datalen);
|
2017-08-09 03:25:31 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = GetLE_ALuint(&data, &datalen);
|
|
|
|
sampleType = GetLE_ALubyte(&data, &datalen);
|
|
|
|
channelType = GetLE_ALubyte(&data, &datalen);
|
|
|
|
|
|
|
|
irSize = GetLE_ALubyte(&data, &datalen);
|
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
fdCount = GetLE_ALubyte(&data, &datalen);
|
2017-08-09 03:25:31 +00:00
|
|
|
|
|
|
|
if(sampleType > SAMPLETYPE_S24)
|
|
|
|
{
|
|
|
|
ERR("Unsupported sample type: %d\n", sampleType);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(channelType > CHANTYPE_LEFTRIGHT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported channel type: %d\n", channelType);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(irSize < MIN_IR_SIZE || irSize > MAX_IR_SIZE || (irSize%MOD_IR_SIZE))
|
|
|
|
{
|
|
|
|
ERR("Unsupported HRIR size: irSize=%d (%d to %d by %d)\n",
|
|
|
|
irSize, MIN_IR_SIZE, MAX_IR_SIZE, MOD_IR_SIZE);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
2017-10-22 22:36:42 +00:00
|
|
|
if(fdCount != 1)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Multiple field-depths not supported: fdCount=%d (%d to %d)\n",
|
|
|
|
evCount, MIN_FD_COUNT, MAX_FD_COUNT);
|
2017-08-09 03:25:31 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(failed)
|
|
|
|
return NULL;
|
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
for(i = 0;i < fdCount;i++)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
if(datalen < 3)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, 3, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
distance = GetLE_ALushort(&data, &datalen);
|
|
|
|
if(distance < MIN_FD_DISTANCE || distance > MAX_FD_DISTANCE)
|
|
|
|
{
|
|
|
|
ERR("Unsupported field distance: distance=%d (%dmm to %dmm)\n",
|
|
|
|
distance, MIN_FD_DISTANCE, MAX_FD_DISTANCE);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
evCount = GetLE_ALubyte(&data, &datalen);
|
|
|
|
if(evCount < MIN_EV_COUNT || evCount > MAX_EV_COUNT)
|
|
|
|
{
|
|
|
|
ERR("Unsupported elevation count: evCount=%d (%d to %d)\n",
|
|
|
|
evCount, MIN_EV_COUNT, MAX_EV_COUNT);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
if(failed)
|
|
|
|
return NULL;
|
2017-08-09 03:25:31 +00:00
|
|
|
|
2017-10-22 22:36:42 +00:00
|
|
|
if(datalen < evCount)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n", filename, evCount, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
azCount = Get_ALubytePtr(&data, &datalen, evCount);
|
|
|
|
for(j = 0;j < evCount;j++)
|
|
|
|
{
|
|
|
|
if(azCount[j] < MIN_AZ_COUNT || azCount[j] > MAX_AZ_COUNT)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
|
|
|
ERR("Unsupported azimuth count: azCount[%d]=%d (%d to %d)\n",
|
2017-10-22 22:36:42 +00:00
|
|
|
j, azCount[j], MIN_AZ_COUNT, MAX_AZ_COUNT);
|
2017-08-09 03:25:31 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-10-22 22:36:42 +00:00
|
|
|
if(failed)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
evOffset = malloc(sizeof(evOffset[0])*evCount);
|
|
|
|
if(azCount == NULL || evOffset == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
evOffset[0] = 0;
|
|
|
|
irCount = azCount[0];
|
|
|
|
for(i = 1;i < evCount;i++)
|
|
|
|
{
|
|
|
|
evOffset[i] = evOffset[i-1] + azCount[i-1];
|
|
|
|
irCount += azCount[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
coeffs = malloc(sizeof(coeffs[0])*irSize*irCount);
|
|
|
|
delays = malloc(sizeof(delays[0])*irCount);
|
|
|
|
if(coeffs == NULL || delays == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
size_t reqsize = 2*irSize*irCount + irCount;
|
|
|
|
if(datalen < reqsize)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
|
|
|
|
filename, reqsize, datalen);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
if(channelType == CHANTYPE_LEFTONLY)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
|
|
|
if(sampleType == SAMPLETYPE_S16)
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
|
|
|
|
}
|
|
|
|
else if(sampleType == SAMPLETYPE_S24)
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
|
|
|
|
}
|
2017-10-22 22:36:42 +00:00
|
|
|
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
delays[i][0] = GetLE_ALubyte(&data, &datalen);
|
|
|
|
if(delays[i][0] > MAX_HRIR_DELAY)
|
|
|
|
{
|
|
|
|
ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
}
|
2017-10-22 22:36:42 +00:00
|
|
|
else if(channelType == CHANTYPE_LEFTRIGHT)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
|
|
|
if(sampleType == SAMPLETYPE_S16)
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
2017-10-22 22:36:42 +00:00
|
|
|
{
|
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALshort(&data, &datalen) / 32768.0f;
|
2017-08-09 03:25:31 +00:00
|
|
|
coeffs[i*irSize + j][1] = GetLE_ALshort(&data, &datalen) / 32768.0f;
|
2017-10-22 22:36:42 +00:00
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
}
|
|
|
|
else if(sampleType == SAMPLETYPE_S24)
|
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
2017-10-22 22:36:42 +00:00
|
|
|
{
|
|
|
|
coeffs[i*irSize + j][0] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
|
2017-08-09 03:25:31 +00:00
|
|
|
coeffs[i*irSize + j][1] = GetLE_ALint24(&data, &datalen) / 8388608.0f;
|
2017-10-22 22:36:42 +00:00
|
|
|
}
|
2017-08-09 03:25:31 +00:00
|
|
|
}
|
2017-10-22 22:36:42 +00:00
|
|
|
|
2017-08-09 03:25:31 +00:00
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
delays[i][0] = GetLE_ALubyte(&data, &datalen);
|
2017-10-22 22:36:42 +00:00
|
|
|
if(delays[i][0] > MAX_HRIR_DELAY)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Invalid delays[%d][0]: %d (%d)\n", i, delays[i][0], MAX_HRIR_DELAY);
|
2017-08-09 03:25:31 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
delays[i][1] = GetLE_ALubyte(&data, &datalen);
|
2017-10-22 22:36:42 +00:00
|
|
|
if(delays[i][1] > MAX_HRIR_DELAY)
|
2017-08-09 03:25:31 +00:00
|
|
|
{
|
2017-10-22 22:36:42 +00:00
|
|
|
ERR("Invalid delays[%d][1]: %d (%d)\n", i, delays[i][1], MAX_HRIR_DELAY);
|
2017-08-09 03:25:31 +00:00
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
if(channelType == CHANTYPE_LEFTONLY)
|
|
|
|
{
|
|
|
|
/* Mirror the left ear responses to the right ear. */
|
|
|
|
for(i = 0;i < evCount;i++)
|
|
|
|
{
|
|
|
|
ALushort evoffset = evOffset[i];
|
|
|
|
ALubyte azcount = azCount[i];
|
|
|
|
for(j = 0;j < azcount;j++)
|
|
|
|
{
|
|
|
|
ALsizei lidx = evoffset + j;
|
|
|
|
ALsizei ridx = evoffset + ((azcount-j) % azcount);
|
|
|
|
ALsizei k;
|
|
|
|
|
|
|
|
for(k = 0;k < irSize;k++)
|
|
|
|
coeffs[ridx*irSize + k][1] = coeffs[lidx*irSize + k][0];
|
|
|
|
delays[ridx][1] = delays[lidx][0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:26:35 +00:00
|
|
|
Hrtf = CreateHrtfStore(rate, irSize,
|
|
|
|
(ALfloat)distance / 1000.0f, evCount, irCount, azCount, evOffset,
|
|
|
|
coeffs, delays, filename
|
|
|
|
);
|
2017-08-09 03:25:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(evOffset);
|
|
|
|
free(coeffs);
|
|
|
|
free(delays);
|
|
|
|
return Hrtf;
|
|
|
|
}
|
|
|
|
|
2017-04-07 13:40:42 +00:00
|
|
|
|
2017-04-05 18:29:58 +00:00
|
|
|
static void AddFileEntry(vector_EnumeratedHrtf *list, const_al_string filename)
|
2015-10-06 07:23:11 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
|
|
|
|
struct HrtfEntry *loaded_entry;
|
|
|
|
const EnumeratedHrtf *iter;
|
2015-10-06 07:23:11 +00:00
|
|
|
const char *name;
|
2016-02-24 12:21:03 +00:00
|
|
|
const char *ext;
|
2015-10-06 11:01:53 +00:00
|
|
|
int i;
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-05 14:09:16 +00:00
|
|
|
/* Check if this file has already been loaded globally. */
|
|
|
|
loaded_entry = LoadedHrtfs;
|
|
|
|
while(loaded_entry)
|
2016-07-25 04:59:02 +00:00
|
|
|
{
|
2017-04-05 14:09:16 +00:00
|
|
|
if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0)
|
|
|
|
{
|
|
|
|
/* Check if this entry has already been added to the list. */
|
2017-04-05 18:29:58 +00:00
|
|
|
#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf)
|
|
|
|
VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY);
|
2017-04-05 14:09:16 +00:00
|
|
|
if(iter != VECTOR_END(*list))
|
|
|
|
{
|
|
|
|
TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename));
|
|
|
|
return;
|
|
|
|
}
|
2016-07-25 04:59:02 +00:00
|
|
|
#undef MATCH_FNAME
|
|
|
|
|
2017-04-05 19:46:02 +00:00
|
|
|
break;
|
2016-02-21 12:46:14 +00:00
|
|
|
}
|
2017-04-05 14:09:16 +00:00
|
|
|
loaded_entry = loaded_entry->next;
|
2015-10-06 11:01:53 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 19:46:02 +00:00
|
|
|
if(!loaded_entry)
|
|
|
|
{
|
|
|
|
TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename));
|
|
|
|
|
|
|
|
loaded_entry = al_calloc(DEF_ALIGN,
|
2017-04-18 21:11:15 +00:00
|
|
|
FAM_SIZE(struct HrtfEntry, filename, alstr_length(filename)+1)
|
2017-04-05 19:46:02 +00:00
|
|
|
);
|
|
|
|
loaded_entry->next = LoadedHrtfs;
|
|
|
|
loaded_entry->handle = NULL;
|
|
|
|
strcpy(loaded_entry->filename, alstr_get_cstr(filename));
|
|
|
|
LoadedHrtfs = loaded_entry;
|
|
|
|
}
|
2017-04-05 14:09:16 +00:00
|
|
|
|
2015-10-06 11:01:53 +00:00
|
|
|
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
|
2015-10-06 07:23:11 +00:00
|
|
|
* format update). */
|
2017-04-04 13:58:53 +00:00
|
|
|
name = strrchr(alstr_get_cstr(filename), '/');
|
|
|
|
if(!name) name = strrchr(alstr_get_cstr(filename), '\\');
|
|
|
|
if(!name) name = alstr_get_cstr(filename);
|
2016-09-02 04:05:24 +00:00
|
|
|
else ++name;
|
|
|
|
|
2016-02-24 12:21:03 +00:00
|
|
|
ext = strrchr(name, '.');
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2015-10-06 11:01:53 +00:00
|
|
|
i = 0;
|
2015-10-06 07:23:11 +00:00
|
|
|
do {
|
2016-02-24 12:21:03 +00:00
|
|
|
if(!ext)
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_copy_cstr(&entry.name, name);
|
2016-02-24 12:21:03 +00:00
|
|
|
else
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_copy_range(&entry.name, name, ext);
|
2015-10-06 07:23:11 +00:00
|
|
|
if(i != 0)
|
|
|
|
{
|
|
|
|
char str[64];
|
|
|
|
snprintf(str, sizeof(str), " #%d", i+1);
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_append_cstr(&entry.name, str);
|
2015-10-06 07:23:11 +00:00
|
|
|
}
|
|
|
|
++i;
|
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0)
|
2017-04-05 18:29:58 +00:00
|
|
|
VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME);
|
2015-10-06 07:23:11 +00:00
|
|
|
#undef MATCH_NAME
|
2016-04-15 19:22:54 +00:00
|
|
|
} while(iter != VECTOR_END(*list));
|
2017-04-05 18:29:58 +00:00
|
|
|
entry.hrtf = loaded_entry;
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
TRACE("Adding entry \"%s\" from file \"%s\"\n", alstr_get_cstr(entry.name),
|
|
|
|
alstr_get_cstr(filename));
|
2015-10-06 07:23:11 +00:00
|
|
|
VECTOR_PUSH_BACK(*list, entry);
|
|
|
|
}
|
|
|
|
|
2016-08-31 15:16:49 +00:00
|
|
|
/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
|
|
|
|
* for input instead of opening the given filename.
|
2016-07-13 02:02:19 +00:00
|
|
|
*/
|
2017-12-17 23:56:30 +00:00
|
|
|
static void AddBuiltInEntry(vector_EnumeratedHrtf *list, const_al_string filename, ALuint residx)
|
2016-07-13 02:02:19 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
EnumeratedHrtf entry = { AL_STRING_INIT_STATIC(), NULL };
|
|
|
|
struct HrtfEntry *loaded_entry;
|
2016-07-13 02:02:19 +00:00
|
|
|
struct Hrtf *hrtf = NULL;
|
2017-04-05 18:29:58 +00:00
|
|
|
const EnumeratedHrtf *iter;
|
2017-04-05 14:09:16 +00:00
|
|
|
const char *name;
|
|
|
|
const char *ext;
|
2016-07-13 02:02:19 +00:00
|
|
|
int i;
|
|
|
|
|
2017-04-05 14:09:16 +00:00
|
|
|
loaded_entry = LoadedHrtfs;
|
|
|
|
while(loaded_entry)
|
2016-07-25 04:59:02 +00:00
|
|
|
{
|
2017-04-05 14:09:16 +00:00
|
|
|
if(alstr_cmp_cstr(filename, loaded_entry->filename) == 0)
|
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
#define MATCH_ENTRY(i) (loaded_entry == (i)->hrtf)
|
|
|
|
VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_ENTRY);
|
2017-04-05 14:09:16 +00:00
|
|
|
if(iter != VECTOR_END(*list))
|
|
|
|
{
|
|
|
|
TRACE("Skipping duplicate file entry %s\n", alstr_get_cstr(filename));
|
|
|
|
return;
|
|
|
|
}
|
2016-07-25 04:59:02 +00:00
|
|
|
#undef MATCH_FNAME
|
|
|
|
|
2017-04-06 08:35:09 +00:00
|
|
|
break;
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
2017-04-05 14:09:16 +00:00
|
|
|
loaded_entry = loaded_entry->next;
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-06 08:35:09 +00:00
|
|
|
if(!loaded_entry)
|
2016-07-13 02:02:19 +00:00
|
|
|
{
|
2017-04-06 08:35:09 +00:00
|
|
|
size_t namelen = alstr_length(filename)+32;
|
2016-07-13 02:02:19 +00:00
|
|
|
|
2017-04-06 08:35:09 +00:00
|
|
|
TRACE("Got new file \"%s\"\n", alstr_get_cstr(filename));
|
2016-07-13 02:02:19 +00:00
|
|
|
|
2017-04-06 08:35:09 +00:00
|
|
|
loaded_entry = al_calloc(DEF_ALIGN,
|
2017-04-18 21:11:15 +00:00
|
|
|
FAM_SIZE(struct HrtfEntry, filename, namelen)
|
2017-04-06 08:35:09 +00:00
|
|
|
);
|
|
|
|
loaded_entry->next = LoadedHrtfs;
|
|
|
|
loaded_entry->handle = hrtf;
|
2017-12-17 23:56:30 +00:00
|
|
|
snprintf(loaded_entry->filename, namelen, "!%u_%s",
|
2017-04-06 08:35:09 +00:00
|
|
|
residx, alstr_get_cstr(filename));
|
|
|
|
LoadedHrtfs = loaded_entry;
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
|
2017-04-05 14:09:16 +00:00
|
|
|
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
|
|
|
|
* format update). */
|
|
|
|
name = strrchr(alstr_get_cstr(filename), '/');
|
|
|
|
if(!name) name = strrchr(alstr_get_cstr(filename), '\\');
|
|
|
|
if(!name) name = alstr_get_cstr(filename);
|
|
|
|
else ++name;
|
|
|
|
|
|
|
|
ext = strrchr(name, '.');
|
|
|
|
|
2016-07-13 02:02:19 +00:00
|
|
|
i = 0;
|
|
|
|
do {
|
2017-04-05 14:09:16 +00:00
|
|
|
if(!ext)
|
|
|
|
alstr_copy_cstr(&entry.name, name);
|
|
|
|
else
|
|
|
|
alstr_copy_range(&entry.name, name, ext);
|
2016-07-13 02:02:19 +00:00
|
|
|
if(i != 0)
|
|
|
|
{
|
|
|
|
char str[64];
|
|
|
|
snprintf(str, sizeof(str), " #%d", i+1);
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_append_cstr(&entry.name, str);
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
++i;
|
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
#define MATCH_NAME(i) (alstr_cmp(entry.name, (i)->name) == 0)
|
2017-04-05 18:29:58 +00:00
|
|
|
VECTOR_FIND_IF(iter, const EnumeratedHrtf, *list, MATCH_NAME);
|
2016-07-13 02:02:19 +00:00
|
|
|
#undef MATCH_NAME
|
|
|
|
} while(iter != VECTOR_END(*list));
|
2017-04-05 18:29:58 +00:00
|
|
|
entry.hrtf = loaded_entry;
|
2016-07-13 02:02:19 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
TRACE("Adding built-in entry \"%s\"\n", alstr_get_cstr(entry.name));
|
2016-07-13 02:02:19 +00:00
|
|
|
VECTOR_PUSH_BACK(*list, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-11-10 20:37:07 +00:00
|
|
|
#define IDR_DEFAULT_44100_MHR 1
|
|
|
|
#define IDR_DEFAULT_48000_MHR 2
|
2016-07-13 02:02:19 +00:00
|
|
|
|
2017-05-05 10:29:52 +00:00
|
|
|
#ifndef ALSOFT_EMBED_HRTF_DATA
|
2016-11-11 05:51:45 +00:00
|
|
|
|
2017-05-05 10:29:52 +00:00
|
|
|
static const ALubyte *GetResource(int UNUSED(name), size_t *size)
|
2016-11-11 05:51:45 +00:00
|
|
|
{
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-07-13 02:02:19 +00:00
|
|
|
#else
|
|
|
|
|
2017-05-05 10:29:52 +00:00
|
|
|
#include "default-44100.mhr.h"
|
|
|
|
#include "default-48000.mhr.h"
|
2016-07-13 02:02:19 +00:00
|
|
|
|
|
|
|
static const ALubyte *GetResource(int name, size_t *size)
|
|
|
|
{
|
|
|
|
if(name == IDR_DEFAULT_44100_MHR)
|
|
|
|
{
|
2017-05-05 10:29:52 +00:00
|
|
|
*size = sizeof(hrtf_default_44100);
|
|
|
|
return hrtf_default_44100;
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
if(name == IDR_DEFAULT_48000_MHR)
|
|
|
|
{
|
2017-05-05 10:29:52 +00:00
|
|
|
*size = sizeof(hrtf_default_48000);
|
|
|
|
return hrtf_default_48000;
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2017-04-05 18:29:58 +00:00
|
|
|
vector_EnumeratedHrtf EnumerateHrtf(const_al_string devname)
|
2015-10-06 07:23:11 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
vector_EnumeratedHrtf list = VECTOR_INIT_STATIC();
|
2016-02-21 10:44:02 +00:00
|
|
|
const char *defaulthrtf = "";
|
2016-02-23 18:54:42 +00:00
|
|
|
const char *pathlist = "";
|
|
|
|
bool usedefaults = true;
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
if(ConfigValueStr(alstr_get_cstr(devname), NULL, "hrtf-paths", &pathlist))
|
2015-10-06 07:23:11 +00:00
|
|
|
{
|
2017-04-01 06:22:06 +00:00
|
|
|
al_string pname = AL_STRING_INIT_STATIC();
|
2016-02-23 18:54:42 +00:00
|
|
|
while(pathlist && *pathlist)
|
2015-10-06 07:23:11 +00:00
|
|
|
{
|
|
|
|
const char *next, *end;
|
|
|
|
|
2016-02-23 18:54:42 +00:00
|
|
|
while(isspace(*pathlist) || *pathlist == ',')
|
|
|
|
pathlist++;
|
|
|
|
if(*pathlist == '\0')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
next = strchr(pathlist, ',');
|
|
|
|
if(next)
|
2015-10-06 07:23:11 +00:00
|
|
|
end = next++;
|
2016-02-23 18:54:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
end = pathlist + strlen(pathlist);
|
|
|
|
usedefaults = false;
|
|
|
|
}
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2016-02-23 18:54:42 +00:00
|
|
|
while(end != pathlist && isspace(*(end-1)))
|
2015-10-06 07:23:11 +00:00
|
|
|
--end;
|
2016-02-23 18:54:42 +00:00
|
|
|
if(end != pathlist)
|
2015-10-06 07:23:11 +00:00
|
|
|
{
|
|
|
|
vector_al_string flist;
|
2017-04-01 06:22:06 +00:00
|
|
|
size_t i;
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-08 10:00:53 +00:00
|
|
|
alstr_copy_range(&pname, pathlist, end);
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
flist = SearchDataFiles(".mhr", alstr_get_cstr(pname));
|
2017-04-01 06:22:06 +00:00
|
|
|
for(i = 0;i < VECTOR_SIZE(flist);i++)
|
|
|
|
AddFileEntry(&list, VECTOR_ELEM(flist, i));
|
2017-04-04 13:58:53 +00:00
|
|
|
VECTOR_FOR_EACH(al_string, flist, alstr_reset);
|
2015-10-06 07:23:11 +00:00
|
|
|
VECTOR_DEINIT(flist);
|
|
|
|
}
|
|
|
|
|
2016-02-23 18:54:42 +00:00
|
|
|
pathlist = next;
|
2015-10-06 07:23:11 +00:00
|
|
|
}
|
2017-04-01 06:22:06 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_reset(&pname);
|
2015-10-06 07:23:11 +00:00
|
|
|
}
|
2017-04-04 13:58:53 +00:00
|
|
|
else if(ConfigValueExists(alstr_get_cstr(devname), NULL, "hrtf_tables"))
|
2016-02-23 18:54:42 +00:00
|
|
|
ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
|
|
|
|
|
|
|
|
if(usedefaults)
|
|
|
|
{
|
2017-04-01 06:22:06 +00:00
|
|
|
al_string ename = AL_STRING_INIT_STATIC();
|
2016-07-13 02:02:19 +00:00
|
|
|
vector_al_string flist;
|
|
|
|
const ALubyte *rdata;
|
2017-04-01 06:22:06 +00:00
|
|
|
size_t rsize, i;
|
2016-07-13 02:02:19 +00:00
|
|
|
|
|
|
|
flist = SearchDataFiles(".mhr", "openal/hrtf");
|
2017-04-01 06:22:06 +00:00
|
|
|
for(i = 0;i < VECTOR_SIZE(flist);i++)
|
|
|
|
AddFileEntry(&list, VECTOR_ELEM(flist, i));
|
2017-04-04 13:58:53 +00:00
|
|
|
VECTOR_FOR_EACH(al_string, flist, alstr_reset);
|
2016-02-23 18:54:42 +00:00
|
|
|
VECTOR_DEINIT(flist);
|
2016-07-13 02:02:19 +00:00
|
|
|
|
|
|
|
rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize);
|
|
|
|
if(rdata != NULL && rsize > 0)
|
|
|
|
{
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_copy_cstr(&ename, "Built-In 44100hz");
|
2017-04-06 08:35:09 +00:00
|
|
|
AddBuiltInEntry(&list, ename, IDR_DEFAULT_44100_MHR);
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize);
|
|
|
|
if(rdata != NULL && rsize > 0)
|
|
|
|
{
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_copy_cstr(&ename, "Built-In 48000hz");
|
2017-04-06 08:35:09 +00:00
|
|
|
AddBuiltInEntry(&list, ename, IDR_DEFAULT_48000_MHR);
|
2016-07-13 02:02:19 +00:00
|
|
|
}
|
2017-04-04 13:58:53 +00:00
|
|
|
alstr_reset(&ename);
|
2016-02-23 18:54:42 +00:00
|
|
|
}
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-04 13:58:53 +00:00
|
|
|
if(VECTOR_SIZE(list) > 1 && ConfigValueStr(alstr_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf))
|
2016-02-21 10:44:02 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
const EnumeratedHrtf *iter;
|
2016-02-21 10:44:02 +00:00
|
|
|
/* Find the preferred HRTF and move it to the front of the list. */
|
2017-04-04 13:58:53 +00:00
|
|
|
#define FIND_ENTRY(i) (alstr_cmp_cstr((i)->name, defaulthrtf) == 0)
|
2017-04-05 18:29:58 +00:00
|
|
|
VECTOR_FIND_IF(iter, const EnumeratedHrtf, list, FIND_ENTRY);
|
2016-09-10 14:55:33 +00:00
|
|
|
#undef FIND_ENTRY
|
|
|
|
if(iter == VECTOR_END(list))
|
|
|
|
WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf);
|
|
|
|
else if(iter != VECTOR_BEGIN(list))
|
2016-02-21 10:44:02 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
EnumeratedHrtf entry = *iter;
|
2016-02-21 10:44:02 +00:00
|
|
|
memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0),
|
2017-04-05 18:29:58 +00:00
|
|
|
(iter-VECTOR_BEGIN(list))*sizeof(EnumeratedHrtf));
|
2016-02-21 10:44:02 +00:00
|
|
|
VECTOR_ELEM(list,0) = entry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-06 07:23:11 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2017-04-05 18:29:58 +00:00
|
|
|
void FreeHrtfList(vector_EnumeratedHrtf *list)
|
2015-10-06 11:01:53 +00:00
|
|
|
{
|
2017-04-04 13:58:53 +00:00
|
|
|
#define CLEAR_ENTRY(i) alstr_reset(&(i)->name)
|
2017-04-05 18:29:58 +00:00
|
|
|
VECTOR_FOR_EACH(EnumeratedHrtf, *list, CLEAR_ENTRY);
|
2015-10-06 11:01:53 +00:00
|
|
|
VECTOR_DEINIT(*list);
|
|
|
|
#undef CLEAR_ENTRY
|
|
|
|
}
|
|
|
|
|
2017-04-05 19:27:30 +00:00
|
|
|
struct Hrtf *GetLoadedHrtf(struct HrtfEntry *entry)
|
|
|
|
{
|
|
|
|
struct Hrtf *hrtf = NULL;
|
|
|
|
struct FileMapping fmap;
|
2017-04-06 08:35:09 +00:00
|
|
|
const ALubyte *rdata;
|
|
|
|
const char *name;
|
2017-12-17 23:56:30 +00:00
|
|
|
ALuint residx;
|
2017-04-06 08:35:09 +00:00
|
|
|
size_t rsize;
|
|
|
|
char ch;
|
2017-04-05 19:27:30 +00:00
|
|
|
|
2017-04-06 20:00:29 +00:00
|
|
|
while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst))
|
2017-04-05 19:27:30 +00:00
|
|
|
althrd_yield();
|
|
|
|
|
|
|
|
if(entry->handle)
|
|
|
|
{
|
|
|
|
hrtf = entry->handle;
|
2017-04-06 20:00:29 +00:00
|
|
|
Hrtf_IncRef(hrtf);
|
2017-04-05 19:27:30 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2017-04-06 08:35:09 +00:00
|
|
|
fmap.ptr = NULL;
|
|
|
|
fmap.len = 0;
|
2017-12-17 23:56:30 +00:00
|
|
|
if(sscanf(entry->filename, "!%u%c", &residx, &ch) == 2 && ch == '_')
|
2017-04-05 19:27:30 +00:00
|
|
|
{
|
2017-04-06 08:35:09 +00:00
|
|
|
name = strchr(entry->filename, ch)+1;
|
|
|
|
|
|
|
|
TRACE("Loading %s...\n", name);
|
|
|
|
rdata = GetResource(residx, &rsize);
|
|
|
|
if(rdata == NULL || rsize == 0)
|
|
|
|
{
|
2017-12-17 23:56:30 +00:00
|
|
|
ERR("Could not get resource %u, %s\n", residx, name);
|
2017-04-06 08:35:09 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
name = entry->filename;
|
|
|
|
|
|
|
|
TRACE("Loading %s...\n", entry->filename);
|
|
|
|
fmap = MapFileToMem(entry->filename);
|
|
|
|
if(fmap.ptr == NULL)
|
|
|
|
{
|
|
|
|
ERR("Could not open %s\n", entry->filename);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
rdata = fmap.ptr;
|
|
|
|
rsize = fmap.len;
|
2017-04-05 19:27:30 +00:00
|
|
|
}
|
|
|
|
|
2017-08-09 03:25:31 +00:00
|
|
|
if(rsize < sizeof(magicMarker02))
|
2017-04-06 08:35:09 +00:00
|
|
|
ERR("%s data is too short ("SZFMT" bytes)\n", name, rsize);
|
2017-08-09 03:25:31 +00:00
|
|
|
else if(memcmp(rdata, magicMarker02, sizeof(magicMarker02)) == 0)
|
|
|
|
{
|
|
|
|
TRACE("Detected data set format v2\n");
|
|
|
|
hrtf = LoadHrtf02(rdata+sizeof(magicMarker02),
|
|
|
|
rsize-sizeof(magicMarker02), name
|
|
|
|
);
|
|
|
|
}
|
2017-04-06 08:35:09 +00:00
|
|
|
else if(memcmp(rdata, magicMarker01, sizeof(magicMarker01)) == 0)
|
2017-04-05 19:27:30 +00:00
|
|
|
{
|
|
|
|
TRACE("Detected data set format v1\n");
|
2017-04-06 08:35:09 +00:00
|
|
|
hrtf = LoadHrtf01(rdata+sizeof(magicMarker01),
|
|
|
|
rsize-sizeof(magicMarker01), name
|
2017-04-05 19:27:30 +00:00
|
|
|
);
|
|
|
|
}
|
2017-04-06 08:35:09 +00:00
|
|
|
else if(memcmp(rdata, magicMarker00, sizeof(magicMarker00)) == 0)
|
2017-04-05 19:27:30 +00:00
|
|
|
{
|
|
|
|
TRACE("Detected data set format v0\n");
|
2017-04-06 08:35:09 +00:00
|
|
|
hrtf = LoadHrtf00(rdata+sizeof(magicMarker00),
|
|
|
|
rsize-sizeof(magicMarker00), name
|
2017-04-05 19:27:30 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
2017-04-06 08:35:09 +00:00
|
|
|
ERR("Invalid header in %s: \"%.8s\"\n", name, (const char*)rdata);
|
|
|
|
if(fmap.ptr)
|
|
|
|
UnmapFileMem(&fmap);
|
2017-04-05 19:27:30 +00:00
|
|
|
|
|
|
|
if(!hrtf)
|
|
|
|
{
|
2017-04-06 08:35:09 +00:00
|
|
|
ERR("Failed to load %s\n", name);
|
2017-04-05 19:27:30 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2017-04-06 20:00:29 +00:00
|
|
|
entry->handle = hrtf;
|
|
|
|
Hrtf_IncRef(hrtf);
|
2017-04-05 19:27:30 +00:00
|
|
|
|
|
|
|
TRACE("Loaded HRTF support for format: %s %uhz\n",
|
|
|
|
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
|
|
|
|
|
|
|
|
done:
|
2017-04-06 20:00:29 +00:00
|
|
|
ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst);
|
2017-04-05 19:27:30 +00:00
|
|
|
return hrtf;
|
|
|
|
}
|
|
|
|
|
2015-10-06 07:23:11 +00:00
|
|
|
|
2017-04-06 20:00:29 +00:00
|
|
|
void Hrtf_IncRef(struct Hrtf *hrtf)
|
|
|
|
{
|
|
|
|
uint ref = IncrementRef(&hrtf->ref);
|
|
|
|
TRACEREF("%p increasing refcount to %u\n", hrtf, ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hrtf_DecRef(struct Hrtf *hrtf)
|
|
|
|
{
|
|
|
|
struct HrtfEntry *Hrtf;
|
|
|
|
uint ref = DecrementRef(&hrtf->ref);
|
|
|
|
TRACEREF("%p decreasing refcount to %u\n", hrtf, ref);
|
|
|
|
if(ref == 0)
|
|
|
|
{
|
|
|
|
while(ATOMIC_FLAG_TEST_AND_SET(&LoadedHrtfLock, almemory_order_seq_cst))
|
|
|
|
althrd_yield();
|
|
|
|
|
|
|
|
Hrtf = LoadedHrtfs;
|
|
|
|
while(Hrtf != NULL)
|
|
|
|
{
|
|
|
|
/* Need to double-check that it's still unused, as another device
|
|
|
|
* could've reacquired this HRTF after its reference went to 0 and
|
|
|
|
* before the lock was taken.
|
|
|
|
*/
|
|
|
|
if(hrtf == Hrtf->handle && ReadRef(&hrtf->ref) == 0)
|
|
|
|
{
|
|
|
|
al_free(Hrtf->handle);
|
|
|
|
Hrtf->handle = NULL;
|
|
|
|
TRACE("Unloaded unused HRTF %s\n", Hrtf->filename);
|
|
|
|
}
|
|
|
|
Hrtf = Hrtf->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
ATOMIC_FLAG_CLEAR(&LoadedHrtfLock, almemory_order_seq_cst);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-11 08:59:42 +00:00
|
|
|
void FreeHrtfs(void)
|
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
struct HrtfEntry *Hrtf = LoadedHrtfs;
|
2016-02-17 03:56:44 +00:00
|
|
|
LoadedHrtfs = NULL;
|
2012-09-11 08:59:42 +00:00
|
|
|
|
2016-02-17 03:56:44 +00:00
|
|
|
while(Hrtf != NULL)
|
2012-09-11 08:59:42 +00:00
|
|
|
{
|
2017-04-05 18:29:58 +00:00
|
|
|
struct HrtfEntry *next = Hrtf->next;
|
|
|
|
al_free(Hrtf->handle);
|
2016-07-07 17:31:43 +00:00
|
|
|
al_free(Hrtf);
|
2016-02-17 03:56:44 +00:00
|
|
|
Hrtf = next;
|
2011-06-03 08:06:00 +00:00
|
|
|
}
|
2011-09-18 17:09:32 +00:00
|
|
|
}
|