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
];
434 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
435 chanmap
[i
].Config
[j
] = 0.0f
;
437 chanmap
[i
].ChanName
= device
->RealOut
.ChannelName
[chan
];
440 if((conf
.ChanMask
&(1<<j
)))
441 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[0];
445 if((conf
.ChanMask
&(1<<j
)))
446 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[1];
450 if((conf
.ChanMask
&(1<<j
)))
451 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[2];
455 if((conf
.ChanMask
&(1<<j
)))
456 chanmap
[i
].Config
[j
] = conf
.HFMatrix
[i
][k
++] / coeff_scale
[j
] * conf
.HFOrderGain
[3];
460 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, conf
.NumSpeakers
,
461 &device
->Dry
.NumChannels
, AL_FALSE
);
462 device
->Dry
.AmbiScale
= ambiscale
;
464 ambdec_deinit(&conf
);
468 ambdec_deinit(&conf
);
472 ALvoid
aluInitPanning(ALCdevice
*device
)
474 /* NOTE: These decoder coefficients are using FuMa channel ordering and
475 * normalization, since that's what was produced by the Ambisonic Decoder
476 * Toolbox. SetChannelMap will convert them to N3D.
478 static const ChannelMap MonoCfg
[1] = {
479 { FrontCenter
, { 1.414213562f
} },
481 { FrontLeft
, { 0.707106781f
, 0.0f
, 0.5f
, 0.0f
} },
482 { FrontRight
, { 0.707106781f
, 0.0f
, -0.5f
, 0.0f
} },
484 { FrontLeft
, { 0.353553f
, 0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
485 { FrontRight
, { 0.353553f
, 0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
486 { BackLeft
, { 0.353553f
, -0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
487 { BackRight
, { 0.353553f
, -0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
489 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
490 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
491 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
492 { SideLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
493 { SideRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
495 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
496 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
497 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
498 { BackLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
499 { BackRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
501 { 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
} },
502 { 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
} },
503 { 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
} },
504 { 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
} },
505 { 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
} },
506 { 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
} },
508 { 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
} },
509 { 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
} },
510 { 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
} },
511 { 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
} },
512 { 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
} },
513 { 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
} },
514 { 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
} },
516 { UpperFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, 0.072168784f
} },
517 { UpperFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, 0.072168784f
} },
518 { UpperBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, 0.072168784f
} },
519 { UpperBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, 0.072168784f
} },
520 { LowerFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, -0.072168784f
} },
521 { LowerFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, -0.072168784f
} },
522 { LowerBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, -0.072168784f
} },
523 { LowerBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, -0.072168784f
} },
525 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
526 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
527 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
529 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
530 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
531 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
532 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
534 const ChannelMap
*chanmap
= NULL
;
535 ALfloat ambiscale
= 1.0f
;
539 device
->Dry
.AmbiScale
= 1.0f
;
540 memset(device
->Dry
.AmbiCoeffs
, 0, sizeof(device
->Dry
.AmbiCoeffs
));
541 device
->Dry
.NumChannels
= 0;
545 static const struct {
546 enum Channel Channel
;
550 { UpperFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD( 45.0f
) },
551 { UpperFrontRight
, DEG2RAD( 45.0f
), DEG2RAD( 45.0f
) },
552 { UpperBackLeft
, DEG2RAD(-135.0f
), DEG2RAD( 45.0f
) },
553 { UpperBackRight
, DEG2RAD( 135.0f
), DEG2RAD( 45.0f
) },
554 { LowerFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(-45.0f
) },
555 { LowerFrontRight
, DEG2RAD( 45.0f
), DEG2RAD(-45.0f
) },
556 { LowerBackLeft
, DEG2RAD(-135.0f
), DEG2RAD(-45.0f
) },
557 { LowerBackRight
, DEG2RAD( 135.0f
), DEG2RAD(-45.0f
) },
560 count
= COUNTOF(Cube8Cfg
);
562 ambiscale
= FIRST_ORDER_SCALE
;
564 for(i
= 0;i
< count
;i
++)
565 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
566 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
567 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
568 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
569 &device
->Dry
.NumChannels
, AL_TRUE
);
570 device
->Dry
.AmbiScale
= ambiscale
;
572 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
574 int chan
= GetChannelIdxByName(device
->Dry
, CubeInfo
[i
].Channel
);
575 GetLerpedHrtfCoeffs(device
->Hrtf
, CubeInfo
[i
].Elevation
, CubeInfo
[i
].Angle
, 1.0f
, 1.0f
,
576 device
->Hrtf_Params
[chan
].Coeffs
, device
->Hrtf_Params
[chan
].Delay
);
580 if(device
->Uhj_Encoder
)
582 count
= COUNTOF(BFormat2D
);
584 ambiscale
= FIRST_ORDER_SCALE
;
586 for(i
= 0;i
< count
;i
++)
587 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
588 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
589 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
590 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
591 &device
->Dry
.NumChannels
, AL_TRUE
);
592 device
->Dry
.AmbiScale
= ambiscale
;
596 if(device
->AmbiDecoder
)
598 /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */
599 static const ChannelMap Ambi3D
[9] = {
600 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
601 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
602 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
603 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
604 { Aux4
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
} },
605 { Aux5
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
606 { Aux6
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
607 { Aux7
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
608 { Aux8
, { 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
610 ALuint speakermap
[MAX_OUTPUT_CHANNELS
];
611 const char *fname
= "";
617 layout
= GetChannelLayoutName(device
->FmtChans
);
618 if(!layout
) goto ambi_fail
;
620 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "ambisonics", layout
, &fname
))
623 if(!ambdec_load(&conf
, fname
))
625 ERR("Failed to load %s\n", fname
);
629 if(conf
.ChanMask
> 0xffff)
631 ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf
.ChanMask
);
634 if(conf
.ChanMask
> 0x1ff)
636 ERR("Only first- and second-order is supported for HQ decoding (mask 0x%04x, max 0x1ff)\n",
641 if(!MakeSpeakerMap(device
, &conf
, speakermap
))
644 count
= (conf
.ChanMask
> 0xf) ? COUNTOF(Ambi3D
) : 4;
648 for(i
= 0;i
< count
;i
++)
649 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
650 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
651 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
652 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
653 &device
->Dry
.NumChannels
, AL_FALSE
);
654 device
->Dry
.AmbiScale
= ambiscale
;
656 TRACE("Enabling %s-band ambisonic decoder\n", (conf
.FreqBands
==1)?"single":"dual");
657 bformatdec_reset(device
->AmbiDecoder
, &conf
, count
, device
->Frequency
, speakermap
);
658 ambdec_deinit(&conf
);
660 if(bformatdec_getOrder(device
->AmbiDecoder
) >= 2)
662 memset(device
->FOAOut
.AmbiCoeffs
, 0, sizeof(device
->FOAOut
.AmbiCoeffs
));
663 device
->FOAOut
.AmbiCoeffs
[0][0] = 1.0f
;
664 device
->FOAOut
.AmbiCoeffs
[1][1] = 1.0f
;
665 device
->FOAOut
.AmbiCoeffs
[2][2] = 1.0f
;
666 device
->FOAOut
.AmbiCoeffs
[3][3] = 1.0f
;
672 ambdec_deinit(&conf
);
673 bformatdec_free(device
->AmbiDecoder
);
674 device
->AmbiDecoder
= NULL
;
677 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
678 device
->Dry
.ChannelName
[i
] = device
->RealOut
.ChannelName
[i
];
680 if(LoadChannelSetup(device
))
683 switch(device
->FmtChans
)
686 count
= COUNTOF(MonoCfg
);
688 ambiscale
= ZERO_ORDER_SCALE
;
692 count
= COUNTOF(StereoCfg
);
694 ambiscale
= FIRST_ORDER_SCALE
;
698 count
= COUNTOF(QuadCfg
);
700 ambiscale
= SECOND_ORDER_SCALE
;
704 count
= COUNTOF(X51SideCfg
);
705 chanmap
= X51SideCfg
;
706 ambiscale
= SECOND_ORDER_SCALE
;
710 count
= COUNTOF(X51RearCfg
);
711 chanmap
= X51RearCfg
;
712 ambiscale
= SECOND_ORDER_SCALE
;
716 count
= COUNTOF(X61Cfg
);
718 ambiscale
= THIRD_ORDER_SCALE
;
722 count
= COUNTOF(X71Cfg
);
724 ambiscale
= THIRD_ORDER_SCALE
;
727 case DevFmtBFormat3D
:
728 count
= COUNTOF(BFormat3D
);
734 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
735 &device
->Dry
.NumChannels
, AL_TRUE
);
736 device
->Dry
.AmbiScale
= ambiscale
;
739 void aluInitEffectPanning(ALeffectslot
*slot
)
741 static const ChannelMap FirstOrderN3D
[4] = {
742 { Aux0
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
743 { Aux1
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
744 { Aux2
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
745 { Aux3
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
747 static const enum Channel AmbiChannels
[MAX_OUTPUT_CHANNELS
] = {
748 Aux0
, Aux1
, Aux2
, Aux3
, InvalidChannel
751 memset(slot
->AmbiCoeffs
, 0, sizeof(slot
->AmbiCoeffs
));
752 slot
->NumChannels
= 0;
754 SetChannelMap(AmbiChannels
, slot
->AmbiCoeffs
, FirstOrderN3D
, COUNTOF(FirstOrderN3D
),
755 &slot
->NumChannels
, AL_FALSE
);