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"
35 #include "filters/splitter.h"
36 #include "uhjfilter.h"
42 constexpr ALsizei FuMa2ACN
[MAX_AMBI_COEFFS
] = {
60 constexpr ALsizei ACN2ACN
[MAX_AMBI_COEFFS
] = {
61 0, 1, 2, 3, 4, 5, 6, 7,
62 8, 9, 10, 11, 12, 13, 14, 15
67 void CalcAmbiCoeffs(const ALfloat y
, const ALfloat z
, const ALfloat x
, const ALfloat spread
,
68 ALfloat coeffs
[MAX_AMBI_COEFFS
])
71 coeffs
[0] = 1.0f
; /* ACN 0 = 1 */
73 coeffs
[1] = SQRTF_3
* y
; /* ACN 1 = sqrt(3) * Y */
74 coeffs
[2] = SQRTF_3
* z
; /* ACN 2 = sqrt(3) * Z */
75 coeffs
[3] = SQRTF_3
* x
; /* ACN 3 = sqrt(3) * X */
77 coeffs
[4] = 3.872983346f
* x
* y
; /* ACN 4 = sqrt(15) * X * Y */
78 coeffs
[5] = 3.872983346f
* y
* z
; /* ACN 5 = sqrt(15) * Y * Z */
79 coeffs
[6] = 1.118033989f
* (3.0f
*z
*z
- 1.0f
); /* ACN 6 = sqrt(5)/2 * (3*Z*Z - 1) */
80 coeffs
[7] = 3.872983346f
* x
* z
; /* ACN 7 = sqrt(15) * X * Z */
81 coeffs
[8] = 1.936491673f
* (x
*x
- y
*y
); /* ACN 8 = sqrt(15)/2 * (X*X - Y*Y) */
83 coeffs
[9] = 2.091650066f
* y
* (3.0f
*x
*x
- y
*y
); /* ACN 9 = sqrt(35/8) * Y * (3*X*X - Y*Y) */
84 coeffs
[10] = 10.246950766f
* z
* x
* y
; /* ACN 10 = sqrt(105) * Z * X * Y */
85 coeffs
[11] = 1.620185175f
* y
* (5.0f
*z
*z
- 1.0f
); /* ACN 11 = sqrt(21/8) * Y * (5*Z*Z - 1) */
86 coeffs
[12] = 1.322875656f
* z
* (5.0f
*z
*z
- 3.0f
); /* ACN 12 = sqrt(7)/2 * Z * (5*Z*Z - 3) */
87 coeffs
[13] = 1.620185175f
* x
* (5.0f
*z
*z
- 1.0f
); /* ACN 13 = sqrt(21/8) * X * (5*Z*Z - 1) */
88 coeffs
[14] = 5.123475383f
* z
* (x
*x
- y
*y
); /* ACN 14 = sqrt(105)/2 * Z * (X*X - Y*Y) */
89 coeffs
[15] = 2.091650066f
* x
* (x
*x
- 3.0f
*y
*y
); /* ACN 15 = sqrt(35/8) * X * (X*X - 3*Y*Y) */
93 /* Implement the spread by using a spherical source that subtends the
95 * http://www.ppsloan.org/publications/StupidSH36.pdf - Appendix A3
97 * When adjusted for N3D normalization instead of SN3D, these
100 * ZH0 = -sqrt(pi) * (-1+ca);
101 * ZH1 = 0.5*sqrt(pi) * sa*sa;
102 * ZH2 = -0.5*sqrt(pi) * ca*(-1+ca)*(ca+1);
103 * ZH3 = -0.125*sqrt(pi) * (-1+ca)*(ca+1)*(5*ca*ca - 1);
104 * ZH4 = -0.125*sqrt(pi) * ca*(-1+ca)*(ca+1)*(7*ca*ca - 3);
105 * ZH5 = -0.0625*sqrt(pi) * (-1+ca)*(ca+1)*(21*ca*ca*ca*ca - 14*ca*ca + 1);
107 * The gain of the source is compensated for size, so that the
108 * loundness doesn't depend on the spread. Thus:
111 * ZH1 = 0.5f * (ca+1.0f);
112 * ZH2 = 0.5f * (ca+1.0f)*ca;
113 * ZH3 = 0.125f * (ca+1.0f)*(5.0f*ca*ca - 1.0f);
114 * ZH4 = 0.125f * (ca+1.0f)*(7.0f*ca*ca - 3.0f)*ca;
115 * ZH5 = 0.0625f * (ca+1.0f)*(21.0f*ca*ca*ca*ca - 14.0f*ca*ca + 1.0f);
117 ALfloat ca
= cosf(spread
* 0.5f
);
118 /* Increase the source volume by up to +3dB for a full spread. */
119 ALfloat scale
= sqrtf(1.0f
+ spread
/F_TAU
);
121 ALfloat ZH0_norm
= scale
;
122 ALfloat ZH1_norm
= 0.5f
* (ca
+1.f
) * scale
;
123 ALfloat ZH2_norm
= 0.5f
* (ca
+1.f
)*ca
* scale
;
124 ALfloat ZH3_norm
= 0.125f
* (ca
+1.f
)*(5.f
*ca
*ca
-1.f
) * scale
;
127 coeffs
[0] *= ZH0_norm
;
129 coeffs
[1] *= ZH1_norm
;
130 coeffs
[2] *= ZH1_norm
;
131 coeffs
[3] *= ZH1_norm
;
133 coeffs
[4] *= ZH2_norm
;
134 coeffs
[5] *= ZH2_norm
;
135 coeffs
[6] *= ZH2_norm
;
136 coeffs
[7] *= ZH2_norm
;
137 coeffs
[8] *= ZH2_norm
;
139 coeffs
[9] *= ZH3_norm
;
140 coeffs
[10] *= ZH3_norm
;
141 coeffs
[11] *= ZH3_norm
;
142 coeffs
[12] *= ZH3_norm
;
143 coeffs
[13] *= ZH3_norm
;
144 coeffs
[14] *= ZH3_norm
;
145 coeffs
[15] *= ZH3_norm
;
150 void ComputePanningGainsMC(const ChannelConfig
*chancoeffs
, ALsizei numchans
, ALsizei numcoeffs
, const ALfloat
*RESTRICT coeffs
, ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
154 for(i
= 0;i
< numchans
;i
++)
157 for(j
= 0;j
< numcoeffs
;j
++)
158 gain
+= chancoeffs
[i
][j
]*coeffs
[j
];
159 gains
[i
] = clampf(gain
, 0.0f
, 1.0f
) * ingain
;
161 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
165 void ComputePanningGainsBF(const BFChannelConfig
*chanmap
, ALsizei numchans
, const ALfloat
*RESTRICT coeffs
, ALfloat ingain
, ALfloat gains
[MAX_OUTPUT_CHANNELS
])
169 for(i
= 0;i
< numchans
;i
++)
170 gains
[i
] = chanmap
[i
].Scale
* coeffs
[chanmap
[i
].Index
] * ingain
;
171 for(;i
< MAX_OUTPUT_CHANNELS
;i
++)
176 static inline const char *GetLabelFromChannel(enum Channel channel
)
180 case FrontLeft
: return "front-left";
181 case FrontRight
: return "front-right";
182 case FrontCenter
: return "front-center";
183 case LFE
: return "lfe";
184 case BackLeft
: return "back-left";
185 case BackRight
: return "back-right";
186 case BackCenter
: return "back-center";
187 case SideLeft
: return "side-left";
188 case SideRight
: return "side-right";
190 case UpperFrontLeft
: return "upper-front-left";
191 case UpperFrontRight
: return "upper-front-right";
192 case UpperBackLeft
: return "upper-back-left";
193 case UpperBackRight
: return "upper-back-right";
194 case LowerFrontLeft
: return "lower-front-left";
195 case LowerFrontRight
: return "lower-front-right";
196 case LowerBackLeft
: return "lower-back-left";
197 case LowerBackRight
: return "lower-back-right";
199 case Aux0
: return "aux-0";
200 case Aux1
: return "aux-1";
201 case Aux2
: return "aux-2";
202 case Aux3
: return "aux-3";
203 case Aux4
: return "aux-4";
204 case Aux5
: return "aux-5";
205 case Aux6
: return "aux-6";
206 case Aux7
: return "aux-7";
207 case Aux8
: return "aux-8";
208 case Aux9
: return "aux-9";
209 case Aux10
: return "aux-10";
210 case Aux11
: return "aux-11";
211 case Aux12
: return "aux-12";
212 case Aux13
: return "aux-13";
213 case Aux14
: return "aux-14";
214 case Aux15
: return "aux-15";
216 case InvalidChannel
: break;
222 typedef struct ChannelMap
{
223 enum Channel ChanName
;
224 ChannelConfig Config
;
227 static void SetChannelMap(const enum Channel devchans
[MAX_OUTPUT_CHANNELS
],
228 ChannelConfig
*ambicoeffs
, const ChannelMap
*chanmap
,
229 ALsizei count
, ALsizei
*outcount
)
231 ALsizei maxchans
= 0;
234 for(i
= 0;i
< count
;i
++)
236 ALint idx
= GetChannelIndex(devchans
, chanmap
[i
].ChanName
);
239 ERR("Failed to find %s channel in device\n",
240 GetLabelFromChannel(chanmap
[i
].ChanName
));
244 maxchans
= maxi(maxchans
, idx
+1);
245 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
246 ambicoeffs
[idx
][j
] = chanmap
[i
].Config
[j
];
248 *outcount
= mini(maxchans
, MAX_OUTPUT_CHANNELS
);
251 static bool MakeSpeakerMap(ALCdevice
*device
, const AmbDecConf
*conf
, ALsizei speakermap
[MAX_OUTPUT_CHANNELS
])
255 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
260 /* NOTE: AmbDec does not define any standard speaker names, however
261 * for this to work we have to by able to find the output channel
262 * the speaker definition corresponds to. Therefore, OpenAL Soft
263 * requires these channel labels to be recognized:
274 * Additionally, surround51 will acknowledge back speakers for side
275 * channels, and surround51rear will acknowledge side speakers for
276 * back channels, to avoid issues with an ambdec expecting 5.1 to
277 * use the side channels when the device is configured for back,
280 if(conf
->Speakers
[i
].Name
== "LF")
282 else if(conf
->Speakers
[i
].Name
== "RF")
284 else if(conf
->Speakers
[i
].Name
== "CE")
286 else if(conf
->Speakers
[i
].Name
== "LS")
288 if(device
->FmtChans
== DevFmtX51Rear
)
293 else if(conf
->Speakers
[i
].Name
== "RS")
295 if(device
->FmtChans
== DevFmtX51Rear
)
300 else if(conf
->Speakers
[i
].Name
== "LB")
302 if(device
->FmtChans
== DevFmtX51
)
307 else if(conf
->Speakers
[i
].Name
== "RB")
309 if(device
->FmtChans
== DevFmtX51
)
314 else if(conf
->Speakers
[i
].Name
== "CB")
318 const char *name
= conf
->Speakers
[i
].Name
.c_str();
322 if(sscanf(name
, "AUX%u%c", &n
, &c
) == 1 && n
< 16)
323 ch
= static_cast<enum Channel
>(Aux0
+n
);
326 ERR("AmbDec speaker label \"%s\" not recognized\n", name
);
330 chidx
= GetChannelIdxByName(&device
->RealOut
, ch
);
333 ERR("Failed to lookup AmbDec speaker label %s\n",
334 conf
->Speakers
[i
].Name
.c_str());
337 speakermap
[i
] = chidx
;
344 static const ChannelMap MonoCfg
[1] = {
345 { FrontCenter
, { 1.0f
} },
347 { FrontLeft
, { 5.00000000e-1f
, 2.88675135e-1f
, 0.0f
, 5.52305643e-2f
} },
348 { FrontRight
, { 5.00000000e-1f
, -2.88675135e-1f
, 0.0f
, 5.52305643e-2f
} },
350 { BackLeft
, { 3.53553391e-1f
, 2.04124145e-1f
, 0.0f
, -2.04124145e-1f
} },
351 { FrontLeft
, { 3.53553391e-1f
, 2.04124145e-1f
, 0.0f
, 2.04124145e-1f
} },
352 { FrontRight
, { 3.53553391e-1f
, -2.04124145e-1f
, 0.0f
, 2.04124145e-1f
} },
353 { BackRight
, { 3.53553391e-1f
, -2.04124145e-1f
, 0.0f
, -2.04124145e-1f
} },
355 { SideLeft
, { 3.33000782e-1f
, 1.89084803e-1f
, 0.0f
, -2.00042375e-1f
, -2.12307769e-2f
, 0.0f
, 0.0f
, 0.0f
, -1.14579885e-2f
} },
356 { FrontLeft
, { 1.88542860e-1f
, 1.27709292e-1f
, 0.0f
, 1.66295695e-1f
, 7.30571517e-2f
, 0.0f
, 0.0f
, 0.0f
, 2.10901184e-2f
} },
357 { FrontRight
, { 1.88542860e-1f
, -1.27709292e-1f
, 0.0f
, 1.66295695e-1f
, -7.30571517e-2f
, 0.0f
, 0.0f
, 0.0f
, 2.10901184e-2f
} },
358 { SideRight
, { 3.33000782e-1f
, -1.89084803e-1f
, 0.0f
, -2.00042375e-1f
, 2.12307769e-2f
, 0.0f
, 0.0f
, 0.0f
, -1.14579885e-2f
} },
360 { BackLeft
, { 3.33000782e-1f
, 1.89084803e-1f
, 0.0f
, -2.00042375e-1f
, -2.12307769e-2f
, 0.0f
, 0.0f
, 0.0f
, -1.14579885e-2f
} },
361 { FrontLeft
, { 1.88542860e-1f
, 1.27709292e-1f
, 0.0f
, 1.66295695e-1f
, 7.30571517e-2f
, 0.0f
, 0.0f
, 0.0f
, 2.10901184e-2f
} },
362 { FrontRight
, { 1.88542860e-1f
, -1.27709292e-1f
, 0.0f
, 1.66295695e-1f
, -7.30571517e-2f
, 0.0f
, 0.0f
, 0.0f
, 2.10901184e-2f
} },
363 { BackRight
, { 3.33000782e-1f
, -1.89084803e-1f
, 0.0f
, -2.00042375e-1f
, 2.12307769e-2f
, 0.0f
, 0.0f
, 0.0f
, -1.14579885e-2f
} },
365 { SideLeft
, { 2.04460341e-1f
, 2.17177926e-1f
, 0.0f
, -4.39996780e-2f
, -2.60790269e-2f
, 0.0f
, 0.0f
, 0.0f
, -6.87239792e-2f
} },
366 { FrontLeft
, { 1.58923161e-1f
, 9.21772680e-2f
, 0.0f
, 1.59658796e-1f
, 6.66278083e-2f
, 0.0f
, 0.0f
, 0.0f
, 3.84686854e-2f
} },
367 { FrontRight
, { 1.58923161e-1f
, -9.21772680e-2f
, 0.0f
, 1.59658796e-1f
, -6.66278083e-2f
, 0.0f
, 0.0f
, 0.0f
, 3.84686854e-2f
} },
368 { SideRight
, { 2.04460341e-1f
, -2.17177926e-1f
, 0.0f
, -4.39996780e-2f
, 2.60790269e-2f
, 0.0f
, 0.0f
, 0.0f
, -6.87239792e-2f
} },
369 { BackCenter
, { 2.50001688e-1f
, 0.00000000e+0f
, 0.0f
, -2.50000094e-1f
, 0.00000000e+0f
, 0.0f
, 0.0f
, 0.0f
, 6.05133395e-2f
} },
371 { BackLeft
, { 2.04124145e-1f
, 1.08880247e-1f
, 0.0f
, -1.88586120e-1f
, -1.29099444e-1f
, 0.0f
, 0.0f
, 0.0f
, 7.45355993e-2f
, 3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
372 { SideLeft
, { 2.04124145e-1f
, 2.17760495e-1f
, 0.0f
, 0.00000000e+0f
, 0.00000000e+0f
, 0.0f
, 0.0f
, 0.0f
, -1.49071198e-1f
, -3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
373 { FrontLeft
, { 2.04124145e-1f
, 1.08880247e-1f
, 0.0f
, 1.88586120e-1f
, 1.29099444e-1f
, 0.0f
, 0.0f
, 0.0f
, 7.45355993e-2f
, 3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
374 { FrontRight
, { 2.04124145e-1f
, -1.08880247e-1f
, 0.0f
, 1.88586120e-1f
, -1.29099444e-1f
, 0.0f
, 0.0f
, 0.0f
, 7.45355993e-2f
, -3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
375 { SideRight
, { 2.04124145e-1f
, -2.17760495e-1f
, 0.0f
, 0.00000000e+0f
, 0.00000000e+0f
, 0.0f
, 0.0f
, 0.0f
, -1.49071198e-1f
, 3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
376 { BackRight
, { 2.04124145e-1f
, -1.08880247e-1f
, 0.0f
, -1.88586120e-1f
, 1.29099444e-1f
, 0.0f
, 0.0f
, 0.0f
, 7.45355993e-2f
, -3.73460789e-2f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.0f
, 0.00000000e+0f
} },
379 static void InitNearFieldCtrl(ALCdevice
*device
, ALfloat ctrl_dist
, ALsizei order
,
380 const ALsizei
*RESTRICT chans_per_order
)
382 const char *devname
= device
->DeviceName
.c_str();
385 if(GetConfigValueBool(devname
, "decoder", "nfc", 1) && ctrl_dist
> 0.0f
)
387 /* NFC is only used when AvgSpeakerDist is greater than 0, and can only
388 * be used when rendering to an ambisonic buffer.
390 device
->AvgSpeakerDist
= minf(ctrl_dist
, 10.0f
);
391 TRACE("Using near-field reference distance: %.2f meters\n", device
->AvgSpeakerDist
);
393 for(i
= 0;i
< order
+1;i
++)
394 device
->NumChannelsPerOrder
[i
] = chans_per_order
[i
];
395 for(;i
< MAX_AMBI_ORDER
+1;i
++)
396 device
->NumChannelsPerOrder
[i
] = 0;
400 static void InitDistanceComp(ALCdevice
*device
, const AmbDecConf
*conf
, const ALsizei speakermap
[MAX_OUTPUT_CHANNELS
])
402 const char *devname
= device
->DeviceName
.c_str();
403 ALfloat maxdist
= 0.0f
;
407 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
408 maxdist
= maxf(maxdist
, conf
->Speakers
[i
].Distance
);
410 if(GetConfigValueBool(devname
, "decoder", "distance-comp", 1) && maxdist
> 0.0f
)
412 ALfloat srate
= (ALfloat
)device
->Frequency
;
413 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
415 ALsizei chan
= speakermap
[i
];
418 /* Distance compensation only delays in steps of the sample rate.
419 * This is a bit less accurate since the delay time falls to the
420 * nearest sample time, but it's far simpler as it doesn't have to
421 * deal with phase offsets. This means at 48khz, for instance, the
422 * distance delay will be in steps of about 7 millimeters.
424 delay
= floorf((maxdist
-conf
->Speakers
[i
].Distance
) / SPEEDOFSOUNDMETRESPERSEC
*
426 if(delay
>= (ALfloat
)MAX_DELAY_LENGTH
)
427 ERR("Delay for speaker \"%s\" exceeds buffer length (%f >= %u)\n",
428 conf
->Speakers
[i
].Name
.c_str(), delay
, MAX_DELAY_LENGTH
);
430 device
->ChannelDelay
[chan
].Length
= (ALsizei
)clampf(
431 delay
, 0.0f
, (ALfloat
)(MAX_DELAY_LENGTH
-1)
433 device
->ChannelDelay
[chan
].Gain
= conf
->Speakers
[i
].Distance
/ maxdist
;
434 TRACE("Channel %u \"%s\" distance compensation: %d samples, %f gain\n", chan
,
435 conf
->Speakers
[i
].Name
.c_str(), device
->ChannelDelay
[chan
].Length
,
436 device
->ChannelDelay
[chan
].Gain
439 /* Round up to the next 4th sample, so each channel buffer starts
442 total
+= RoundUp(device
->ChannelDelay
[chan
].Length
, 4);
448 device
->ChannelDelay
[0].Buffer
= reinterpret_cast<float*>(
449 al_calloc(16, total
* sizeof(ALfloat
)));
450 for(i
= 1;i
< MAX_OUTPUT_CHANNELS
;i
++)
452 size_t len
= RoundUp(device
->ChannelDelay
[i
-1].Length
, 4);
453 device
->ChannelDelay
[i
].Buffer
= device
->ChannelDelay
[i
-1].Buffer
+ len
;
458 static void InitPanning(ALCdevice
*device
)
460 const ChannelMap
*chanmap
= NULL
;
461 ALsizei coeffcount
= 0;
465 switch(device
->FmtChans
)
468 count
= COUNTOF(MonoCfg
);
474 count
= COUNTOF(StereoCfg
);
480 count
= COUNTOF(QuadCfg
);
486 count
= COUNTOF(X51SideCfg
);
487 chanmap
= X51SideCfg
;
492 count
= COUNTOF(X51RearCfg
);
493 chanmap
= X51RearCfg
;
498 count
= COUNTOF(X61Cfg
);
504 count
= COUNTOF(X71Cfg
);
513 if(device
->FmtChans
== DevFmtAmbi3D
)
515 const char *devname
= device
->DeviceName
.c_str();
516 const ALsizei
*acnmap
= (device
->mAmbiLayout
== AmbiLayout_FuMa
) ? FuMa2ACN
: ACN2ACN
;
517 const ALfloat
*n3dscale
= (device
->mAmbiScale
== AmbiNorm_FuMa
) ? FuMa2N3DScale
:
518 (device
->mAmbiScale
== AmbiNorm_SN3D
) ? SN3D2N3DScale
:
519 /*(device->mAmbiScale == AmbiNorm_N3D) ?*/ N3D2N3DScale
;
520 ALfloat nfc_delay
= 0.0f
;
522 count
= (device
->mAmbiOrder
== 3) ? 16 :
523 (device
->mAmbiOrder
== 2) ? 9 :
524 (device
->mAmbiOrder
== 1) ? 4 : 1;
525 for(i
= 0;i
< count
;i
++)
527 ALsizei acn
= acnmap
[i
];
528 device
->Dry
.Ambi
.Map
[i
].Scale
= 1.0f
/n3dscale
[acn
];
529 device
->Dry
.Ambi
.Map
[i
].Index
= acn
;
531 device
->Dry
.CoeffCount
= 0;
532 device
->Dry
.NumChannels
= count
;
534 if(device
->mAmbiOrder
< 2)
536 device
->FOAOut
.Ambi
= device
->Dry
.Ambi
;
537 device
->FOAOut
.CoeffCount
= device
->Dry
.CoeffCount
;
538 device
->FOAOut
.NumChannels
= 0;
542 ALfloat w_scale
=1.0f
, xyz_scale
=1.0f
;
544 /* FOA output is always ACN+N3D for higher-order ambisonic output.
545 * The upsampler expects this and will convert it for output.
547 memset(&device
->FOAOut
.Ambi
, 0, sizeof(device
->FOAOut
.Ambi
));
550 device
->FOAOut
.Ambi
.Map
[i
].Scale
= 1.0f
;
551 device
->FOAOut
.Ambi
.Map
[i
].Index
= i
;
553 device
->FOAOut
.CoeffCount
= 0;
554 device
->FOAOut
.NumChannels
= 4;
556 if(device
->mAmbiOrder
>= 3)
558 w_scale
= W_SCALE_3H3P
;
559 xyz_scale
= XYZ_SCALE_3H3P
;
563 w_scale
= W_SCALE_2H2P
;
564 xyz_scale
= XYZ_SCALE_2H2P
;
566 ambiup_reset(device
->AmbiUp
, device
, w_scale
, xyz_scale
);
569 if(ConfigValueFloat(devname
, "decoder", "nfc-ref-delay", &nfc_delay
) && nfc_delay
> 0.0f
)
571 static const ALsizei chans_per_order
[MAX_AMBI_ORDER
+1] = {
574 nfc_delay
= clampf(nfc_delay
, 0.001f
, 1000.0f
);
575 InitNearFieldCtrl(device
, nfc_delay
* SPEEDOFSOUNDMETRESPERSEC
,
576 device
->mAmbiOrder
, chans_per_order
);
581 ALfloat w_scale
, xyz_scale
;
583 SetChannelMap(device
->RealOut
.ChannelName
, device
->Dry
.Ambi
.Coeffs
,
584 chanmap
, count
, &device
->Dry
.NumChannels
);
585 device
->Dry
.CoeffCount
= coeffcount
;
587 w_scale
= (device
->Dry
.CoeffCount
> 9) ? W_SCALE_3H0P
:
588 (device
->Dry
.CoeffCount
> 4) ? W_SCALE_2H0P
: 1.0f
;
589 xyz_scale
= (device
->Dry
.CoeffCount
> 9) ? XYZ_SCALE_3H0P
:
590 (device
->Dry
.CoeffCount
> 4) ? XYZ_SCALE_2H0P
: 1.0f
;
592 memset(&device
->FOAOut
.Ambi
, 0, sizeof(device
->FOAOut
.Ambi
));
593 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
595 device
->FOAOut
.Ambi
.Coeffs
[i
][0] = device
->Dry
.Ambi
.Coeffs
[i
][0] * w_scale
;
597 device
->FOAOut
.Ambi
.Coeffs
[i
][j
] = device
->Dry
.Ambi
.Coeffs
[i
][j
] * xyz_scale
;
599 device
->FOAOut
.CoeffCount
= 4;
600 device
->FOAOut
.NumChannels
= 0;
602 device
->RealOut
.NumChannels
= 0;
605 static void InitCustomPanning(ALCdevice
*device
, const AmbDecConf
*conf
, const ALsizei speakermap
[MAX_OUTPUT_CHANNELS
])
607 ChannelMap chanmap
[MAX_OUTPUT_CHANNELS
];
608 const ALfloat
*coeff_scale
= N3D2N3DScale
;
609 ALfloat w_scale
= 1.0f
;
610 ALfloat xyz_scale
= 1.0f
;
613 if(conf
->FreqBands
!= 1)
614 ERR("Basic renderer uses the high-frequency matrix as single-band (xover_freq = %.0fhz)\n",
617 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
619 if(conf
->ChanMask
> 0x1ff)
621 w_scale
= W_SCALE_3H3P
;
622 xyz_scale
= XYZ_SCALE_3H3P
;
624 else if(conf
->ChanMask
> 0xf)
626 w_scale
= W_SCALE_2H2P
;
627 xyz_scale
= XYZ_SCALE_2H2P
;
632 if(conf
->ChanMask
> 0x1ff)
634 w_scale
= W_SCALE_3H0P
;
635 xyz_scale
= XYZ_SCALE_3H0P
;
637 else if(conf
->ChanMask
> 0xf)
639 w_scale
= W_SCALE_2H0P
;
640 xyz_scale
= XYZ_SCALE_2H0P
;
644 if(conf
->CoeffScale
== AmbDecScale::SN3D
)
645 coeff_scale
= SN3D2N3DScale
;
646 else if(conf
->CoeffScale
== AmbDecScale::FuMa
)
647 coeff_scale
= FuMa2N3DScale
;
649 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
651 ALsizei chan
= speakermap
[i
];
655 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
656 chanmap
[i
].Config
[j
] = 0.0f
;
658 chanmap
[i
].ChanName
= device
->RealOut
.ChannelName
[chan
];
659 for(j
= 0;j
< MAX_AMBI_COEFFS
;j
++)
661 if(j
== 0) gain
= conf
->HFOrderGain
[0];
662 else if(j
== 1) gain
= conf
->HFOrderGain
[1];
663 else if(j
== 4) gain
= conf
->HFOrderGain
[2];
664 else if(j
== 9) gain
= conf
->HFOrderGain
[3];
665 if((conf
->ChanMask
&(1<<j
)))
666 chanmap
[i
].Config
[j
] = conf
->HFMatrix
[i
][k
++] / coeff_scale
[j
] * gain
;
670 SetChannelMap(device
->RealOut
.ChannelName
, device
->Dry
.Ambi
.Coeffs
, chanmap
,
671 conf
->NumSpeakers
, &device
->Dry
.NumChannels
);
672 device
->Dry
.CoeffCount
= (conf
->ChanMask
> 0x1ff) ? 16 :
673 (conf
->ChanMask
> 0xf) ? 9 : 4;
675 memset(&device
->FOAOut
.Ambi
, 0, sizeof(device
->FOAOut
.Ambi
));
676 for(i
= 0;i
< device
->Dry
.NumChannels
;i
++)
678 device
->FOAOut
.Ambi
.Coeffs
[i
][0] = device
->Dry
.Ambi
.Coeffs
[i
][0] * w_scale
;
680 device
->FOAOut
.Ambi
.Coeffs
[i
][j
] = device
->Dry
.Ambi
.Coeffs
[i
][j
] * xyz_scale
;
682 device
->FOAOut
.CoeffCount
= 4;
683 device
->FOAOut
.NumChannels
= 0;
685 device
->RealOut
.NumChannels
= 0;
687 InitDistanceComp(device
, conf
, speakermap
);
690 static void InitHQPanning(ALCdevice
*device
, const AmbDecConf
*conf
, const ALsizei speakermap
[MAX_OUTPUT_CHANNELS
])
692 static const ALsizei chans_per_order2d
[MAX_AMBI_ORDER
+1] = { 1, 2, 2, 2 };
693 static const ALsizei chans_per_order3d
[MAX_AMBI_ORDER
+1] = { 1, 3, 5, 7 };
698 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
700 count
= (conf
->ChanMask
> 0x1ff) ? 16 :
701 (conf
->ChanMask
> 0xf) ? 9 : 4;
702 for(i
= 0;i
< count
;i
++)
704 device
->Dry
.Ambi
.Map
[i
].Scale
= 1.0f
;
705 device
->Dry
.Ambi
.Map
[i
].Index
= i
;
710 static const int map
[MAX_AMBI2D_COEFFS
] = { 0, 1, 3, 4, 8, 9, 15 };
712 count
= (conf
->ChanMask
> 0x1ff) ? 7 :
713 (conf
->ChanMask
> 0xf) ? 5 : 3;
714 for(i
= 0;i
< count
;i
++)
716 device
->Dry
.Ambi
.Map
[i
].Scale
= 1.0f
;
717 device
->Dry
.Ambi
.Map
[i
].Index
= map
[i
];
720 device
->Dry
.CoeffCount
= 0;
721 device
->Dry
.NumChannels
= count
;
723 TRACE("Enabling %s-band %s-order%s ambisonic decoder\n",
724 (conf
->FreqBands
== 1) ? "single" : "dual",
725 (conf
->ChanMask
> 0xf) ? (conf
->ChanMask
> 0x1ff) ? "third" : "second" : "first",
726 (conf
->ChanMask
&AMBI_PERIPHONIC_MASK
) ? " periphonic" : ""
728 bformatdec_reset(device
->AmbiDecoder
, conf
, count
, device
->Frequency
, speakermap
);
730 if(conf
->ChanMask
<= 0xf)
732 device
->FOAOut
.Ambi
= device
->Dry
.Ambi
;
733 device
->FOAOut
.CoeffCount
= device
->Dry
.CoeffCount
;
734 device
->FOAOut
.NumChannels
= 0;
738 memset(&device
->FOAOut
.Ambi
, 0, sizeof(device
->FOAOut
.Ambi
));
739 if((conf
->ChanMask
&AMBI_PERIPHONIC_MASK
))
742 for(i
= 0;i
< count
;i
++)
744 device
->FOAOut
.Ambi
.Map
[i
].Scale
= 1.0f
;
745 device
->FOAOut
.Ambi
.Map
[i
].Index
= i
;
750 static const int map
[3] = { 0, 1, 3 };
752 for(i
= 0;i
< count
;i
++)
754 device
->FOAOut
.Ambi
.Map
[i
].Scale
= 1.0f
;
755 device
->FOAOut
.Ambi
.Map
[i
].Index
= map
[i
];
758 device
->FOAOut
.CoeffCount
= 0;
759 device
->FOAOut
.NumChannels
= count
;
762 device
->RealOut
.NumChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
765 for(i
= 0;i
< conf
->NumSpeakers
;i
++)
766 avg_dist
+= conf
->Speakers
[i
].Distance
;
767 avg_dist
/= (ALfloat
)conf
->NumSpeakers
;
768 InitNearFieldCtrl(device
, avg_dist
,
769 (conf
->ChanMask
> 0x1ff) ? 3 : (conf
->ChanMask
> 0xf) ? 2 : 1,
770 (conf
->ChanMask
&AMBI_PERIPHONIC_MASK
) ? chans_per_order3d
: chans_per_order2d
773 InitDistanceComp(device
, conf
, speakermap
);
776 static void InitHrtfPanning(ALCdevice
*device
)
778 /* NOTE: azimuth goes clockwise. */
779 static const struct AngularPoint AmbiPoints
[] = {
780 { DEG2RAD( 90.0f
), DEG2RAD( 0.0f
) },
781 { DEG2RAD( 35.2643897f
), DEG2RAD( 45.0f
) },
782 { DEG2RAD( 35.2643897f
), DEG2RAD( 135.0f
) },
783 { DEG2RAD( 35.2643897f
), DEG2RAD(-135.0f
) },
784 { DEG2RAD( 35.2643897f
), DEG2RAD( -45.0f
) },
785 { DEG2RAD( 0.0f
), DEG2RAD( 0.0f
) },
786 { DEG2RAD( 0.0f
), DEG2RAD( 45.0f
) },
787 { DEG2RAD( 0.0f
), DEG2RAD( 90.0f
) },
788 { DEG2RAD( 0.0f
), DEG2RAD( 135.0f
) },
789 { DEG2RAD( 0.0f
), DEG2RAD( 180.0f
) },
790 { DEG2RAD( 0.0f
), DEG2RAD(-135.0f
) },
791 { DEG2RAD( 0.0f
), DEG2RAD( -90.0f
) },
792 { DEG2RAD( 0.0f
), DEG2RAD( -45.0f
) },
793 { DEG2RAD(-35.2643897f
), DEG2RAD( 45.0f
) },
794 { DEG2RAD(-35.2643897f
), DEG2RAD( 135.0f
) },
795 { DEG2RAD(-35.2643897f
), DEG2RAD(-135.0f
) },
796 { DEG2RAD(-35.2643897f
), DEG2RAD( -45.0f
) },
797 { DEG2RAD(-90.0f
), DEG2RAD( 0.0f
) },
799 static const ALfloat AmbiMatrixFOA
[][MAX_AMBI_COEFFS
] = {
800 { 5.55555556e-02f
, 0.00000000e+00f
, 1.23717915e-01f
, 0.00000000e+00f
},
801 { 5.55555556e-02f
, -5.00000000e-02f
, 7.14285715e-02f
, 5.00000000e-02f
},
802 { 5.55555556e-02f
, -5.00000000e-02f
, 7.14285715e-02f
, -5.00000000e-02f
},
803 { 5.55555556e-02f
, 5.00000000e-02f
, 7.14285715e-02f
, -5.00000000e-02f
},
804 { 5.55555556e-02f
, 5.00000000e-02f
, 7.14285715e-02f
, 5.00000000e-02f
},
805 { 5.55555556e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, 8.66025404e-02f
},
806 { 5.55555556e-02f
, -6.12372435e-02f
, 0.00000000e+00f
, 6.12372435e-02f
},
807 { 5.55555556e-02f
, -8.66025404e-02f
, 0.00000000e+00f
, 0.00000000e+00f
},
808 { 5.55555556e-02f
, -6.12372435e-02f
, 0.00000000e+00f
, -6.12372435e-02f
},
809 { 5.55555556e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, -8.66025404e-02f
},
810 { 5.55555556e-02f
, 6.12372435e-02f
, 0.00000000e+00f
, -6.12372435e-02f
},
811 { 5.55555556e-02f
, 8.66025404e-02f
, 0.00000000e+00f
, 0.00000000e+00f
},
812 { 5.55555556e-02f
, 6.12372435e-02f
, 0.00000000e+00f
, 6.12372435e-02f
},
813 { 5.55555556e-02f
, -5.00000000e-02f
, -7.14285715e-02f
, 5.00000000e-02f
},
814 { 5.55555556e-02f
, -5.00000000e-02f
, -7.14285715e-02f
, -5.00000000e-02f
},
815 { 5.55555556e-02f
, 5.00000000e-02f
, -7.14285715e-02f
, -5.00000000e-02f
},
816 { 5.55555556e-02f
, 5.00000000e-02f
, -7.14285715e-02f
, 5.00000000e-02f
},
817 { 5.55555556e-02f
, 0.00000000e+00f
, -1.23717915e-01f
, 0.00000000e+00f
},
818 }, AmbiMatrixHOA
[][MAX_AMBI_COEFFS
] = {
819 { 5.55555556e-02f
, 0.00000000e+00f
, 1.23717915e-01f
, 0.00000000e+00f
, 0.00000000e+00f
, 0.00000000e+00f
},
820 { 5.55555556e-02f
, -5.00000000e-02f
, 7.14285715e-02f
, 5.00000000e-02f
, -4.55645099e-02f
, 0.00000000e+00f
},
821 { 5.55555556e-02f
, -5.00000000e-02f
, 7.14285715e-02f
, -5.00000000e-02f
, 4.55645099e-02f
, 0.00000000e+00f
},
822 { 5.55555556e-02f
, 5.00000000e-02f
, 7.14285715e-02f
, -5.00000000e-02f
, -4.55645099e-02f
, 0.00000000e+00f
},
823 { 5.55555556e-02f
, 5.00000000e-02f
, 7.14285715e-02f
, 5.00000000e-02f
, 4.55645099e-02f
, 0.00000000e+00f
},
824 { 5.55555556e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, 8.66025404e-02f
, 0.00000000e+00f
, 1.29099445e-01f
},
825 { 5.55555556e-02f
, -6.12372435e-02f
, 0.00000000e+00f
, 6.12372435e-02f
, -6.83467648e-02f
, 0.00000000e+00f
},
826 { 5.55555556e-02f
, -8.66025404e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, 0.00000000e+00f
, -1.29099445e-01f
},
827 { 5.55555556e-02f
, -6.12372435e-02f
, 0.00000000e+00f
, -6.12372435e-02f
, 6.83467648e-02f
, 0.00000000e+00f
},
828 { 5.55555556e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, -8.66025404e-02f
, 0.00000000e+00f
, 1.29099445e-01f
},
829 { 5.55555556e-02f
, 6.12372435e-02f
, 0.00000000e+00f
, -6.12372435e-02f
, -6.83467648e-02f
, 0.00000000e+00f
},
830 { 5.55555556e-02f
, 8.66025404e-02f
, 0.00000000e+00f
, 0.00000000e+00f
, 0.00000000e+00f
, -1.29099445e-01f
},
831 { 5.55555556e-02f
, 6.12372435e-02f
, 0.00000000e+00f
, 6.12372435e-02f
, 6.83467648e-02f
, 0.00000000e+00f
},
832 { 5.55555556e-02f
, -5.00000000e-02f
, -7.14285715e-02f
, 5.00000000e-02f
, -4.55645099e-02f
, 0.00000000e+00f
},
833 { 5.55555556e-02f
, -5.00000000e-02f
, -7.14285715e-02f
, -5.00000000e-02f
, 4.55645099e-02f
, 0.00000000e+00f
},
834 { 5.55555556e-02f
, 5.00000000e-02f
, -7.14285715e-02f
, -5.00000000e-02f
, -4.55645099e-02f
, 0.00000000e+00f
},
835 { 5.55555556e-02f
, 5.00000000e-02f
, -7.14285715e-02f
, 5.00000000e-02f
, 4.55645099e-02f
, 0.00000000e+00f
},
836 { 5.55555556e-02f
, 0.00000000e+00f
, -1.23717915e-01f
, 0.00000000e+00f
, 0.00000000e+00f
, 0.00000000e+00f
},
838 static const ALfloat AmbiOrderHFGainFOA
[MAX_AMBI_ORDER
+1] = {
839 3.00000000e+00f
, 1.73205081e+00f
840 }, AmbiOrderHFGainHOA
[MAX_AMBI_ORDER
+1] = {
841 2.40192231e+00f
, 1.86052102e+00f
, 9.60768923e-01f
843 static const ALsizei IndexMap
[6] = { 0, 1, 2, 3, 4, 8 };
844 static const ALsizei ChansPerOrder
[MAX_AMBI_ORDER
+1] = { 1, 3, 2, 0 };
845 const ALfloat (*RESTRICT AmbiMatrix
)[MAX_AMBI_COEFFS
] = AmbiMatrixFOA
;
846 const ALfloat
*RESTRICT AmbiOrderHFGain
= AmbiOrderHFGainFOA
;
850 static_assert(COUNTOF(AmbiPoints
) == COUNTOF(AmbiMatrixFOA
), "FOA Ambisonic HRTF mismatch");
851 static_assert(COUNTOF(AmbiPoints
) == COUNTOF(AmbiMatrixHOA
), "HOA Ambisonic HRTF mismatch");
855 AmbiMatrix
= AmbiMatrixHOA
;
856 AmbiOrderHFGain
= AmbiOrderHFGainHOA
;
857 count
= COUNTOF(IndexMap
);
860 device
->Hrtf
= reinterpret_cast<DirectHrtfState
*>(
861 al_calloc(16, FAM_SIZE(DirectHrtfState
, Chan
, count
)));
863 for(i
= 0;i
< count
;i
++)
865 device
->Dry
.Ambi
.Map
[i
].Scale
= 1.0f
;
866 device
->Dry
.Ambi
.Map
[i
].Index
= IndexMap
[i
];
868 device
->Dry
.CoeffCount
= 0;
869 device
->Dry
.NumChannels
= count
;
873 memset(&device
->FOAOut
.Ambi
, 0, sizeof(device
->FOAOut
.Ambi
));
876 device
->FOAOut
.Ambi
.Map
[i
].Scale
= 1.0f
;
877 device
->FOAOut
.Ambi
.Map
[i
].Index
= i
;
879 device
->FOAOut
.CoeffCount
= 0;
880 device
->FOAOut
.NumChannels
= 4;
882 ambiup_reset(device
->AmbiUp
, device
, AmbiOrderHFGainFOA
[0] / AmbiOrderHFGain
[0],
883 AmbiOrderHFGainFOA
[1] / AmbiOrderHFGain
[1]);
887 device
->FOAOut
.Ambi
= device
->Dry
.Ambi
;
888 device
->FOAOut
.CoeffCount
= device
->Dry
.CoeffCount
;
889 device
->FOAOut
.NumChannels
= 0;
892 device
->RealOut
.NumChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
894 BuildBFormatHrtf(device
->HrtfHandle
,
895 device
->Hrtf
, device
->Dry
.NumChannels
, AmbiPoints
, AmbiMatrix
, COUNTOF(AmbiPoints
),
899 InitNearFieldCtrl(device
, device
->HrtfHandle
->distance
, device
->AmbiUp
? 2 : 1,
903 static void InitUhjPanning(ALCdevice
*device
)
908 for(i
= 0;i
< count
;i
++)
910 ALsizei acn
= FuMa2ACN
[i
];
911 device
->Dry
.Ambi
.Map
[i
].Scale
= 1.0f
/FuMa2N3DScale
[acn
];
912 device
->Dry
.Ambi
.Map
[i
].Index
= acn
;
914 device
->Dry
.CoeffCount
= 0;
915 device
->Dry
.NumChannels
= count
;
917 device
->FOAOut
.Ambi
= device
->Dry
.Ambi
;
918 device
->FOAOut
.CoeffCount
= device
->Dry
.CoeffCount
;
919 device
->FOAOut
.NumChannels
= 0;
921 device
->RealOut
.NumChannels
= ChannelsFromDevFmt(device
->FmtChans
, device
->mAmbiOrder
);
924 void aluInitRenderer(ALCdevice
*device
, ALint hrtf_id
, enum HrtfRequestMode hrtf_appreq
, enum HrtfRequestMode hrtf_userreq
)
926 /* Hold the HRTF the device last used, in case it's used again. */
927 struct Hrtf
*old_hrtf
= device
->HrtfHandle
;
933 al_free(device
->Hrtf
);
935 device
->HrtfHandle
= NULL
;
936 device
->HrtfName
.clear();
937 device
->Render_Mode
= NormalRender
;
939 memset(&device
->Dry
.Ambi
, 0, sizeof(device
->Dry
.Ambi
));
940 device
->Dry
.CoeffCount
= 0;
941 device
->Dry
.NumChannels
= 0;
942 for(i
= 0;i
< MAX_AMBI_ORDER
+1;i
++)
943 device
->NumChannelsPerOrder
[i
] = 0;
945 device
->AvgSpeakerDist
= 0.0f
;
946 memset(device
->ChannelDelay
, 0, sizeof(device
->ChannelDelay
));
947 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
949 device
->ChannelDelay
[i
].Gain
= 1.0f
;
950 device
->ChannelDelay
[i
].Length
= 0;
953 al_free(device
->Stablizer
);
954 device
->Stablizer
= NULL
;
956 if(device
->FmtChans
!= DevFmtStereo
)
958 ALsizei speakermap
[MAX_OUTPUT_CHANNELS
];
959 const char *devname
, *layout
= NULL
;
960 AmbDecConf conf
, *pconf
= NULL
;
963 Hrtf_DecRef(old_hrtf
);
965 if(hrtf_appreq
== Hrtf_Enable
)
966 device
->HrtfStatus
= ALC_HRTF_UNSUPPORTED_FORMAT_SOFT
;
968 devname
= device
->DeviceName
.c_str();
969 switch(device
->FmtChans
)
971 case DevFmtQuad
: layout
= "quad"; break;
972 case DevFmtX51
: /* fall-through */
973 case DevFmtX51Rear
: layout
= "surround51"; break;
974 case DevFmtX61
: layout
= "surround61"; break;
975 case DevFmtX71
: layout
= "surround71"; break;
976 /* Mono, Stereo, and Ambisonics output don't use custom decoders. */
985 if(ConfigValueStr(devname
, "decoder", layout
, &fname
))
987 if(!conf
.load(fname
))
988 ERR("Failed to load layout file %s\n", fname
);
991 if(conf
.ChanMask
> 0xffff)
992 ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf
.ChanMask
);
995 if(MakeSpeakerMap(device
, &conf
, speakermap
))
1002 if(pconf
&& GetConfigValueBool(devname
, "decoder", "hq-mode", 0))
1004 ambiup_free(&device
->AmbiUp
);
1005 if(!device
->AmbiDecoder
)
1006 device
->AmbiDecoder
= bformatdec_alloc();
1010 bformatdec_free(&device
->AmbiDecoder
);
1011 if(device
->FmtChans
!= DevFmtAmbi3D
|| device
->mAmbiOrder
< 2)
1012 ambiup_free(&device
->AmbiUp
);
1016 device
->AmbiUp
= ambiup_alloc();
1021 InitPanning(device
);
1022 else if(device
->AmbiDecoder
)
1023 InitHQPanning(device
, pconf
, speakermap
);
1025 InitCustomPanning(device
, pconf
, speakermap
);
1027 /* Enable the stablizer only for formats that have front-left, front-
1028 * right, and front-center outputs.
1030 switch(device
->FmtChans
)
1036 if(GetConfigValueBool(devname
, NULL
, "front-stablizer", 0))
1038 /* Initialize band-splitting filters for the front-left and
1039 * front-right channels, with a crossover at 5khz (could be
1042 ALfloat scale
= (ALfloat
)(5000.0 / device
->Frequency
);
1043 FrontStablizer
*stablizer
= reinterpret_cast<FrontStablizer
*>(
1044 al_calloc(16, sizeof(*stablizer
)));
1046 bandsplit_init(&stablizer
->LFilter
, scale
);
1047 stablizer
->RFilter
= stablizer
->LFilter
;
1049 /* Initialize all-pass filters for all other channels. */
1050 splitterap_init(&stablizer
->APFilter
[0], scale
);
1051 for(i
= 1;i
< (size_t)device
->RealOut
.NumChannels
;i
++)
1052 stablizer
->APFilter
[i
] = stablizer
->APFilter
[0];
1054 device
->Stablizer
= stablizer
;
1063 TRACE("Front stablizer %s\n", device
->Stablizer
? "enabled" : "disabled");
1068 bformatdec_free(&device
->AmbiDecoder
);
1070 headphones
= device
->IsHeadphones
;
1071 if(device
->Type
!= Loopback
)
1074 if(ConfigValueStr(device
->DeviceName
.c_str(), NULL
, "stereo-mode", &mode
))
1076 if(strcasecmp(mode
, "headphones") == 0)
1078 else if(strcasecmp(mode
, "speakers") == 0)
1080 else if(strcasecmp(mode
, "auto") != 0)
1081 ERR("Unexpected stereo-mode: %s\n", mode
);
1085 if(hrtf_userreq
== Hrtf_Default
)
1087 bool usehrtf
= (headphones
&& hrtf_appreq
!= Hrtf_Disable
) ||
1088 (hrtf_appreq
== Hrtf_Enable
);
1089 if(!usehrtf
) goto no_hrtf
;
1091 device
->HrtfStatus
= ALC_HRTF_ENABLED_SOFT
;
1092 if(headphones
&& hrtf_appreq
!= Hrtf_Disable
)
1093 device
->HrtfStatus
= ALC_HRTF_HEADPHONES_DETECTED_SOFT
;
1097 if(hrtf_userreq
!= Hrtf_Enable
)
1099 if(hrtf_appreq
== Hrtf_Enable
)
1100 device
->HrtfStatus
= ALC_HRTF_DENIED_SOFT
;
1103 device
->HrtfStatus
= ALC_HRTF_REQUIRED_SOFT
;
1106 if(device
->HrtfList
.empty())
1107 device
->HrtfList
= EnumerateHrtf(device
->DeviceName
.c_str());
1109 if(hrtf_id
>= 0 && (size_t)hrtf_id
< device
->HrtfList
.size())
1111 const EnumeratedHrtf
&entry
= device
->HrtfList
[hrtf_id
];
1112 struct Hrtf
*hrtf
= GetLoadedHrtf(entry
.hrtf
);
1113 if(hrtf
&& hrtf
->sampleRate
== device
->Frequency
)
1115 device
->HrtfHandle
= hrtf
;
1116 device
->HrtfName
= entry
.name
;
1122 for(i
= 0;!device
->HrtfHandle
&& i
< device
->HrtfList
.size();i
++)
1124 const EnumeratedHrtf
&entry
= device
->HrtfList
[i
];
1125 struct Hrtf
*hrtf
= GetLoadedHrtf(entry
.hrtf
);
1126 if(hrtf
&& hrtf
->sampleRate
== device
->Frequency
)
1128 device
->HrtfHandle
= hrtf
;
1129 device
->HrtfName
= entry
.name
;
1135 if(device
->HrtfHandle
)
1138 Hrtf_DecRef(old_hrtf
);
1141 device
->Render_Mode
= HrtfRender
;
1142 if(ConfigValueStr(device
->DeviceName
.c_str(), NULL
, "hrtf-mode", &mode
))
1144 if(strcasecmp(mode
, "full") == 0)
1145 device
->Render_Mode
= HrtfRender
;
1146 else if(strcasecmp(mode
, "basic") == 0)
1147 device
->Render_Mode
= NormalRender
;
1149 ERR("Unexpected hrtf-mode: %s\n", mode
);
1152 if(device
->Render_Mode
== HrtfRender
)
1154 /* Don't bother with HOA when using full HRTF rendering. Nothing
1155 * needs it, and it eases the CPU/memory load.
1157 ambiup_free(&device
->AmbiUp
);
1162 device
->AmbiUp
= ambiup_alloc();
1165 TRACE("%s HRTF rendering enabled, using \"%s\"\n",
1166 ((device
->Render_Mode
== HrtfRender
) ? "Full" : "Basic"), device
->HrtfName
.c_str()
1168 InitHrtfPanning(device
);
1171 device
->HrtfStatus
= ALC_HRTF_UNSUPPORTED_FORMAT_SOFT
;
1175 Hrtf_DecRef(old_hrtf
);
1177 TRACE("HRTF disabled\n");
1179 device
->Render_Mode
= StereoPair
;
1181 ambiup_free(&device
->AmbiUp
);
1183 bs2blevel
= ((headphones
&& hrtf_appreq
!= Hrtf_Disable
) ||
1184 (hrtf_appreq
== Hrtf_Enable
)) ? 5 : 0;
1185 if(device
->Type
!= Loopback
)
1186 ConfigValueInt(device
->DeviceName
.c_str(), NULL
, "cf_level", &bs2blevel
);
1187 if(bs2blevel
> 0 && bs2blevel
<= 6)
1189 device
->Bs2b
= reinterpret_cast<struct bs2b
*>(al_calloc(16, sizeof(*device
->Bs2b
)));
1190 bs2b_set_params(device
->Bs2b
, bs2blevel
, device
->Frequency
);
1191 TRACE("BS2B enabled\n");
1192 InitPanning(device
);
1196 TRACE("BS2B disabled\n");
1198 if(ConfigValueStr(device
->DeviceName
.c_str(), NULL
, "stereo-encoding", &mode
))
1200 if(strcasecmp(mode
, "uhj") == 0)
1201 device
->Render_Mode
= NormalRender
;
1202 else if(strcasecmp(mode
, "panpot") != 0)
1203 ERR("Unexpected stereo-encoding: %s\n", mode
);
1205 if(device
->Render_Mode
== NormalRender
)
1207 device
->Uhj_Encoder
= reinterpret_cast<Uhj2Encoder
*>(al_calloc(16, sizeof(Uhj2Encoder
)));
1208 TRACE("UHJ enabled\n");
1209 InitUhjPanning(device
);
1213 TRACE("UHJ disabled\n");
1214 InitPanning(device
);
1218 void aluInitEffectPanning(ALeffectslot
*slot
)
1222 memset(slot
->ChanMap
, 0, sizeof(slot
->ChanMap
));
1223 slot
->NumChannels
= 0;
1225 for(i
= 0;i
< MAX_EFFECT_CHANNELS
;i
++)
1227 slot
->ChanMap
[i
].Scale
= 1.0f
;
1228 slot
->ChanMap
[i
].Index
= i
;
1230 slot
->NumChannels
= i
;