2010-08-03 07:21:36 +00:00
|
|
|
/**
|
|
|
|
* OpenAL cross platform audio library
|
|
|
|
* Copyright (C) 1999-2010 by authors.
|
|
|
|
* 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.
|
2010-08-03 07:21:36 +00:00
|
|
|
* Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "alMain.h"
|
2016-01-28 08:02:46 +00:00
|
|
|
#include "alAuxEffectSlot.h"
|
2010-08-03 07:21:36 +00:00
|
|
|
#include "alu.h"
|
2014-11-11 01:53:42 +00:00
|
|
|
#include "bool.h"
|
2016-03-15 12:08:05 +00:00
|
|
|
#include "ambdec.h"
|
|
|
|
#include "bformatdec.h"
|
2016-04-14 22:25:12 +00:00
|
|
|
#include "uhjfilter.h"
|
|
|
|
#include "bs2b.h"
|
2010-08-03 07:21:36 +00:00
|
|
|
|
|
|
|
|
2016-04-25 04:42:59 +00:00
|
|
|
extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
|
2016-01-25 14:11:51 +00:00
|
|
|
|
|
|
|
|
2015-08-18 14:44:17 +00:00
|
|
|
#define ZERO_ORDER_SCALE 0.0f
|
|
|
|
#define FIRST_ORDER_SCALE 1.0f
|
|
|
|
#define SECOND_ORDER_SCALE (1.0f / 1.22474f)
|
|
|
|
#define THIRD_ORDER_SCALE (1.0f / 1.30657f)
|
|
|
|
|
2015-08-22 14:23:43 +00:00
|
|
|
|
2017-01-16 15:45:07 +00:00
|
|
|
static const ALsizei FuMa2ACN[MAX_AMBI_COEFFS] = {
|
2015-08-28 17:58:30 +00:00
|
|
|
0, /* W */
|
|
|
|
3, /* X */
|
|
|
|
1, /* Y */
|
|
|
|
2, /* Z */
|
|
|
|
6, /* R */
|
|
|
|
7, /* S */
|
|
|
|
5, /* T */
|
|
|
|
8, /* U */
|
|
|
|
4, /* V */
|
|
|
|
12, /* K */
|
|
|
|
13, /* L */
|
|
|
|
11, /* M */
|
|
|
|
14, /* N */
|
|
|
|
10, /* O */
|
|
|
|
15, /* P */
|
|
|
|
9, /* Q */
|
|
|
|
};
|
2017-01-16 15:45:07 +00:00
|
|
|
static const ALsizei ACN2ACN[MAX_AMBI_COEFFS] = {
|
2016-07-31 14:46:38 +00:00
|
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
|
|
8, 9, 10, 11, 12, 13, 14, 15
|
|
|
|
};
|
2015-08-28 17:58:30 +00:00
|
|
|
|
2016-03-15 15:00:03 +00:00
|
|
|
/* NOTE: These are scale factors as applied to Ambisonics content. Decoder
|
|
|
|
* coefficients should be divided by these values to get proper N3D scalings.
|
2015-09-23 22:03:53 +00:00
|
|
|
*/
|
2016-03-15 15:00:03 +00:00
|
|
|
static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
|
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
|
|
|
|
1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
|
|
|
|
};
|
|
|
|
static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
|
|
|
|
1.000000000f, /* ACN 0 (W), sqrt(1) */
|
|
|
|
1.732050808f, /* ACN 1 (Y), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 2 (Z), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 3 (X), sqrt(3) */
|
|
|
|
2.236067978f, /* ACN 4 (V), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 5 (T), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 6 (R), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 7 (S), sqrt(5) */
|
|
|
|
2.236067978f, /* ACN 8 (U), sqrt(5) */
|
|
|
|
2.645751311f, /* ACN 9 (Q), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 10 (O), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 11 (M), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 12 (K), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 13 (L), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 14 (N), sqrt(7) */
|
|
|
|
2.645751311f, /* ACN 15 (P), sqrt(7) */
|
|
|
|
};
|
2015-09-23 22:03:53 +00:00
|
|
|
static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
|
2015-11-06 18:27:28 +00:00
|
|
|
1.414213562f, /* ACN 0 (W), sqrt(2) */
|
|
|
|
1.732050808f, /* ACN 1 (Y), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 2 (Z), sqrt(3) */
|
|
|
|
1.732050808f, /* ACN 3 (X), sqrt(3) */
|
|
|
|
1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
|
|
|
|
1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
|
|
|
|
2.236067978f, /* ACN 6 (R), sqrt(5) */
|
|
|
|
1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
|
|
|
|
1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
|
|
|
|
2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
|
|
|
|
1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
|
|
|
|
2.231093404f, /* ACN 11 (M), sqrt(224/45) */
|
|
|
|
2.645751311f, /* ACN 12 (K), sqrt(7) */
|
|
|
|
2.231093404f, /* ACN 13 (L), sqrt(224/45) */
|
|
|
|
1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
|
|
|
|
2.091650066f, /* ACN 15 (P), sqrt(35/8) */
|
2015-08-28 17:58:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-04-25 04:42:59 +00:00
|
|
|
void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 14:33:13 +00:00
|
|
|
{
|
|
|
|
/* Convert from OpenAL coords to Ambisonics. */
|
2014-10-03 03:25:30 +00:00
|
|
|
ALfloat x = -dir[2];
|
|
|
|
ALfloat y = -dir[0];
|
|
|
|
ALfloat z = dir[1];
|
|
|
|
|
2015-08-28 17:58:30 +00:00
|
|
|
/* Zeroth-order */
|
2015-09-23 22:03:53 +00:00
|
|
|
coeffs[0] = 1.0f; /* ACN 0 = 1 */
|
2015-08-28 17:58:30 +00:00
|
|
|
/* First-order */
|
2015-11-06 18:27:28 +00:00
|
|
|
coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */
|
|
|
|
coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */
|
|
|
|
coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */
|
2015-08-28 17:58:30 +00:00
|
|
|
/* Second-order */
|
2015-11-06 18:27:28 +00:00
|
|
|
coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */
|
|
|
|
coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */
|
|
|
|
coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
|
|
|
|
coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */
|
|
|
|
coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
|
2015-08-28 17:58:30 +00:00
|
|
|
/* Third-order */
|
2015-11-06 18:27:28 +00:00
|
|
|
coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
|
|
|
|
coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */
|
|
|
|
coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
|
|
|
|
coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
|
|
|
|
coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
|
|
|
|
coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
|
|
|
|
coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
|
2016-04-25 04:42:59 +00:00
|
|
|
|
|
|
|
if(spread > 0.0f)
|
|
|
|
{
|
|
|
|
/* Implement the spread by using a spherical source that subtends the
|
|
|
|
* angle spread. See:
|
|
|
|
* http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3
|
|
|
|
*
|
2016-07-11 05:00:27 +00:00
|
|
|
* When adjusted for N3D normalization instead of SN3D, these
|
|
|
|
* calculations are:
|
|
|
|
*
|
|
|
|
* ZH0 = -sqrt(pi) * (-1+ca);
|
|
|
|
* ZH1 = 0.5*sqrt(pi) * sa*sa;
|
|
|
|
* ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1);
|
|
|
|
* ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1);
|
|
|
|
* ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3);
|
|
|
|
* ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1);
|
2016-04-25 04:42:59 +00:00
|
|
|
*
|
2016-07-11 05:00:27 +00:00
|
|
|
* The gain of the source is compensated for size, so that the
|
|
|
|
* loundness doesn't depend on the spread. That is, the factors are
|
|
|
|
* scaled so that ZH0 remains 1 regardless of the spread. Thus:
|
2016-04-25 04:42:59 +00:00
|
|
|
*
|
2016-07-11 05:00:27 +00:00
|
|
|
* ZH0 = 1.0f;
|
|
|
|
* ZH1 = 0.5f * (ca+1.0f);
|
|
|
|
* ZH2 = 0.5f * (ca+1.0f)*ca;
|
|
|
|
* ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f);
|
|
|
|
* ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca;
|
|
|
|
* ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f);
|
2016-04-25 04:42:59 +00:00
|
|
|
*/
|
|
|
|
ALfloat ca = cosf(spread * 0.5f);
|
|
|
|
|
|
|
|
ALfloat ZH0_norm = 1.0f;
|
|
|
|
ALfloat ZH1_norm = 0.5f * (ca+1.f);
|
|
|
|
ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca;
|
|
|
|
ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f);
|
|
|
|
|
|
|
|
/* Zeroth-order */
|
|
|
|
coeffs[0] *= ZH0_norm;
|
|
|
|
/* First-order */
|
|
|
|
coeffs[1] *= ZH1_norm;
|
|
|
|
coeffs[2] *= ZH1_norm;
|
|
|
|
coeffs[3] *= ZH1_norm;
|
|
|
|
/* Second-order */
|
|
|
|
coeffs[4] *= ZH2_norm;
|
|
|
|
coeffs[5] *= ZH2_norm;
|
|
|
|
coeffs[6] *= ZH2_norm;
|
|
|
|
coeffs[7] *= ZH2_norm;
|
|
|
|
coeffs[8] *= ZH2_norm;
|
|
|
|
/* Third-order */
|
|
|
|
coeffs[9] *= ZH3_norm;
|
|
|
|
coeffs[10] *= ZH3_norm;
|
|
|
|
coeffs[11] *= ZH3_norm;
|
|
|
|
coeffs[12] *= ZH3_norm;
|
|
|
|
coeffs[13] *= ZH3_norm;
|
|
|
|
coeffs[14] *= ZH3_norm;
|
|
|
|
coeffs[15] *= ZH3_norm;
|
|
|
|
}
|
2016-01-25 14:11:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-25 04:42:59 +00:00
|
|
|
void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
|
2016-01-25 14:11:51 +00:00
|
|
|
{
|
|
|
|
ALfloat dir[3] = {
|
2016-04-16 01:14:19 +00:00
|
|
|
sinf(azimuth) * cosf(elevation),
|
2016-01-25 14:11:51 +00:00
|
|
|
sinf(elevation),
|
2016-04-16 01:14:19 +00:00
|
|
|
-cosf(azimuth) * cosf(elevation)
|
2016-01-25 14:11:51 +00:00
|
|
|
};
|
2016-04-25 04:42:59 +00:00
|
|
|
CalcDirectionCoeffs(dir, spread, coeffs);
|
2016-01-25 14:11:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2016-01-25 14:11:51 +00:00
|
|
|
{
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i;
|
2016-01-25 14:11:51 +00:00
|
|
|
|
|
|
|
for(i = 0;i < numchans;i++)
|
|
|
|
{
|
|
|
|
// The W coefficients are based on a mathematical average of the
|
|
|
|
// output. The square root of the base average provides for a more
|
|
|
|
// perceptual average volume, better suited to non-directional gains.
|
|
|
|
gains[i] = sqrtf(chancoeffs[i][0]) * ingain;
|
|
|
|
}
|
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2016-04-16 05:05:47 +00:00
|
|
|
{
|
|
|
|
ALfloat gain = 0.0f;
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i;
|
2016-04-16 05:05:47 +00:00
|
|
|
|
|
|
|
for(i = 0;i < numchans;i++)
|
|
|
|
{
|
|
|
|
if(chanmap[i].Index == 0)
|
|
|
|
gain += chanmap[i].Scale;
|
|
|
|
}
|
|
|
|
gains[0] = gain * 1.414213562f * ingain;
|
|
|
|
for(i = 1;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, ALsizei numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2016-01-25 14:11:51 +00:00
|
|
|
{
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i, j;
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 14:33:13 +00:00
|
|
|
|
2016-01-25 14:11:51 +00:00
|
|
|
for(i = 0;i < numchans;i++)
|
Use an ambisonics-based panning method
For mono sources, third-order ambisonics is utilized to generate panning gains.
The general idea is that a panned mono sound can be encoded into b-format
ambisonics as:
w[i] = sample[i] * 0.7071;
x[i] = sample[i] * dir[0];
y[i] = sample[i] * dir[1];
...
and subsequently rendered using:
output[chan][i] = w[i] * w_coeffs[chan] +
x[i] * x_coeffs[chan] +
y[i] * y_coeffs[chan] +
...;
By reordering the math, channel gains can be generated by doing:
gain[chan] = 0.7071 * w_coeffs[chan] +
dir[0] * x_coeffs[chan] +
dir[1] * y_coeffs[chan] +
...;
which then get applied as normal:
output[chan][i] = sample[i] * gain[chan];
One of the reasons to use ambisonics for panning is that it provides arguably
better reproduction for sounds emanating from between two speakers. As well,
this makes it easier to pan in all 3 dimensions, with for instance a "3D7.1" or
8-channel cube speaker configuration by simply providing the necessary
coefficients (this will need some work since some methods still use angle-based
panpot, particularly multi-channel sources).
Unfortunately, the math to reliably generate the coefficients for a given
speaker configuration is too costly to do at run-time. They have to be pre-
generated based on a pre-specified speaker arangement, which means the config
options for tweaking speaker angles are no longer supportable. Eventually I
hope to provide config options for custom coefficients, which can either be
generated and written in manually, or via alsoft-config from user-specified
speaker positions.
The current default set of coefficients were generated using the MATLAB scripts
(compatible with GNU Octave) from the excellent Ambisonic Decoder Toolbox, at
https://bitbucket.org/ambidecodertoolbox/adt/
2014-09-30 14:33:13 +00:00
|
|
|
{
|
2015-08-22 14:23:43 +00:00
|
|
|
float gain = 0.0f;
|
2016-04-16 00:31:04 +00:00
|
|
|
for(j = 0;j < numcoeffs;j++)
|
2016-01-25 14:11:51 +00:00
|
|
|
gain += chancoeffs[i][j]*coeffs[j];
|
2015-08-22 14:23:43 +00:00
|
|
|
gains[i] = gain * ingain;
|
2014-11-15 12:11:22 +00:00
|
|
|
}
|
2015-09-24 19:36:02 +00:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
2014-11-04 11:33:35 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2016-04-15 04:50:36 +00:00
|
|
|
{
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i;
|
2016-04-15 04:50:36 +00:00
|
|
|
|
|
|
|
for(i = 0;i < numchans;i++)
|
|
|
|
gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain;
|
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2014-11-01 00:18:45 +00:00
|
|
|
{
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i, j;
|
2014-11-01 00:18:45 +00:00
|
|
|
|
2016-01-25 14:11:51 +00:00
|
|
|
for(i = 0;i < numchans;i++)
|
2014-11-01 00:18:45 +00:00
|
|
|
{
|
2015-09-24 19:36:02 +00:00
|
|
|
float gain = 0.0f;
|
2015-08-28 17:58:30 +00:00
|
|
|
for(j = 0;j < 4;j++)
|
2016-01-25 14:11:51 +00:00
|
|
|
gain += chancoeffs[i][j] * mtx[j];
|
2015-09-24 19:36:02 +00:00
|
|
|
gains[i] = gain * ingain;
|
2014-11-01 00:18:45 +00:00
|
|
|
}
|
2015-09-24 19:36:02 +00:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
2014-11-01 00:18:45 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 15:13:23 +00:00
|
|
|
void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALsizei numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2016-04-15 04:50:36 +00:00
|
|
|
{
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i;
|
2016-04-15 04:50:36 +00:00
|
|
|
|
|
|
|
for(i = 0;i < numchans;i++)
|
|
|
|
gains[i] = chanmap[i].Scale * mtx[chanmap[i].Index] * ingain;
|
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
|
|
|
}
|
|
|
|
|
2012-04-29 12:04:46 +00:00
|
|
|
|
2016-09-06 16:09:25 +00:00
|
|
|
static inline const char *GetLabelFromChannel(enum Channel channel)
|
2014-11-15 08:19:56 +00:00
|
|
|
{
|
|
|
|
switch(channel)
|
|
|
|
{
|
|
|
|
case FrontLeft: return "front-left";
|
|
|
|
case FrontRight: return "front-right";
|
|
|
|
case FrontCenter: return "front-center";
|
|
|
|
case LFE: return "lfe";
|
|
|
|
case BackLeft: return "back-left";
|
|
|
|
case BackRight: return "back-right";
|
|
|
|
case BackCenter: return "back-center";
|
|
|
|
case SideLeft: return "side-left";
|
|
|
|
case SideRight: return "side-right";
|
2014-11-22 12:20:17 +00:00
|
|
|
|
2016-02-20 08:53:01 +00:00
|
|
|
case UpperFrontLeft: return "upper-front-left";
|
|
|
|
case UpperFrontRight: return "upper-front-right";
|
|
|
|
case UpperBackLeft: return "upper-back-left";
|
|
|
|
case UpperBackRight: return "upper-back-right";
|
|
|
|
case LowerFrontLeft: return "lower-front-left";
|
|
|
|
case LowerFrontRight: return "lower-front-right";
|
|
|
|
case LowerBackLeft: return "lower-back-left";
|
|
|
|
case LowerBackRight: return "lower-back-right";
|
|
|
|
|
2016-03-16 13:49:35 +00:00
|
|
|
case Aux0: return "aux-0";
|
|
|
|
case Aux1: return "aux-1";
|
|
|
|
case Aux2: return "aux-2";
|
|
|
|
case Aux3: return "aux-3";
|
2016-03-23 17:39:14 +00:00
|
|
|
case Aux4: return "aux-4";
|
|
|
|
case Aux5: return "aux-5";
|
|
|
|
case Aux6: return "aux-6";
|
|
|
|
case Aux7: return "aux-7";
|
|
|
|
case Aux8: return "aux-8";
|
2016-04-20 01:58:19 +00:00
|
|
|
case Aux9: return "aux-9";
|
|
|
|
case Aux10: return "aux-10";
|
|
|
|
case Aux11: return "aux-11";
|
|
|
|
case Aux12: return "aux-12";
|
|
|
|
case Aux13: return "aux-13";
|
|
|
|
case Aux14: return "aux-14";
|
|
|
|
case Aux15: return "aux-15";
|
2014-11-26 06:20:00 +00:00
|
|
|
|
2014-11-15 08:19:56 +00:00
|
|
|
case InvalidChannel: break;
|
|
|
|
}
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-05 11:46:00 +00:00
|
|
|
typedef struct ChannelMap {
|
|
|
|
enum Channel ChanName;
|
|
|
|
ChannelConfig Config;
|
|
|
|
} ChannelMap;
|
|
|
|
|
2016-01-27 12:44:21 +00:00
|
|
|
static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs,
|
2017-01-21 19:05:05 +00:00
|
|
|
const ChannelMap *chanmap, size_t count, ALsizei *outcount)
|
2014-11-13 03:26:53 +00:00
|
|
|
{
|
2015-11-06 10:21:24 +00:00
|
|
|
size_t j, k;
|
2017-01-18 15:13:23 +00:00
|
|
|
ALsizei i;
|
2014-11-13 03:26:53 +00:00
|
|
|
|
2016-01-27 12:44:21 +00:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++)
|
2014-11-13 03:26:53 +00:00
|
|
|
{
|
2016-01-27 12:44:21 +00:00
|
|
|
if(devchans[i] == LFE)
|
2014-11-13 03:26:53 +00:00
|
|
|
{
|
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
2016-01-27 12:44:21 +00:00
|
|
|
ambicoeffs[i][j] = 0.0f;
|
2014-11-13 03:26:53 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(j = 0;j < count;j++)
|
|
|
|
{
|
2016-01-27 12:44:21 +00:00
|
|
|
if(devchans[i] != chanmap[j].ChanName)
|
|
|
|
continue;
|
|
|
|
|
2016-08-02 16:16:12 +00:00
|
|
|
for(k = 0;k < MAX_AMBI_COEFFS;++k)
|
2017-01-21 19:05:05 +00:00
|
|
|
ambicoeffs[i][k] = chanmap[j].Config[k];
|
2016-01-27 12:44:21 +00:00
|
|
|
break;
|
2014-11-13 03:26:53 +00:00
|
|
|
}
|
|
|
|
if(j == count)
|
2016-01-27 12:44:21 +00:00
|
|
|
ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans[i]), i);
|
2014-11-13 03:26:53 +00:00
|
|
|
}
|
2016-01-27 12:44:21 +00:00
|
|
|
*outcount = i;
|
2014-11-13 03:26:53 +00:00
|
|
|
}
|
|
|
|
|
2016-03-15 12:08:05 +00:00
|
|
|
static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS])
|
|
|
|
{
|
2017-01-16 17:37:55 +00:00
|
|
|
ALsizei i;
|
2016-03-15 12:08:05 +00:00
|
|
|
|
|
|
|
for(i = 0;i < conf->NumSpeakers;i++)
|
|
|
|
{
|
|
|
|
int c = -1;
|
|
|
|
|
|
|
|
/* NOTE: AmbDec does not define any standard speaker names, however
|
|
|
|
* for this to work we have to by able to find the output channel
|
|
|
|
* the speaker definition corresponds to. Therefore, OpenAL Soft
|
|
|
|
* requires these channel labels to be recognized:
|
|
|
|
*
|
|
|
|
* LF = Front left
|
|
|
|
* RF = Front right
|
|
|
|
* LS = Side left
|
|
|
|
* RS = Side right
|
|
|
|
* LB = Back left
|
|
|
|
* RB = Back right
|
|
|
|
* CE = Front center
|
|
|
|
* CB = Back center
|
|
|
|
*
|
|
|
|
* Additionally, surround51 will acknowledge back speakers for side
|
|
|
|
* channels, and surround51rear will acknowledge side speakers for
|
|
|
|
* back channels, to avoid issues with an ambdec expecting 5.1 to
|
|
|
|
* use the side channels when the device is configured for back,
|
|
|
|
* and vice-versa.
|
|
|
|
*/
|
|
|
|
if(al_string_cmp_cstr(conf->Speakers[i].Name, "LF") == 0)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, FrontLeft);
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RF") == 0)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, FrontRight);
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CE") == 0)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, FrontCenter);
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LS") == 0)
|
|
|
|
{
|
|
|
|
if(device->FmtChans == DevFmtX51Rear)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, BackLeft);
|
|
|
|
else
|
|
|
|
c = GetChannelIdxByName(device->RealOut, SideLeft);
|
|
|
|
}
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RS") == 0)
|
|
|
|
{
|
|
|
|
if(device->FmtChans == DevFmtX51Rear)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, BackRight);
|
|
|
|
else
|
|
|
|
c = GetChannelIdxByName(device->RealOut, SideRight);
|
|
|
|
}
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LB") == 0)
|
|
|
|
{
|
|
|
|
if(device->FmtChans == DevFmtX51)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, SideLeft);
|
|
|
|
else
|
|
|
|
c = GetChannelIdxByName(device->RealOut, BackLeft);
|
|
|
|
}
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RB") == 0)
|
|
|
|
{
|
|
|
|
if(device->FmtChans == DevFmtX51)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, SideRight);
|
|
|
|
else
|
|
|
|
c = GetChannelIdxByName(device->RealOut, BackRight);
|
|
|
|
}
|
|
|
|
else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CB") == 0)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, BackCenter);
|
|
|
|
else
|
|
|
|
{
|
2016-05-13 06:41:23 +00:00
|
|
|
const char *name = al_string_get_cstr(conf->Speakers[i].Name);
|
|
|
|
unsigned int n;
|
|
|
|
char ch;
|
|
|
|
|
|
|
|
if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16)
|
|
|
|
c = GetChannelIdxByName(device->RealOut, Aux0+n);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("AmbDec speaker label \"%s\" not recognized\n", name);
|
|
|
|
return false;
|
|
|
|
}
|
2016-03-15 12:08:05 +00:00
|
|
|
}
|
|
|
|
if(c == -1)
|
|
|
|
{
|
|
|
|
ERR("Failed to lookup AmbDec speaker label %s\n",
|
|
|
|
al_string_get_cstr(conf->Speakers[i].Name));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
speakermap[i] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2016-04-14 17:44:57 +00:00
|
|
|
|
|
|
|
static const ChannelMap MonoCfg[1] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ FrontCenter, { 1.0f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
}, StereoCfg[2] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ FrontLeft, { 5.00000000e-1f, 2.88675135e-1f, 0.0f, 0.0f } },
|
|
|
|
{ FrontRight, { 5.00000000e-1f, -2.88675135e-1f, 0.0f, 0.0f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
}, QuadCfg[4] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ BackLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, -2.04124145e-1f } },
|
|
|
|
{ FrontLeft, { 3.53553391e-1f, 2.04124145e-1f, 0.0f, 2.04124145e-1f } },
|
|
|
|
{ FrontRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, 2.04124145e-1f } },
|
|
|
|
{ BackRight, { 3.53553391e-1f, -2.04124145e-1f, 0.0f, -2.04124145e-1f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
}, X51SideCfg[5] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ SideLeft, { 3.33001372e-1f, 1.89085671e-1f, 0.0f, -2.00041334e-1f, -2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } },
|
|
|
|
{ FrontLeft, { 1.47751298e-1f, 1.28994110e-1f, 0.0f, 1.15190495e-1f, 7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } },
|
|
|
|
{ FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } },
|
|
|
|
{ FrontRight, { 1.47751298e-1f, -1.28994110e-1f, 0.0f, 1.15190495e-1f, -7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } },
|
|
|
|
{ SideRight, { 3.33001372e-1f, -1.89085671e-1f, 0.0f, -2.00041334e-1f, 2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
}, X51RearCfg[5] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ BackLeft, { 3.33001372e-1f, 1.89085671e-1f, 0.0f, -2.00041334e-1f, -2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } },
|
|
|
|
{ FrontLeft, { 1.47751298e-1f, 1.28994110e-1f, 0.0f, 1.15190495e-1f, 7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } },
|
|
|
|
{ FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } },
|
|
|
|
{ FrontRight, { 1.47751298e-1f, -1.28994110e-1f, 0.0f, 1.15190495e-1f, -7.44949143e-2f, 0.0f, 0.0f, 0.0f, -6.47739980e-3f } },
|
|
|
|
{ BackRight, { 3.33001372e-1f, -1.89085671e-1f, 0.0f, -2.00041334e-1f, 2.12309737e-2f, 0.0f, 0.0f, 0.0f, -1.14573483e-2f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
}, X61Cfg[6] = {
|
2017-01-21 19:05:05 +00:00
|
|
|
{ SideLeft, { 2.04462744e-1f, 2.17178497e-1f, 0.0f, -4.39990188e-2f, -2.60787329e-2f, 0.0f, 0.0f, 0.0f, -6.87238843e-2f } },
|
|
|
|
{ FrontLeft, { 1.18130342e-1f, 9.34633906e-2f, 0.0f, 1.08553749e-1f, 6.80658795e-2f, 0.0f, 0.0f, 0.0f, 1.08999485e-2f } },
|
|
|
|
{ FrontCenter, { 7.73595729e-2f, 0.00000000e+0f, 0.0f, 9.71390298e-2f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 5.18625335e-2f } },
|
|
|
|
{ FrontRight, { 1.18130342e-1f, -9.34633906e-2f, 0.0f, 1.08553749e-1f, -6.80658795e-2f, 0.0f, 0.0f, 0.0f, 1.08999485e-2f } },
|
|
|
|
{ SideRight, { 2.04462744e-1f, -2.17178497e-1f, 0.0f, -4.39990188e-2f, 2.60787329e-2f, 0.0f, 0.0f, 0.0f, -6.87238843e-2f } },
|
|
|
|
{ BackCenter, { 2.50001688e-1f, 0.00000000e+0f, 0.0f, -2.50000094e-1f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, 6.05133395e-2f } },
|
|
|
|
}, X71Cfg[6] = {
|
|
|
|
{ BackLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, -1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
|
|
|
{ SideLeft, { 2.04124145e-1f, 2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
|
|
|
{ FrontLeft, { 2.04124145e-1f, 1.08880247e-1f, 0.0f, 1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
|
|
|
{ FrontRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, 1.88586120e-1f, -1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
|
|
|
{ SideRight, { 2.04124145e-1f, -2.17760495e-1f, 0.0f, 0.00000000e+0f, 0.00000000e+0f, 0.0f, 0.0f, 0.0f, -1.49071198e-1f, 3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
|
|
|
{ BackRight, { 2.04124145e-1f, -1.08880247e-1f, 0.0f, -1.88586120e-1f, 1.29099444e-1f, 0.0f, 0.0f, 0.0f, 7.45355993e-2f, -3.73460789e-2f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.00000000e+0f } },
|
2016-04-14 17:44:57 +00:00
|
|
|
};
|
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
static void InitPanning(ALCdevice *device)
|
2016-04-14 17:44:57 +00:00
|
|
|
{
|
|
|
|
const ChannelMap *chanmap = NULL;
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei coeffcount = 0;
|
2016-04-14 17:44:57 +00:00
|
|
|
ALfloat ambiscale;
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei count = 0;
|
|
|
|
ALsizei i, j;
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2016-03-26 06:25:13 +00:00
|
|
|
ambiscale = 1.0f;
|
2014-09-11 00:53:01 +00:00
|
|
|
switch(device->FmtChans)
|
2010-08-03 07:21:36 +00:00
|
|
|
{
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtMono:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(MonoCfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = MonoCfg;
|
2015-08-18 14:44:17 +00:00
|
|
|
ambiscale = ZERO_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 1;
|
2010-08-03 07:21:36 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtStereo:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(StereoCfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = StereoCfg;
|
2015-08-18 14:44:17 +00:00
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 4;
|
2010-08-03 07:21:36 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtQuad:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(QuadCfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = QuadCfg;
|
2017-01-21 19:05:05 +00:00
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 9;
|
2010-08-03 07:21:36 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtX51:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(X51SideCfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = X51SideCfg;
|
2016-03-13 10:32:32 +00:00
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 9;
|
2011-05-29 02:35:32 +00:00
|
|
|
break;
|
|
|
|
|
2014-11-07 08:54:16 +00:00
|
|
|
case DevFmtX51Rear:
|
|
|
|
count = COUNTOF(X51RearCfg);
|
|
|
|
chanmap = X51RearCfg;
|
2016-03-13 10:32:32 +00:00
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 9;
|
2014-11-07 08:54:16 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtX61:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(X61Cfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = X61Cfg;
|
2017-01-21 19:05:05 +00:00
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 16;
|
2010-08-03 07:21:36 +00:00
|
|
|
break;
|
|
|
|
|
2010-12-05 03:50:00 +00:00
|
|
|
case DevFmtX71:
|
2014-11-05 10:54:11 +00:00
|
|
|
count = COUNTOF(X71Cfg);
|
2014-11-05 11:46:00 +00:00
|
|
|
chanmap = X71Cfg;
|
2015-08-18 14:44:17 +00:00
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
2016-04-16 00:31:04 +00:00
|
|
|
coeffcount = 16;
|
2010-08-03 07:21:36 +00:00
|
|
|
break;
|
2014-11-26 06:20:00 +00:00
|
|
|
|
2016-07-30 04:55:43 +00:00
|
|
|
case DevFmtAmbi1:
|
|
|
|
case DevFmtAmbi2:
|
|
|
|
case DevFmtAmbi3:
|
2014-11-26 06:20:00 +00:00
|
|
|
break;
|
2010-08-03 07:21:36 +00:00
|
|
|
}
|
2014-11-13 03:26:53 +00:00
|
|
|
|
2016-07-31 15:13:41 +00:00
|
|
|
if(device->FmtChans >= DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3)
|
2016-07-30 04:55:43 +00:00
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
const ALsizei *acnmap = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2ACN : ACN2ACN;
|
2016-08-02 16:16:12 +00:00
|
|
|
const ALfloat *n3dscale = (device->AmbiFmt == AmbiFormat_FuMa) ? FuMa2N3DScale :
|
|
|
|
(device->AmbiFmt == AmbiFormat_ACN_SN3D) ? SN3D2N3DScale :
|
|
|
|
/*(device->AmbiFmt == AmbiFormat_ACN_N3D) ?*/ UnitScale;
|
2016-07-30 04:55:43 +00:00
|
|
|
|
|
|
|
count = (device->FmtChans == DevFmtAmbi3) ? 16 :
|
2016-07-31 14:46:38 +00:00
|
|
|
(device->FmtChans == DevFmtAmbi2) ? 9 :
|
|
|
|
(device->FmtChans == DevFmtAmbi1) ? 4 : 1;
|
2016-07-30 04:55:43 +00:00
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei acn = acnmap[i];
|
2016-08-02 16:16:12 +00:00
|
|
|
device->Dry.Ambi.Map[i].Scale = 1.0f/n3dscale[acn];
|
2016-07-31 14:46:38 +00:00
|
|
|
device->Dry.Ambi.Map[i].Index = acn;
|
2016-07-30 04:55:43 +00:00
|
|
|
}
|
|
|
|
device->Dry.CoeffCount = 0;
|
|
|
|
device->Dry.NumChannels = count;
|
|
|
|
|
2016-07-31 14:46:38 +00:00
|
|
|
if(device->FmtChans == DevFmtAmbi1)
|
2016-07-30 04:55:43 +00:00
|
|
|
{
|
2016-07-31 14:46:38 +00:00
|
|
|
device->FOAOut.Ambi = device->Dry.Ambi;
|
|
|
|
device->FOAOut.CoeffCount = device->Dry.CoeffCount;
|
2016-07-30 04:55:43 +00:00
|
|
|
}
|
2016-07-31 14:46:38 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/* FOA output is always ACN+N3D for higher-order ambisonic output.
|
|
|
|
* The upsampler expects this and will convert it for output.
|
|
|
|
*/
|
|
|
|
memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
|
|
|
|
for(i = 0;i < 4;i++)
|
|
|
|
{
|
|
|
|
device->FOAOut.Ambi.Map[i].Scale = 1.0f;
|
|
|
|
device->FOAOut.Ambi.Map[i].Index = i;
|
|
|
|
}
|
|
|
|
device->FOAOut.CoeffCount = 0;
|
2016-07-30 16:29:21 +00:00
|
|
|
|
2016-07-31 14:46:38 +00:00
|
|
|
ambiup_reset(device->AmbiUp, device);
|
|
|
|
}
|
2016-07-30 04:55:43 +00:00
|
|
|
}
|
2016-04-16 05:05:47 +00:00
|
|
|
else
|
2016-03-26 06:25:13 +00:00
|
|
|
{
|
2016-04-17 00:21:31 +00:00
|
|
|
SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs,
|
2017-01-21 19:05:05 +00:00
|
|
|
chanmap, count, &device->Dry.NumChannels);
|
2016-04-16 05:05:47 +00:00
|
|
|
device->Dry.CoeffCount = coeffcount;
|
|
|
|
|
|
|
|
memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
|
2017-01-16 15:45:07 +00:00
|
|
|
for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++)
|
2016-04-16 05:05:47 +00:00
|
|
|
{
|
|
|
|
device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0];
|
|
|
|
for(j = 1;j < 4;j++)
|
|
|
|
device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale;
|
|
|
|
}
|
|
|
|
device->FOAOut.CoeffCount = 4;
|
2016-03-26 06:25:13 +00:00
|
|
|
}
|
2010-08-03 07:21:36 +00:00
|
|
|
}
|
2016-01-28 08:02:46 +00:00
|
|
|
|
2016-04-14 23:42:32 +00:00
|
|
|
static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS])
|
|
|
|
{
|
|
|
|
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
|
|
|
|
const ALfloat *coeff_scale = UnitScale;
|
|
|
|
ALfloat ambiscale = 1.0f;
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei i, j;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
|
|
|
if(conf->FreqBands != 1)
|
|
|
|
ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n",
|
|
|
|
conf->XOverFreq);
|
|
|
|
|
|
|
|
if(conf->ChanMask > 0x1ff)
|
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
|
|
|
else if(conf->ChanMask > 0xf)
|
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
|
|
|
else if(conf->ChanMask > 0x1)
|
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
|
|
|
else
|
|
|
|
ambiscale = 0.0f;
|
|
|
|
|
|
|
|
if(conf->CoeffScale == ADS_SN3D)
|
|
|
|
coeff_scale = SN3D2N3DScale;
|
|
|
|
else if(conf->CoeffScale == ADS_FuMa)
|
|
|
|
coeff_scale = FuMa2N3DScale;
|
|
|
|
|
2017-01-16 17:37:55 +00:00
|
|
|
for(i = 0;i < conf->NumSpeakers;i++)
|
2016-04-14 23:42:32 +00:00
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei chan = speakermap[i];
|
2016-04-14 23:42:32 +00:00
|
|
|
ALfloat gain;
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei k = 0;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
|
|
|
chanmap[i].Config[j] = 0.0f;
|
|
|
|
|
|
|
|
chanmap[i].ChanName = device->RealOut.ChannelName[chan];
|
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
|
|
|
{
|
|
|
|
if(j == 0) gain = conf->HFOrderGain[0];
|
|
|
|
else if(j == 1) gain = conf->HFOrderGain[1];
|
|
|
|
else if(j == 4) gain = conf->HFOrderGain[2];
|
|
|
|
else if(j == 9) gain = conf->HFOrderGain[3];
|
|
|
|
if((conf->ChanMask&(1<<j)))
|
|
|
|
chanmap[i].Config[j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-17 00:21:31 +00:00
|
|
|
SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap,
|
2017-01-21 19:05:05 +00:00
|
|
|
conf->NumSpeakers, &device->Dry.NumChannels);
|
2016-04-16 00:31:04 +00:00
|
|
|
device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 :
|
|
|
|
(conf->ChanMask > 0xf) ? 9 : 4;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
2016-04-16 05:05:47 +00:00
|
|
|
memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
|
2017-01-16 15:45:07 +00:00
|
|
|
for(i = 0;i < (ALsizei)device->Dry.NumChannels;i++)
|
2016-04-14 23:42:32 +00:00
|
|
|
{
|
2016-04-16 05:05:47 +00:00
|
|
|
device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0];
|
2016-04-14 23:42:32 +00:00
|
|
|
for(j = 1;j < 4;j++)
|
2016-04-16 05:05:47 +00:00
|
|
|
device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale;
|
2016-04-14 23:42:32 +00:00
|
|
|
}
|
2016-04-16 05:05:47 +00:00
|
|
|
device->FOAOut.CoeffCount = 4;
|
2016-04-14 23:42:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS])
|
|
|
|
{
|
|
|
|
const char *devname;
|
|
|
|
int decflags = 0;
|
|
|
|
size_t count;
|
2017-01-16 15:45:07 +00:00
|
|
|
size_t i;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
|
|
|
devname = al_string_get_cstr(device->DeviceName);
|
|
|
|
if(GetConfigValueBool(devname, "decoder", "distance-comp", 1))
|
|
|
|
decflags |= BFDF_DistanceComp;
|
|
|
|
|
2016-06-01 12:30:06 +00:00
|
|
|
if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
|
2016-04-16 05:05:47 +00:00
|
|
|
{
|
2016-04-20 01:58:19 +00:00
|
|
|
count = (conf->ChanMask > 0x1ff) ? 16 :
|
|
|
|
(conf->ChanMask > 0xf) ? 9 : 4;
|
2016-04-16 05:05:47 +00:00
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
|
|
|
device->Dry.Ambi.Map[i].Scale = 1.0f;
|
|
|
|
device->Dry.Ambi.Map[i].Index = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-07-17 22:38:39 +00:00
|
|
|
static const int map[MAX_AMBI2D_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 };
|
2016-04-19 20:58:33 +00:00
|
|
|
|
2016-04-20 01:58:19 +00:00
|
|
|
count = (conf->ChanMask > 0x1ff) ? 7 :
|
|
|
|
(conf->ChanMask > 0xf) ? 5 : 3;
|
2016-04-16 05:05:47 +00:00
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
|
|
|
device->Dry.Ambi.Map[i].Scale = 1.0f;
|
|
|
|
device->Dry.Ambi.Map[i].Index = map[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
device->Dry.CoeffCount = 0;
|
|
|
|
device->Dry.NumChannels = count;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
|
|
|
TRACE("Enabling %s-band %s-order%s ambisonic decoder\n",
|
|
|
|
(conf->FreqBands == 1) ? "single" : "dual",
|
|
|
|
(conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first",
|
2016-06-01 12:30:06 +00:00
|
|
|
(conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : ""
|
2016-04-14 23:42:32 +00:00
|
|
|
);
|
|
|
|
bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency,
|
|
|
|
speakermap, decflags);
|
|
|
|
|
|
|
|
if(bformatdec_getOrder(device->AmbiDecoder) < 2)
|
2016-04-16 05:05:47 +00:00
|
|
|
{
|
2016-07-06 20:33:40 +00:00
|
|
|
device->FOAOut.Ambi = device->Dry.Ambi;
|
2016-04-16 05:05:47 +00:00
|
|
|
device->FOAOut.CoeffCount = device->Dry.CoeffCount;
|
|
|
|
}
|
2016-04-14 23:42:32 +00:00
|
|
|
else
|
|
|
|
{
|
2016-04-16 05:05:47 +00:00
|
|
|
memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
|
|
|
|
for(i = 0;i < 4;i++)
|
|
|
|
{
|
|
|
|
device->FOAOut.Ambi.Map[i].Scale = 1.0f;
|
|
|
|
device->FOAOut.Ambi.Map[i].Index = i;
|
|
|
|
}
|
|
|
|
device->FOAOut.CoeffCount = 0;
|
2016-04-14 23:42:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-15 21:57:22 +00:00
|
|
|
static void InitHrtfPanning(ALCdevice *device, bool hoa_mode)
|
2016-04-14 17:44:57 +00:00
|
|
|
{
|
2017-01-19 03:16:24 +00:00
|
|
|
/* NOTE: azimuth goes clockwise. */
|
|
|
|
static const ALfloat AmbiPoints[][2] = {
|
|
|
|
{ DEG2RAD( 90.0f), DEG2RAD( 0.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) },
|
|
|
|
{ DEG2RAD( 0.0f), DEG2RAD( 0.0f) },
|
|
|
|
{ DEG2RAD( 0.0f), DEG2RAD( 90.0f) },
|
|
|
|
{ DEG2RAD( 0.0f), DEG2RAD( 180.0f) },
|
|
|
|
{ DEG2RAD( 0.0f), DEG2RAD( -90.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) },
|
|
|
|
{ DEG2RAD(-90.0f), DEG2RAD( 0.0f) },
|
|
|
|
};
|
|
|
|
static const ALfloat AmbiMatrixFOA[][2][MAX_AMBI_COEFFS] = {
|
|
|
|
{ { 1.88982237e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f } },
|
|
|
|
{ { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f } },
|
|
|
|
{ { 1.88982237e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } },
|
|
|
|
{ { 1.88982237e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f }, { 7.14285714e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f } },
|
|
|
|
{ { 1.88982237e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.14285714e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f } },
|
|
|
|
{ { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f }, { 7.14285714e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f } },
|
|
|
|
{ { 1.88982237e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f }, { 7.14285714e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f } }
|
|
|
|
}, AmbiMatrixHOA[][2][MAX_AMBI_COEFFS] = {
|
|
|
|
{ { 1.43315266e-001f, 0.00000000e+000f, 1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, 1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, -1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, 1.09057783e-001f, 1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, 7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } },
|
|
|
|
{ { 1.39644596e-001f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } },
|
|
|
|
{ { 1.39644596e-001f, 0.00000000e+000f, 0.00000000e+000f, -1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, 1.01835015e-001f }, { 7.08127349e-002f, 0.00000000e+000f, 0.00000000e+000f, -1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, 1.29099445e-001f } },
|
|
|
|
{ { 1.39644596e-001f, 1.88281281e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -5.83538687e-002f, 0.00000000e+000f, -1.01835015e-001f }, { 7.08127349e-002f, 1.23259031e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, -7.39770307e-002f, 0.00000000e+000f, -1.29099445e-001f } },
|
|
|
|
{ { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, 7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, 9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, 1.09057783e-001f, -7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, -7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, 7.13950780e-002f, -9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, -9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, -1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, 7.58818830e-002f, 7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, -7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, 9.61978444e-002f, 9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.40852210e-001f, 1.09057783e-001f, -1.09208910e-001f, -1.09057783e-001f, -7.58818830e-002f, -7.66295578e-002f, -3.28314629e-004f, 7.66295578e-002f, 0.00000000e+000f }, { 7.14251066e-002f, 7.13950780e-002f, -7.14940135e-002f, -7.13950780e-002f, -9.61978444e-002f, -9.71456952e-002f, -4.16214759e-004f, 9.71456952e-002f, 0.00000000e+000f } },
|
|
|
|
{ { 1.43315266e-001f, 0.00000000e+000f, -1.90399923e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.18020996e-001f, 0.00000000e+000f, 0.00000000e+000f }, { 7.26741039e-002f, 0.00000000e+000f, -1.24646009e-001f, 0.00000000e+000f, 0.00000000e+000f, 0.00000000e+000f, 1.49618920e-001f, 0.00000000e+000f, 0.00000000e+000f } },
|
|
|
|
};
|
|
|
|
const ALfloat (*AmbiMatrix)[2][MAX_AMBI_COEFFS] = hoa_mode ? AmbiMatrixHOA : AmbiMatrixFOA;
|
|
|
|
size_t count = hoa_mode ? 9 : 4;
|
2017-01-16 15:45:07 +00:00
|
|
|
size_t i;
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2017-01-19 03:16:24 +00:00
|
|
|
static_assert(9 <= COUNTOF(device->Hrtf.Coeffs), "ALCdevice::Hrtf.Values/Coeffs size is too small");
|
|
|
|
static_assert(COUNTOF(AmbiPoints) <= HRTF_AMBI_MAX_CHANNELS, "HRTF_AMBI_MAX_CHANNELS is too small");
|
2017-01-15 21:57:22 +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
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
|
|
|
device->Dry.Ambi.Map[i].Scale = 1.0f;
|
2017-01-19 03:16:24 +00:00
|
|
|
device->Dry.Ambi.Map[i].Index = 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-12 06:20:35 +00:00
|
|
|
}
|
|
|
|
device->Dry.CoeffCount = 0;
|
|
|
|
device->Dry.NumChannels = count;
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2017-01-15 21:57:22 +00:00
|
|
|
if(!hoa_mode)
|
|
|
|
{
|
|
|
|
device->FOAOut.Ambi = device->Dry.Ambi;
|
|
|
|
device->FOAOut.CoeffCount = device->Dry.CoeffCount;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
|
|
|
|
for(i = 0;i < 4;i++)
|
|
|
|
{
|
|
|
|
device->FOAOut.Ambi.Map[i].Scale = 1.0f;
|
|
|
|
device->FOAOut.Ambi.Map[i].Index = i;
|
|
|
|
}
|
|
|
|
device->FOAOut.CoeffCount = 0;
|
|
|
|
|
|
|
|
ambiup_reset(device->AmbiUp, device);
|
|
|
|
}
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
memset(device->Hrtf.Coeffs, 0, sizeof(device->Hrtf.Coeffs));
|
|
|
|
device->Hrtf.IrSize = BuildBFormatHrtf(device->Hrtf.Handle,
|
2017-01-19 03:16:24 +00:00
|
|
|
device->Hrtf.Coeffs, device->Dry.NumChannels,
|
|
|
|
AmbiPoints, AmbiMatrix, COUNTOF(AmbiPoints)
|
2016-08-24 07:25:28 +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
|
|
|
|
|
|
|
/* Round up to the nearest multiple of 8 */
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.IrSize = (device->Hrtf.IrSize+7)&~7;
|
2016-04-14 17:44:57 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
static void InitUhjPanning(ALCdevice *device)
|
2016-04-14 17:44:57 +00:00
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei count = 3;
|
|
|
|
ALsizei i;
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2016-04-16 05:05:47 +00:00
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei acn = FuMa2ACN[i];
|
2016-04-16 05:05:47 +00:00
|
|
|
device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn];
|
|
|
|
device->Dry.Ambi.Map[i].Index = acn;
|
|
|
|
}
|
|
|
|
device->Dry.CoeffCount = 0;
|
|
|
|
device->Dry.NumChannels = count;
|
2016-04-14 17:44:57 +00:00
|
|
|
|
2016-07-06 20:33:40 +00:00
|
|
|
device->FOAOut.Ambi = device->Dry.Ambi;
|
2016-04-16 05:05:47 +00:00
|
|
|
device->FOAOut.CoeffCount = device->Dry.CoeffCount;
|
2016-04-14 17:44:57 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq)
|
|
|
|
{
|
|
|
|
const char *mode;
|
|
|
|
bool headphones;
|
|
|
|
int bs2blevel;
|
|
|
|
size_t i;
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Handle = NULL;
|
|
|
|
al_string_clear(&device->Hrtf.Name);
|
2016-04-14 22:25:12 +00:00
|
|
|
device->Render_Mode = NormalRender;
|
|
|
|
|
2016-04-16 05:05:47 +00:00
|
|
|
memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi));
|
2016-04-16 00:31:04 +00:00
|
|
|
device->Dry.CoeffCount = 0;
|
|
|
|
device->Dry.NumChannels = 0;
|
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
if(device->FmtChans != DevFmtStereo)
|
|
|
|
{
|
2016-04-14 23:42:32 +00:00
|
|
|
ALuint speakermap[MAX_OUTPUT_CHANNELS];
|
2016-04-16 21:00:22 +00:00
|
|
|
const char *devname, *layout = NULL;
|
|
|
|
AmbDecConf conf, *pconf = NULL;
|
2016-04-14 23:42:32 +00:00
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
if(hrtf_appreq == Hrtf_Enable)
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
|
2016-04-14 22:25:12 +00:00
|
|
|
|
2016-04-14 23:42:32 +00:00
|
|
|
ambdec_init(&conf);
|
|
|
|
|
|
|
|
devname = al_string_get_cstr(device->DeviceName);
|
2016-04-16 21:00:22 +00:00
|
|
|
switch(device->FmtChans)
|
|
|
|
{
|
|
|
|
case DevFmtQuad: layout = "quad"; break;
|
|
|
|
case DevFmtX51: layout = "surround51"; break;
|
|
|
|
case DevFmtX51Rear: layout = "surround51rear"; break;
|
|
|
|
case DevFmtX61: layout = "surround61"; break;
|
|
|
|
case DevFmtX71: layout = "surround71"; break;
|
2016-07-30 04:55:43 +00:00
|
|
|
/* Mono, Stereo, and Ambisonics output don't use custom decoders. */
|
2016-04-16 21:00:22 +00:00
|
|
|
case DevFmtMono:
|
|
|
|
case DevFmtStereo:
|
2016-07-30 04:55:43 +00:00
|
|
|
case DevFmtAmbi1:
|
|
|
|
case DevFmtAmbi2:
|
|
|
|
case DevFmtAmbi3:
|
2016-04-16 21:00:22 +00:00
|
|
|
break;
|
|
|
|
}
|
2016-04-14 23:42:32 +00:00
|
|
|
if(layout)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-04-14 23:42:32 +00:00
|
|
|
const char *fname;
|
|
|
|
if(ConfigValueStr(devname, "decoder", layout, &fname))
|
|
|
|
{
|
|
|
|
if(!ambdec_load(&conf, fname))
|
|
|
|
ERR("Failed to load layout file %s\n", fname);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(conf.ChanMask > 0xffff)
|
|
|
|
ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(MakeSpeakerMap(device, &conf, speakermap))
|
|
|
|
pconf = &conf;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0))
|
|
|
|
{
|
2016-07-30 16:29:21 +00:00
|
|
|
ambiup_free(device->AmbiUp);
|
|
|
|
device->AmbiUp = NULL;
|
2016-04-20 01:58:19 +00:00
|
|
|
if(!device->AmbiDecoder)
|
2016-04-14 22:25:12 +00:00
|
|
|
device->AmbiDecoder = bformatdec_alloc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bformatdec_free(device->AmbiDecoder);
|
|
|
|
device->AmbiDecoder = NULL;
|
2016-07-30 16:29:21 +00:00
|
|
|
if(device->FmtChans > DevFmtAmbi1 && device->FmtChans <= DevFmtAmbi3)
|
|
|
|
{
|
|
|
|
if(!device->AmbiUp)
|
|
|
|
device->AmbiUp = ambiup_alloc();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ambiup_free(device->AmbiUp);
|
|
|
|
device->AmbiUp = NULL;
|
|
|
|
}
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
|
2016-04-14 23:42:32 +00:00
|
|
|
if(!pconf)
|
|
|
|
InitPanning(device);
|
|
|
|
else if(device->AmbiDecoder)
|
|
|
|
InitHQPanning(device, pconf, speakermap);
|
|
|
|
else
|
|
|
|
InitCustomPanning(device, pconf, speakermap);
|
|
|
|
|
|
|
|
ambdec_deinit(&conf);
|
2016-04-14 22:25:12 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bformatdec_free(device->AmbiDecoder);
|
|
|
|
device->AmbiDecoder = NULL;
|
|
|
|
|
|
|
|
headphones = device->IsHeadphones;
|
|
|
|
if(device->Type != Loopback)
|
|
|
|
{
|
|
|
|
const char *mode;
|
|
|
|
if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode))
|
|
|
|
{
|
|
|
|
if(strcasecmp(mode, "headphones") == 0)
|
|
|
|
headphones = true;
|
|
|
|
else if(strcasecmp(mode, "speakers") == 0)
|
|
|
|
headphones = false;
|
|
|
|
else if(strcasecmp(mode, "auto") != 0)
|
|
|
|
ERR("Unexpected stereo-mode: %s\n", mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hrtf_userreq == Hrtf_Default)
|
|
|
|
{
|
2016-04-16 21:00:22 +00:00
|
|
|
bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) ||
|
|
|
|
(hrtf_appreq == Hrtf_Enable);
|
|
|
|
if(!usehrtf) goto no_hrtf;
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_ENABLED_SOFT;
|
2016-04-14 22:25:12 +00:00
|
|
|
if(headphones && hrtf_appreq != Hrtf_Disable)
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT;
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-16 21:00:22 +00:00
|
|
|
if(hrtf_userreq != Hrtf_Enable)
|
|
|
|
{
|
|
|
|
if(hrtf_appreq == Hrtf_Enable)
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_DENIED_SOFT;
|
2016-04-16 21:00:22 +00:00
|
|
|
goto no_hrtf;
|
|
|
|
}
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_REQUIRED_SOFT;
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
if(VECTOR_SIZE(device->Hrtf.List) == 0)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-08-24 07:25:28 +00:00
|
|
|
VECTOR_DEINIT(device->Hrtf.List);
|
|
|
|
device->Hrtf.List = EnumerateHrtf(device->DeviceName);
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf.List))
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-08-24 07:25:28 +00:00
|
|
|
const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, hrtf_id);
|
2016-07-07 17:26:42 +00:00
|
|
|
if(entry->hrtf->sampleRate == device->Frequency)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Handle = entry->hrtf;
|
|
|
|
al_string_copy(&device->Hrtf.Name, entry->name);
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
for(i = 0;!device->Hrtf.Handle && i < VECTOR_SIZE(device->Hrtf.List);i++)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-08-24 07:25:28 +00:00
|
|
|
const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf.List, i);
|
2016-07-07 17:26:42 +00:00
|
|
|
if(entry->hrtf->sampleRate == device->Frequency)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Handle = entry->hrtf;
|
|
|
|
al_string_copy(&device->Hrtf.Name, entry->name);
|
2016-04-14 22:25:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-24 07:25:28 +00:00
|
|
|
if(device->Hrtf.Handle)
|
2016-04-14 22:25:12 +00:00
|
|
|
{
|
2017-01-15 21:57:22 +00:00
|
|
|
bool hoa_mode;
|
|
|
|
|
2016-04-16 21:00:22 +00:00
|
|
|
device->Render_Mode = HrtfRender;
|
2016-04-14 22:25:12 +00:00
|
|
|
if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode))
|
|
|
|
{
|
|
|
|
if(strcasecmp(mode, "full") == 0)
|
|
|
|
device->Render_Mode = HrtfRender;
|
|
|
|
else if(strcasecmp(mode, "basic") == 0)
|
|
|
|
device->Render_Mode = NormalRender;
|
|
|
|
else
|
|
|
|
ERR("Unexpected hrtf-mode: %s\n", mode);
|
|
|
|
}
|
|
|
|
|
2017-01-15 21:57:22 +00:00
|
|
|
if(device->Render_Mode == HrtfRender)
|
|
|
|
{
|
|
|
|
/* Don't bother with HOA when using full HRTF rendering. Nothing
|
|
|
|
* needs it, and it eases the CPU/memory load.
|
|
|
|
*/
|
|
|
|
ambiup_free(device->AmbiUp);
|
|
|
|
device->AmbiUp = NULL;
|
|
|
|
hoa_mode = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!device->AmbiUp)
|
|
|
|
device->AmbiUp = ambiup_alloc();
|
|
|
|
hoa_mode = true;
|
|
|
|
}
|
|
|
|
|
2016-11-01 21:07:14 +00:00
|
|
|
TRACE("%s HRTF rendering enabled, using \"%s\"\n",
|
|
|
|
((device->Render_Mode == HrtfRender) ? "Full" : "Basic"),
|
|
|
|
al_string_get_cstr(device->Hrtf.Name)
|
|
|
|
);
|
2017-01-15 21:57:22 +00:00
|
|
|
InitHrtfPanning(device, hoa_mode);
|
2016-04-14 22:25:12 +00:00
|
|
|
return;
|
|
|
|
}
|
2016-08-24 07:25:28 +00:00
|
|
|
device->Hrtf.Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
|
2016-04-14 22:25:12 +00:00
|
|
|
|
|
|
|
no_hrtf:
|
|
|
|
TRACE("HRTF disabled\n");
|
|
|
|
|
2017-01-15 21:57:22 +00:00
|
|
|
ambiup_free(device->AmbiUp);
|
|
|
|
device->AmbiUp = NULL;
|
|
|
|
|
2016-04-14 22:25:12 +00:00
|
|
|
bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) ||
|
|
|
|
(hrtf_appreq == Hrtf_Enable)) ? 5 : 0;
|
|
|
|
if(device->Type != Loopback)
|
|
|
|
ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel);
|
|
|
|
if(bs2blevel > 0 && bs2blevel <= 6)
|
|
|
|
{
|
|
|
|
device->Bs2b = al_calloc(16, sizeof(*device->Bs2b));
|
|
|
|
bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency);
|
|
|
|
device->Render_Mode = StereoPair;
|
|
|
|
TRACE("BS2B enabled\n");
|
|
|
|
InitPanning(device);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("BS2B disabled\n");
|
|
|
|
|
|
|
|
device->Render_Mode = NormalRender;
|
|
|
|
if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode))
|
|
|
|
{
|
|
|
|
if(strcasecmp(mode, "paired") == 0)
|
|
|
|
device->Render_Mode = StereoPair;
|
|
|
|
else if(strcasecmp(mode, "uhj") != 0)
|
|
|
|
ERR("Unexpected stereo-panning: %s\n", mode);
|
|
|
|
}
|
|
|
|
if(device->Render_Mode == NormalRender)
|
|
|
|
{
|
|
|
|
device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder));
|
|
|
|
TRACE("UHJ enabled\n");
|
|
|
|
InitUhjPanning(device);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TRACE("UHJ disabled\n");
|
|
|
|
InitPanning(device);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-28 08:02:46 +00:00
|
|
|
void aluInitEffectPanning(ALeffectslot *slot)
|
|
|
|
{
|
2017-01-16 15:45:07 +00:00
|
|
|
ALsizei i;
|
2016-01-28 08:02:46 +00:00
|
|
|
|
2016-04-15 04:50:36 +00:00
|
|
|
memset(slot->ChanMap, 0, sizeof(slot->ChanMap));
|
2016-01-28 08:02:46 +00:00
|
|
|
slot->NumChannels = 0;
|
|
|
|
|
2016-04-15 04:50:36 +00:00
|
|
|
for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
|
|
|
|
{
|
|
|
|
slot->ChanMap[i].Scale = 1.0f;
|
|
|
|
slot->ChanMap[i].Index = i;
|
|
|
|
}
|
|
|
|
slot->NumChannels = i;
|
2016-01-28 08:02:46 +00:00
|
|
|
}
|