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";
224 case InvalidChannel
: break;
230 DECL_CONST
static const char *GetChannelLayoutName(enum DevFmtChannels chans
)
234 case DevFmtMono
: return "mono";
235 case DevFmtStereo
: return "stereo";
236 case DevFmtQuad
: return "quad";
237 case DevFmtX51
: return "surround51";
238 case DevFmtX51Rear
: return "surround51rear";
239 case DevFmtX61
: return "surround61";
240 case DevFmtX71
: return "surround71";
241 case DevFmtBFormat3D
:
247 typedef struct ChannelMap
{
248 enum Channel ChanName
;
249 ChannelConfig Config
;
252 static void SetChannelMap(const enum Channel
*devchans
, ChannelConfig
*ambicoeffs
,
253 const ChannelMap
*chanmap
, size_t count
, ALuint
*outcount
,
259 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& devchans
[i
] != InvalidChannel
;i
++)
261 if(devchans
[i
] == LFE
)
263 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
264 ambicoeffs
[i
][j
] = 0.0f
;
268 for(j
= 0;j
< count
;j
++)
270 if(devchans
[i
] != chanmap
[j
].ChanName
)
275 /* Reformat FuMa -> ACN/N3D */
276 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
278 ALuint acn
= FuMa2ACN
[k
];
279 ambicoeffs
[i
][acn
] = chanmap
[j
].Config
[k
] / FuMa2N3DScale
[acn
];
284 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
285 ambicoeffs
[i
][k
] = chanmap
[j
].Config
[k
];
290 ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans
[i
]), i
);
295 static bool MakeSpeakerMap(ALCdevice
*device
, const AmbDecConf
*conf
, ALuint speakermap
[MAX_OUTPUT_CHANNELS
])
299 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
303 /* NOTE: AmbDec does not define any standard speaker names, however
304 * for this to work we have to by able to find the output channel
305 * the speaker definition corresponds to. Therefore, OpenAL Soft
306 * requires these channel labels to be recognized:
317 * Additionally, surround51 will acknowledge back speakers for side
318 * channels, and surround51rear will acknowledge side speakers for
319 * back channels, to avoid issues with an ambdec expecting 5.1 to
320 * use the side channels when the device is configured for back,
323 if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LF") == 0)
324 c
= GetChannelIdxByName(device
->RealOut
, FrontLeft
);
325 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RF") == 0)
326 c
= GetChannelIdxByName(device
->RealOut
, FrontRight
);
327 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CE") == 0)
328 c
= GetChannelIdxByName(device
->RealOut
, FrontCenter
);
329 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LS") == 0)
331 if(device
->FmtChans
== DevFmtX51Rear
)
332 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
334 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
336 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RS") == 0)
338 if(device
->FmtChans
== DevFmtX51Rear
)
339 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
341 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
343 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LB") == 0)
345 if(device
->FmtChans
== DevFmtX51
)
346 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
348 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
350 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RB") == 0)
352 if(device
->FmtChans
== DevFmtX51
)
353 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
355 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
357 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CB") == 0)
358 c
= GetChannelIdxByName(device
->RealOut
, BackCenter
);
361 ERR("AmbDec speaker label \"%s\" not recognized\n",
362 al_string_get_cstr(conf
->Speakers
[i
].Name
));
367 ERR("Failed to lookup AmbDec speaker label %s\n",
368 al_string_get_cstr(conf
->Speakers
[i
].Name
));
377 static bool LoadChannelSetup(ALCdevice
*device
)
379 ChannelMap chanmap
[MAX_OUTPUT_CHANNELS
];
380 ALuint speakermap
[MAX_OUTPUT_CHANNELS
];
381 const ALfloat
*coeff_scale
= UnitScale
;
382 const char *layout
= NULL
;
383 ALfloat ambiscale
= 1.0f
;
388 layout
= GetChannelLayoutName(device
->FmtChans
);
389 if(!layout
) return false;
391 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", layout
, &fname
))
395 if(!ambdec_load(&conf
, fname
))
397 ERR("Failed to load layout file %s\n", fname
);
401 if(conf
.FreqBands
!= 1)
403 ERR("AmbDec layout file must be single-band (freq_bands = %u)\n", conf
.FreqBands
);
407 if(!MakeSpeakerMap(device
, &conf
, speakermap
))
410 if(conf
.ChanMask
> 0x1ff)
411 ambiscale
= THIRD_ORDER_SCALE
;
412 else if(conf
.ChanMask
> 0xf)
413 ambiscale
= SECOND_ORDER_SCALE
;
414 else if(conf
.ChanMask
> 0x1)
415 ambiscale
= FIRST_ORDER_SCALE
;
419 if(conf
.CoeffScale
== ADS_SN3D
)
420 coeff_scale
= SN3D2N3DScale
;
421 else if(conf
.CoeffScale
== ADS_FuMa
)
422 coeff_scale
= FuMa2N3DScale
;
424 for(i
= 0;i
< conf
.NumSpeakers
;i
++)
426 ALuint chan
= speakermap
[i
];
429 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
430 chanmap
[i
].Config
[j
] = 0.0f
;
432 chanmap
[i
].ChanName
= device
->RealOut
.ChannelName
[chan
];
435 if((conf
.ChanMask
&(1<<j
)))
436 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[0];
440 if((conf
.ChanMask
&(1<<j
)))
441 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[1];
445 if((conf
.ChanMask
&(1<<j
)))
446 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[2];
450 if((conf
.ChanMask
&(1<<j
)))
451 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[3];
455 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, conf
.NumSpeakers
,
456 &device
->Dry
.NumChannels
, AL_FALSE
);
457 device
->Dry
.AmbiScale
= ambiscale
;
459 ambdec_deinit(&conf
);
463 ambdec_deinit(&conf
);
467 ALvoid
aluInitPanning(ALCdevice
*device
)
469 /* NOTE: These decoder coefficients are using FuMa channel ordering and
470 * normalization, since that's what was produced by the Ambisonic Decoder
471 * Toolbox. SetChannelMap will convert them to N3D.
473 static const ChannelMap MonoCfg
[1] = {
474 { FrontCenter
, { 1.414213562f
} },
476 { FrontLeft
, { 0.707106781f
, 0.0f
, 0.5f
, 0.0f
} },
477 { FrontRight
, { 0.707106781f
, 0.0f
, -0.5f
, 0.0f
} },
479 { FrontLeft
, { 0.353553f
, 0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
480 { FrontRight
, { 0.353553f
, 0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
481 { BackLeft
, { 0.353553f
, -0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
482 { BackRight
, { 0.353553f
, -0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
484 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
485 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
486 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
487 { SideLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
488 { SideRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
490 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
491 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
492 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
493 { BackLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
494 { BackRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
496 { 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
} },
497 { 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
} },
498 { 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
} },
499 { 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
} },
500 { 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
} },
501 { 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
} },
503 { 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
} },
504 { 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
} },
505 { 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
} },
506 { 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
} },
507 { 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
} },
508 { 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
} },
509 { 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
} },
511 { UpperFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, 0.072168784f
} },
512 { UpperFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, 0.072168784f
} },
513 { UpperBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, 0.072168784f
} },
514 { UpperBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, 0.072168784f
} },
515 { LowerFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, -0.072168784f
} },
516 { LowerFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, -0.072168784f
} },
517 { LowerBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, -0.072168784f
} },
518 { LowerBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, -0.072168784f
} },
520 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
521 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
522 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
524 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
525 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
526 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
527 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
529 const ChannelMap
*chanmap
= NULL
;
530 ALfloat ambiscale
= 1.0f
;
534 device
->Dry
.AmbiScale
= 1.0f
;
535 memset(device
->Dry
.AmbiCoeffs
, 0, sizeof(device
->Dry
.AmbiCoeffs
));
536 device
->Dry
.NumChannels
= 0;
540 static const struct {
541 enum Channel Channel
;
545 { UpperFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD( 45.0f
) },
546 { UpperFrontRight
, DEG2RAD( 45.0f
), DEG2RAD( 45.0f
) },
547 { UpperBackLeft
, DEG2RAD(-135.0f
), DEG2RAD( 45.0f
) },
548 { UpperBackRight
, DEG2RAD( 135.0f
), DEG2RAD( 45.0f
) },
549 { LowerFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(-45.0f
) },
550 { LowerFrontRight
, DEG2RAD( 45.0f
), DEG2RAD(-45.0f
) },
551 { LowerBackLeft
, DEG2RAD(-135.0f
), DEG2RAD(-45.0f
) },
552 { LowerBackRight
, DEG2RAD( 135.0f
), DEG2RAD(-45.0f
) },
555 count
= COUNTOF(Cube8Cfg
);
557 ambiscale
= FIRST_ORDER_SCALE
;
559 for(i
= 0;i
< count
;i
++)
560 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
561 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
562 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
563 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
564 &device
->Dry
.NumChannels
, AL_TRUE
);
565 device
->Dry
.AmbiScale
= ambiscale
;
567 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
569 int chan
= GetChannelIdxByName(device
->Dry
, CubeInfo
[i
].Channel
);
570 GetLerpedHrtfCoeffs(device
->Hrtf
, CubeInfo
[i
].Elevation
, CubeInfo
[i
].Angle
, 1.0f
, 1.0f
,
571 device
->Hrtf_Params
[chan
].Coeffs
, device
->Hrtf_Params
[chan
].Delay
);
575 if(device
->Uhj_Encoder
)
577 count
= COUNTOF(BFormat2D
);
579 ambiscale
= FIRST_ORDER_SCALE
;
581 for(i
= 0;i
< count
;i
++)
582 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
583 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
584 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
585 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
586 &device
->Dry
.NumChannels
, AL_TRUE
);
587 device
->Dry
.AmbiScale
= ambiscale
;
591 if(device
->AmbiDecoder
)
593 /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */
594 static const ChannelMap Ambi3D
[4] = {
595 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
596 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
597 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
598 { Aux3
, { 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
), "ambisonics", 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
> 0xf)
626 ERR("Only first-order is supported for HQ decoding (mask 0x%04x, max 0xf)\n",
631 if(!MakeSpeakerMap(device
, &conf
, speakermap
))
634 count
= COUNTOF(Ambi3D
);
636 ambiscale
= FIRST_ORDER_SCALE
;
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 ambisonic decoder\n", (conf
.FreqBands
==1)?"single":"dual");
647 bformatdec_reset(device
->AmbiDecoder
, &conf
, count
, device
->Frequency
, speakermap
);
648 ambdec_deinit(&conf
);
652 ambdec_deinit(&conf
);
653 bformatdec_free(device
->AmbiDecoder
);
654 device
->AmbiDecoder
= NULL
;
657 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
658 device
->Dry
.ChannelName
[i
] = device
->RealOut
.ChannelName
[i
];
660 if(LoadChannelSetup(device
))
663 switch(device
->FmtChans
)
666 count
= COUNTOF(MonoCfg
);
668 ambiscale
= ZERO_ORDER_SCALE
;
672 count
= COUNTOF(StereoCfg
);
674 ambiscale
= FIRST_ORDER_SCALE
;
678 count
= COUNTOF(QuadCfg
);
680 ambiscale
= SECOND_ORDER_SCALE
;
684 count
= COUNTOF(X51SideCfg
);
685 chanmap
= X51SideCfg
;
686 ambiscale
= SECOND_ORDER_SCALE
;
690 count
= COUNTOF(X51RearCfg
);
691 chanmap
= X51RearCfg
;
692 ambiscale
= SECOND_ORDER_SCALE
;
696 count
= COUNTOF(X61Cfg
);
698 ambiscale
= THIRD_ORDER_SCALE
;
702 count
= COUNTOF(X71Cfg
);
704 ambiscale
= THIRD_ORDER_SCALE
;
707 case DevFmtBFormat3D
:
708 count
= COUNTOF(BFormat3D
);
714 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
715 &device
->Dry
.NumChannels
, AL_TRUE
);
716 device
->Dry
.AmbiScale
= ambiscale
;
719 void aluInitEffectPanning(ALeffectslot
*slot
)
721 static const ChannelMap FirstOrderN3D
[4] = {
722 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
723 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
724 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
725 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
727 static const enum Channel AmbiChannels
[MAX_OUTPUT_CHANNELS
] = {
728 Aux0
, Aux1
, Aux2
, Aux3
, InvalidChannel
731 memset(slot
->AmbiCoeffs
, 0, sizeof(slot
->AmbiCoeffs
));
732 slot
->NumChannels
= 0;
734 SetChannelMap(AmbiChannels
, slot
->AmbiCoeffs
, FirstOrderN3D
, COUNTOF(FirstOrderN3D
),
735 &slot
->NumChannels
, AL_FALSE
);