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"
35 extern inline void CalcXYZCoeffs(ALfloat x
, ALfloat y
, ALfloat z
, ALfloat coeffs
[MAX_AMBI_COEFFS
]);
38 #define ZERO_ORDER_SCALE 0.0f
39 #define FIRST_ORDER_SCALE 1.0f
40 #define SECOND_ORDER_SCALE (1.0f / 1.22474f)
41 #define THIRD_ORDER_SCALE (1.0f / 1.30657f)
44 static const ALuint FuMa2ACN
[MAX_AMBI_COEFFS
] = {
63 /* NOTE: These are scale factors as applied to Ambisonics content. FuMa
64 * decoder coefficients should be divided by these values to get N3D decoder
67 static const ALfloat FuMa2N3DScale
[MAX_AMBI_COEFFS
] = {
68 1.414213562f
, /* ACN 0 (W), sqrt(2) */
69 1.732050808f
, /* ACN 1 (Y), sqrt(3) */
70 1.732050808f
, /* ACN 2 (Z), sqrt(3) */
71 1.732050808f
, /* ACN 3 (X), sqrt(3) */
72 1.936491673f
, /* ACN 4 (V), sqrt(15)/2 */
73 1.936491673f
, /* ACN 5 (T), sqrt(15)/2 */
74 2.236067978f
, /* ACN 6 (R), sqrt(5) */
75 1.936491673f
, /* ACN 7 (S), sqrt(15)/2 */
76 1.936491673f
, /* ACN 8 (U), sqrt(15)/2 */
77 2.091650066f
, /* ACN 9 (Q), sqrt(35/8) */
78 1.972026594f
, /* ACN 10 (O), sqrt(35)/3 */
79 2.231093404f
, /* ACN 11 (M), sqrt(224/45) */
80 2.645751311f
, /* ACN 12 (K), sqrt(7) */
81 2.231093404f
, /* ACN 13 (L), sqrt(224/45) */
82 1.972026594f
, /* ACN 14 (N), sqrt(35)/3 */
83 2.091650066f
, /* ACN 15 (P), sqrt(35/8) */
87 void CalcDirectionCoeffs(const ALfloat dir
[3], ALfloat coeffs
[MAX_AMBI_COEFFS
])
89 /* Convert from OpenAL coords to Ambisonics. */
95 coeffs
[0] = 1.0f
; /* ACN 0 = 1 */
97 coeffs
[1] = 1.732050808f
* y
; /* ACN 1 = sqrt(3) * Y */
98 coeffs
[2] = 1.732050808f
* z
; /* ACN 2 = sqrt(3) * Z */
99 coeffs
[3] = 1.732050808f
* x
; /* ACN 3 = sqrt(3) * X */
101 coeffs
[4] = 3.872983346f
* x
* y
; /* ACN 4 = sqrt(15) * X * Y */
102 coeffs
[5] = 3.872983346f
* y
* z
; /* ACN 5 = sqrt(15) * Y * Z */
103 coeffs
[6] = 1.118033989f
* (3.0f
*z
*z
- 1.0f
); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
104 coeffs
[7] = 3.872983346f
* x
* z
; /* ACN 7 = sqrt(15) * X * Z */
105 coeffs
[8] = 1.936491673f
* (x
*x
- y
*y
); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
107 coeffs
[9] = 2.091650066f
* y
* (3.0f
*x
*x
- y
*y
); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
108 coeffs
[10] = 10.246950766f
* z
* x
* y
; /* ACN 10 = sqrt(105) * Z * X * Y */
109 coeffs
[11] = 1.620185175f
* y
* (5.0f
*z
*z
- 1.0f
); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
110 coeffs
[12] = 1.322875656f
* z
* (5.0f
*z
*z
- 3.0f
); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
111 coeffs
[13] = 1.620185175f
* x
* (5.0f
*z
*z
- 1.0f
); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
112 coeffs
[14] = 5.123475383f
* z
* (x
*x
- y
*y
); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
113 coeffs
[15] = 2.091650066f
* x
* (x
*x
- 3.0f
*y
*y
); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
116 void CalcAngleCoeffs(ALfloat angle
, ALfloat elevation
, ALfloat coeffs
[MAX_AMBI_COEFFS
])
119 sinf(angle
) * cosf(elevation
),
121 -cosf(angle
) * cosf(elevation
)
123 CalcDirectionCoeffs(dir
, coeffs
);
127 void ComputeAmbientGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
131 for(i
= 0;i
< numchans
;i
++)
133 // The W coefficients are based on a mathematical average of the
134 // output. The square root of the base average provides for a more
135 // perceptual average volume, better suited to non-directional gains.
136 gains
[i
] = sqrtf(chancoeffs
[i
][0]) * ingain
;
138 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
142 void ComputePanningGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat coeffs
[MAX_AMBI_COEFFS
], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
146 for(i
= 0;i
< numchans
;i
++)
149 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
150 gain
+= chancoeffs
[i
][j
]*coeffs
[j
];
151 gains
[i
] = gain
* ingain
;
153 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
157 void ComputeFirstOrderGains(const ChannelConfig
*chancoeffs
, ALuint numchans
, const ALfloat mtx
[4], ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
161 for(i
= 0;i
< numchans
;i
++)
165 gain
+= chancoeffs
[i
][j
] * mtx
[j
];
166 gains
[i
] = gain
* ingain
;
168 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
173 DECL_CONST
static inline const char *GetLabelFromChannel(enum Channel channel
)
177 case FrontLeft
: return "front-left";
178 case FrontRight
: return "front-right";
179 case FrontCenter
: return "front-center";
180 case LFE
: return "lfe";
181 case BackLeft
: return "back-left";
182 case BackRight
: return "back-right";
183 case BackCenter
: return "back-center";
184 case SideLeft
: return "side-left";
185 case SideRight
: return "side-right";
187 case UpperFrontLeft
: return "upper-front-left";
188 case UpperFrontRight
: return "upper-front-right";
189 case UpperBackLeft
: return "upper-back-left";
190 case UpperBackRight
: return "upper-back-right";
191 case LowerFrontLeft
: return "lower-front-left";
192 case LowerFrontRight
: return "lower-front-right";
193 case LowerBackLeft
: return "lower-back-left";
194 case LowerBackRight
: return "lower-back-right";
196 case BFormatW
: return "bformat-w";
197 case BFormatX
: return "bformat-x";
198 case BFormatY
: return "bformat-y";
199 case BFormatZ
: return "bformat-z";
201 case InvalidChannel
: break;
207 typedef struct ChannelMap
{
208 enum Channel ChanName
;
209 ChannelConfig Config
;
212 static void SetChannelMap(const enum Channel
*devchans
, ChannelConfig
*ambicoeffs
,
213 const ChannelMap
*chanmap
, size_t count
, ALuint
*outcount
,
219 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
&& devchans
[i
] != InvalidChannel
;i
++)
221 if(devchans
[i
] == LFE
)
223 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
224 ambicoeffs
[i
][j
] = 0.0f
;
228 for(j
= 0;j
< count
;j
++)
230 if(devchans
[i
] != chanmap
[j
].ChanName
)
235 /* Reformat FuMa -> ACN/N3D */
236 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
238 ALuint acn
= FuMa2ACN
[k
];
239 ambicoeffs
[i
][acn
] = chanmap
[j
].Config
[k
] / FuMa2N3DScale
[acn
];
244 for(k
= 0;k
< MAX_AMBI_COEFFS
;++k
)
245 ambicoeffs
[i
][k
] = chanmap
[j
].Config
[k
];
250 ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans
[i
]), i
);
255 static bool LoadChannelSetup(ALCdevice
*device
)
257 static const enum Channel mono_chans
[1] = {
259 }, stereo_chans
[2] = {
260 FrontLeft
, FrontRight
262 FrontLeft
, FrontRight
,
264 }, surround51_chans
[5] = {
265 FrontLeft
, FrontRight
, FrontCenter
,
267 }, surround51rear_chans
[5] = {
268 FrontLeft
, FrontRight
, FrontCenter
,
270 }, surround61_chans
[6] = {
271 FrontLeft
, FrontRight
,
272 FrontCenter
, BackCenter
,
274 }, surround71_chans
[7] = {
275 FrontLeft
, FrontRight
, FrontCenter
,
279 ChannelMap chanmap
[MAX_OUTPUT_CHANNELS
];
280 const enum Channel
*channels
= NULL
;
281 const char *layout
= NULL
;
282 ALfloat ambiscale
= 1.0f
;
288 switch(device
->FmtChans
)
292 channels
= mono_chans
;
293 count
= COUNTOF(mono_chans
);
297 channels
= stereo_chans
;
298 count
= COUNTOF(stereo_chans
);
302 channels
= quad_chans
;
303 count
= COUNTOF(quad_chans
);
306 layout
= "surround51";
307 channels
= surround51_chans
;
308 count
= COUNTOF(surround51_chans
);
311 layout
= "surround51rear";
312 channels
= surround51rear_chans
;
313 count
= COUNTOF(surround51rear_chans
);
316 layout
= "surround61";
317 channels
= surround61_chans
;
318 count
= COUNTOF(surround61_chans
);
321 layout
= "surround71";
322 channels
= surround71_chans
;
323 count
= COUNTOF(surround71_chans
);
325 case DevFmtBFormat3D
:
337 snprintf(name
, sizeof(name
), "%s/type", layout
);
338 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", name
, &type
))
341 if(sscanf(type
, " %31[^: ] : %d%c", name
, &order
, &eol
) != 2)
343 ERR("Invalid type value '%s' (expected name:order) for layout %s\n", type
, layout
);
347 if(strcasecmp(name
, "fuma") == 0)
349 else if(strcasecmp(name
, "n3d") == 0)
353 ERR("Unhandled type name '%s' (expected FuMa or N3D) for layout %s\n", name
, layout
);
358 ambiscale
= THIRD_ORDER_SCALE
;
360 ambiscale
= SECOND_ORDER_SCALE
;
362 ambiscale
= FIRST_ORDER_SCALE
;
364 ambiscale
= ZERO_ORDER_SCALE
;
367 ERR("Unhandled type order %d (expected 0, 1, 2, or 3) for layout %s\n", order
, layout
);
372 for(i
= 0;i
< count
;i
++)
374 float coeffs
[MAX_AMBI_COEFFS
] = {0.0f
};
375 const char *channame
;
382 chanmap
[i
].ChanName
= channels
[i
];
383 channame
= GetLabelFromChannel(channels
[i
]);
385 snprintf(chanlayout
, sizeof(chanlayout
), "%s/%s", layout
, channame
);
386 if(!ConfigValueStr(al_string_get_cstr(device
->DeviceName
), "layouts", chanlayout
, &value
))
388 ERR("Missing channel %s\n", channame
);
392 props
= sscanf(value
, " %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %c",
393 &coeffs
[0], &coeffs
[1], &coeffs
[2], &coeffs
[3],
394 &coeffs
[4], &coeffs
[5], &coeffs
[6], &coeffs
[7],
395 &coeffs
[8], &coeffs
[9], &coeffs
[10], &coeffs
[11],
396 &coeffs
[12], &coeffs
[13], &coeffs
[14], &coeffs
[15],
400 props
= sscanf(value
, " %f %f %f %f %f %f %f %f %f %c",
401 &coeffs
[0], &coeffs
[1], &coeffs
[2],
402 &coeffs
[3], &coeffs
[4], &coeffs
[5],
403 &coeffs
[6], &coeffs
[7], &coeffs
[8],
407 props
= sscanf(value
, " %f %f %f %f %c",
408 &coeffs
[0], &coeffs
[1],
409 &coeffs
[2], &coeffs
[3],
413 props
= sscanf(value
, " %f %c", &coeffs
[0], &eol
);
416 ERR("Failed to parse option %s properties\n", chanlayout
);
420 if(props
> (order
+1)*(order
+1))
422 ERR("Excess elements in option %s (expected %d)\n", chanlayout
, (order
+1)*(order
+1));
426 for(j
= 0;j
< MAX_AMBI_COEFFS
;++j
)
427 chanmap
[i
].Config
[j
] = coeffs
[j
];
429 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
430 &device
->Dry
.NumChannels
, isfuma
);
431 device
->Dry
.AmbiScale
= ambiscale
;
435 ALvoid
aluInitPanning(ALCdevice
*device
)
437 /* NOTE: These decoder coefficients are using FuMa channel ordering and
438 * normalization, since that's what was produced by the Ambisonic Decoder
439 * Toolbox. SetChannelMap will convert them to N3D.
441 static const ChannelMap MonoCfg
[1] = {
442 { FrontCenter
, { 1.414213562f
} },
444 { FrontLeft
, { 0.707106781f
, 0.0f
, 0.5f
, 0.0f
} },
445 { FrontRight
, { 0.707106781f
, 0.0f
, -0.5f
, 0.0f
} },
447 { FrontLeft
, { 0.353553f
, 0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
448 { FrontRight
, { 0.353553f
, 0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
449 { BackLeft
, { 0.353553f
, -0.306184f
, 0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, -0.117186f
} },
450 { BackRight
, { 0.353553f
, -0.306184f
, -0.306184f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.000000f
, 0.117186f
} },
452 { FrontLeft
, { 0.208954f
, 0.212846f
, 0.238350f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.017738f
, 0.204014f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.051023f
, 0.047490f
} },
453 { FrontRight
, { 0.208954f
, 0.212846f
, -0.238350f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.017738f
, -0.204014f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.051023f
, -0.047490f
} },
454 { 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
} },
455 { SideLeft
, { 0.470936f
, -0.369626f
, 0.349386f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.031375f
, -0.058144f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.007119f
, -0.043968f
} },
456 { SideRight
, { 0.470936f
, -0.369626f
, -0.349386f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.031375f
, 0.058144f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.007119f
, 0.043968f
} },
458 { FrontLeft
, { 0.208954f
, 0.212846f
, 0.238350f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.017738f
, 0.204014f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.051023f
, 0.047490f
} },
459 { FrontRight
, { 0.208954f
, 0.212846f
, -0.238350f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.017738f
, -0.204014f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.051023f
, -0.047490f
} },
460 { 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
} },
461 { BackLeft
, { 0.470936f
, -0.369626f
, 0.349386f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.031375f
, -0.058144f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.007119f
, -0.043968f
} },
462 { BackRight
, { 0.470936f
, -0.369626f
, -0.349386f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.031375f
, 0.058144f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, -0.007119f
, 0.043968f
} },
464 { 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
} },
465 { 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
} },
466 { 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
} },
467 { 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
} },
468 { 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
} },
469 { 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
} },
471 { 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
} },
472 { 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
} },
473 { 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
} },
474 { 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
} },
475 { 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
} },
476 { 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
} },
477 { 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
} },
479 { UpperFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, 0.072168784f
} },
480 { UpperFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, 0.072168784f
} },
481 { UpperBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, 0.072168784f
} },
482 { UpperBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, 0.072168784f
} },
483 { LowerFrontLeft
, { 0.176776695f
, 0.072168784f
, 0.072168784f
, -0.072168784f
} },
484 { LowerFrontRight
, { 0.176776695f
, 0.072168784f
, -0.072168784f
, -0.072168784f
} },
485 { LowerBackLeft
, { 0.176776695f
, -0.072168784f
, 0.072168784f
, -0.072168784f
} },
486 { LowerBackRight
, { 0.176776695f
, -0.072168784f
, -0.072168784f
, -0.072168784f
} },
488 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
489 { BFormatX
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
490 { BFormatY
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
492 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
493 { BFormatX
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
494 { BFormatY
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
495 { BFormatZ
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
497 const ChannelMap
*chanmap
= NULL
;
498 ALfloat ambiscale
= 1.0f
;
502 device
->Dry
.AmbiScale
= 1.0f
;
503 memset(device
->Dry
.AmbiCoeffs
, 0, sizeof(device
->Dry
.AmbiCoeffs
));
504 device
->Dry
.NumChannels
= 0;
508 static const struct {
509 enum Channel Channel
;
513 { UpperFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD( 45.0f
) },
514 { UpperFrontRight
, DEG2RAD( 45.0f
), DEG2RAD( 45.0f
) },
515 { UpperBackLeft
, DEG2RAD(-135.0f
), DEG2RAD( 45.0f
) },
516 { UpperBackRight
, DEG2RAD( 135.0f
), DEG2RAD( 45.0f
) },
517 { LowerFrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(-45.0f
) },
518 { LowerFrontRight
, DEG2RAD( 45.0f
), DEG2RAD(-45.0f
) },
519 { LowerBackLeft
, DEG2RAD(-135.0f
), DEG2RAD(-45.0f
) },
520 { LowerBackRight
, DEG2RAD( 135.0f
), DEG2RAD(-45.0f
) },
523 count
= COUNTOF(Cube8Cfg
);
525 ambiscale
= FIRST_ORDER_SCALE
;
527 for(i
= 0;i
< count
;i
++)
528 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
529 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
530 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
531 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
532 &device
->Dry
.NumChannels
, AL_TRUE
);
533 device
->Dry
.AmbiScale
= ambiscale
;
535 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
537 int chan
= GetChannelIdxByName(device
, CubeInfo
[i
].Channel
);
538 GetLerpedHrtfCoeffs(device
->Hrtf
, CubeInfo
[i
].Elevation
, CubeInfo
[i
].Angle
, 1.0f
, 1.0f
,
539 device
->Hrtf_Params
[chan
].Coeffs
, device
->Hrtf_Params
[chan
].Delay
);
543 if(device
->Uhj_Encoder
)
545 count
= COUNTOF(BFormat2D
);
547 ambiscale
= FIRST_ORDER_SCALE
;
549 for(i
= 0;i
< count
;i
++)
550 device
->Dry
.ChannelName
[i
] = chanmap
[i
].ChanName
;
551 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
552 device
->Dry
.ChannelName
[i
] = InvalidChannel
;
553 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
554 &device
->Dry
.NumChannels
, AL_TRUE
);
555 device
->Dry
.AmbiScale
= ambiscale
;
560 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
561 device
->Dry
.ChannelName
[i
] = device
->RealOut
.ChannelName
[i
];
563 if(LoadChannelSetup(device
))
566 switch(device
->FmtChans
)
569 count
= COUNTOF(MonoCfg
);
571 ambiscale
= ZERO_ORDER_SCALE
;
575 count
= COUNTOF(StereoCfg
);
577 ambiscale
= FIRST_ORDER_SCALE
;
581 count
= COUNTOF(QuadCfg
);
583 ambiscale
= SECOND_ORDER_SCALE
;
587 count
= COUNTOF(X51SideCfg
);
588 chanmap
= X51SideCfg
;
589 ambiscale
= THIRD_ORDER_SCALE
;
593 count
= COUNTOF(X51RearCfg
);
594 chanmap
= X51RearCfg
;
595 ambiscale
= THIRD_ORDER_SCALE
;
599 count
= COUNTOF(X61Cfg
);
601 ambiscale
= THIRD_ORDER_SCALE
;
605 count
= COUNTOF(X71Cfg
);
607 ambiscale
= THIRD_ORDER_SCALE
;
610 case DevFmtBFormat3D
:
611 count
= COUNTOF(BFormat3D
);
617 SetChannelMap(device
->Dry
.ChannelName
, device
->Dry
.AmbiCoeffs
, chanmap
, count
,
618 &device
->Dry
.NumChannels
, AL_TRUE
);
619 device
->Dry
.AmbiScale
= ambiscale
;
622 void aluInitEffectPanning(ALeffectslot
*slot
)
624 static const ChannelMap FirstOrderN3D
[4] = {
625 { BFormatW
, { 1.0f
, 0.0f
, 0.0f
, 0.0f
} },
626 { BFormatY
, { 0.0f
, 1.0f
, 0.0f
, 0.0f
} },
627 { BFormatZ
, { 0.0f
, 0.0f
, 1.0f
, 0.0f
} },
628 { BFormatX
, { 0.0f
, 0.0f
, 0.0f
, 1.0f
} },
630 static const enum Channel AmbiChannels
[MAX_OUTPUT_CHANNELS
] = {
631 BFormatW
, BFormatY
, BFormatZ
, BFormatX
, InvalidChannel
634 memset(slot
->AmbiCoeffs
, 0, sizeof(slot
->AmbiCoeffs
));
635 slot
->NumChannels
= 0;
637 SetChannelMap(AmbiChannels
, slot
->AmbiCoeffs
, FirstOrderN3D
, COUNTOF(FirstOrderN3D
),
638 &slot
->NumChannels
, AL_FALSE
);