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. FuMa
66 * decoder coefficients should be divided by these values to get N3D decoder
69 static const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
70 1.414213562f
, /* ACN 0 (W), sqrt(2) */
71 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
72 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
73 1.732050808f
, /* ACN 3 (X), sqrt(3) */
74 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
75 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
76 2.236067978f
, /* ACN 6 (R), sqrt(5) */
77 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
78 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
79 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
80 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
81 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
82 2.645751311f
, /* ACN 12 (K), sqrt(7) */
83 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
84 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
85 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
89 void CalcDirectionCoeffs(const ALfloat dir
[3], ALfloat coeffs
[MAX_AMBI_COEFFS
])
91 /* Convert from OpenAL coords to Ambisonics. */
97 coeffs
[0] = 1.0f
; /* ACN 0 = 1 */
99 coeffs
[1] = 1.732050808f
* y
; /* ACN 1 = sqrt(3) * Y */
100 coeffs
[2] = 1.732050808f
* z
; /* ACN 2 = sqrt(3) * Z */
101 coeffs
[3] = 1.732050808f
* x
; /* ACN 3 = sqrt(3) * X */
103 coeffs
[4] = 3.872983346f
* x
* y
; /* ACN 4 = sqrt(15) * X * Y */
104 coeffs
[5] = 3.872983346f
* y
* z
; /* ACN 5 = sqrt(15) * Y * Z */
105 coeffs
[6] = 1.118033989f
* (3.0f
*z
*z
- 1.0f
); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
106 coeffs
[7] = 3.872983346f
* x
* z
; /* ACN 7 = sqrt(15) * X * Z */
107 coeffs
[8] = 1.936491673f
* (x
*x
- y
*y
); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
109 coeffs
[9] = 2.091650066f
* y
* (3.0f
*x
*x
- y
*y
); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
110 coeffs
[10] = 10.246950766f
* z
* x
* y
; /* ACN 10 = sqrt(105) * Z * X * Y */
111 coeffs
[11] = 1.620185175f
* y
* (5.0f
*z
*z
- 1.0f
); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
112 coeffs
[12] = 1.322875656f
* z
* (5.0f
*z
*z
- 3.0f
); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
113 coeffs
[13] = 1.620185175f
* x
* (5.0f
*z
*z
- 1.0f
); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
114 coeffs
[14] = 5.123475383f
* z
* (x
*x
- y
*y
); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
115 coeffs
[15] = 2.091650066f
* x
* (x
*x
- 3.0f
*y
*y
); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
118 void CalcAngleCoeffs(ALfloat angle
, ALfloat elevation
, ALfloat coeffs
[MAX_AMBI_COEFFS
])
121 sinf(angle
) * cosf(elevation
),
123 -cosf(angle
) * cosf(elevation
)
125 CalcDirectionCoeffs(dir
, coeffs
);
129 void ComputeAmbientGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
133 for(i
= 0;i
< numchans
;i
++)
135 // The W coefficients are based on a mathematical average of the
136 // output. The square root of the base average provides for a more
137 // perceptual average volume, better suited to non-directional gains.
138 gains
[i
] = sqrtf(chancoeffs
[i
][0]) * ingain
;
140 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
144 void ComputePanningGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat coeffs
[MAX_AMBI_COEFFS
], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
148 for(i
= 0;i
< numchans
;i
++)
151 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
152 gain
+= chancoeffs
[i
][j
]*coeffs
[j
];
153 gains
[i
] = gain
* ingain
;
155 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
159 void ComputeFirstOrderGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat mtx
[4], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
163 for(i
= 0;i
< numchans
;i
++)
167 gain
+= chancoeffs
[i
][j
] * mtx
[j
];
168 gains
[i
] = gain
* ingain
;
170 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
175 DECL_CONST
static inline const char *GetLabelFromChannel(enum Channel channel
)
179 case FrontLeft
: return "front-left";
180 case FrontRight
: return "front-right";
181 case FrontCenter
: return "front-center";
182 case LFE
: return "lfe";
183 case BackLeft
: return "back-left";
184 case BackRight
: return "back-right";
185 case BackCenter
: return "back-center";
186 case SideLeft
: return "side-left";
187 case SideRight
: return "side-right";
189 case UpperFrontLeft
: return "upper-front-left";
190 case UpperFrontRight
: return "upper-front-right";
191 case UpperBackLeft
: return "upper-back-left";
192 case UpperBackRight
: return "upper-back-right";
193 case LowerFrontLeft
: return "lower-front-left";
194 case LowerFrontRight
: return "lower-front-right";
195 case LowerBackLeft
: return "lower-back-left";
196 case LowerBackRight
: return "lower-back-right";
198 case BFormatW
: return "bformat-w";
199 case BFormatX
: return "bformat-x";
200 case BFormatY
: return "bformat-y";
201 case BFormatZ
: return "bformat-z";
203 case InvalidChannel
: break;
209 typedef struct ChannelMap
{
210 enum Channel ChanName
;
211 ChannelConfig Config
;
214 static void SetChannelMap(const enum Channel
*devchans
, ChannelConfig
*ambicoeffs
,
215 const ChannelMap
*chanmap
, size_t count
, ALuint
*outcount
,
221 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& devchans
[i
] != InvalidChannel
;i
++)
223 if(devchans
[i
] == LFE
)
225 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
226 ambicoeffs
[i
][j
] = 0.0f
;
230 for(j
= 0;j
< count
;j
++)
232 if(devchans
[i
] != chanmap
[j
].ChanName
)
237 /* Reformat FuMa -> ACN/N3D */
238 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
240 ALuint acn
= FuMa2ACN
[k
];
241 ambicoeffs
[i
][acn
] = chanmap
[j
].Config
[k
] / FuMa2N3DScale
[acn
];
246 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
247 ambicoeffs
[i
][k
] = chanmap
[j
].Config
[k
];
252 ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans
[i
]), i
);
257 static bool MakeSpeakerMap(ALCdevice
*device
, const AmbDecConf
*conf
, ALuint speakermap
[MAX_OUTPUT_CHANNELS
])
261 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
265 /* NOTE: AmbDec does not define any standard speaker names, however
266 * for this to work we have to by able to find the output channel
267 * the speaker definition corresponds to. Therefore, OpenAL Soft
268 * requires these channel labels to be recognized:
279 * Additionally, surround51 will acknowledge back speakers for side
280 * channels, and surround51rear will acknowledge side speakers for
281 * back channels, to avoid issues with an ambdec expecting 5.1 to
282 * use the side channels when the device is configured for back,
285 if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LF") == 0)
286 c
= GetChannelIdxByName(device
->RealOut
, FrontLeft
);
287 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RF") == 0)
288 c
= GetChannelIdxByName(device
->RealOut
, FrontRight
);
289 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CE") == 0)
290 c
= GetChannelIdxByName(device
->RealOut
, FrontCenter
);
291 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LS") == 0)
293 if(device
->FmtChans
== DevFmtX51Rear
)
294 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
296 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
298 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RS") == 0)
300 if(device
->FmtChans
== DevFmtX51Rear
)
301 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
303 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
305 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "LB") == 0)
307 if(device
->FmtChans
== DevFmtX51
)
308 c
= GetChannelIdxByName(device
->RealOut
, SideLeft
);
310 c
= GetChannelIdxByName(device
->RealOut
, BackLeft
);
312 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "RB") == 0)
314 if(device
->FmtChans
== DevFmtX51
)
315 c
= GetChannelIdxByName(device
->RealOut
, SideRight
);
317 c
= GetChannelIdxByName(device
->RealOut
, BackRight
);
319 else if(al_string_cmp_cstr(conf
->Speakers
[i
].Name
, "CB") == 0)
320 c
= GetChannelIdxByName(device
->RealOut
, BackCenter
);
323 ERR("AmbDec speaker label \"%s\" not recognized\n",
324 al_string_get_cstr(conf
->Speakers
[i
].Name
));
329 ERR("Failed to lookup AmbDec speaker label %s\n",
330 al_string_get_cstr(conf
->Speakers
[i
].Name
));
339 static bool LoadChannelSetup(ALCdevice
*device
)
341 static const enum Channel mono_chans
[1] = {
343 }, stereo_chans
[2] = {
344 FrontLeft
, FrontRight
346 FrontLeft
, FrontRight
,
348 }, surround51_chans
[5] = {
349 FrontLeft
, FrontRight
, FrontCenter
,
351 }, surround51rear_chans
[5] = {
352 FrontLeft
, FrontRight
, FrontCenter
,
354 }, surround61_chans
[6] = {
355 FrontLeft
, FrontRight
,
356 FrontCenter
, BackCenter
,
358 }, surround71_chans
[7] = {
359 FrontLeft
, FrontRight
, FrontCenter
,
363 ChannelMap chanmap
[MAX_OUTPUT_CHANNELS
];
364 const enum Channel
*channels
= NULL
;
365 const char *layout
= NULL
;
366 ALfloat ambiscale
= 1.0f
;
372 switch(device
->FmtChans
)
376 channels
= mono_chans
;
377 count
= COUNTOF(mono_chans
);
381 channels
= stereo_chans
;
382 count
= COUNTOF(stereo_chans
);
386 channels
= quad_chans
;
387 count
= COUNTOF(quad_chans
);
390 layout
= "surround51";
391 channels
= surround51_chans
;
392 count
= COUNTOF(surround51_chans
);
395 layout
= "surround51rear";
396 channels
= surround51rear_chans
;
397 count
= COUNTOF(surround51rear_chans
);
400 layout
= "surround61";
401 channels
= surround61_chans
;
402 count
= COUNTOF(surround61_chans
);
405 layout
= "surround71";
406 channels
= surround71_chans
;
407 count
= COUNTOF(surround71_chans
);
409 case DevFmtBFormat3D
:
421 snprintf(name
, sizeof(name
), "%s/type", layout
);
422 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", name
, &type
))
425 if(sscanf(type
, " %31[^: ] : %d%c", name
, &order
, &eol
) != 2)
427 ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type
, layout
);
431 if(strcasecmp(name
, "fuma") == 0)
433 else if(strcasecmp(name
, "n3d") == 0)
437 ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name
, layout
);
442 ambiscale
= THIRD_ORDER_SCALE
;
444 ambiscale
= SECOND_ORDER_SCALE
;
446 ambiscale
= FIRST_ORDER_SCALE
;
448 ambiscale
= ZERO_ORDER_SCALE
;
451 ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order
, layout
);
456 for(i
= 0;i
< count
;i
++)
458 float coeffs
[MAX_AMBI_COEFFS
] = {0.0f
};
459 const char *channame
;
466 chanmap
[i
].ChanName
= channels
[i
];
467 channame
= GetLabelFromChannel(channels
[i
]);
469 snprintf(chanlayout
, sizeof(chanlayout
), "%s/%s", layout
, channame
);
470 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", chanlayout
, &value
))
472 ERR("Missing channel %s\n", channame
);
476 props
= sscanf(value
, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
477 &coeffs
[0], &coeffs
[1], &coeffs
[2], &coeffs
[3],
478 &coeffs
[4], &coeffs
[5], &coeffs
[6], &coeffs
[7],
479 &coeffs
[8], &coeffs
[9], &coeffs
[10], &coeffs
[11],
480 &coeffs
[12], &coeffs
[13], &coeffs
[14], &coeffs
[15],
484 props
= sscanf(value
, " %f %f %f %f %f %f %f %f %f %c",
485 &coeffs
[0], &coeffs
[1], &coeffs
[2],
486 &coeffs
[3], &coeffs
[4], &coeffs
[5],
487 &coeffs
[6], &coeffs
[7], &coeffs
[8],
491 props
= sscanf(value
, " %f %f %f %f %c",
492 &coeffs
[0], &coeffs
[1],
493 &coeffs
[2], &coeffs
[3],
497 props
= sscanf(value
, " %f %c", &coeffs
[0], &eol
);
500 ERR("Failed to parse option %s properties\n", chanlayout
);
504 if(props
> (order
+1)*(order
+1))
506 ERR("Excess elements in option %s (expected %d)\n", chanlayout
, (order
+1)*(order
+1));
510 for(j
= 0;j
< MAX_AMBI_COEFFS
;++j
)
511 chanmap
[i
].Config
[j
] = coeffs
[j
];
513 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
514 &device
->Dry
.NumChannels
, isfuma
);
515 device
->Dry
.AmbiScale
= ambiscale
;
519 ALvoid
aluInitPanning(ALCdevice
*device
, const AmbDecConf
*conf
)
521 /* NOTE: These decoder coefficients are using FuMa channel ordering and
522 * normalization, since that's what was produced by the Ambisonic Decoder
523 * Toolbox. SetChannelMap will convert them to N3D.
525 static const ChannelMap MonoCfg
[1] = {
526 { FrontCenter
, { 1.414213562f
} },
528 { FrontLeft
, { 0.707106781f
, 0.0f
, 0.5f
, 0.0f
} },
529 { FrontRight
, { 0.707106781f
, 0.0f
, -0.5f
, 0.0f
} },
531 { FrontLeft
, { 0.353553f
, 0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
532 { FrontRight
, { 0.353553f
, 0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
533 { BackLeft
, { 0.353553f
, -0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
534 { BackRight
, { 0.353553f
, -0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
536 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
537 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
538 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
539 { SideLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
540 { SideRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
542 { FrontLeft
, { 0.208954f
, 0.199518f
, 0.223424f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012543f
, 0.144260f
} },
543 { FrontRight
, { 0.208950f
, 0.199514f
, -0.223425f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.012544f
, -0.144258f
} },
544 { FrontCenter
, { 0.109403f
, 0.168250f
, -0.000002f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.100431f
, -0.000001f
} },
545 { BackLeft
, { 0.470934f
, -0.346484f
, 0.327504f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022188f
, -0.041113f
} },
546 { BackRight
, { 0.470936f
, -0.346480f
, -0.327507f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.022186f
, 0.041114f
} },
548 { 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
} },
549 { 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
} },
550 { 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
} },
551 { 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
} },
552 { 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
} },
553 { 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
} },
555 { 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
} },
556 { 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
} },
557 { 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
} },
558 { 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
} },
559 { 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
} },
560 { 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
} },
561 { 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
} },
563 { UpperFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, 0.072168784f
} },
564 { UpperFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, 0.072168784f
} },
565 { UpperBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, 0.072168784f
} },
566 { UpperBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, 0.072168784f
} },
567 { LowerFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, -0.072168784f
} },
568 { LowerFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, -0.072168784f
} },
569 { LowerBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, -0.072168784f
} },
570 { LowerBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, -0.072168784f
} },
572 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
573 { BFormatX
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
574 { BFormatY
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
576 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
577 { BFormatX
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
578 { BFormatY
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
579 { BFormatZ
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
581 const ChannelMap
*chanmap
= NULL
;
582 ALfloat ambiscale
= 1.0f
;
586 device
->Dry
.AmbiScale
= 1.0f
;
587 memset(device
->Dry
.AmbiCoeffs
, 0, sizeof(device
->Dry
.AmbiCoeffs
));
588 device
->Dry
.NumChannels
= 0;
592 static const struct {
593 enum Channel Channel
;
597 { UpperFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD( 45.0f
) },
598 { UpperFrontRight
, DEG2RAD( 45.0f
), DEG2RAD( 45.0f
) },
599 { UpperBackLeft
, DEG2RAD(-135.0f
), DEG2RAD( 45.0f
) },
600 { UpperBackRight
, DEG2RAD( 135.0f
), DEG2RAD( 45.0f
) },
601 { LowerFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(-45.0f
) },
602 { LowerFrontRight
, DEG2RAD( 45.0f
), DEG2RAD(-45.0f
) },
603 { LowerBackLeft
, DEG2RAD(-135.0f
), DEG2RAD(-45.0f
) },
604 { LowerBackRight
, DEG2RAD( 135.0f
), DEG2RAD(-45.0f
) },
607 count
= COUNTOF(Cube8Cfg
);
609 ambiscale
= FIRST_ORDER_SCALE
;
611 for(i
= 0;i
< count
;i
++)
612 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
613 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
614 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
615 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
616 &device
->Dry
.NumChannels
, AL_TRUE
);
617 device
->Dry
.AmbiScale
= ambiscale
;
619 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
621 int chan
= GetChannelIdxByName(device
->Dry
, CubeInfo
[i
].Channel
);
622 GetLerpedHrtfCoeffs(device
->Hrtf
, CubeInfo
[i
].Elevation
, CubeInfo
[i
].Angle
, 1.0f
, 1.0f
,
623 device
->Hrtf_Params
[chan
].Coeffs
, device
->Hrtf_Params
[chan
].Delay
);
627 if(device
->Uhj_Encoder
)
629 count
= COUNTOF(BFormat2D
);
631 ambiscale
= FIRST_ORDER_SCALE
;
633 for(i
= 0;i
< count
;i
++)
634 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
635 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
636 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
637 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
638 &device
->Dry
.NumChannels
, AL_TRUE
);
639 device
->Dry
.AmbiScale
= ambiscale
;
643 if(device
->AmbiDecoder
)
645 /* NOTE: This is ACN/N3D ordering and scaling, rather than FuMa. */
646 static const ChannelMap Ambi3D
[4] = {
647 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
648 { BFormatY
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
649 { BFormatZ
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
650 { BFormatX
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
652 ALuint speakermap
[MAX_OUTPUT_CHANNELS
];
654 if(conf
->ChanMask
> 0xffff)
656 ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf
->ChanMask
);
659 if(conf
->ChanMask
> 0xf)
661 ERR("Only first-order is supported for HQ decoding (mask 0x%04x, max 0xf)\n",
666 if(!MakeSpeakerMap(device
, conf
, speakermap
))
668 bformatdec_reset(device
->AmbiDecoder
, conf
, count
, device
->Frequency
, speakermap
);
670 count
= COUNTOF(Ambi3D
);
672 ambiscale
= FIRST_ORDER_SCALE
;
674 for(i
= 0;i
< count
;i
++)
675 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
676 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
677 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
678 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
679 &device
->Dry
.NumChannels
, AL_FALSE
);
680 device
->Dry
.AmbiScale
= ambiscale
;
685 bformatdec_free(device
->AmbiDecoder
);
686 device
->AmbiDecoder
= NULL
;
689 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
690 device
->Dry
.ChannelName
[i
] = device
->RealOut
.ChannelName
[i
];
692 if(LoadChannelSetup(device
))
695 switch(device
->FmtChans
)
698 count
= COUNTOF(MonoCfg
);
700 ambiscale
= ZERO_ORDER_SCALE
;
704 count
= COUNTOF(StereoCfg
);
706 ambiscale
= FIRST_ORDER_SCALE
;
710 count
= COUNTOF(QuadCfg
);
712 ambiscale
= SECOND_ORDER_SCALE
;
716 count
= COUNTOF(X51SideCfg
);
717 chanmap
= X51SideCfg
;
718 ambiscale
= SECOND_ORDER_SCALE
;
722 count
= COUNTOF(X51RearCfg
);
723 chanmap
= X51RearCfg
;
724 ambiscale
= SECOND_ORDER_SCALE
;
728 count
= COUNTOF(X61Cfg
);
730 ambiscale
= THIRD_ORDER_SCALE
;
734 count
= COUNTOF(X71Cfg
);
736 ambiscale
= THIRD_ORDER_SCALE
;
739 case DevFmtBFormat3D
:
740 count
= COUNTOF(BFormat3D
);
746 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
747 &device
->Dry
.NumChannels
, AL_TRUE
);
748 device
->Dry
.AmbiScale
= ambiscale
;
751 void aluInitEffectPanning(ALeffectslot
*slot
)
753 static const ChannelMap FirstOrderN3D
[4] = {
754 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
755 { BFormatY
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
756 { BFormatZ
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
757 { BFormatX
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
759 static const enum Channel AmbiChannels
[MAX_OUTPUT_CHANNELS
] = {
760 BFormatW
, BFormatY
, BFormatZ
, BFormatX
, InvalidChannel
763 memset(slot
->AmbiCoeffs
, 0, sizeof(slot
->AmbiCoeffs
));
764 slot
->NumChannels
= 0;
766 SetChannelMap(AmbiChannels
, slot
->AmbiCoeffs
, FirstOrderN3D
, COUNTOF(FirstOrderN3D
),
767 &slot
->NumChannels
, AL_FALSE
);