2011-05-01 13:59:44 -07: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 14:11:03 +02:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2011-05-01 13:59:44 -07:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2011-09-18 10:09:32 -07:00
|
|
|
#include <stdlib.h>
|
2011-09-18 11:10:32 -07:00
|
|
|
#include <ctype.h>
|
2011-09-18 10:09:32 -07:00
|
|
|
|
2011-05-01 13:59:44 -07:00
|
|
|
#include "AL/al.h"
|
|
|
|
#include "AL/alc.h"
|
|
|
|
#include "alMain.h"
|
2011-06-03 01:06:00 -07:00
|
|
|
#include "alSource.h"
|
2012-09-11 01:59:42 -07:00
|
|
|
#include "alu.h"
|
2016-08-21 03:05:42 -07:00
|
|
|
#include "bformatdec.h"
|
2014-02-23 21:11:01 -08:00
|
|
|
#include "hrtf.h"
|
2011-05-01 13:59:44 -07:00
|
|
|
|
2015-10-06 04:01:53 -07:00
|
|
|
#include "compat.h"
|
2016-07-07 10:31:43 -07:00
|
|
|
#include "almalloc.h"
|
2015-10-06 04:01:53 -07:00
|
|
|
|
2012-09-12 03:45:26 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Current data set limits defined by the makehrtf utility. */
|
|
|
|
#define MIN_IR_SIZE (8)
|
|
|
|
#define MAX_IR_SIZE (128)
|
|
|
|
#define MOD_IR_SIZE (8)
|
2011-07-16 00:22:01 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
#define MIN_EV_COUNT (5)
|
|
|
|
#define MAX_EV_COUNT (128)
|
2011-07-16 00:22:01 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
#define MIN_AZ_COUNT (1)
|
|
|
|
#define MAX_AZ_COUNT (128)
|
2011-05-01 13:59:44 -07:00
|
|
|
|
2012-09-12 07:25:05 -07:00
|
|
|
static const ALchar magicMarker00[8] = "MinPHR00";
|
|
|
|
static const ALchar magicMarker01[8] = "MinPHR01";
|
2012-09-11 01:59:42 -07:00
|
|
|
|
2014-11-23 10:49:54 -08:00
|
|
|
/* First value for pass-through coefficients (remaining are 0), used for omni-
|
|
|
|
* directional sounds. */
|
|
|
|
static const ALfloat PassthruCoeff = 32767.0f * 0.707106781187f/*sqrt(0.5)*/;
|
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
static struct Hrtf *LoadedHrtfs = NULL;
|
2011-09-18 10:09:32 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Calculate the elevation indices given the polar elevation in radians.
|
2014-07-16 13:26:47 -07:00
|
|
|
* This will return two indices between 0 and (evcount - 1) and an
|
2012-09-11 01:59:42 -07:00
|
|
|
* interpolation factor between 0.0 and 1.0.
|
|
|
|
*/
|
2014-07-16 13:26:47 -07:00
|
|
|
static void CalcEvIndices(ALuint evcount, ALfloat ev, ALuint *evidx, ALfloat *evmu)
|
2011-05-01 13:59:44 -07:00
|
|
|
{
|
2014-07-16 13:26:47 -07:00
|
|
|
ev = (F_PI_2 + ev) * (evcount-1) / F_PI;
|
2011-09-29 03:51:46 -07:00
|
|
|
evidx[0] = fastf2u(ev);
|
2014-07-16 13:26:47 -07:00
|
|
|
evidx[1] = minu(evidx[0] + 1, evcount-1);
|
2011-07-04 07:14:45 -07:00
|
|
|
*evmu = ev - evidx[0];
|
2011-06-03 01:06:00 -07:00
|
|
|
}
|
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Calculate the azimuth indices given the polar azimuth in radians. This
|
2014-07-16 13:26:47 -07:00
|
|
|
* will return two indices between 0 and (azcount - 1) and an interpolation
|
|
|
|
* factor between 0.0 and 1.0.
|
2012-09-11 01:59:42 -07:00
|
|
|
*/
|
2014-07-16 13:26:47 -07:00
|
|
|
static void CalcAzIndices(ALuint azcount, ALfloat az, ALuint *azidx, ALfloat *azmu)
|
2011-06-03 01:06:00 -07:00
|
|
|
{
|
2015-09-13 08:46:48 -07:00
|
|
|
az = (F_TAU + az) * azcount / F_TAU;
|
2014-07-16 13:26:47 -07:00
|
|
|
azidx[0] = fastf2u(az) % azcount;
|
|
|
|
azidx[1] = (azidx[0] + 1) % azcount;
|
2012-06-29 02:12:36 -07:00
|
|
|
*azmu = az - floorf(az);
|
2011-05-01 13:59:44 -07:00
|
|
|
}
|
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Calculates static HRIR coefficients and delays for the given polar
|
|
|
|
* elevation and azimuth in radians. Linear interpolation is used to
|
|
|
|
* increase the apparent resolution of the HRIR data set. The coefficients
|
|
|
|
* are also normalized and attenuated by the specified gain.
|
|
|
|
*/
|
2016-04-24 21:42:59 -07:00
|
|
|
void GetLerpedHrtfCoeffs(const struct Hrtf *Hrtf, ALfloat elevation, ALfloat azimuth, ALfloat spread, ALfloat gain, ALfloat (*coeffs)[2], ALuint *delays)
|
2011-05-01 13:59:44 -07:00
|
|
|
{
|
2014-07-16 13:26:47 -07:00
|
|
|
ALuint evidx[2], lidx[4], ridx[4];
|
2012-08-11 02:16:34 -07:00
|
|
|
ALfloat mu[3], blend[4];
|
2016-04-24 21:42:59 -07:00
|
|
|
ALfloat dirfact;
|
2011-07-04 07:14:45 -07:00
|
|
|
ALuint i;
|
2011-06-03 01:06:00 -07:00
|
|
|
|
2016-04-24 21:42:59 -07:00
|
|
|
dirfact = 1.0f - (spread / F_TAU);
|
|
|
|
|
2014-07-16 13:26:47 -07:00
|
|
|
/* Claculate elevation indices and interpolation factor. */
|
|
|
|
CalcEvIndices(Hrtf->evCount, elevation, evidx, &mu[2]);
|
2011-06-03 01:06:00 -07:00
|
|
|
|
2014-07-16 13:26:47 -07:00
|
|
|
for(i = 0;i < 2;i++)
|
|
|
|
{
|
|
|
|
ALuint azcount = Hrtf->azCount[evidx[i]];
|
|
|
|
ALuint evoffset = Hrtf->evOffset[evidx[i]];
|
|
|
|
ALuint azidx[2];
|
|
|
|
|
|
|
|
/* Calculate azimuth indices and interpolation factor for this elevation. */
|
|
|
|
CalcAzIndices(azcount, azimuth, azidx, &mu[i]);
|
|
|
|
|
|
|
|
/* Calculate a set of linear HRIR indices for left and right channels. */
|
|
|
|
lidx[i*2 + 0] = evoffset + azidx[0];
|
|
|
|
lidx[i*2 + 1] = evoffset + azidx[1];
|
|
|
|
ridx[i*2 + 0] = evoffset + ((azcount-azidx[0]) % azcount);
|
|
|
|
ridx[i*2 + 1] = evoffset + ((azcount-azidx[1]) % azcount);
|
|
|
|
}
|
2011-07-04 07:14:45 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Calculate 4 blending weights for 2D bilinear interpolation. */
|
2012-08-11 02:16:34 -07:00
|
|
|
blend[0] = (1.0f-mu[0]) * (1.0f-mu[2]);
|
|
|
|
blend[1] = ( mu[0]) * (1.0f-mu[2]);
|
|
|
|
blend[2] = (1.0f-mu[1]) * ( mu[2]);
|
|
|
|
blend[3] = ( mu[1]) * ( mu[2]);
|
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
/* Calculate the HRIR delays using linear interpolation. */
|
2014-11-23 10:49:54 -08:00
|
|
|
delays[0] = fastf2u((Hrtf->delays[lidx[0]]*blend[0] + Hrtf->delays[lidx[1]]*blend[1] +
|
|
|
|
Hrtf->delays[lidx[2]]*blend[2] + Hrtf->delays[lidx[3]]*blend[3]) *
|
|
|
|
dirfact + 0.5f) << HRTFDELAY_BITS;
|
|
|
|
delays[1] = fastf2u((Hrtf->delays[ridx[0]]*blend[0] + Hrtf->delays[ridx[1]]*blend[1] +
|
|
|
|
Hrtf->delays[ridx[2]]*blend[2] + Hrtf->delays[ridx[3]]*blend[3]) *
|
|
|
|
dirfact + 0.5f) << HRTFDELAY_BITS;
|
2012-09-11 01:59:42 -07:00
|
|
|
|
|
|
|
/* Calculate the sample offsets for the HRIR indices. */
|
|
|
|
lidx[0] *= Hrtf->irSize;
|
|
|
|
lidx[1] *= Hrtf->irSize;
|
|
|
|
lidx[2] *= Hrtf->irSize;
|
|
|
|
lidx[3] *= Hrtf->irSize;
|
|
|
|
ridx[0] *= Hrtf->irSize;
|
|
|
|
ridx[1] *= Hrtf->irSize;
|
|
|
|
ridx[2] *= Hrtf->irSize;
|
|
|
|
ridx[3] *= Hrtf->irSize;
|
|
|
|
|
2014-11-23 10:49:54 -08:00
|
|
|
/* Calculate the normalized and attenuated HRIR coefficients using linear
|
|
|
|
* interpolation when there is enough gain to warrant it. Zero the
|
|
|
|
* coefficients if gain is too low.
|
|
|
|
*/
|
|
|
|
if(gain > 0.0001f)
|
2011-07-04 07:14:45 -07:00
|
|
|
{
|
2014-07-08 09:13:35 -07:00
|
|
|
ALfloat c;
|
2014-11-23 10:49:54 -08:00
|
|
|
|
|
|
|
i = 0;
|
2014-07-08 09:13:35 -07:00
|
|
|
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
|
|
|
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
2014-11-23 10:49:54 -08:00
|
|
|
coeffs[i][0] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
|
2014-07-08 09:13:35 -07:00
|
|
|
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
|
|
|
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
2014-11-23 10:49:54 -08:00
|
|
|
coeffs[i][1] = lerp(PassthruCoeff, c, dirfact) * gain * (1.0f/32767.0f);
|
|
|
|
|
|
|
|
for(i = 1;i < Hrtf->irSize;i++)
|
|
|
|
{
|
|
|
|
c = (Hrtf->coeffs[lidx[0]+i]*blend[0] + Hrtf->coeffs[lidx[1]+i]*blend[1] +
|
|
|
|
Hrtf->coeffs[lidx[2]+i]*blend[2] + Hrtf->coeffs[lidx[3]+i]*blend[3]);
|
|
|
|
coeffs[i][0] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
|
|
|
|
c = (Hrtf->coeffs[ridx[0]+i]*blend[0] + Hrtf->coeffs[ridx[1]+i]*blend[1] +
|
|
|
|
Hrtf->coeffs[ridx[2]+i]*blend[2] + Hrtf->coeffs[ridx[3]+i]*blend[3]);
|
|
|
|
coeffs[i][1] = lerp(0.0f, c, dirfact) * gain * (1.0f/32767.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
{
|
|
|
|
coeffs[i][0] = 0.0f;
|
|
|
|
coeffs[i][1] = 0.0f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-09 15:59:29 -08: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-11 23:20:35 -07:00
|
|
|
ALuint BuildBFormatHrtf(const struct Hrtf *Hrtf, ALfloat (*coeffs)[HRIR_LENGTH][2], ALuint NumChannels)
|
|
|
|
{
|
2016-08-17 05:34:09 -07:00
|
|
|
static const struct {
|
|
|
|
ALfloat elevation;
|
|
|
|
ALfloat azimuth;
|
|
|
|
} CubePoints[8] = {
|
|
|
|
{ DEG2RAD( 35.0f), DEG2RAD( -45.0f) },
|
|
|
|
{ DEG2RAD( 35.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ DEG2RAD( 35.0f), DEG2RAD(-135.0f) },
|
|
|
|
{ DEG2RAD( 35.0f), DEG2RAD( 135.0f) },
|
|
|
|
{ DEG2RAD(-35.0f), DEG2RAD( -45.0f) },
|
|
|
|
{ DEG2RAD(-35.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ DEG2RAD(-35.0f), DEG2RAD(-135.0f) },
|
|
|
|
{ DEG2RAD(-35.0f), DEG2RAD( 135.0f) },
|
|
|
|
};
|
2016-08-21 03:05:42 -07:00
|
|
|
static const ALfloat CubeMatrix[8][2][MAX_AMBI_COEFFS] = {
|
2016-09-05 10:33:52 -07:00
|
|
|
{ { 0.25f, 0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, 0.125f, 0.125f } },
|
|
|
|
{ { 0.25f, -0.1443375672f, 0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, 0.125f, 0.125f } },
|
|
|
|
{ { 0.25f, 0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, 0.125f, -0.125f } },
|
|
|
|
{ { 0.25f, -0.1443375672f, 0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, 0.125f, -0.125f } },
|
|
|
|
{ { 0.25f, 0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, 0.125f, -0.125f, 0.125f } },
|
|
|
|
{ { 0.25f, -0.1443375672f, -0.1443375672f, 0.1443375672f }, { 0.125f, -0.125f, -0.125f, 0.125f } },
|
|
|
|
{ { 0.25f, 0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, 0.125f, -0.125f, -0.125f } },
|
|
|
|
{ { 0.25f, -0.1443375672f, -0.1443375672f, -0.1443375672f }, { 0.125f, -0.125f, -0.125f, -0.125f } },
|
2016-08-17 05:34:09 -07:00
|
|
|
};
|
2016-08-30 22:33:33 -07:00
|
|
|
/* Change this to 2 for dual-band HRTF processing. May require a higher quality
|
|
|
|
* band-splitter, or better calculation of the new IR length to deal with the
|
|
|
|
* tail generated by the filter.
|
|
|
|
*/
|
|
|
|
#define NUM_BANDS 1
|
2016-08-21 03:05:42 -07:00
|
|
|
BandSplitter splitter;
|
|
|
|
ALfloat temps[3][HRIR_LENGTH];
|
2016-08-17 05:34:09 -07:00
|
|
|
ALuint lidx[8], ridx[8];
|
|
|
|
ALuint min_delay = HRTF_HISTORY_LENGTH;
|
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
|
|
|
ALuint max_length = 0;
|
2016-08-21 03:05:42 -07:00
|
|
|
ALuint i, j, 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-11 23:20:35 -07:00
|
|
|
|
|
|
|
assert(NumChannels == 4);
|
|
|
|
|
2016-08-17 05:34:09 -07:00
|
|
|
for(c = 0;c < 8;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-11 23:20:35 -07:00
|
|
|
{
|
2016-08-18 23:33:08 -07:00
|
|
|
ALuint evidx, azidx;
|
2016-08-17 05:34:09 -07: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-11 23:20:35 -07:00
|
|
|
|
2016-08-17 05:34:09 -07:00
|
|
|
/* Calculate elevation index. */
|
2016-08-18 23:33:08 -07:00
|
|
|
evidx = (ALuint)floorf((F_PI_2 + CubePoints[c].elevation) *
|
|
|
|
(Hrtf->evCount-1)/F_PI + 0.5f);
|
|
|
|
evidx = minu(evidx, Hrtf->evCount-1);
|
2016-08-17 05:34:09 -07:00
|
|
|
|
2016-08-18 23:33:08 -07:00
|
|
|
azcount = Hrtf->azCount[evidx];
|
|
|
|
evoffset = Hrtf->evOffset[evidx];
|
2016-08-17 05:34:09 -07:00
|
|
|
|
|
|
|
/* Calculate azimuth index for this elevation. */
|
2016-08-18 23:33:08 -07:00
|
|
|
azidx = (ALuint)floorf((F_TAU+CubePoints[c].azimuth) *
|
|
|
|
azcount/F_TAU + 0.5f) % azcount;
|
2016-08-17 05:34:09 -07:00
|
|
|
|
|
|
|
/* Calculate indices for left and right channels. */
|
2016-08-18 23:33:08 -07:00
|
|
|
lidx[c] = evoffset + azidx;
|
|
|
|
ridx[c] = evoffset + ((azcount-azidx) % azcount);
|
2016-08-17 05:34:09 -07:00
|
|
|
|
|
|
|
min_delay = minu(min_delay, minu(Hrtf->delays[lidx[c]], Hrtf->delays[ridx[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-11 23:20:35 -07:00
|
|
|
}
|
|
|
|
|
2016-08-21 03:05:42 -07:00
|
|
|
memset(temps, 0, sizeof(temps));
|
|
|
|
bandsplit_init(&splitter, 400.0f / (ALfloat)Hrtf->sampleRate);
|
2016-08-17 05:34:09 -07:00
|
|
|
for(c = 0;c < 8;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-11 23:20:35 -07:00
|
|
|
{
|
2016-08-17 05:34:09 -07:00
|
|
|
const ALshort *fir;
|
|
|
|
ALuint delay;
|
|
|
|
|
2016-08-30 22:33:33 -07:00
|
|
|
/* Convert the left FIR from shorts to float */
|
2016-08-17 05:34:09 -07:00
|
|
|
fir = &Hrtf->coeffs[lidx[c] * Hrtf->irSize];
|
2016-08-30 22:33:33 -07:00
|
|
|
if(NUM_BANDS == 1)
|
|
|
|
{
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
temps[0][i] = fir[i] / 32767.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Band-split left HRIR into low and high frequency responses. */
|
|
|
|
bandsplit_clear(&splitter);
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
temps[2][i] = fir[i] / 32767.0f;
|
|
|
|
bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
|
|
|
|
}
|
2016-08-21 03:05:42 -07:00
|
|
|
|
|
|
|
/* Add to the left output coefficients with the specified delay. */
|
2016-08-17 05:34:09 -07:00
|
|
|
delay = Hrtf->delays[lidx[c]] - min_delay;
|
|
|
|
for(i = 0;i < NumChannels;++i)
|
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
|
|
|
{
|
2016-08-30 22:33:33 -07:00
|
|
|
for(b = 0;b < NUM_BANDS;b++)
|
2016-08-21 03:05:42 -07:00
|
|
|
{
|
|
|
|
ALuint k = 0;
|
|
|
|
for(j = delay;j < HRIR_LENGTH;++j)
|
|
|
|
coeffs[i][j][0] += temps[b][k++] * CubeMatrix[c][b][i];
|
|
|
|
}
|
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
|
|
|
}
|
2016-08-21 03:05:42 -07:00
|
|
|
max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH));
|
2016-08-17 05:34:09 -07:00
|
|
|
|
2016-08-30 22:33:33 -07:00
|
|
|
/* Convert the right FIR from shorts to float */
|
2016-08-17 05:34:09 -07:00
|
|
|
fir = &Hrtf->coeffs[ridx[c] * Hrtf->irSize];
|
2016-08-30 22:33:33 -07:00
|
|
|
if(NUM_BANDS == 1)
|
|
|
|
{
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
temps[0][i] = fir[i] / 32767.0f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Band-split right HRIR into low and high frequency responses. */
|
|
|
|
bandsplit_clear(&splitter);
|
|
|
|
for(i = 0;i < Hrtf->irSize;i++)
|
|
|
|
temps[2][i] = fir[i] / 32767.0f;
|
|
|
|
bandsplit_process(&splitter, temps[0], temps[1], temps[2], HRIR_LENGTH);
|
|
|
|
}
|
2016-08-21 03:05:42 -07:00
|
|
|
|
|
|
|
/* Add to the right output coefficients with the specified delay. */
|
2016-08-17 05:34:09 -07:00
|
|
|
delay = Hrtf->delays[ridx[c]] - min_delay;
|
|
|
|
for(i = 0;i < NumChannels;++i)
|
|
|
|
{
|
2016-08-30 22:33:33 -07:00
|
|
|
for(b = 0;b < NUM_BANDS;b++)
|
2016-08-21 03:05:42 -07:00
|
|
|
{
|
|
|
|
ALuint k = 0;
|
|
|
|
for(j = delay;j < HRIR_LENGTH;++j)
|
|
|
|
coeffs[i][j][1] += temps[b][k++] * CubeMatrix[c][b][i];
|
|
|
|
}
|
2016-08-17 05:34:09 -07:00
|
|
|
}
|
2016-08-21 03:05:42 -07:00
|
|
|
max_length = maxu(max_length, minu(delay + Hrtf->irSize, HRIR_LENGTH));
|
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
|
|
|
}
|
2016-08-17 05:34:09 -07:00
|
|
|
TRACE("Skipped min delay: %u, new combined length: %u\n", min_delay, max_length);
|
2016-08-30 22:33:33 -07:00
|
|
|
#undef NUM_BANDS
|
2016-08-17 05:34:09 -07: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-11 23:20:35 -07:00
|
|
|
return max_length;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
static struct Hrtf *LoadHrtf00(const ALubyte *data, size_t datalen, const_al_string filename)
|
2012-09-12 07:25:05 -07:00
|
|
|
{
|
2014-11-22 04:20:17 -08:00
|
|
|
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
2012-09-12 07:25:05 -07:00
|
|
|
struct Hrtf *Hrtf = NULL;
|
|
|
|
ALboolean failed = AL_FALSE;
|
|
|
|
ALuint rate = 0, irCount = 0;
|
2012-10-07 08:19:09 -07:00
|
|
|
ALushort irSize = 0;
|
|
|
|
ALubyte evCount = 0;
|
2012-09-12 07:25:05 -07:00
|
|
|
ALubyte *azCount = NULL;
|
|
|
|
ALushort *evOffset = NULL;
|
|
|
|
ALshort *coeffs = NULL;
|
2016-08-31 08:16:49 -07:00
|
|
|
const ALubyte *delays = NULL;
|
2012-09-12 07:25:05 -07:00
|
|
|
ALuint i, j;
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
if(datalen < 9)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
|
|
|
|
al_string_get_cstr(filename), 9, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = *(data++);
|
|
|
|
rate |= *(data++)<<8;
|
|
|
|
rate |= *(data++)<<16;
|
|
|
|
rate |= *(data++)<<24;
|
|
|
|
datalen -= 4;
|
2012-09-12 07:25:05 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
irCount = *(data++);
|
|
|
|
irCount |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
irSize = *(data++);
|
|
|
|
irSize |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
evCount = *(data++);
|
|
|
|
datalen -= 1;
|
2012-09-12 07:25:05 -07: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 08:16:49 -07:00
|
|
|
if(datalen < evCount*2)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT")\n",
|
|
|
|
al_string_get_cstr(filename), evCount*2, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-09-12 07:25:05 -07: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)
|
|
|
|
{
|
2016-08-31 08:16:49 -07:00
|
|
|
evOffset[0] = *(data++);
|
|
|
|
evOffset[0] |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07:00
|
|
|
for(i = 1;i < evCount;i++)
|
|
|
|
{
|
2016-08-31 08:16:49 -07:00
|
|
|
evOffset[i] = *(data++);
|
|
|
|
evOffset[i] |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07: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);
|
2016-08-31 08:16:49 -07:00
|
|
|
if(coeffs == NULL)
|
2012-09-12 07:25:05 -07:00
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
size_t reqsize = 2*irSize*irCount + irCount;
|
|
|
|
if(datalen < reqsize)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT")\n",
|
|
|
|
al_string_get_cstr(filename), reqsize, datalen);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-12 07:25:05 -07:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
for(i = 0;i < irCount*irSize;i+=irSize)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
|
|
|
{
|
2016-08-31 08:16:49 -07:00
|
|
|
coeffs[i+j] = *(data++);
|
|
|
|
coeffs[i+j] |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07:00
|
|
|
}
|
|
|
|
}
|
2016-08-31 08:16:49 -07:00
|
|
|
|
|
|
|
delays = data;
|
|
|
|
data += irCount;
|
|
|
|
datalen -= irCount;
|
2012-09-12 07:25:05 -07:00
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
if(delays[i] > maxDelay)
|
|
|
|
{
|
|
|
|
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
2016-02-16 19:56:44 -08:00
|
|
|
size_t total = sizeof(struct Hrtf);
|
|
|
|
total += sizeof(azCount[0])*evCount;
|
|
|
|
total += sizeof(evOffset[0])*evCount;
|
|
|
|
total += sizeof(coeffs[0])*irSize*irCount;
|
|
|
|
total += sizeof(delays[0])*irCount;
|
2016-02-20 05:32:42 -08:00
|
|
|
total += al_string_length(filename)+1;
|
2016-02-16 19:56:44 -08:00
|
|
|
|
2016-07-07 10:31:43 -07:00
|
|
|
Hrtf = al_calloc(16, total);
|
2012-09-12 07:25:05 -07:00
|
|
|
if(Hrtf == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
Hrtf->sampleRate = rate;
|
|
|
|
Hrtf->irSize = irSize;
|
|
|
|
Hrtf->evCount = evCount;
|
2016-02-16 19:56:44 -08:00
|
|
|
Hrtf->azCount = ((ALubyte*)(Hrtf+1));
|
|
|
|
Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount));
|
|
|
|
Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount));
|
|
|
|
Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount));
|
2016-02-20 05:32:42 -08:00
|
|
|
Hrtf->filename = ((char*)(Hrtf->delays + irCount));
|
2012-09-12 07:25:05 -07:00
|
|
|
Hrtf->next = NULL;
|
2016-02-16 19:56:44 -08:00
|
|
|
|
|
|
|
memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount);
|
|
|
|
memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount);
|
|
|
|
memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount);
|
|
|
|
memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount);
|
2016-02-20 05:32:42 -08:00
|
|
|
memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1);
|
2012-09-12 07:25:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
free(azCount);
|
|
|
|
free(evOffset);
|
|
|
|
free(coeffs);
|
2016-02-16 19:56:44 -08:00
|
|
|
return Hrtf;
|
2012-09-12 07:25:05 -07:00
|
|
|
}
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
static struct Hrtf *LoadHrtf01(const ALubyte *data, size_t datalen, const_al_string filename)
|
2012-09-12 07:25:05 -07:00
|
|
|
{
|
2014-11-22 04:20:17 -08:00
|
|
|
const ALubyte maxDelay = HRTF_HISTORY_LENGTH-1;
|
2012-09-12 07:25:05 -07:00
|
|
|
struct Hrtf *Hrtf = NULL;
|
|
|
|
ALboolean failed = AL_FALSE;
|
|
|
|
ALuint rate = 0, irCount = 0;
|
|
|
|
ALubyte irSize = 0, evCount = 0;
|
2016-08-31 08:16:49 -07:00
|
|
|
const ALubyte *azCount = NULL;
|
2012-09-12 07:25:05 -07:00
|
|
|
ALushort *evOffset = NULL;
|
|
|
|
ALshort *coeffs = NULL;
|
2016-08-31 08:16:49 -07:00
|
|
|
const ALubyte *delays = NULL;
|
2012-09-12 07:25:05 -07:00
|
|
|
ALuint i, j;
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
if(datalen < 6)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
|
|
|
|
al_string_get_cstr(filename), 6, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rate = *(data++);
|
|
|
|
rate |= *(data++)<<8;
|
|
|
|
rate |= *(data++)<<16;
|
|
|
|
rate |= *(data++)<<24;
|
|
|
|
datalen -= 4;
|
2012-09-12 07:25:05 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
irSize = *(data++);
|
|
|
|
datalen -= 1;
|
2012-09-12 07:25:05 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
evCount = *(data++);
|
|
|
|
datalen -= 1;
|
2012-09-12 07:25:05 -07: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 08:16:49 -07:00
|
|
|
if(datalen < evCount)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req %d, rem "SZFMT"\n",
|
|
|
|
al_string_get_cstr(filename), evCount, datalen);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
azCount = data;
|
|
|
|
data += evCount;
|
|
|
|
datalen -= evCount;
|
|
|
|
|
2012-09-12 07:25:05 -07: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);
|
2016-08-31 08:16:49 -07:00
|
|
|
if(coeffs == NULL)
|
2012-09-12 07:25:05 -07:00
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
size_t reqsize = 2*irSize*irCount + irCount;
|
|
|
|
if(datalen < reqsize)
|
|
|
|
{
|
|
|
|
ERR("Unexpected end of %s data (req "SZFMT", rem "SZFMT"\n",
|
|
|
|
al_string_get_cstr(filename), reqsize, datalen);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-12 07:25:05 -07:00
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
for(i = 0;i < irCount*irSize;i+=irSize)
|
|
|
|
{
|
|
|
|
for(j = 0;j < irSize;j++)
|
|
|
|
{
|
|
|
|
ALshort coeff;
|
2016-08-31 08:16:49 -07:00
|
|
|
coeff = *(data++);
|
|
|
|
coeff |= *(data++)<<8;
|
|
|
|
datalen -= 2;
|
2012-09-12 07:25:05 -07:00
|
|
|
coeffs[i+j] = coeff;
|
|
|
|
}
|
|
|
|
}
|
2016-08-31 08:16:49 -07:00
|
|
|
|
|
|
|
delays = data;
|
|
|
|
data += irCount;
|
|
|
|
datalen -= irCount;
|
2012-09-12 07:25:05 -07:00
|
|
|
for(i = 0;i < irCount;i++)
|
|
|
|
{
|
|
|
|
if(delays[i] > maxDelay)
|
|
|
|
{
|
|
|
|
ERR("Invalid delays[%d]: %d (%d)\n", i, delays[i], maxDelay);
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
2016-02-16 19:56:44 -08:00
|
|
|
size_t total = sizeof(struct Hrtf);
|
|
|
|
total += sizeof(azCount[0])*evCount;
|
|
|
|
total += sizeof(evOffset[0])*evCount;
|
|
|
|
total += sizeof(coeffs[0])*irSize*irCount;
|
|
|
|
total += sizeof(delays[0])*irCount;
|
2016-02-20 05:32:42 -08:00
|
|
|
total += al_string_length(filename)+1;
|
2016-02-16 19:56:44 -08:00
|
|
|
|
2016-07-07 10:31:43 -07:00
|
|
|
Hrtf = al_calloc(16, total);
|
2012-09-12 07:25:05 -07:00
|
|
|
if(Hrtf == NULL)
|
|
|
|
{
|
|
|
|
ERR("Out of memory.\n");
|
|
|
|
failed = AL_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!failed)
|
|
|
|
{
|
|
|
|
Hrtf->sampleRate = rate;
|
|
|
|
Hrtf->irSize = irSize;
|
|
|
|
Hrtf->evCount = evCount;
|
2016-02-16 19:56:44 -08:00
|
|
|
Hrtf->azCount = ((ALubyte*)(Hrtf+1));
|
|
|
|
Hrtf->evOffset = ((ALushort*)(Hrtf->azCount + evCount));
|
|
|
|
Hrtf->coeffs = ((ALshort*)(Hrtf->evOffset + evCount));
|
|
|
|
Hrtf->delays = ((ALubyte*)(Hrtf->coeffs + irSize*irCount));
|
2016-02-20 05:32:42 -08:00
|
|
|
Hrtf->filename = ((char*)(Hrtf->delays + irCount));
|
2012-09-12 07:25:05 -07:00
|
|
|
Hrtf->next = NULL;
|
2016-02-16 19:56:44 -08:00
|
|
|
|
|
|
|
memcpy((void*)Hrtf->azCount, azCount, sizeof(azCount[0])*evCount);
|
|
|
|
memcpy((void*)Hrtf->evOffset, evOffset, sizeof(evOffset[0])*evCount);
|
|
|
|
memcpy((void*)Hrtf->coeffs, coeffs, sizeof(coeffs[0])*irSize*irCount);
|
|
|
|
memcpy((void*)Hrtf->delays, delays, sizeof(delays[0])*irCount);
|
2016-02-20 05:32:42 -08:00
|
|
|
memcpy((void*)Hrtf->filename, al_string_get_cstr(filename), al_string_length(filename)+1);
|
2012-09-12 07:25:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
free(evOffset);
|
|
|
|
free(coeffs);
|
2016-02-16 19:56:44 -08:00
|
|
|
return Hrtf;
|
2012-09-12 07:25:05 -07:00
|
|
|
}
|
|
|
|
|
2015-10-06 00:23:11 -07:00
|
|
|
static void AddFileEntry(vector_HrtfEntry *list, al_string *filename)
|
|
|
|
{
|
2016-02-20 05:32:42 -08:00
|
|
|
HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL };
|
2016-02-21 04:46:14 -08:00
|
|
|
struct Hrtf *hrtf = NULL;
|
|
|
|
const HrtfEntry *iter;
|
2016-08-31 08:16:49 -07:00
|
|
|
struct FileMapping fmap;
|
2015-10-06 00:23:11 -07:00
|
|
|
const char *name;
|
2016-02-24 04:21:03 -08:00
|
|
|
const char *ext;
|
2015-10-06 04:01:53 -07:00
|
|
|
int i;
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2016-07-24 21:59:02 -07:00
|
|
|
#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0)
|
|
|
|
VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME);
|
|
|
|
if(iter != VECTOR_END(*list))
|
|
|
|
{
|
|
|
|
TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#undef MATCH_FNAME
|
|
|
|
|
2015-10-06 04:01:53 -07:00
|
|
|
entry.hrtf = LoadedHrtfs;
|
|
|
|
while(entry.hrtf)
|
|
|
|
{
|
2016-02-20 05:32:42 -08:00
|
|
|
if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0)
|
2016-02-21 04:46:14 -08:00
|
|
|
{
|
2016-07-24 21:59:02 -07:00
|
|
|
TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto skip_load;
|
2016-02-21 04:46:14 -08:00
|
|
|
}
|
2015-10-06 04:01:53 -07:00
|
|
|
entry.hrtf = entry.hrtf->next;
|
|
|
|
}
|
|
|
|
|
2016-02-21 04:46:14 -08:00
|
|
|
TRACE("Loading %s...\n", al_string_get_cstr(*filename));
|
2016-08-31 08:16:49 -07:00
|
|
|
fmap = MapFileToMem(al_string_get_cstr(*filename));
|
|
|
|
if(fmap.ptr == NULL)
|
2015-10-06 04:01:53 -07:00
|
|
|
{
|
2016-02-21 04:46:14 -08:00
|
|
|
ERR("Could not open %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto done;
|
|
|
|
}
|
2015-10-06 04:01:53 -07:00
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
if(fmap.len < sizeof(magicMarker01))
|
|
|
|
ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), fmap.len);
|
|
|
|
else if(memcmp(fmap.ptr, magicMarker01, sizeof(magicMarker01)) == 0)
|
2016-02-21 04:46:14 -08:00
|
|
|
{
|
2016-08-31 08:16:49 -07:00
|
|
|
TRACE("Detected data set format v1\n");
|
|
|
|
hrtf = LoadHrtf01((const ALubyte*)fmap.ptr+sizeof(magicMarker01),
|
|
|
|
fmap.len-sizeof(magicMarker01), *filename
|
|
|
|
);
|
2016-02-21 04:46:14 -08:00
|
|
|
}
|
2016-08-31 08:16:49 -07:00
|
|
|
else if(memcmp(fmap.ptr, magicMarker00, sizeof(magicMarker00)) == 0)
|
|
|
|
{
|
|
|
|
TRACE("Detected data set format v0\n");
|
|
|
|
hrtf = LoadHrtf00((const ALubyte*)fmap.ptr+sizeof(magicMarker00),
|
|
|
|
fmap.len-sizeof(magicMarker00), *filename
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), (const char*)fmap.ptr);
|
|
|
|
UnmapFileMem(&fmap);
|
2015-10-06 04:01:53 -07:00
|
|
|
|
2016-02-21 04:46:14 -08:00
|
|
|
if(!hrtf)
|
|
|
|
{
|
|
|
|
ERR("Failed to load %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto done;
|
2015-10-06 04:01:53 -07:00
|
|
|
}
|
|
|
|
|
2016-02-21 04:46:14 -08:00
|
|
|
hrtf->next = LoadedHrtfs;
|
|
|
|
LoadedHrtfs = hrtf;
|
|
|
|
TRACE("Loaded HRTF support for format: %s %uhz\n",
|
|
|
|
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
|
|
|
|
entry.hrtf = hrtf;
|
|
|
|
|
2016-07-24 21:59:02 -07:00
|
|
|
skip_load:
|
2015-10-06 04:01:53 -07:00
|
|
|
/* TODO: Get a human-readable name from the HRTF data (possibly coming in a
|
2015-10-06 00:23:11 -07:00
|
|
|
* format update). */
|
2016-09-01 21:05:24 -07:00
|
|
|
name = strrchr(al_string_get_cstr(*filename), '/');
|
|
|
|
if(!name) name = strrchr(al_string_get_cstr(*filename), '\\');
|
|
|
|
if(!name) name = al_string_get_cstr(*filename);
|
|
|
|
else ++name;
|
|
|
|
|
2016-02-24 04:21:03 -08:00
|
|
|
ext = strrchr(name, '.');
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2015-10-06 04:01:53 -07:00
|
|
|
i = 0;
|
2015-10-06 00:23:11 -07:00
|
|
|
do {
|
2016-02-24 04:21:03 -08:00
|
|
|
if(!ext)
|
|
|
|
al_string_copy_cstr(&entry.name, name);
|
|
|
|
else
|
2016-02-24 04:53:32 -08:00
|
|
|
al_string_copy_range(&entry.name, name, ext);
|
2015-10-06 00:23:11 -07:00
|
|
|
if(i != 0)
|
|
|
|
{
|
|
|
|
char str[64];
|
|
|
|
snprintf(str, sizeof(str), " #%d", i+1);
|
|
|
|
al_string_append_cstr(&entry.name, str);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
|
|
|
|
#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
|
2016-02-21 04:46:14 -08:00
|
|
|
VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME);
|
2015-10-06 00:23:11 -07:00
|
|
|
#undef MATCH_NAME
|
2016-04-15 12:22:54 -07:00
|
|
|
} while(iter != VECTOR_END(*list));
|
2015-10-06 00:23:11 -07:00
|
|
|
|
|
|
|
TRACE("Adding entry \"%s\" from file \"%s\"\n", al_string_get_cstr(entry.name),
|
2016-02-20 05:32:42 -08:00
|
|
|
al_string_get_cstr(*filename));
|
2015-10-06 00:23:11 -07:00
|
|
|
VECTOR_PUSH_BACK(*list, entry);
|
|
|
|
|
2016-02-21 04:46:14 -08:00
|
|
|
done:
|
2016-02-20 05:32:42 -08:00
|
|
|
al_string_deinit(filename);
|
2015-10-06 00:23:11 -07:00
|
|
|
}
|
|
|
|
|
2016-08-31 08:16:49 -07:00
|
|
|
/* Unfortunate that we have to duplicate AddFileEntry to take a memory buffer
|
|
|
|
* for input instead of opening the given filename.
|
2016-07-12 19:02:19 -07:00
|
|
|
*/
|
|
|
|
static void AddBuiltInEntry(vector_HrtfEntry *list, const ALubyte *data, size_t datalen, al_string *filename)
|
|
|
|
{
|
|
|
|
HrtfEntry entry = { AL_STRING_INIT_STATIC(), NULL };
|
|
|
|
struct Hrtf *hrtf = NULL;
|
|
|
|
const HrtfEntry *iter;
|
|
|
|
int i;
|
|
|
|
|
2016-07-24 21:59:02 -07:00
|
|
|
#define MATCH_FNAME(i) (al_string_cmp_cstr(*filename, (i)->hrtf->filename) == 0)
|
|
|
|
VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_FNAME);
|
|
|
|
if(iter != VECTOR_END(*list))
|
|
|
|
{
|
|
|
|
TRACE("Skipping duplicate file entry %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
#undef MATCH_FNAME
|
|
|
|
|
2016-07-12 19:02:19 -07:00
|
|
|
entry.hrtf = LoadedHrtfs;
|
|
|
|
while(entry.hrtf)
|
|
|
|
{
|
|
|
|
if(al_string_cmp_cstr(*filename, entry.hrtf->filename) == 0)
|
|
|
|
{
|
2016-07-24 21:59:02 -07:00
|
|
|
TRACE("Skipping load of already-loaded file %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto skip_load;
|
2016-07-12 19:02:19 -07:00
|
|
|
}
|
|
|
|
entry.hrtf = entry.hrtf->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("Loading %s...\n", al_string_get_cstr(*filename));
|
|
|
|
if(datalen < sizeof(magicMarker01))
|
|
|
|
{
|
|
|
|
ERR("%s data is too short ("SZFMT" bytes)\n", al_string_get_cstr(*filename), datalen);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(memcmp(data, magicMarker01, sizeof(magicMarker01)) == 0)
|
|
|
|
{
|
|
|
|
TRACE("Detected data set format v1\n");
|
2016-08-31 08:16:49 -07:00
|
|
|
hrtf = LoadHrtf01(data+sizeof(magicMarker01),
|
|
|
|
datalen-sizeof(magicMarker01), *filename
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else if(memcmp(data, magicMarker00, sizeof(magicMarker00)) == 0)
|
|
|
|
{
|
|
|
|
TRACE("Detected data set format v0\n");
|
|
|
|
hrtf = LoadHrtf00(data+sizeof(magicMarker00),
|
|
|
|
datalen-sizeof(magicMarker00), *filename
|
2016-07-12 19:02:19 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ERR("Invalid header in %s: \"%.8s\"\n", al_string_get_cstr(*filename), data);
|
|
|
|
|
|
|
|
if(!hrtf)
|
|
|
|
{
|
|
|
|
ERR("Failed to load %s\n", al_string_get_cstr(*filename));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
hrtf->next = LoadedHrtfs;
|
|
|
|
LoadedHrtfs = hrtf;
|
|
|
|
TRACE("Loaded HRTF support for format: %s %uhz\n",
|
|
|
|
DevFmtChannelsString(DevFmtStereo), hrtf->sampleRate);
|
|
|
|
entry.hrtf = hrtf;
|
|
|
|
|
2016-07-24 21:59:02 -07:00
|
|
|
skip_load:
|
2016-07-12 19:02:19 -07:00
|
|
|
i = 0;
|
|
|
|
do {
|
|
|
|
al_string_copy(&entry.name, *filename);
|
|
|
|
if(i != 0)
|
|
|
|
{
|
|
|
|
char str[64];
|
|
|
|
snprintf(str, sizeof(str), " #%d", i+1);
|
|
|
|
al_string_append_cstr(&entry.name, str);
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
|
|
|
|
#define MATCH_NAME(i) (al_string_cmp(entry.name, (i)->name) == 0)
|
|
|
|
VECTOR_FIND_IF(iter, const HrtfEntry, *list, MATCH_NAME);
|
|
|
|
#undef MATCH_NAME
|
|
|
|
} while(iter != VECTOR_END(*list));
|
|
|
|
|
|
|
|
TRACE("Adding built-in entry \"%s\"\n", al_string_get_cstr(entry.name));
|
|
|
|
VECTOR_PUSH_BACK(*list, entry);
|
|
|
|
|
|
|
|
done:
|
|
|
|
al_string_deinit(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef ALSOFT_EMBED_HRTF_DATA
|
|
|
|
#define IDR_DEFAULT_44100_MHR 0
|
|
|
|
#define IDR_DEFAULT_48000_MHR 1
|
|
|
|
|
|
|
|
static const ALubyte *GetResource(int UNUSED(name), size_t *size)
|
|
|
|
{
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
#include "hrtf_res.h"
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
static const ALubyte *GetResource(int name, size_t *size)
|
|
|
|
{
|
|
|
|
HMODULE handle;
|
|
|
|
HGLOBAL res;
|
|
|
|
HRSRC rc;
|
|
|
|
|
|
|
|
GetModuleHandleExW(
|
|
|
|
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
|
|
|
|
(LPCWSTR)GetResource, &handle
|
|
|
|
);
|
|
|
|
rc = FindResourceW(handle, MAKEINTRESOURCEW(name), MAKEINTRESOURCEW(MHRTYPE));
|
|
|
|
res = LoadResource(handle, rc);
|
|
|
|
|
|
|
|
*size = SizeofResource(handle, rc);
|
|
|
|
return LockResource(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
extern const ALubyte _binary_default_44100_mhr_start[] HIDDEN_DECL;
|
|
|
|
extern const ALubyte _binary_default_44100_mhr_end[] HIDDEN_DECL;
|
|
|
|
extern const ALubyte _binary_default_44100_mhr_size[] HIDDEN_DECL;
|
|
|
|
|
|
|
|
extern const ALubyte _binary_default_48000_mhr_start[] HIDDEN_DECL;
|
|
|
|
extern const ALubyte _binary_default_48000_mhr_end[] HIDDEN_DECL;
|
|
|
|
extern const ALubyte _binary_default_48000_mhr_size[] HIDDEN_DECL;
|
|
|
|
|
|
|
|
static const ALubyte *GetResource(int name, size_t *size)
|
|
|
|
{
|
|
|
|
if(name == IDR_DEFAULT_44100_MHR)
|
|
|
|
{
|
|
|
|
/* Make sure all symbols are referenced, to ensure the compiler won't
|
|
|
|
* ignore the declarations and lose the visibility attribute used to
|
|
|
|
* hide them (would be nice if ld or objcopy could automatically mark
|
|
|
|
* them as hidden when generating them, but apparently they can't).
|
|
|
|
*/
|
|
|
|
const void *volatile ptr =_binary_default_44100_mhr_size;
|
|
|
|
(void)ptr;
|
|
|
|
*size = _binary_default_44100_mhr_end - _binary_default_44100_mhr_start;
|
|
|
|
return _binary_default_44100_mhr_start;
|
|
|
|
}
|
|
|
|
if(name == IDR_DEFAULT_48000_MHR)
|
|
|
|
{
|
|
|
|
const void *volatile ptr =_binary_default_48000_mhr_size;
|
|
|
|
(void)ptr;
|
|
|
|
*size = _binary_default_48000_mhr_end - _binary_default_48000_mhr_start;
|
|
|
|
return _binary_default_48000_mhr_start;
|
|
|
|
}
|
|
|
|
*size = 0;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2015-10-06 00:23:11 -07:00
|
|
|
vector_HrtfEntry EnumerateHrtf(const_al_string devname)
|
|
|
|
{
|
|
|
|
vector_HrtfEntry list = VECTOR_INIT_STATIC();
|
2016-02-21 02:44:02 -08:00
|
|
|
const char *defaulthrtf = "";
|
2016-02-23 10:54:42 -08:00
|
|
|
const char *pathlist = "";
|
|
|
|
bool usedefaults = true;
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
if(ConfigValueStr(al_string_get_cstr(devname), NULL, "hrtf-paths", &pathlist))
|
2015-10-06 00:23:11 -07:00
|
|
|
{
|
2016-02-23 10:54:42 -08:00
|
|
|
while(pathlist && *pathlist)
|
2015-10-06 00:23:11 -07:00
|
|
|
{
|
|
|
|
const char *next, *end;
|
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
while(isspace(*pathlist) || *pathlist == ',')
|
|
|
|
pathlist++;
|
|
|
|
if(*pathlist == '\0')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
next = strchr(pathlist, ',');
|
|
|
|
if(next)
|
2015-10-06 00:23:11 -07:00
|
|
|
end = next++;
|
2016-02-23 10:54:42 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
end = pathlist + strlen(pathlist);
|
|
|
|
usedefaults = false;
|
|
|
|
}
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
while(end != pathlist && isspace(*(end-1)))
|
2015-10-06 00:23:11 -07:00
|
|
|
--end;
|
2016-02-23 10:54:42 -08:00
|
|
|
if(end != pathlist)
|
2015-10-06 00:23:11 -07:00
|
|
|
{
|
2016-02-23 10:54:42 -08:00
|
|
|
al_string pname = AL_STRING_INIT_STATIC();
|
2015-10-06 00:23:11 -07:00
|
|
|
vector_al_string flist;
|
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
al_string_append_range(&pname, pathlist, end);
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
flist = SearchDataFiles(".mhr", al_string_get_cstr(pname));
|
2015-10-06 00:23:11 -07:00
|
|
|
VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
|
|
|
|
VECTOR_DEINIT(flist);
|
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
al_string_deinit(&pname);
|
2015-10-06 00:23:11 -07:00
|
|
|
}
|
|
|
|
|
2016-02-23 10:54:42 -08:00
|
|
|
pathlist = next;
|
2015-10-06 00:23:11 -07:00
|
|
|
}
|
|
|
|
}
|
2016-02-23 10:54:42 -08:00
|
|
|
else if(ConfigValueExists(al_string_get_cstr(devname), NULL, "hrtf_tables"))
|
|
|
|
ERR("The hrtf_tables option is deprecated, please use hrtf-paths instead.\n");
|
|
|
|
|
|
|
|
if(usedefaults)
|
|
|
|
{
|
2016-07-12 19:02:19 -07:00
|
|
|
vector_al_string flist;
|
|
|
|
const ALubyte *rdata;
|
|
|
|
size_t rsize;
|
|
|
|
|
|
|
|
flist = SearchDataFiles(".mhr", "openal/hrtf");
|
2016-02-23 10:54:42 -08:00
|
|
|
VECTOR_FOR_EACH_PARAMS(al_string, flist, AddFileEntry, &list);
|
|
|
|
VECTOR_DEINIT(flist);
|
2016-07-12 19:02:19 -07:00
|
|
|
|
|
|
|
rdata = GetResource(IDR_DEFAULT_44100_MHR, &rsize);
|
|
|
|
if(rdata != NULL && rsize > 0)
|
|
|
|
{
|
|
|
|
al_string ename = AL_STRING_INIT_STATIC();
|
|
|
|
al_string_copy_cstr(&ename, "Built-In 44100hz");
|
|
|
|
AddBuiltInEntry(&list, rdata, rsize, &ename);
|
|
|
|
}
|
|
|
|
|
|
|
|
rdata = GetResource(IDR_DEFAULT_48000_MHR, &rsize);
|
|
|
|
if(rdata != NULL && rsize > 0)
|
|
|
|
{
|
|
|
|
al_string ename = AL_STRING_INIT_STATIC();
|
|
|
|
al_string_copy_cstr(&ename, "Built-In 48000hz");
|
|
|
|
AddBuiltInEntry(&list, rdata, rsize, &ename);
|
|
|
|
}
|
2016-02-23 10:54:42 -08:00
|
|
|
}
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2016-02-23 06:52:13 -08:00
|
|
|
if(VECTOR_SIZE(list) > 1 && ConfigValueStr(al_string_get_cstr(devname), NULL, "default-hrtf", &defaulthrtf))
|
2016-02-21 02:44:02 -08:00
|
|
|
{
|
|
|
|
const HrtfEntry *iter;
|
|
|
|
/* Find the preferred HRTF and move it to the front of the list. */
|
|
|
|
#define FIND_ENTRY(i) (al_string_cmp_cstr((i)->name, defaulthrtf) == 0)
|
|
|
|
VECTOR_FIND_IF(iter, const HrtfEntry, list, FIND_ENTRY);
|
2016-04-15 12:22:54 -07:00
|
|
|
if(iter != VECTOR_END(list) && iter != VECTOR_BEGIN(list))
|
2016-02-21 02:44:02 -08:00
|
|
|
{
|
|
|
|
HrtfEntry entry = *iter;
|
|
|
|
memmove(&VECTOR_ELEM(list,1), &VECTOR_ELEM(list,0),
|
2016-04-15 12:22:54 -07:00
|
|
|
(iter-VECTOR_BEGIN(list))*sizeof(HrtfEntry));
|
2016-02-21 02:44:02 -08:00
|
|
|
VECTOR_ELEM(list,0) = entry;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
WARN("Failed to find default HRTF \"%s\"\n", defaulthrtf);
|
|
|
|
#undef FIND_ENTRY
|
|
|
|
}
|
|
|
|
|
2015-10-06 00:23:11 -07:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
2015-10-06 04:01:53 -07:00
|
|
|
void FreeHrtfList(vector_HrtfEntry *list)
|
|
|
|
{
|
|
|
|
#define CLEAR_ENTRY(i) do { \
|
|
|
|
al_string_deinit(&(i)->name); \
|
|
|
|
} while(0)
|
|
|
|
VECTOR_FOR_EACH(HrtfEntry, *list, CLEAR_ENTRY);
|
|
|
|
VECTOR_DEINIT(*list);
|
|
|
|
#undef CLEAR_ENTRY
|
|
|
|
}
|
|
|
|
|
2015-10-06 00:23:11 -07:00
|
|
|
|
2012-09-11 01:59:42 -07:00
|
|
|
void FreeHrtfs(void)
|
|
|
|
{
|
2016-02-16 19:56:44 -08:00
|
|
|
struct Hrtf *Hrtf = LoadedHrtfs;
|
|
|
|
LoadedHrtfs = NULL;
|
2012-09-11 01:59:42 -07:00
|
|
|
|
2016-02-16 19:56:44 -08:00
|
|
|
while(Hrtf != NULL)
|
2012-09-11 01:59:42 -07:00
|
|
|
{
|
2016-02-16 19:56:44 -08:00
|
|
|
struct Hrtf *next = Hrtf->next;
|
2016-07-07 10:31:43 -07:00
|
|
|
al_free(Hrtf);
|
2016-02-16 19:56:44 -08:00
|
|
|
Hrtf = next;
|
2011-06-03 01:06:00 -07:00
|
|
|
}
|
2011-09-18 10:09:32 -07:00
|
|
|
}
|