2010-08-03 00:21:36 -07: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 14:11:03 +02:00
|
|
|
* Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2010-08-03 00:21:36 -07: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 00:02:46 -08:00
|
|
|
#include "alAuxEffectSlot.h"
|
2010-08-03 00:21:36 -07:00
|
|
|
#include "alu.h"
|
2014-11-10 17:53:42 -08:00
|
|
|
#include "bool.h"
|
2010-08-03 00:21:36 -07:00
|
|
|
|
|
|
|
|
2016-01-25 06:11:51 -08:00
|
|
|
extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat coeffs[MAX_AMBI_COEFFS]);
|
|
|
|
|
|
|
|
|
2015-08-18 07:44:17 -07: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 07:23:43 -07:00
|
|
|
|
2015-08-28 10:58:30 -07:00
|
|
|
static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = {
|
|
|
|
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 */
|
|
|
|
};
|
|
|
|
|
2015-09-23 15:03:53 -07:00
|
|
|
/* NOTE: These are scale factors as applied to Ambisonics content. FuMa
|
|
|
|
* decoder coefficients should be divided by these values to get N3D decoder
|
|
|
|
* coefficients.
|
|
|
|
*/
|
|
|
|
static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
|
2015-11-06 10:27:28 -08: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 10:58:30 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-01-25 06:11:51 -08:00
|
|
|
void CalcDirectionCoeffs(const ALfloat dir[3], 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 07:33:13 -07:00
|
|
|
{
|
|
|
|
/* Convert from OpenAL coords to Ambisonics. */
|
2014-10-02 20:25:30 -07:00
|
|
|
ALfloat x = -dir[2];
|
|
|
|
ALfloat y = -dir[0];
|
|
|
|
ALfloat z = dir[1];
|
|
|
|
|
2015-08-28 10:58:30 -07:00
|
|
|
/* Zeroth-order */
|
2015-09-23 15:03:53 -07:00
|
|
|
coeffs[0] = 1.0f; /* ACN 0 = 1 */
|
2015-08-28 10:58:30 -07:00
|
|
|
/* First-order */
|
2015-11-06 10:27:28 -08: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 10:58:30 -07:00
|
|
|
/* Second-order */
|
2015-11-06 10:27:28 -08: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 10:58:30 -07:00
|
|
|
/* Third-order */
|
2015-11-06 10:27:28 -08: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-01-25 06:11:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
void CalcAngleCoeffs(ALfloat angle, ALfloat elevation, ALfloat coeffs[MAX_AMBI_COEFFS])
|
|
|
|
{
|
|
|
|
ALfloat dir[3] = {
|
|
|
|
sinf(angle) * cosf(elevation),
|
|
|
|
sinf(elevation),
|
|
|
|
-cosf(angle) * cosf(elevation)
|
|
|
|
};
|
|
|
|
CalcDirectionCoeffs(dir, coeffs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ComputeAmbientGains(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
|
|
{
|
|
|
|
ALuint i;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComputePanningGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
|
|
|
{
|
|
|
|
ALuint 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 07:33:13 -07:00
|
|
|
|
2016-01-25 06:11:51 -08: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 07:33:13 -07:00
|
|
|
{
|
2015-08-22 07:23:43 -07:00
|
|
|
float gain = 0.0f;
|
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 07:33:13 -07:00
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
2016-01-25 06:11:51 -08:00
|
|
|
gain += chancoeffs[i][j]*coeffs[j];
|
2015-08-22 07:23:43 -07:00
|
|
|
gains[i] = gain * ingain;
|
2014-11-15 04:11:22 -08:00
|
|
|
}
|
2015-09-24 12:36:02 -07:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
2014-11-04 03:33:35 -08:00
|
|
|
}
|
|
|
|
|
2016-01-31 09:00:23 -08:00
|
|
|
void ComputeFirstOrderGains(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
|
2014-10-31 17:18:45 -07:00
|
|
|
{
|
2014-10-31 22:43:13 -07:00
|
|
|
ALuint i, j;
|
2014-10-31 17:18:45 -07:00
|
|
|
|
2016-01-25 06:11:51 -08:00
|
|
|
for(i = 0;i < numchans;i++)
|
2014-10-31 17:18:45 -07:00
|
|
|
{
|
2015-09-24 12:36:02 -07:00
|
|
|
float gain = 0.0f;
|
2015-08-28 10:58:30 -07:00
|
|
|
for(j = 0;j < 4;j++)
|
2016-01-25 06:11:51 -08:00
|
|
|
gain += chancoeffs[i][j] * mtx[j];
|
2015-09-24 12:36:02 -07:00
|
|
|
gains[i] = gain * ingain;
|
2014-10-31 17:18:45 -07:00
|
|
|
}
|
2015-09-24 12:36:02 -07:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
gains[i] = 0.0f;
|
2014-10-31 17:18:45 -07:00
|
|
|
}
|
|
|
|
|
2012-04-29 05:04:46 -07:00
|
|
|
|
2014-11-15 23:20:38 -08:00
|
|
|
DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
|
2014-11-15 00:19:56 -08: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 04:20:17 -08:00
|
|
|
|
2016-02-20 00:53:01 -08: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";
|
|
|
|
|
2015-08-28 10:58:30 -07:00
|
|
|
case BFormatW: return "bformat-w";
|
|
|
|
case BFormatX: return "bformat-x";
|
|
|
|
case BFormatY: return "bformat-y";
|
|
|
|
case BFormatZ: return "bformat-z";
|
2014-11-25 22:20:00 -08:00
|
|
|
|
2014-11-15 00:19:56 -08:00
|
|
|
case InvalidChannel: break;
|
|
|
|
}
|
|
|
|
return "(unknown)";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-05 03:46:00 -08:00
|
|
|
typedef struct ChannelMap {
|
|
|
|
enum Channel ChanName;
|
|
|
|
ChannelConfig Config;
|
|
|
|
} ChannelMap;
|
|
|
|
|
2016-01-27 04:44:21 -08:00
|
|
|
static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs,
|
|
|
|
const ChannelMap *chanmap, size_t count, ALuint *outcount,
|
|
|
|
ALboolean isfuma)
|
2014-11-12 19:26:53 -08:00
|
|
|
{
|
2015-11-06 02:21:24 -08:00
|
|
|
size_t j, k;
|
|
|
|
ALuint i;
|
2014-11-12 19:26:53 -08:00
|
|
|
|
2016-01-27 04:44:21 -08:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++)
|
2014-11-12 19:26:53 -08:00
|
|
|
{
|
2016-01-27 04:44:21 -08:00
|
|
|
if(devchans[i] == LFE)
|
2014-11-12 19:26:53 -08:00
|
|
|
{
|
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;j++)
|
2016-01-27 04:44:21 -08:00
|
|
|
ambicoeffs[i][j] = 0.0f;
|
2014-11-12 19:26:53 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(j = 0;j < count;j++)
|
|
|
|
{
|
2016-01-27 04:44:21 -08:00
|
|
|
if(devchans[i] != chanmap[j].ChanName)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(isfuma)
|
2014-11-12 19:26:53 -08:00
|
|
|
{
|
2016-01-27 04:44:21 -08:00
|
|
|
/* Reformat FuMa -> ACN/N3D */
|
|
|
|
for(k = 0;k < MAX_AMBI_COEFFS;++k)
|
2015-09-23 15:03:53 -07:00
|
|
|
{
|
2016-01-27 04:44:21 -08:00
|
|
|
ALuint acn = FuMa2ACN[k];
|
|
|
|
ambicoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn];
|
2015-09-23 15:03:53 -07:00
|
|
|
}
|
2014-11-12 19:26:53 -08:00
|
|
|
}
|
2016-01-27 04:44:21 -08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
for(k = 0;k < MAX_AMBI_COEFFS;++k)
|
|
|
|
ambicoeffs[i][k] = chanmap[j].Config[k];
|
|
|
|
}
|
|
|
|
break;
|
2014-11-12 19:26:53 -08:00
|
|
|
}
|
|
|
|
if(j == count)
|
2016-01-27 04:44:21 -08:00
|
|
|
ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans[i]), i);
|
2014-11-12 19:26:53 -08:00
|
|
|
}
|
2016-01-27 04:44:21 -08:00
|
|
|
*outcount = i;
|
2014-11-12 19:26:53 -08:00
|
|
|
}
|
|
|
|
|
2014-11-10 17:53:42 -08:00
|
|
|
static bool LoadChannelSetup(ALCdevice *device)
|
|
|
|
{
|
2014-11-15 00:19:56 -08:00
|
|
|
static const enum Channel mono_chans[1] = {
|
|
|
|
FrontCenter
|
|
|
|
}, stereo_chans[2] = {
|
|
|
|
FrontLeft, FrontRight
|
|
|
|
}, quad_chans[4] = {
|
|
|
|
FrontLeft, FrontRight,
|
|
|
|
BackLeft, BackRight
|
|
|
|
}, surround51_chans[5] = {
|
|
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
|
|
SideLeft, SideRight
|
|
|
|
}, surround51rear_chans[5] = {
|
|
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
|
|
BackLeft, BackRight
|
|
|
|
}, surround61_chans[6] = {
|
|
|
|
FrontLeft, FrontRight,
|
|
|
|
FrontCenter, BackCenter,
|
|
|
|
SideLeft, SideRight
|
|
|
|
}, surround71_chans[7] = {
|
|
|
|
FrontLeft, FrontRight, FrontCenter,
|
|
|
|
BackLeft, BackRight,
|
|
|
|
SideLeft, SideRight
|
2014-11-10 17:53:42 -08:00
|
|
|
};
|
2014-11-12 19:26:53 -08:00
|
|
|
ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
|
2014-11-15 00:19:56 -08:00
|
|
|
const enum Channel *channels = NULL;
|
2014-11-10 17:53:42 -08:00
|
|
|
const char *layout = NULL;
|
2015-08-18 07:44:17 -07:00
|
|
|
ALfloat ambiscale = 1.0f;
|
2014-11-10 17:53:42 -08:00
|
|
|
size_t count = 0;
|
2015-08-28 10:58:30 -07:00
|
|
|
int isfuma;
|
2015-08-18 07:44:17 -07:00
|
|
|
int order;
|
2014-11-10 17:53:42 -08:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
switch(device->FmtChans)
|
|
|
|
{
|
|
|
|
case DevFmtMono:
|
|
|
|
layout = "mono";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = mono_chans;
|
|
|
|
count = COUNTOF(mono_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtStereo:
|
|
|
|
layout = "stereo";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = stereo_chans;
|
|
|
|
count = COUNTOF(stereo_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtQuad:
|
|
|
|
layout = "quad";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = quad_chans;
|
|
|
|
count = COUNTOF(quad_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtX51:
|
|
|
|
layout = "surround51";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = surround51_chans;
|
|
|
|
count = COUNTOF(surround51_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtX51Rear:
|
|
|
|
layout = "surround51rear";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = surround51rear_chans;
|
|
|
|
count = COUNTOF(surround51rear_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtX61:
|
|
|
|
layout = "surround61";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = surround61_chans;
|
|
|
|
count = COUNTOF(surround61_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
|
|
|
case DevFmtX71:
|
|
|
|
layout = "surround71";
|
2014-11-15 00:19:56 -08:00
|
|
|
channels = surround71_chans;
|
|
|
|
count = COUNTOF(surround71_chans);
|
2014-11-10 17:53:42 -08:00
|
|
|
break;
|
2014-11-25 22:20:00 -08:00
|
|
|
case DevFmtBFormat3D:
|
|
|
|
break;
|
2014-11-10 17:53:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!layout)
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
{
|
2015-08-28 10:58:30 -07:00
|
|
|
char name[32] = {0};
|
|
|
|
const char *type;
|
|
|
|
char eol;
|
|
|
|
|
|
|
|
snprintf(name, sizeof(name), "%s/type", layout);
|
2015-08-28 14:10:39 -07:00
|
|
|
if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", name, &type))
|
2015-08-28 10:58:30 -07:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if(sscanf(type, " %31[^: ] : %d%c", name, &order, &eol) != 2)
|
|
|
|
{
|
|
|
|
ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type, layout);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strcasecmp(name, "fuma") == 0)
|
|
|
|
isfuma = 1;
|
|
|
|
else if(strcasecmp(name, "n3d") == 0)
|
|
|
|
isfuma = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name, layout);
|
2015-08-18 07:44:17 -07:00
|
|
|
return false;
|
2015-08-28 10:58:30 -07:00
|
|
|
}
|
|
|
|
|
2015-08-18 07:44:17 -07:00
|
|
|
if(order == 3)
|
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
|
|
|
else if(order == 2)
|
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
|
|
|
else if(order == 1)
|
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
|
|
|
else if(order == 0)
|
|
|
|
ambiscale = ZERO_ORDER_SCALE;
|
|
|
|
else
|
|
|
|
{
|
2015-08-28 10:58:30 -07:00
|
|
|
ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order, layout);
|
2014-11-10 17:53:42 -08:00
|
|
|
return false;
|
2015-08-18 07:44:17 -07:00
|
|
|
}
|
2014-11-10 17:53:42 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0;i < count;i++)
|
|
|
|
{
|
2015-08-28 10:58:30 -07:00
|
|
|
float coeffs[MAX_AMBI_COEFFS] = {0.0f};
|
2014-11-15 00:19:56 -08:00
|
|
|
const char *channame;
|
2014-11-10 17:53:42 -08:00
|
|
|
char chanlayout[32];
|
|
|
|
const char *value;
|
2015-08-18 07:44:17 -07:00
|
|
|
int props = 0;
|
|
|
|
char eol = 0;
|
|
|
|
int j;
|
2014-11-10 17:53:42 -08:00
|
|
|
|
2014-11-15 00:19:56 -08:00
|
|
|
chanmap[i].ChanName = channels[i];
|
|
|
|
channame = GetLabelFromChannel(channels[i]);
|
|
|
|
|
2014-11-10 17:53:42 -08:00
|
|
|
snprintf(chanlayout, sizeof(chanlayout), "%s/%s", layout, channame);
|
2015-08-28 14:10:39 -07:00
|
|
|
if(!ConfigValueStr(al_string_get_cstr(device->DeviceName), "layouts", chanlayout, &value))
|
2014-11-10 17:53:42 -08:00
|
|
|
{
|
|
|
|
ERR("Missing channel %s\n", channame);
|
|
|
|
return false;
|
|
|
|
}
|
2015-08-18 07:44:17 -07:00
|
|
|
if(order == 3)
|
|
|
|
props = sscanf(value, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
|
2015-08-28 10:58:30 -07:00
|
|
|
&coeffs[0], &coeffs[1], &coeffs[2], &coeffs[3],
|
|
|
|
&coeffs[4], &coeffs[5], &coeffs[6], &coeffs[7],
|
|
|
|
&coeffs[8], &coeffs[9], &coeffs[10], &coeffs[11],
|
|
|
|
&coeffs[12], &coeffs[13], &coeffs[14], &coeffs[15],
|
2015-08-22 07:23:43 -07:00
|
|
|
&eol
|
2015-08-18 07:44:17 -07:00
|
|
|
);
|
|
|
|
else if(order == 2)
|
|
|
|
props = sscanf(value, " %f %f %f %f %f %f %f %f %f %c",
|
2015-08-28 10:58:30 -07:00
|
|
|
&coeffs[0], &coeffs[1], &coeffs[2],
|
|
|
|
&coeffs[3], &coeffs[4], &coeffs[5],
|
|
|
|
&coeffs[6], &coeffs[7], &coeffs[8],
|
2015-08-18 07:44:17 -07:00
|
|
|
&eol
|
|
|
|
);
|
|
|
|
else if(order == 1)
|
|
|
|
props = sscanf(value, " %f %f %f %f %c",
|
2015-08-28 10:58:30 -07:00
|
|
|
&coeffs[0], &coeffs[1],
|
|
|
|
&coeffs[2], &coeffs[3],
|
2015-08-22 07:23:43 -07:00
|
|
|
&eol
|
2015-08-18 07:44:17 -07:00
|
|
|
);
|
|
|
|
else if(order == 0)
|
2015-08-28 10:58:30 -07:00
|
|
|
props = sscanf(value, " %f %c", &coeffs[0], &eol);
|
2014-11-10 17:53:42 -08:00
|
|
|
if(props == 0)
|
|
|
|
{
|
2015-08-22 07:23:43 -07:00
|
|
|
ERR("Failed to parse option %s properties\n", chanlayout);
|
2014-11-10 17:53:42 -08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-08-18 07:44:17 -07:00
|
|
|
if(props > (order+1)*(order+1))
|
2014-11-10 17:53:42 -08:00
|
|
|
{
|
2015-08-22 07:23:43 -07:00
|
|
|
ERR("Excess elements in option %s (expected %d)\n", chanlayout, (order+1)*(order+1));
|
2014-11-10 17:53:42 -08:00
|
|
|
return false;
|
|
|
|
}
|
2015-08-18 07:44:17 -07:00
|
|
|
|
2015-09-23 15:03:53 -07:00
|
|
|
for(j = 0;j < MAX_AMBI_COEFFS;++j)
|
|
|
|
chanmap[i].Config[j] = coeffs[j];
|
2014-11-10 17:53:42 -08:00
|
|
|
}
|
2016-03-09 23:43:57 -08:00
|
|
|
SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count,
|
|
|
|
&device->Dry.NumChannels, isfuma);
|
|
|
|
device->Dry.AmbiScale = ambiscale;
|
2014-11-10 17:53:42 -08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-09-10 17:53:01 -07:00
|
|
|
ALvoid aluInitPanning(ALCdevice *device)
|
2010-08-03 00:21:36 -07:00
|
|
|
{
|
2015-09-23 15:03:53 -07:00
|
|
|
/* NOTE: These decoder coefficients are using FuMa channel ordering and
|
|
|
|
* normalization, since that's what was produced by the Ambisonic Decoder
|
|
|
|
* Toolbox. SetChannelMap will convert them to N3D.
|
|
|
|
*/
|
2014-11-05 03:46:00 -08:00
|
|
|
static const ChannelMap MonoCfg[1] = {
|
2015-11-06 10:27:28 -08:00
|
|
|
{ FrontCenter, { 1.414213562f } },
|
2014-10-02 20:25:30 -07:00
|
|
|
}, StereoCfg[2] = {
|
2015-11-06 10:27:28 -08:00
|
|
|
{ FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } },
|
|
|
|
{ FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } },
|
2014-10-02 20:25:30 -07:00
|
|
|
}, QuadCfg[4] = {
|
2015-09-23 15:03:53 -07:00
|
|
|
{ FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
|
|
|
|
{ FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
|
|
|
|
{ BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
|
|
|
|
{ BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
|
2014-11-12 19:26:53 -08:00
|
|
|
}, X51SideCfg[5] = {
|
2015-09-23 15:03:53 -07:00
|
|
|
{ FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
|
|
|
|
{ FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
|
|
|
|
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
|
|
|
|
{ SideLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
|
|
|
|
{ SideRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
|
2014-11-12 19:26:53 -08:00
|
|
|
}, X51RearCfg[5] = {
|
2015-09-23 15:03:53 -07:00
|
|
|
{ FrontLeft, { 0.208954f, 0.212846f, 0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, 0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, 0.047490f } },
|
|
|
|
{ FrontRight, { 0.208954f, 0.212846f, -0.238350f, 0.0f, 0.0f, 0.0f, 0.0f, -0.017738f, -0.204014f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.051023f, -0.047490f } },
|
|
|
|
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
|
|
|
|
{ BackLeft, { 0.470936f, -0.369626f, 0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, -0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, -0.043968f } },
|
|
|
|
{ BackRight, { 0.470936f, -0.369626f, -0.349386f, 0.0f, 0.0f, 0.0f, 0.0f, -0.031375f, 0.058144f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.007119f, 0.043968f } },
|
2014-11-12 19:26:53 -08:00
|
|
|
}, X61Cfg[6] = {
|
2015-09-23 15:03:53 -07:00
|
|
|
{ FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
|
|
|
|
{ FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
|
|
|
|
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
|
|
|
|
{ BackCenter, { 0.353556f, -0.461940f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.165723f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.000000f } },
|
|
|
|
{ SideLeft, { 0.289151f, -0.081301f, 0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, -0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, -0.032897f } },
|
|
|
|
{ SideRight, { 0.289151f, -0.081301f, -0.401292f, 0.0f, 0.0f, 0.0f, 0.0f, -0.188208f, 0.071420f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.010099f, 0.032897f } },
|
2014-11-12 19:26:53 -08:00
|
|
|
}, X71Cfg[7] = {
|
2015-09-23 15:03:53 -07:00
|
|
|
{ FrontLeft, { 0.167065f, 0.200583f, 0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, 0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, 0.068910f } },
|
|
|
|
{ FrontRight, { 0.167065f, 0.200583f, -0.172695f, 0.0f, 0.0f, 0.0f, 0.0f, 0.029855f, -0.186407f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, -0.039241f, -0.068910f } },
|
|
|
|
{ FrontCenter, { 0.109403f, 0.179490f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.142031f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.072024f, 0.000000f } },
|
|
|
|
{ BackLeft, { 0.224752f, -0.295009f, 0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, -0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065799f } },
|
|
|
|
{ BackRight, { 0.224752f, -0.295009f, -0.170325f, 0.0f, 0.0f, 0.0f, 0.0f, 0.105349f, 0.182473f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065799f } },
|
|
|
|
{ SideLeft, { 0.224739f, 0.000000f, 0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.065795f } },
|
|
|
|
{ SideRight, { 0.224739f, 0.000000f, -0.340644f, 0.0f, 0.0f, 0.0f, 0.0f, -0.210697f, 0.000000f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.065795f } },
|
2016-02-20 00:53:01 -08:00
|
|
|
}, Cube8Cfg[8] = {
|
|
|
|
{ UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } },
|
|
|
|
{ UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } },
|
|
|
|
{ UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } },
|
|
|
|
{ UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } },
|
|
|
|
{ LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } },
|
|
|
|
{ LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } },
|
|
|
|
{ LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } },
|
|
|
|
{ LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } },
|
2016-02-26 16:09:06 -08:00
|
|
|
}, BFormat2D[3] = {
|
|
|
|
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
|
|
|
|
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
|
|
|
|
{ BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
|
2014-11-25 22:20:00 -08:00
|
|
|
}, BFormat3D[4] = {
|
2015-08-28 10:58:30 -07:00
|
|
|
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
|
2015-09-23 15:03:53 -07:00
|
|
|
{ BFormatX, { 0.0f, 1.0f, 0.0f, 0.0f } },
|
|
|
|
{ BFormatY, { 0.0f, 0.0f, 1.0f, 0.0f } },
|
|
|
|
{ BFormatZ, { 0.0f, 0.0f, 0.0f, 1.0f } },
|
2014-10-02 20:25:30 -07:00
|
|
|
};
|
2014-11-06 23:05:21 -08:00
|
|
|
const ChannelMap *chanmap = NULL;
|
2015-08-18 07:44:17 -07:00
|
|
|
ALfloat ambiscale = 1.0f;
|
2014-11-06 23:05:21 -08:00
|
|
|
size_t count = 0;
|
2016-02-26 16:09:06 -08:00
|
|
|
ALuint i;
|
2014-10-02 20:25:30 -07:00
|
|
|
|
2016-03-09 23:43:57 -08:00
|
|
|
device->Dry.AmbiScale = 1.0f;
|
|
|
|
memset(device->Dry.AmbiCoeffs, 0, sizeof(device->Dry.AmbiCoeffs));
|
|
|
|
device->Dry.NumChannels = 0;
|
2010-08-03 00:21:36 -07:00
|
|
|
|
2014-11-22 04:20:17 -08:00
|
|
|
if(device->Hrtf)
|
|
|
|
{
|
2016-02-20 00:53:01 -08:00
|
|
|
static const struct {
|
|
|
|
enum Channel Channel;
|
|
|
|
ALfloat Angle;
|
|
|
|
ALfloat Elevation;
|
|
|
|
} CubeInfo[8] = {
|
|
|
|
{ UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) },
|
|
|
|
{ LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) },
|
|
|
|
{ LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) },
|
|
|
|
{ LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) },
|
|
|
|
{ LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) },
|
|
|
|
};
|
2014-11-22 04:20:17 -08:00
|
|
|
|
2016-02-20 00:53:01 -08:00
|
|
|
count = COUNTOF(Cube8Cfg);
|
|
|
|
chanmap = Cube8Cfg;
|
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
2014-11-22 04:20:17 -08:00
|
|
|
|
|
|
|
for(i = 0;i < count;i++)
|
2016-03-09 23:43:57 -08:00
|
|
|
device->Dry.ChannelName[i] = chanmap[i].ChanName;
|
2015-02-09 15:59:29 -08:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
2016-03-09 23:43:57 -08:00
|
|
|
device->Dry.ChannelName[i] = InvalidChannel;
|
|
|
|
SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count,
|
|
|
|
&device->Dry.NumChannels, AL_TRUE);
|
|
|
|
device->Dry.AmbiScale = ambiscale;
|
2015-02-10 11:22:28 -08:00
|
|
|
|
2016-03-09 23:43:57 -08:00
|
|
|
for(i = 0;i < device->Dry.NumChannels;i++)
|
2015-02-09 15:59:29 -08:00
|
|
|
{
|
2016-03-10 14:29:44 -08:00
|
|
|
int chan = GetChannelIdxByName(device->Dry, CubeInfo[i].Channel);
|
2016-02-20 00:53:01 -08:00
|
|
|
GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 1.0f,
|
|
|
|
device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay);
|
2015-02-09 15:59:29 -08:00
|
|
|
}
|
2014-11-22 04:20:17 -08:00
|
|
|
return;
|
|
|
|
}
|
2016-02-26 16:09:06 -08:00
|
|
|
if(device->Uhj_Encoder)
|
|
|
|
{
|
|
|
|
count = COUNTOF(BFormat2D);
|
|
|
|
chanmap = BFormat2D;
|
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
|
|
|
|
|
|
|
for(i = 0;i < count;i++)
|
2016-03-09 23:43:57 -08:00
|
|
|
device->Dry.ChannelName[i] = chanmap[i].ChanName;
|
2016-02-26 16:09:06 -08:00
|
|
|
for(;i < MAX_OUTPUT_CHANNELS;i++)
|
2016-03-09 23:43:57 -08:00
|
|
|
device->Dry.ChannelName[i] = InvalidChannel;
|
|
|
|
SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count,
|
|
|
|
&device->Dry.NumChannels, AL_TRUE);
|
|
|
|
device->Dry.AmbiScale = ambiscale;
|
2016-02-26 16:09:06 -08:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2014-11-22 04:20:17 -08:00
|
|
|
|
2016-03-10 01:04:28 -08:00
|
|
|
for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
|
|
|
|
device->Dry.ChannelName[i] = device->RealOut.ChannelName[i];
|
|
|
|
|
2014-11-10 17:53:42 -08:00
|
|
|
if(LoadChannelSetup(device))
|
|
|
|
return;
|
|
|
|
|
2014-09-10 17:53:01 -07:00
|
|
|
switch(device->FmtChans)
|
2010-08-03 00:21:36 -07:00
|
|
|
{
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtMono:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(MonoCfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = MonoCfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = ZERO_ORDER_SCALE;
|
2010-08-03 00:21:36 -07:00
|
|
|
break;
|
|
|
|
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtStereo:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(StereoCfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = StereoCfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = FIRST_ORDER_SCALE;
|
2010-08-03 00:21:36 -07:00
|
|
|
break;
|
|
|
|
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtQuad:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(QuadCfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = QuadCfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = SECOND_ORDER_SCALE;
|
2010-08-03 00:21:36 -07:00
|
|
|
break;
|
|
|
|
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtX51:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(X51SideCfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = X51SideCfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
2011-05-28 19:35:32 -07:00
|
|
|
break;
|
|
|
|
|
2014-11-07 00:54:16 -08:00
|
|
|
case DevFmtX51Rear:
|
|
|
|
count = COUNTOF(X51RearCfg);
|
|
|
|
chanmap = X51RearCfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
2014-11-07 00:54:16 -08:00
|
|
|
break;
|
|
|
|
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtX61:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(X61Cfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = X61Cfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
2010-08-03 00:21:36 -07:00
|
|
|
break;
|
|
|
|
|
2010-12-04 19:50:00 -08:00
|
|
|
case DevFmtX71:
|
2014-11-05 02:54:11 -08:00
|
|
|
count = COUNTOF(X71Cfg);
|
2014-11-05 03:46:00 -08:00
|
|
|
chanmap = X71Cfg;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = THIRD_ORDER_SCALE;
|
2010-08-03 00:21:36 -07:00
|
|
|
break;
|
2014-11-25 22:20:00 -08:00
|
|
|
|
|
|
|
case DevFmtBFormat3D:
|
|
|
|
count = COUNTOF(BFormat3D);
|
|
|
|
chanmap = BFormat3D;
|
2015-08-18 07:44:17 -07:00
|
|
|
ambiscale = 1.0f;
|
2014-11-25 22:20:00 -08:00
|
|
|
break;
|
2010-08-03 00:21:36 -07:00
|
|
|
}
|
2014-11-12 19:26:53 -08:00
|
|
|
|
2016-03-09 23:43:57 -08:00
|
|
|
SetChannelMap(device->Dry.ChannelName, device->Dry.AmbiCoeffs, chanmap, count,
|
|
|
|
&device->Dry.NumChannels, AL_TRUE);
|
|
|
|
device->Dry.AmbiScale = ambiscale;
|
2010-08-03 00:21:36 -07:00
|
|
|
}
|
2016-01-28 00:02:46 -08:00
|
|
|
|
|
|
|
void aluInitEffectPanning(ALeffectslot *slot)
|
|
|
|
{
|
|
|
|
static const ChannelMap FirstOrderN3D[4] = {
|
|
|
|
{ BFormatW, { 1.0f, 0.0f, 0.0f, 0.0f } },
|
|
|
|
{ BFormatY, { 0.0f, 1.0f, 0.0f, 0.0f } },
|
|
|
|
{ BFormatZ, { 0.0f, 0.0f, 1.0f, 0.0f } },
|
|
|
|
{ BFormatX, { 0.0f, 0.0f, 0.0f, 1.0f } },
|
|
|
|
};
|
|
|
|
static const enum Channel AmbiChannels[MAX_OUTPUT_CHANNELS] = {
|
|
|
|
BFormatW, BFormatY, BFormatZ, BFormatX, InvalidChannel
|
|
|
|
};
|
|
|
|
|
|
|
|
memset(slot->AmbiCoeffs, 0, sizeof(slot->AmbiCoeffs));
|
|
|
|
slot->NumChannels = 0;
|
|
|
|
|
|
|
|
SetChannelMap(AmbiChannels, slot->AmbiCoeffs, FirstOrderN3D, COUNTOF(FirstOrderN3D),
|
|
|
|
&slot->NumChannels, AL_FALSE);
|
|
|
|
}
|