Use a macro to specify the ambisonic periphonic channel mask
[openal-soft.git] / Alc / panning.c
blob6949c56557874b118c1a0e786221f5260c6438aa
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "alAuxEffectSlot.h"
31 #include "alu.h"
32 #include "bool.h"
33 #include "ambdec.h"
34 #include "bformatdec.h"
35 #include "uhjfilter.h"
36 #include "bs2b.h"
39 extern inline void CalcXYZCoeffs(ALfloat x, ALfloat y, ALfloat z, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS]);
42 #define ZERO_ORDER_SCALE 0.0f
43 #define FIRST_ORDER_SCALE 1.0f
44 #define SECOND_ORDER_SCALE (1.0f / 1.22474f)
45 #define THIRD_ORDER_SCALE (1.0f / 1.30657f)
48 static const ALuint FuMa2ACN[MAX_AMBI_COEFFS] = {
49 0, /* W */
50 3, /* X */
51 1, /* Y */
52 2, /* Z */
53 6, /* R */
54 7, /* S */
55 5, /* T */
56 8, /* U */
57 4, /* V */
58 12, /* K */
59 13, /* L */
60 11, /* M */
61 14, /* N */
62 10, /* O */
63 15, /* P */
64 9, /* Q */
67 /* NOTE: These are scale factors as applied to Ambisonics content. Decoder
68 * coefficients should be divided by these values to get proper N3D scalings.
70 static const ALfloat UnitScale[MAX_AMBI_COEFFS] = {
71 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
72 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
74 static const ALfloat SN3D2N3DScale[MAX_AMBI_COEFFS] = {
75 1.000000000f, /* ACN 0 (W), sqrt(1) */
76 1.732050808f, /* ACN 1 (Y), sqrt(3) */
77 1.732050808f, /* ACN 2 (Z), sqrt(3) */
78 1.732050808f, /* ACN 3 (X), sqrt(3) */
79 2.236067978f, /* ACN 4 (V), sqrt(5) */
80 2.236067978f, /* ACN 5 (T), sqrt(5) */
81 2.236067978f, /* ACN 6 (R), sqrt(5) */
82 2.236067978f, /* ACN 7 (S), sqrt(5) */
83 2.236067978f, /* ACN 8 (U), sqrt(5) */
84 2.645751311f, /* ACN 9 (Q), sqrt(7) */
85 2.645751311f, /* ACN 10 (O), sqrt(7) */
86 2.645751311f, /* ACN 11 (M), sqrt(7) */
87 2.645751311f, /* ACN 12 (K), sqrt(7) */
88 2.645751311f, /* ACN 13 (L), sqrt(7) */
89 2.645751311f, /* ACN 14 (N), sqrt(7) */
90 2.645751311f, /* ACN 15 (P), sqrt(7) */
92 static const ALfloat FuMa2N3DScale[MAX_AMBI_COEFFS] = {
93 1.414213562f, /* ACN 0 (W), sqrt(2) */
94 1.732050808f, /* ACN 1 (Y), sqrt(3) */
95 1.732050808f, /* ACN 2 (Z), sqrt(3) */
96 1.732050808f, /* ACN 3 (X), sqrt(3) */
97 1.936491673f, /* ACN 4 (V), sqrt(15)/2 */
98 1.936491673f, /* ACN 5 (T), sqrt(15)/2 */
99 2.236067978f, /* ACN 6 (R), sqrt(5) */
100 1.936491673f, /* ACN 7 (S), sqrt(15)/2 */
101 1.936491673f, /* ACN 8 (U), sqrt(15)/2 */
102 2.091650066f, /* ACN 9 (Q), sqrt(35/8) */
103 1.972026594f, /* ACN 10 (O), sqrt(35)/3 */
104 2.231093404f, /* ACN 11 (M), sqrt(224/45) */
105 2.645751311f, /* ACN 12 (K), sqrt(7) */
106 2.231093404f, /* ACN 13 (L), sqrt(224/45) */
107 1.972026594f, /* ACN 14 (N), sqrt(35)/3 */
108 2.091650066f, /* ACN 15 (P), sqrt(35/8) */
112 void CalcDirectionCoeffs(const ALfloat dir[3], ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
114 /* Convert from OpenAL coords to Ambisonics. */
115 ALfloat x = -dir[2];
116 ALfloat y = -dir[0];
117 ALfloat z = dir[1];
119 /* Zeroth-order */
120 coeffs[0] = 1.0f; /* ACN 0 = 1 */
121 /* First-order */
122 coeffs[1] = 1.732050808f * y; /* ACN 1 = sqrt(3) * Y */
123 coeffs[2] = 1.732050808f * z; /* ACN 2 = sqrt(3) * Z */
124 coeffs[3] = 1.732050808f * x; /* ACN 3 = sqrt(3) * X */
125 /* Second-order */
126 coeffs[4] = 3.872983346f * x * y; /* ACN 4 = sqrt(15) * X * Y */
127 coeffs[5] = 3.872983346f * y * z; /* ACN 5 = sqrt(15) * Y * Z */
128 coeffs[6] = 1.118033989f * (3.0f*z*z - 1.0f); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
129 coeffs[7] = 3.872983346f * x * z; /* ACN 7 = sqrt(15) * X * Z */
130 coeffs[8] = 1.936491673f * (x*x - y*y); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
131 /* Third-order */
132 coeffs[9] = 2.091650066f * y * (3.0f*x*x - y*y); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
133 coeffs[10] = 10.246950766f * z * x * y; /* ACN 10 = sqrt(105) * Z * X * Y */
134 coeffs[11] = 1.620185175f * y * (5.0f*z*z - 1.0f); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
135 coeffs[12] = 1.322875656f * z * (5.0f*z*z - 3.0f); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
136 coeffs[13] = 1.620185175f * x * (5.0f*z*z - 1.0f); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
137 coeffs[14] = 5.123475383f * z * (x*x - y*y); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
138 coeffs[15] = 2.091650066f * x * (x*x - 3.0f*y*y); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
140 if(spread > 0.0f)
142 /* Implement the spread by using a spherical source that subtends the
143 * angle spread. See:
144 * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3
146 * The gain of the source is compensated for size, so that the
147 * loundness doesn't depend on the spread.
149 * ZH0 = (-sqrt_pi * (-1.f + ca));
150 * ZH1 = ( 0.5f*sqrtf(3.f)*sqrt_pi * sa*sa);
151 * ZH2 = (-0.5f*sqrtf(5.f)*sqrt_pi * ca*(-1.f+ca)*(ca+1.f));
152 * ZH3 = (-0.125f*sqrtf(7.f)*sqrt_pi * (-1.f+ca)*(ca+1.f)*(5.f*ca*ca-1.f));
153 * solidangle = 2.f*F_PI*(1.f-ca)
154 * size_normalisation_coef = 1.f/ZH0;
156 * This is then adjusted for N3D normalization over SN3D.
158 ALfloat ca = cosf(spread * 0.5f);
160 ALfloat ZH0_norm = 1.0f;
161 ALfloat ZH1_norm = 0.5f * (ca+1.f);
162 ALfloat ZH2_norm = 0.5f * (ca+1.f)*ca;
163 ALfloat ZH3_norm = 0.125f * (ca+1.f)*(5.f*ca*ca-1.f);
165 /* Zeroth-order */
166 coeffs[0] *= ZH0_norm;
167 /* First-order */
168 coeffs[1] *= ZH1_norm;
169 coeffs[2] *= ZH1_norm;
170 coeffs[3] *= ZH1_norm;
171 /* Second-order */
172 coeffs[4] *= ZH2_norm;
173 coeffs[5] *= ZH2_norm;
174 coeffs[6] *= ZH2_norm;
175 coeffs[7] *= ZH2_norm;
176 coeffs[8] *= ZH2_norm;
177 /* Third-order */
178 coeffs[9] *= ZH3_norm;
179 coeffs[10] *= ZH3_norm;
180 coeffs[11] *= ZH3_norm;
181 coeffs[12] *= ZH3_norm;
182 coeffs[13] *= ZH3_norm;
183 coeffs[14] *= ZH3_norm;
184 coeffs[15] *= ZH3_norm;
188 void CalcAngleCoeffs(ALfloat azimuth, ALfloat elevation, ALfloat spread, ALfloat coeffs[MAX_AMBI_COEFFS])
190 ALfloat dir[3] = {
191 sinf(azimuth) * cosf(elevation),
192 sinf(elevation),
193 -cosf(azimuth) * cosf(elevation)
195 CalcDirectionCoeffs(dir, spread, coeffs);
199 void ComputeAmbientGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
201 ALuint i;
203 for(i = 0;i < numchans;i++)
205 // The W coefficients are based on a mathematical average of the
206 // output. The square root of the base average provides for a more
207 // perceptual average volume, better suited to non-directional gains.
208 gains[i] = sqrtf(chancoeffs[i][0]) * ingain;
210 for(;i < MAX_OUTPUT_CHANNELS;i++)
211 gains[i] = 0.0f;
214 void ComputeAmbientGainsBF(const BFChannelConfig *chanmap, ALuint numchans, ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
216 ALfloat gain = 0.0f;
217 ALuint i;
219 for(i = 0;i < numchans;i++)
221 if(chanmap[i].Index == 0)
222 gain += chanmap[i].Scale;
224 gains[0] = gain * 1.414213562f * ingain;
225 for(i = 1;i < MAX_OUTPUT_CHANNELS;i++)
226 gains[i] = 0.0f;
229 void ComputePanningGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, ALuint numcoeffs, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
231 ALuint i, j;
233 for(i = 0;i < numchans;i++)
235 float gain = 0.0f;
236 for(j = 0;j < numcoeffs;j++)
237 gain += chancoeffs[i][j]*coeffs[j];
238 gains[i] = gain * ingain;
240 for(;i < MAX_OUTPUT_CHANNELS;i++)
241 gains[i] = 0.0f;
244 void ComputePanningGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat coeffs[MAX_AMBI_COEFFS], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
246 ALuint i;
248 for(i = 0;i < numchans;i++)
249 gains[i] = chanmap[i].Scale * coeffs[chanmap[i].Index] * ingain;
250 for(;i < MAX_OUTPUT_CHANNELS;i++)
251 gains[i] = 0.0f;
254 void ComputeFirstOrderGainsMC(const ChannelConfig *chancoeffs, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
256 ALuint i, j;
258 for(i = 0;i < numchans;i++)
260 float gain = 0.0f;
261 for(j = 0;j < 4;j++)
262 gain += chancoeffs[i][j] * mtx[j];
263 gains[i] = gain * ingain;
265 for(;i < MAX_OUTPUT_CHANNELS;i++)
266 gains[i] = 0.0f;
269 void ComputeFirstOrderGainsBF(const BFChannelConfig *chanmap, ALuint numchans, const ALfloat mtx[4], ALfloat ingain, ALfloat gains[MAX_OUTPUT_CHANNELS])
271 ALuint i;
273 for(i = 0;i < numchans;i++)
274 gains[i] = chanmap[i].Scale * mtx[chanmap[i].Index] * ingain;
275 for(;i < MAX_OUTPUT_CHANNELS;i++)
276 gains[i] = 0.0f;
280 DECL_CONST static inline const char *GetLabelFromChannel(enum Channel channel)
282 switch(channel)
284 case FrontLeft: return "front-left";
285 case FrontRight: return "front-right";
286 case FrontCenter: return "front-center";
287 case LFE: return "lfe";
288 case BackLeft: return "back-left";
289 case BackRight: return "back-right";
290 case BackCenter: return "back-center";
291 case SideLeft: return "side-left";
292 case SideRight: return "side-right";
294 case UpperFrontLeft: return "upper-front-left";
295 case UpperFrontRight: return "upper-front-right";
296 case UpperBackLeft: return "upper-back-left";
297 case UpperBackRight: return "upper-back-right";
298 case LowerFrontLeft: return "lower-front-left";
299 case LowerFrontRight: return "lower-front-right";
300 case LowerBackLeft: return "lower-back-left";
301 case LowerBackRight: return "lower-back-right";
303 case Aux0: return "aux-0";
304 case Aux1: return "aux-1";
305 case Aux2: return "aux-2";
306 case Aux3: return "aux-3";
307 case Aux4: return "aux-4";
308 case Aux5: return "aux-5";
309 case Aux6: return "aux-6";
310 case Aux7: return "aux-7";
311 case Aux8: return "aux-8";
312 case Aux9: return "aux-9";
313 case Aux10: return "aux-10";
314 case Aux11: return "aux-11";
315 case Aux12: return "aux-12";
316 case Aux13: return "aux-13";
317 case Aux14: return "aux-14";
318 case Aux15: return "aux-15";
320 case InvalidChannel: break;
322 return "(unknown)";
326 typedef struct ChannelMap {
327 enum Channel ChanName;
328 ChannelConfig Config;
329 } ChannelMap;
331 static void SetChannelMap(const enum Channel *devchans, ChannelConfig *ambicoeffs,
332 const ChannelMap *chanmap, size_t count, ALuint *outcount,
333 ALboolean isfuma)
335 size_t j, k;
336 ALuint i;
338 for(i = 0;i < MAX_OUTPUT_CHANNELS && devchans[i] != InvalidChannel;i++)
340 if(devchans[i] == LFE)
342 for(j = 0;j < MAX_AMBI_COEFFS;j++)
343 ambicoeffs[i][j] = 0.0f;
344 continue;
347 for(j = 0;j < count;j++)
349 if(devchans[i] != chanmap[j].ChanName)
350 continue;
352 if(isfuma)
354 /* Reformat FuMa -> ACN/N3D */
355 for(k = 0;k < MAX_AMBI_COEFFS;++k)
357 ALuint acn = FuMa2ACN[k];
358 ambicoeffs[i][acn] = chanmap[j].Config[k] / FuMa2N3DScale[acn];
361 else
363 for(k = 0;k < MAX_AMBI_COEFFS;++k)
364 ambicoeffs[i][k] = chanmap[j].Config[k];
366 break;
368 if(j == count)
369 ERR("Failed to match %s channel (%u) in channel map\n", GetLabelFromChannel(devchans[i]), i);
371 *outcount = i;
374 static bool MakeSpeakerMap(ALCdevice *device, const AmbDecConf *conf, ALuint speakermap[MAX_OUTPUT_CHANNELS])
376 ALuint i;
378 for(i = 0;i < conf->NumSpeakers;i++)
380 int c = -1;
382 /* NOTE: AmbDec does not define any standard speaker names, however
383 * for this to work we have to by able to find the output channel
384 * the speaker definition corresponds to. Therefore, OpenAL Soft
385 * requires these channel labels to be recognized:
387 * LF = Front left
388 * RF = Front right
389 * LS = Side left
390 * RS = Side right
391 * LB = Back left
392 * RB = Back right
393 * CE = Front center
394 * CB = Back center
396 * Additionally, surround51 will acknowledge back speakers for side
397 * channels, and surround51rear will acknowledge side speakers for
398 * back channels, to avoid issues with an ambdec expecting 5.1 to
399 * use the side channels when the device is configured for back,
400 * and vice-versa.
402 if(al_string_cmp_cstr(conf->Speakers[i].Name, "LF") == 0)
403 c = GetChannelIdxByName(device->RealOut, FrontLeft);
404 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RF") == 0)
405 c = GetChannelIdxByName(device->RealOut, FrontRight);
406 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CE") == 0)
407 c = GetChannelIdxByName(device->RealOut, FrontCenter);
408 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LS") == 0)
410 if(device->FmtChans == DevFmtX51Rear)
411 c = GetChannelIdxByName(device->RealOut, BackLeft);
412 else
413 c = GetChannelIdxByName(device->RealOut, SideLeft);
415 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RS") == 0)
417 if(device->FmtChans == DevFmtX51Rear)
418 c = GetChannelIdxByName(device->RealOut, BackRight);
419 else
420 c = GetChannelIdxByName(device->RealOut, SideRight);
422 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "LB") == 0)
424 if(device->FmtChans == DevFmtX51)
425 c = GetChannelIdxByName(device->RealOut, SideLeft);
426 else
427 c = GetChannelIdxByName(device->RealOut, BackLeft);
429 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "RB") == 0)
431 if(device->FmtChans == DevFmtX51)
432 c = GetChannelIdxByName(device->RealOut, SideRight);
433 else
434 c = GetChannelIdxByName(device->RealOut, BackRight);
436 else if(al_string_cmp_cstr(conf->Speakers[i].Name, "CB") == 0)
437 c = GetChannelIdxByName(device->RealOut, BackCenter);
438 else
440 const char *name = al_string_get_cstr(conf->Speakers[i].Name);
441 unsigned int n;
442 char ch;
444 if(sscanf(name, "AUX%u%c", &n, &ch) == 1 && n < 16)
445 c = GetChannelIdxByName(device->RealOut, Aux0+n);
446 else
448 ERR("AmbDec speaker label \"%s\" not recognized\n", name);
449 return false;
452 if(c == -1)
454 ERR("Failed to lookup AmbDec speaker label %s\n",
455 al_string_get_cstr(conf->Speakers[i].Name));
456 return false;
458 speakermap[i] = c;
461 return true;
465 /* NOTE: These decoder coefficients are using FuMa channel ordering and
466 * normalization, since that's what was produced by the Ambisonic Decoder
467 * Toolbox. SetChannelMap will convert them to N3D.
469 static const ChannelMap MonoCfg[1] = {
470 { FrontCenter, { 1.414213562f } },
471 }, StereoCfg[2] = {
472 { FrontLeft, { 0.707106781f, 0.0f, 0.5f, 0.0f } },
473 { FrontRight, { 0.707106781f, 0.0f, -0.5f, 0.0f } },
474 }, QuadCfg[4] = {
475 { FrontLeft, { 0.353553f, 0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
476 { FrontRight, { 0.353553f, 0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
477 { BackLeft, { 0.353553f, -0.306184f, 0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, -0.117186f } },
478 { BackRight, { 0.353553f, -0.306184f, -0.306184f, 0.0f, 0.0f, 0.0f, 0.0f, 0.000000f, 0.117186f } },
479 }, X51SideCfg[5] = {
480 { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } },
481 { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } },
482 { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } },
483 { SideLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } },
484 { SideRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } },
485 }, X51RearCfg[5] = {
486 { FrontLeft, { 0.208954f, 0.199518f, 0.223424f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012543f, 0.144260f } },
487 { FrontRight, { 0.208950f, 0.199514f, -0.223425f, 0.0f, 0.0f, 0.0f, 0.0f, -0.012544f, -0.144258f } },
488 { FrontCenter, { 0.109403f, 0.168250f, -0.000002f, 0.0f, 0.0f, 0.0f, 0.0f, 0.100431f, -0.000001f } },
489 { BackLeft, { 0.470934f, -0.346484f, 0.327504f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022188f, -0.041113f } },
490 { BackRight, { 0.470936f, -0.346480f, -0.327507f, 0.0f, 0.0f, 0.0f, 0.0f, -0.022186f, 0.041114f } },
491 }, X61Cfg[6] = {
492 { 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 } },
493 { 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 } },
494 { 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 } },
495 { 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 } },
496 { 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 } },
497 { 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 }, X71Cfg[7] = {
499 { 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 } },
500 { 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 } },
501 { 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 } },
502 { 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 } },
503 { 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 } },
504 { 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 } },
505 { 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 } },
508 static void InitPanning(ALCdevice *device)
510 const ChannelMap *chanmap = NULL;
511 ALuint coeffcount = 0;
512 ALfloat ambiscale;
513 size_t count = 0;
514 ALuint i, j;
516 ambiscale = 1.0f;
517 switch(device->FmtChans)
519 case DevFmtMono:
520 count = COUNTOF(MonoCfg);
521 chanmap = MonoCfg;
522 ambiscale = ZERO_ORDER_SCALE;
523 coeffcount = 1;
524 break;
526 case DevFmtStereo:
527 count = COUNTOF(StereoCfg);
528 chanmap = StereoCfg;
529 ambiscale = FIRST_ORDER_SCALE;
530 coeffcount = 4;
531 break;
533 case DevFmtQuad:
534 count = COUNTOF(QuadCfg);
535 chanmap = QuadCfg;
536 ambiscale = SECOND_ORDER_SCALE;
537 coeffcount = 9;
538 break;
540 case DevFmtX51:
541 count = COUNTOF(X51SideCfg);
542 chanmap = X51SideCfg;
543 ambiscale = SECOND_ORDER_SCALE;
544 coeffcount = 9;
545 break;
547 case DevFmtX51Rear:
548 count = COUNTOF(X51RearCfg);
549 chanmap = X51RearCfg;
550 ambiscale = SECOND_ORDER_SCALE;
551 coeffcount = 9;
552 break;
554 case DevFmtX61:
555 count = COUNTOF(X61Cfg);
556 chanmap = X61Cfg;
557 ambiscale = THIRD_ORDER_SCALE;
558 coeffcount = 16;
559 break;
561 case DevFmtX71:
562 count = COUNTOF(X71Cfg);
563 chanmap = X71Cfg;
564 ambiscale = THIRD_ORDER_SCALE;
565 coeffcount = 16;
566 break;
568 case DevFmtBFormat3D:
569 break;
572 if(device->FmtChans == DevFmtBFormat3D)
574 count = 4;
575 for(i = 0;i < count;i++)
577 ALuint acn = FuMa2ACN[i];
578 device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn];
579 device->Dry.Ambi.Map[i].Index = acn;
581 device->Dry.CoeffCount = 0;
582 device->Dry.NumChannels = count;
584 memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi));
585 device->FOAOut.CoeffCount = device->Dry.CoeffCount;
587 else
589 SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs,
590 chanmap, count, &device->Dry.NumChannels, AL_TRUE);
591 device->Dry.CoeffCount = coeffcount;
593 memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
594 for(i = 0;i < device->Dry.NumChannels;i++)
596 device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0];
597 for(j = 1;j < 4;j++)
598 device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale;
600 device->FOAOut.CoeffCount = 4;
604 static void InitCustomPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS])
606 ChannelMap chanmap[MAX_OUTPUT_CHANNELS];
607 const ALfloat *coeff_scale = UnitScale;
608 ALfloat ambiscale = 1.0f;
609 ALuint i, j;
611 if(conf->FreqBands != 1)
612 ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n",
613 conf->XOverFreq);
615 if(conf->ChanMask > 0x1ff)
616 ambiscale = THIRD_ORDER_SCALE;
617 else if(conf->ChanMask > 0xf)
618 ambiscale = SECOND_ORDER_SCALE;
619 else if(conf->ChanMask > 0x1)
620 ambiscale = FIRST_ORDER_SCALE;
621 else
622 ambiscale = 0.0f;
624 if(conf->CoeffScale == ADS_SN3D)
625 coeff_scale = SN3D2N3DScale;
626 else if(conf->CoeffScale == ADS_FuMa)
627 coeff_scale = FuMa2N3DScale;
629 for(i = 0;i < conf->NumSpeakers;i++)
631 ALuint chan = speakermap[i];
632 ALfloat gain;
633 ALuint k = 0;
635 for(j = 0;j < MAX_AMBI_COEFFS;j++)
636 chanmap[i].Config[j] = 0.0f;
638 chanmap[i].ChanName = device->RealOut.ChannelName[chan];
639 for(j = 0;j < MAX_AMBI_COEFFS;j++)
641 if(j == 0) gain = conf->HFOrderGain[0];
642 else if(j == 1) gain = conf->HFOrderGain[1];
643 else if(j == 4) gain = conf->HFOrderGain[2];
644 else if(j == 9) gain = conf->HFOrderGain[3];
645 if((conf->ChanMask&(1<<j)))
646 chanmap[i].Config[j] = conf->HFMatrix[i][k++] / coeff_scale[j] * gain;
650 SetChannelMap(device->RealOut.ChannelName, device->Dry.Ambi.Coeffs, chanmap,
651 conf->NumSpeakers, &device->Dry.NumChannels, AL_FALSE);
652 device->Dry.CoeffCount = (conf->ChanMask > 0x1ff) ? 16 :
653 (conf->ChanMask > 0xf) ? 9 : 4;
655 memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
656 for(i = 0;i < device->Dry.NumChannels;i++)
658 device->FOAOut.Ambi.Coeffs[i][0] = device->Dry.Ambi.Coeffs[i][0];
659 for(j = 1;j < 4;j++)
660 device->FOAOut.Ambi.Coeffs[i][j] = device->Dry.Ambi.Coeffs[i][j] * ambiscale;
662 device->FOAOut.CoeffCount = 4;
665 static void InitHQPanning(ALCdevice *device, const AmbDecConf *conf, const ALuint speakermap[MAX_OUTPUT_CHANNELS])
667 const char *devname;
668 int decflags = 0;
669 size_t count;
670 ALuint i;
672 devname = al_string_get_cstr(device->DeviceName);
673 if(GetConfigValueBool(devname, "decoder", "distance-comp", 1))
674 decflags |= BFDF_DistanceComp;
676 if((conf->ChanMask&AMBI_PERIPHONIC_MASK))
678 count = (conf->ChanMask > 0x1ff) ? 16 :
679 (conf->ChanMask > 0xf) ? 9 : 4;
680 for(i = 0;i < count;i++)
682 device->Dry.Ambi.Map[i].Scale = 1.0f;
683 device->Dry.Ambi.Map[i].Index = i;
686 else
688 static int map[MAX_AMBI_COEFFS] = { 0, 1, 3, 4, 8, 9, 15 };
690 count = (conf->ChanMask > 0x1ff) ? 7 :
691 (conf->ChanMask > 0xf) ? 5 : 3;
692 for(i = 0;i < count;i++)
694 device->Dry.Ambi.Map[i].Scale = 1.0f;
695 device->Dry.Ambi.Map[i].Index = map[i];
698 device->Dry.CoeffCount = 0;
699 device->Dry.NumChannels = count;
701 TRACE("Enabling %s-band %s-order%s ambisonic decoder\n",
702 (conf->FreqBands == 1) ? "single" : "dual",
703 (conf->ChanMask > 0xf) ? (conf->ChanMask > 0x1ff) ? "third" : "second" : "first",
704 (conf->ChanMask&AMBI_PERIPHONIC_MASK) ? " periphonic" : ""
706 bformatdec_reset(device->AmbiDecoder, conf, count, device->Frequency,
707 speakermap, decflags);
709 if(bformatdec_getOrder(device->AmbiDecoder) < 2)
711 memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi));
712 device->FOAOut.CoeffCount = device->Dry.CoeffCount;
714 else
716 memset(&device->FOAOut.Ambi, 0, sizeof(device->FOAOut.Ambi));
717 for(i = 0;i < 4;i++)
719 device->FOAOut.Ambi.Map[i].Scale = 1.0f;
720 device->FOAOut.Ambi.Map[i].Index = i;
722 device->FOAOut.CoeffCount = 0;
726 static void InitHrtfPanning(ALCdevice *device)
728 static const enum Channel CubeChannels[MAX_OUTPUT_CHANNELS] = {
729 UpperFrontLeft, UpperFrontRight, UpperBackLeft, UpperBackRight,
730 LowerFrontLeft, LowerFrontRight, LowerBackLeft, LowerBackRight,
731 InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel,
732 InvalidChannel, InvalidChannel, InvalidChannel, InvalidChannel
734 static const ChannelMap Cube8Cfg[8] = {
735 { UpperFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, 0.072168784f } },
736 { UpperFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, 0.072168784f } },
737 { UpperBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, 0.072168784f } },
738 { UpperBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, 0.072168784f } },
739 { LowerFrontLeft, { 0.176776695f, 0.072168784f, 0.072168784f, -0.072168784f } },
740 { LowerFrontRight, { 0.176776695f, 0.072168784f, -0.072168784f, -0.072168784f } },
741 { LowerBackLeft, { 0.176776695f, -0.072168784f, 0.072168784f, -0.072168784f } },
742 { LowerBackRight, { 0.176776695f, -0.072168784f, -0.072168784f, -0.072168784f } },
744 static const struct {
745 enum Channel Channel;
746 ALfloat Angle;
747 ALfloat Elevation;
748 } CubeInfo[8] = {
749 { UpperFrontLeft, DEG2RAD( -45.0f), DEG2RAD( 45.0f) },
750 { UpperFrontRight, DEG2RAD( 45.0f), DEG2RAD( 45.0f) },
751 { UpperBackLeft, DEG2RAD(-135.0f), DEG2RAD( 45.0f) },
752 { UpperBackRight, DEG2RAD( 135.0f), DEG2RAD( 45.0f) },
753 { LowerFrontLeft, DEG2RAD( -45.0f), DEG2RAD(-45.0f) },
754 { LowerFrontRight, DEG2RAD( 45.0f), DEG2RAD(-45.0f) },
755 { LowerBackLeft, DEG2RAD(-135.0f), DEG2RAD(-45.0f) },
756 { LowerBackRight, DEG2RAD( 135.0f), DEG2RAD(-45.0f) },
758 const ChannelMap *chanmap = Cube8Cfg;
759 size_t count = COUNTOF(Cube8Cfg);
760 ALuint i;
762 SetChannelMap(CubeChannels, device->Dry.Ambi.Coeffs, chanmap, count,
763 &device->Dry.NumChannels, AL_TRUE);
764 device->Dry.CoeffCount = 4;
766 memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi));
767 device->FOAOut.CoeffCount = device->Dry.CoeffCount;
769 for(i = 0;i < device->Dry.NumChannels;i++)
771 int chan = GetChannelIndex(CubeChannels, CubeInfo[i].Channel);
772 GetLerpedHrtfCoeffs(device->Hrtf, CubeInfo[i].Elevation, CubeInfo[i].Angle, 1.0f, 0.0f,
773 device->Hrtf_Params[chan].Coeffs, device->Hrtf_Params[chan].Delay);
777 static void InitUhjPanning(ALCdevice *device)
779 size_t count = 3;
780 ALuint i;
782 for(i = 0;i < count;i++)
784 ALuint acn = FuMa2ACN[i];
785 device->Dry.Ambi.Map[i].Scale = 1.0f/FuMa2N3DScale[acn];
786 device->Dry.Ambi.Map[i].Index = acn;
788 device->Dry.CoeffCount = 0;
789 device->Dry.NumChannels = count;
791 memcpy(&device->FOAOut.Ambi, &device->Dry.Ambi, sizeof(device->FOAOut.Ambi));
792 device->FOAOut.CoeffCount = device->Dry.CoeffCount;
795 void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq)
797 const char *mode;
798 bool headphones;
799 int bs2blevel;
800 size_t i;
802 device->Hrtf = NULL;
803 al_string_clear(&device->Hrtf_Name);
804 device->Render_Mode = NormalRender;
806 memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi));
807 device->Dry.CoeffCount = 0;
808 device->Dry.NumChannels = 0;
810 if(device->FmtChans != DevFmtStereo)
812 ALuint speakermap[MAX_OUTPUT_CHANNELS];
813 const char *devname, *layout = NULL;
814 AmbDecConf conf, *pconf = NULL;
816 if(hrtf_appreq == Hrtf_Enable)
817 device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
819 ambdec_init(&conf);
821 devname = al_string_get_cstr(device->DeviceName);
822 switch(device->FmtChans)
824 case DevFmtQuad: layout = "quad"; break;
825 case DevFmtX51: layout = "surround51"; break;
826 case DevFmtX51Rear: layout = "surround51rear"; break;
827 case DevFmtX61: layout = "surround61"; break;
828 case DevFmtX71: layout = "surround71"; break;
829 /* Mono, Stereo, and B-Fornat output don't use custom decoders. */
830 case DevFmtMono:
831 case DevFmtStereo:
832 case DevFmtBFormat3D:
833 break;
835 if(layout)
837 const char *fname;
838 if(ConfigValueStr(devname, "decoder", layout, &fname))
840 if(!ambdec_load(&conf, fname))
841 ERR("Failed to load layout file %s\n", fname);
842 else
844 if(conf.ChanMask > 0xffff)
845 ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask);
846 else
848 if(MakeSpeakerMap(device, &conf, speakermap))
849 pconf = &conf;
855 if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0))
857 if(!device->AmbiDecoder)
858 device->AmbiDecoder = bformatdec_alloc();
860 else
862 bformatdec_free(device->AmbiDecoder);
863 device->AmbiDecoder = NULL;
866 if(!pconf)
867 InitPanning(device);
868 else if(device->AmbiDecoder)
869 InitHQPanning(device, pconf, speakermap);
870 else
871 InitCustomPanning(device, pconf, speakermap);
873 ambdec_deinit(&conf);
874 return;
877 bformatdec_free(device->AmbiDecoder);
878 device->AmbiDecoder = NULL;
880 headphones = device->IsHeadphones;
881 if(device->Type != Loopback)
883 const char *mode;
884 if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode))
886 if(strcasecmp(mode, "headphones") == 0)
887 headphones = true;
888 else if(strcasecmp(mode, "speakers") == 0)
889 headphones = false;
890 else if(strcasecmp(mode, "auto") != 0)
891 ERR("Unexpected stereo-mode: %s\n", mode);
895 if(hrtf_userreq == Hrtf_Default)
897 bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) ||
898 (hrtf_appreq == Hrtf_Enable);
899 if(!usehrtf) goto no_hrtf;
901 device->Hrtf_Status = ALC_HRTF_ENABLED_SOFT;
902 if(headphones && hrtf_appreq != Hrtf_Disable)
903 device->Hrtf_Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT;
905 else
907 if(hrtf_userreq != Hrtf_Enable)
909 if(hrtf_appreq == Hrtf_Enable)
910 device->Hrtf_Status = ALC_HRTF_DENIED_SOFT;
911 goto no_hrtf;
913 device->Hrtf_Status = ALC_HRTF_REQUIRED_SOFT;
916 if(VECTOR_SIZE(device->Hrtf_List) == 0)
918 VECTOR_DEINIT(device->Hrtf_List);
919 device->Hrtf_List = EnumerateHrtf(device->DeviceName);
922 if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List))
924 const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id);
925 if(GetHrtfSampleRate(entry->hrtf) == device->Frequency)
927 device->Hrtf = entry->hrtf;
928 al_string_copy(&device->Hrtf_Name, entry->name);
932 for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++)
934 const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i);
935 if(GetHrtfSampleRate(entry->hrtf) == device->Frequency)
937 device->Hrtf = entry->hrtf;
938 al_string_copy(&device->Hrtf_Name, entry->name);
942 if(device->Hrtf)
944 device->Render_Mode = HrtfRender;
945 if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode))
947 if(strcasecmp(mode, "full") == 0)
948 device->Render_Mode = HrtfRender;
949 else if(strcasecmp(mode, "basic") == 0)
950 device->Render_Mode = NormalRender;
951 else
952 ERR("Unexpected hrtf-mode: %s\n", mode);
955 TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name));
956 InitHrtfPanning(device);
957 return;
959 device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT;
961 no_hrtf:
962 TRACE("HRTF disabled\n");
964 bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) ||
965 (hrtf_appreq == Hrtf_Enable)) ? 5 : 0;
966 if(device->Type != Loopback)
967 ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel);
968 if(bs2blevel > 0 && bs2blevel <= 6)
970 device->Bs2b = al_calloc(16, sizeof(*device->Bs2b));
971 bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency);
972 device->Render_Mode = StereoPair;
973 TRACE("BS2B enabled\n");
974 InitPanning(device);
975 return;
978 TRACE("BS2B disabled\n");
980 device->Render_Mode = NormalRender;
981 if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode))
983 if(strcasecmp(mode, "paired") == 0)
984 device->Render_Mode = StereoPair;
985 else if(strcasecmp(mode, "uhj") != 0)
986 ERR("Unexpected stereo-panning: %s\n", mode);
988 if(device->Render_Mode == NormalRender)
990 device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder));
991 TRACE("UHJ enabled\n");
992 InitUhjPanning(device);
993 return;
996 TRACE("UHJ disabled\n");
997 InitPanning(device);
1001 void aluInitEffectPanning(ALeffectslot *slot)
1003 ALuint i;
1005 memset(slot->ChanMap, 0, sizeof(slot->ChanMap));
1006 slot->NumChannels = 0;
1008 for(i = 0;i < MAX_EFFECT_CHANNELS;i++)
1010 slot->ChanMap[i].Scale = 1.0f;
1011 slot->ChanMap[i].Index = i;
1013 slot->NumChannels = i;