2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2010 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
30 #include "alAuxEffectSlot.h"
34 #include "bformatdec.h"
37 extern inline void CalcXYZCoeffs(ALfloat x
, ALfloat y
, ALfloat z
, ALfloat coeffs
[MAX_AMBI_COEFFS
]);
40 #define ZERO_ORDER_SCALE 0.0f
41 #define FIRST_ORDER_SCALE 1.0f
42 #define SECOND_ORDER_SCALE (1.0f / 1.22474f)
43 #define THIRD_ORDER_SCALE (1.0f / 1.30657f)
46 static const ALuint FuMa2ACN
[MAX_AMBI_COEFFS
] = {
65 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
66 * coefficients should be divided by these values to get proper N3D scalings.
68 static const ALfloat UnitScale
[MAX_AMBI_COEFFS
] = {
69 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
,
70 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
, 1.0f
72 static const ALfloat SN3D2N3DScale
[MAX_AMBI_COEFFS
] = {
73 1.000000000f
, /* ACN 0 (W), sqrt(1) */
74 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
75 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
76 1.732050808f
, /* ACN 3 (X), sqrt(3) */
77 2.236067978f
, /* ACN 4 (V), sqrt(5) */
78 2.236067978f
, /* ACN 5 (T), sqrt(5) */
79 2.236067978f
, /* ACN 6 (R), sqrt(5) */
80 2.236067978f
, /* ACN 7 (S), sqrt(5) */
81 2.236067978f
, /* ACN 8 (U), sqrt(5) */
82 2.645751311f
, /* ACN 9 (Q), sqrt(7) */
83 2.645751311f
, /* ACN 10 (O), sqrt(7) */
84 2.645751311f
, /* ACN 11 (M), sqrt(7) */
85 2.645751311f
, /* ACN 12 (K), sqrt(7) */
86 2.645751311f
, /* ACN 13 (L), sqrt(7) */
87 2.645751311f
, /* ACN 14 (N), sqrt(7) */
88 2.645751311f
, /* ACN 15 (P), sqrt(7) */
90 static const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
91 1.414213562f
, /* ACN 0 (W), sqrt(2) */
92 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
93 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
94 1.732050808f
, /* ACN 3 (X), sqrt(3) */
95 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
96 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
97 2.236067978f
, /* ACN 6 (R), sqrt(5) */
98 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
99 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
100 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
101 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
102 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
103 2.645751311f
, /* ACN 12 (K), sqrt(7) */
104 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
105 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
106 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
110 void CalcDirectionCoeffs(const ALfloat dir
[3], ALfloat coeffs
[MAX_AMBI_COEFFS
])
112 /* Convert from OpenAL coords to Ambisonics. */
118 coeffs
[0] = 1.0f
; /* ACN 0 = 1 */
120 coeffs
[1] = 1.732050808f
* y
; /* ACN 1 = sqrt(3) * Y */
121 coeffs
[2] = 1.732050808f
* z
; /* ACN 2 = sqrt(3) * Z */
122 coeffs
[3] = 1.732050808f
* x
; /* ACN 3 = sqrt(3) * X */
124 coeffs
[4] = 3.872983346f
* x
* y
; /* ACN 4 = sqrt(15) * X * Y */
125 coeffs
[5] = 3.872983346f
* y
* z
; /* ACN 5 = sqrt(15) * Y * Z */
126 coeffs
[6] = 1.118033989f
* (3.0f
*z
*z
- 1.0f
); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
127 coeffs
[7] = 3.872983346f
* x
* z
; /* ACN 7 = sqrt(15) * X * Z */
128 coeffs
[8] = 1.936491673f
* (x
*x
- y
*y
); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
130 coeffs
[9] = 2.091650066f
* y
* (3.0f
*x
*x
- y
*y
); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
131 coeffs
[10] = 10.246950766f
* z
* x
* y
; /* ACN 10 = sqrt(105) * Z * X * Y */
132 coeffs
[11] = 1.620185175f
* y
* (5.0f
*z
*z
- 1.0f
); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
133 coeffs
[12] = 1.322875656f
* z
* (5.0f
*z
*z
- 3.0f
); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
134 coeffs
[13] = 1.620185175f
* x
* (5.0f
*z
*z
- 1.0f
); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
135 coeffs
[14] = 5.123475383f
* z
* (x
*x
- y
*y
); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
136 coeffs
[15] = 2.091650066f
* x
* (x
*x
- 3.0f
*y
*y
); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
139 void CalcAngleCoeffs(ALfloat angle
, ALfloat elevation
, ALfloat coeffs
[MAX_AMBI_COEFFS
])
142 sinf(angle
) * cosf(elevation
),
144 -cosf(angle
) * cosf(elevation
)
146 CalcDirectionCoeffs(dir
, coeffs
);
150 void ComputeAmbientGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
154 for(i
= 0;i
< numchans
;i
++)
156 // The W coefficients are based on a mathematical average of the
157 // output. The square root of the base average provides for a more
158 // perceptual average volume, better suited to non-directional gains.
159 gains
[i
] = sqrtf(chancoeffs
[i
][0]) * ingain
;
161 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
165 void ComputePanningGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat coeffs
[MAX_AMBI_COEFFS
], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
169 for(i
= 0;i
< numchans
;i
++)
172 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
173 gain
+= chancoeffs
[i
][j
]*coeffs
[j
];
174 gains
[i
] = gain
* ingain
;
176 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
180 void ComputeFirstOrderGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat mtx
[4], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
184 for(i
= 0;i
< numchans
;i
++)
188 gain
+= chancoeffs
[i
][j
] * mtx
[j
];
189 gains
[i
] = gain
* ingain
;
191 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
196 DECL_CONST
static inline const char *GetLabelFromChannel(enum Channel channel
)
200 case FrontLeft
: return "front-left";
201 case FrontRight
: return "front-right";
202 case FrontCenter
: return "front-center";
203 case LFE
: return "lfe";
204 case BackLeft
: return "back-left";
205 case BackRight
: return "back-right";
206 case BackCenter
: return "back-center";
207 case SideLeft
: return "side-left";
208 case SideRight
: return "side-right";
210 case UpperFrontLeft
: return "upper-front-left";
211 case UpperFrontRight
: return "upper-front-right";
212 case UpperBackLeft
: return "upper-back-left";
213 case UpperBackRight
: return "upper-back-right";
214 case LowerFrontLeft
: return "lower-front-left";
215 case LowerFrontRight
: return "lower-front-right";
216 case LowerBackLeft
: return "lower-back-left";
217 case LowerBackRight
: return "lower-back-right";
219 case Aux0
: return "aux-0";
220 case Aux1
: return "aux-1";
221 case Aux2
: return "aux-2";
222 case Aux3
: return "aux-3";
223 case Aux4
: return "aux-4";
224 case Aux5
: return "aux-5";
225 case Aux6
: return "aux-6";
226 case Aux7
: return "aux-7";
227 case Aux8
: return "aux-8";
229 case InvalidChannel
: break;
235 DECL_CONST
static const char *GetChannelLayoutName(enum DevFmtChannels chans
)
239 case DevFmtMono
: return "mono";
240 case DevFmtStereo
: return "stereo";
241 case DevFmtQuad
: return "quad";
242 case DevFmtX51
: return "surround51";
243 case DevFmtX51Rear
: return "surround51rear";
244 case DevFmtX61
: return "surround61";
245 case DevFmtX71
: return "surround71";
246 case DevFmtBFormat3D
:
252 typedef struct ChannelMap
{
253 enum Channel ChanName
;
254 ChannelConfig Config
;
257 static void SetChannelMap(const enum Channel
*devchans
, ChannelConfig
*ambicoeffs
,
258 const ChannelMap
*chanmap
, size_t count
, ALuint
*outcount
,
264 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& devchans
[i
] != InvalidChannel
;i
++)
266 if(devchans
[i
] == LFE
)
268 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
269 ambicoeffs
[i
][j
] = 0.0f
;
273 for(j
= 0;j
< count
;j
++)
275 if(devchans
[i
] != chanmap
[j
].ChanName
)
280 /* Reformat FuMa -> ACN/N3D */
281 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
283 ALuint acn
= FuMa2ACN
[k
];
284 ambicoeffs
[i
][acn
] = chanmap
[j
].Config
[k
] / FuMa2N3DScale
[acn
];
289 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
290 ambicoeffs
[i
][k
] = chanmap
[j
].Config
[k
];
295 ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans
[i
]), i
);
300 static bool MakeSpeakerMap(ALCdevice
*device
, const AmbDecConf
*conf
, ALuint speakermap
[MAX_OUTPUT_CHANNELS
])
304 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
308 /* NOTE: AmbDec does not define any standard speaker names, however
309 * for this to work we have to by able to find the output channel
310 * the speaker definition corresponds to. Therefore, OpenAL Soft
311 * requires these channel labels to be recognized:
322 * Additionally, surround51 will acknowledge back speakers for side
323 * channels, and surround51rear will acknowledge side speakers for
324 * back channels, to avoid issues with an ambdec expecting 5.1 to
325 * use the side channels when the device is configured for back,
328 if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LF") == 0)
329 c
= GetChannelIdxByName(device
->RealOut
, FrontLeft
);
330 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RF") == 0)
331 c
= GetChannelIdxByName(device
->RealOut
, FrontRight
);
332 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CE") == 0)
333 c
= GetChannelIdxByName(device
->RealOut
, FrontCenter
);
334 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LS") == 0)
336 if(device
->FmtChans
== DevFmtX51Rear
)
337 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
339 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
341 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RS") == 0)
343 if(device
->FmtChans
== DevFmtX51Rear
)
344 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
346 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
348 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LB") == 0)
350 if(device
->FmtChans
== DevFmtX51
)
351 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
353 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
355 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RB") == 0)
357 if(device
->FmtChans
== DevFmtX51
)
358 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
360 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
362 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CB") == 0)
363 c
= GetChannelIdxByName(device
->RealOut
, BackCenter
);
366 ERR("AmbDec speaker label \"%s\" not recognized\n",
367 al_string_get_cstr(conf
->Speakers
[i
].Name
));
372 ERR("Failed to lookup AmbDec speaker label %s\n",
373 al_string_get_cstr(conf
->Speakers
[i
].Name
));
382 static bool LoadChannelSetup(ALCdevice
*device
)
384 ChannelMap chanmap
[MAX_OUTPUT_CHANNELS
];
385 ALuint speakermap
[MAX_OUTPUT_CHANNELS
];
386 const ALfloat
*coeff_scale
= UnitScale
;
387 const char *layout
= NULL
;
388 ALfloat ambiscale
= 1.0f
;
393 layout
= GetChannelLayoutName(device
->FmtChans
);
394 if(!layout
) return false;
396 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", layout
, &fname
))
400 if(!ambdec_load(&conf
, fname
))
402 ERR("Failed to load layout file %s\n", fname
);
406 if(conf
.FreqBands
!= 1)
408 ERR("AmbDec layout file must be single-band (freq_bands = %u)\n", conf
.FreqBands
);
412 if(!MakeSpeakerMap(device
, &conf
, speakermap
))
415 if(conf
.ChanMask
> 0x1ff)
416 ambiscale
= THIRD_ORDER_SCALE
;
417 else if(conf
.ChanMask
> 0xf)
418 ambiscale
= SECOND_ORDER_SCALE
;
419 else if(conf
.ChanMask
> 0x1)
420 ambiscale
= FIRST_ORDER_SCALE
;
424 if(conf
.CoeffScale
== ADS_SN3D
)
425 coeff_scale
= SN3D2N3DScale
;
426 else if(conf
.CoeffScale
== ADS_FuMa
)
427 coeff_scale
= FuMa2N3DScale
;
429 for(i
= 0;i
< conf
.NumSpeakers
;i
++)
431 ALuint chan
= speakermap
[i
];
435 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
436 chanmap
[i
].Config
[j
] = 0.0f
;
438 chanmap
[i
].ChanName
= device
->RealOut
.ChannelName
[chan
];
439 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
441 if(j
== 0) gain
= conf
.HFOrderGain
[0];
442 else if(j
== 1) gain
= conf
.HFOrderGain
[1];
443 else if(j
== 4) gain
= conf
.HFOrderGain
[2];
444 else if(j
== 9) gain
= conf
.HFOrderGain
[3];
445 if((conf
.ChanMask
&(1<<j
)))
446 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * gain
;
450 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, conf
.NumSpeakers
,
451 &device
->Dry
.NumChannels
, AL_FALSE
);
452 device
->Dry
.AmbiScale
= ambiscale
;
454 ambdec_deinit(&conf
);
458 ambdec_deinit(&conf
);
462 ALvoid
aluInitPanning(ALCdevice
*device
)
464 /* NOTE: These decoder coefficients are using FuMa channel ordering and
465 * normalization, since that's what was produced by the Ambisonic Decoder
466 * Toolbox. SetChannelMap will convert them to N3D.
468 static const ChannelMap MonoCfg
[1] = {
469 { FrontCenter
, { 1.414213562f
} },
471 { FrontLeft
, { 0.707106781f
, 0.0f
, 0.5f
, 0.0f
} },
472 { FrontRight
, { 0.707106781f
, 0.0f
, -0.5f
, 0.0f
} },
474 { FrontLeft
, { 0.353553f
, 0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
475 { FrontRight
, { 0.353553f
, 0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
476 { BackLeft
, { 0.353553f
, -0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
477 { BackRight
, { 0.353553f
, -0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
479 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
480 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
481 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
482 { SideLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
483 { SideRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
485 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
486 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
487 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
488 { BackLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
489 { BackRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
491 { 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
} },
492 { 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
} },
493 { 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
} },
494 { 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
} },
495 { 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
} },
496 { 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
} },
498 { 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
} },
499 { 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
} },
500 { 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
} },
501 { 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
} },
502 { 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
} },
503 { 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
} },
504 { 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
} },
506 { UpperFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, 0.072168784f
} },
507 { UpperFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, 0.072168784f
} },
508 { UpperBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, 0.072168784f
} },
509 { UpperBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, 0.072168784f
} },
510 { LowerFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, -0.072168784f
} },
511 { LowerFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, -0.072168784f
} },
512 { LowerBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, -0.072168784f
} },
513 { LowerBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, -0.072168784f
} },
515 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
516 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
517 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
519 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
520 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
521 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
522 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
524 const ChannelMap
*chanmap
= NULL
;
525 ALfloat ambiscale
= 1.0f
;
529 device
->Dry
.AmbiScale
= 1.0f
;
530 memset(device
->Dry
.AmbiCoeffs
, 0, sizeof(device
->Dry
.AmbiCoeffs
));
531 device
->Dry
.NumChannels
= 0;
535 static const struct {
536 enum Channel Channel
;
540 { UpperFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD( 45.0f
) },
541 { UpperFrontRight
, DEG2RAD( 45.0f
), DEG2RAD( 45.0f
) },
542 { UpperBackLeft
, DEG2RAD(-135.0f
), DEG2RAD( 45.0f
) },
543 { UpperBackRight
, DEG2RAD( 135.0f
), DEG2RAD( 45.0f
) },
544 { LowerFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(-45.0f
) },
545 { LowerFrontRight
, DEG2RAD( 45.0f
), DEG2RAD(-45.0f
) },
546 { LowerBackLeft
, DEG2RAD(-135.0f
), DEG2RAD(-45.0f
) },
547 { LowerBackRight
, DEG2RAD( 135.0f
), DEG2RAD(-45.0f
) },
550 count
= COUNTOF(Cube8Cfg
);
552 ambiscale
= FIRST_ORDER_SCALE
;
554 for(i
= 0;i
< count
;i
++)
555 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
556 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
557 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
558 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
559 &device
->Dry
.NumChannels
, AL_TRUE
);
560 device
->Dry
.AmbiScale
= ambiscale
;
562 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
564 int chan
= GetChannelIdxByName(device
->Dry
, CubeInfo
[i
].Channel
);
565 GetLerpedHrtfCoeffs(device
->Hrtf
, CubeInfo
[i
].Elevation
, CubeInfo
[i
].Angle
, 1.0f
, 1.0f
,
566 device
->Hrtf_Params
[chan
].Coeffs
, device
->Hrtf_Params
[chan
].Delay
);
570 if(device
->Uhj_Encoder
)
572 count
= COUNTOF(BFormat2D
);
574 ambiscale
= FIRST_ORDER_SCALE
;
576 for(i
= 0;i
< count
;i
++)
577 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
578 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
579 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
580 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
581 &device
->Dry
.NumChannels
, AL_TRUE
);
582 device
->Dry
.AmbiScale
= ambiscale
;
586 if(device
->AmbiDecoder
)
588 /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */
589 static const ChannelMap Ambi3D
[9] = {
590 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
591 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
592 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
593 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
594 { Aux4
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
595 { Aux5
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
596 { Aux6
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
597 { Aux7
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
598 { Aux8
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
600 ALuint speakermap
[MAX_OUTPUT_CHANNELS
];
601 const char *fname
= "";
607 layout
= GetChannelLayoutName(device
->FmtChans
);
608 if(!layout
) goto ambi_fail
;
610 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "decoder", layout
, &fname
))
613 if(!ambdec_load(&conf
, fname
))
615 ERR("Failed to load %s\n", fname
);
619 if(conf
.ChanMask
> 0xffff)
621 ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf
.ChanMask
);
624 if(conf
.ChanMask
> 0x1ff)
626 ERR("Only first- and second-order is supported for HQ decoding (mask 0x%04x, max 0x1ff)\n",
631 if(!MakeSpeakerMap(device
, &conf
, speakermap
))
634 count
= (conf
.ChanMask
> 0xf) ? COUNTOF(Ambi3D
) : 4;
638 for(i
= 0;i
< count
;i
++)
639 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
640 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
641 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
642 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
643 &device
->Dry
.NumChannels
, AL_FALSE
);
644 device
->Dry
.AmbiScale
= ambiscale
;
646 TRACE("Enabling %s-band %s-order ambisonic decoder\n",
647 (conf
.FreqBands
== 1) ? "single" : "dual",
648 (conf
.ChanMask
> 0x1ff) ? "third" : (conf
.ChanMask
> 0xf) ? "second" : "first"
650 bformatdec_reset(device
->AmbiDecoder
, &conf
, count
, device
->Frequency
, speakermap
);
651 ambdec_deinit(&conf
);
653 if(bformatdec_getOrder(device
->AmbiDecoder
) >= 2)
655 memset(device
->FOAOut
.AmbiCoeffs
, 0, sizeof(device
->FOAOut
.AmbiCoeffs
));
656 device
->FOAOut
.AmbiCoeffs
[0][0] = 1.0f
;
657 device
->FOAOut
.AmbiCoeffs
[1][1] = 1.0f
;
658 device
->FOAOut
.AmbiCoeffs
[2][2] = 1.0f
;
659 device
->FOAOut
.AmbiCoeffs
[3][3] = 1.0f
;
665 ambdec_deinit(&conf
);
666 bformatdec_free(device
->AmbiDecoder
);
667 device
->AmbiDecoder
= NULL
;
670 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
671 device
->Dry
.ChannelName
[i
] = device
->RealOut
.ChannelName
[i
];
673 if(LoadChannelSetup(device
))
676 switch(device
->FmtChans
)
679 count
= COUNTOF(MonoCfg
);
681 ambiscale
= ZERO_ORDER_SCALE
;
685 count
= COUNTOF(StereoCfg
);
687 ambiscale
= FIRST_ORDER_SCALE
;
691 count
= COUNTOF(QuadCfg
);
693 ambiscale
= SECOND_ORDER_SCALE
;
697 count
= COUNTOF(X51SideCfg
);
698 chanmap
= X51SideCfg
;
699 ambiscale
= SECOND_ORDER_SCALE
;
703 count
= COUNTOF(X51RearCfg
);
704 chanmap
= X51RearCfg
;
705 ambiscale
= SECOND_ORDER_SCALE
;
709 count
= COUNTOF(X61Cfg
);
711 ambiscale
= THIRD_ORDER_SCALE
;
715 count
= COUNTOF(X71Cfg
);
717 ambiscale
= THIRD_ORDER_SCALE
;
720 case DevFmtBFormat3D
:
721 count
= COUNTOF(BFormat3D
);
727 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
728 &device
->Dry
.NumChannels
, AL_TRUE
);
729 device
->Dry
.AmbiScale
= ambiscale
;
732 void aluInitEffectPanning(ALeffectslot
*slot
)
734 static const ChannelMap FirstOrderN3D
[4] = {
735 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
736 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
737 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
738 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
740 static const enum Channel AmbiChannels
[MAX_OUTPUT_CHANNELS
] = {
741 Aux0
, Aux1
, Aux2
, Aux3
, InvalidChannel
744 memset(slot
->AmbiCoeffs
, 0, sizeof(slot
->AmbiCoeffs
));
745 slot
->NumChannels
= 0;
747 SetChannelMap(AmbiChannels
, slot
->AmbiCoeffs
, FirstOrderN3D
, COUNTOF(FirstOrderN3D
),
748 &slot
->NumChannels
, AL_FALSE
);