Use the proper left and right channels for UHJ output
[openal-soft.git] / Alc / ALu.c
blob17c91e52ace5eedd61aceaa053ced9bae3ea8942
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 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 "alSource.h"
31 #include "alBuffer.h"
32 #include "alListener.h"
33 #include "alAuxEffectSlot.h"
34 #include "alu.h"
35 #include "bs2b.h"
36 #include "hrtf.h"
37 #include "uhjfilter.h"
38 #include "static_assert.h"
40 #include "mixer_defs.h"
42 #include "backends/base.h"
45 struct ChanMap {
46 enum Channel channel;
47 ALfloat angle;
48 ALfloat elevation;
51 /* Cone scalar */
52 ALfloat ConeScale = 1.0f;
54 /* Localized Z scalar for mono sources */
55 ALfloat ZScale = 1.0f;
57 extern inline ALfloat minf(ALfloat a, ALfloat b);
58 extern inline ALfloat maxf(ALfloat a, ALfloat b);
59 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
61 extern inline ALdouble mind(ALdouble a, ALdouble b);
62 extern inline ALdouble maxd(ALdouble a, ALdouble b);
63 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
65 extern inline ALuint minu(ALuint a, ALuint b);
66 extern inline ALuint maxu(ALuint a, ALuint b);
67 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
69 extern inline ALint mini(ALint a, ALint b);
70 extern inline ALint maxi(ALint a, ALint b);
71 extern inline ALint clampi(ALint val, ALint min, ALint max);
73 extern inline ALint64 mini64(ALint64 a, ALint64 b);
74 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
75 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
77 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
78 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
79 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
81 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
82 extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
83 extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac);
85 extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
87 extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
88 ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
89 extern inline void aluMatrixfSet(aluMatrixf *matrix,
90 ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
91 ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
92 ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
93 ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
95 extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
96 ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3);
97 extern inline void aluMatrixdSet(aluMatrixd *matrix,
98 ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
99 ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
100 ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
101 ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
104 static inline HrtfMixerFunc SelectHrtfMixer(void)
106 #ifdef HAVE_SSE
107 if((CPUCapFlags&CPU_CAP_SSE))
108 return MixHrtf_SSE;
109 #endif
110 #ifdef HAVE_NEON
111 if((CPUCapFlags&CPU_CAP_NEON))
112 return MixHrtf_Neon;
113 #endif
115 return MixHrtf_C;
119 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
121 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
122 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
123 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
126 static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2)
128 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
131 static inline ALfloat aluNormalize(ALfloat *vec)
133 ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
134 if(length > 0.0f)
136 ALfloat inv_length = 1.0f/length;
137 vec[0] *= inv_length;
138 vec[1] *= inv_length;
139 vec[2] *= inv_length;
141 return length;
145 static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *outVector)
147 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
148 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
149 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
152 static inline ALdouble aluNormalized(ALdouble *vec)
154 ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
155 if(length > 0.0)
157 ALdouble inv_length = 1.0/length;
158 vec[0] *= inv_length;
159 vec[1] *= inv_length;
160 vec[2] *= inv_length;
162 return length;
165 static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx)
167 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
169 vec[0] = (ALfloat)(v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0]);
170 vec[1] = (ALfloat)(v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1]);
171 vec[2] = (ALfloat)(v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2]);
174 static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx)
176 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
178 vec[0] = v[0]*mtx->m[0][0] + v[1]*mtx->m[1][0] + v[2]*mtx->m[2][0] + v[3]*mtx->m[3][0];
179 vec[1] = v[0]*mtx->m[0][1] + v[1]*mtx->m[1][1] + v[2]*mtx->m[2][1] + v[3]*mtx->m[3][1];
180 vec[2] = v[0]*mtx->m[0][2] + v[1]*mtx->m[1][2] + v[2]*mtx->m[2][2] + v[3]*mtx->m[3][2];
183 static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec)
185 aluVector v;
186 v.v[0] = (ALfloat)(vec->v[0]*mtx->m[0][0] + vec->v[1]*mtx->m[1][0] + vec->v[2]*mtx->m[2][0] + vec->v[3]*mtx->m[3][0]);
187 v.v[1] = (ALfloat)(vec->v[0]*mtx->m[0][1] + vec->v[1]*mtx->m[1][1] + vec->v[2]*mtx->m[2][1] + vec->v[3]*mtx->m[3][1]);
188 v.v[2] = (ALfloat)(vec->v[0]*mtx->m[0][2] + vec->v[1]*mtx->m[1][2] + vec->v[2]*mtx->m[2][2] + vec->v[3]*mtx->m[3][2]);
189 v.v[3] = (ALfloat)(vec->v[0]*mtx->m[0][3] + vec->v[1]*mtx->m[1][3] + vec->v[2]*mtx->m[2][3] + vec->v[3]*mtx->m[3][3]);
190 return v;
194 /* Prepares the interpolator for a given rate (determined by increment). A
195 * result of AL_FALSE indicates that the filter output will completely cut
196 * the input signal.
198 * With a bit of work, and a trade of memory for CPU cost, this could be
199 * modified for use with an interpolated increment for buttery-smooth pitch
200 * changes.
202 static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
204 static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f;
205 static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 };
206 static const ALuint to[4][BSINC_SCALE_COUNT] =
208 { 0, 24, 408, 792, 1176, 1560, 1944, 2328, 2648, 2968, 3288, 3544, 3800, 4056, 4248, 4440 },
209 { 4632, 5016, 5400, 5784, 6168, 6552, 6936, 7320, 7640, 7960, 8280, 8536, 8792, 9048, 9240, 0 },
210 { 0, 9432, 9816, 10200, 10584, 10968, 11352, 11736, 12056, 12376, 12696, 12952, 13208, 13464, 13656, 13848 },
211 { 14040, 14424, 14808, 15192, 15576, 15960, 16344, 16728, 17048, 17368, 17688, 17944, 18200, 18456, 18648, 0 }
213 static const ALuint tm[2][BSINC_SCALE_COUNT] =
215 { 0, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 },
216 { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 }
218 ALfloat sf;
219 ALuint si, pi;
220 ALboolean uncut = AL_TRUE;
222 if(increment > FRACTIONONE)
224 sf = (ALfloat)FRACTIONONE / increment;
225 if(sf < scaleBase)
227 /* Signal has been completely cut. The return result can be used
228 * to skip the filter (and output zeros) as an optimization.
230 sf = 0.0f;
231 si = 0;
232 uncut = AL_FALSE;
234 else
236 sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange;
237 si = fastf2u(sf);
238 /* The interpolation factor is fit to this diagonally-symmetric
239 * curve to reduce the transition ripple caused by interpolating
240 * different scales of the sinc function.
242 sf = 1.0f - cosf(asinf(sf - si));
245 else
247 sf = 0.0f;
248 si = BSINC_SCALE_COUNT - 1;
251 state->sf = sf;
252 state->m = m[si];
253 state->l = -(ALint)((m[si] / 2) - 1);
254 /* The CPU cost of this table re-mapping could be traded for the memory
255 * cost of a complete table map (1024 elements large).
257 for(pi = 0;pi < BSINC_PHASE_COUNT;pi++)
259 state->coeffs[pi].filter = &bsincTab[to[0][si] + tm[0][si]*pi];
260 state->coeffs[pi].scDelta = &bsincTab[to[1][si] + tm[1][si]*pi];
261 state->coeffs[pi].phDelta = &bsincTab[to[2][si] + tm[0][si]*pi];
262 state->coeffs[pi].spDelta = &bsincTab[to[3][si] + tm[1][si]*pi];
264 return uncut;
268 static ALvoid CalcListenerParams(ALlistener *Listener)
270 ALdouble N[3], V[3], U[3], P[3];
272 /* AT then UP */
273 N[0] = Listener->Forward[0];
274 N[1] = Listener->Forward[1];
275 N[2] = Listener->Forward[2];
276 aluNormalized(N);
277 V[0] = Listener->Up[0];
278 V[1] = Listener->Up[1];
279 V[2] = Listener->Up[2];
280 aluNormalized(V);
281 /* Build and normalize right-vector */
282 aluCrossproductd(N, V, U);
283 aluNormalized(U);
285 aluMatrixdSet(&Listener->Params.Matrix,
286 U[0], V[0], -N[0], 0.0,
287 U[1], V[1], -N[1], 0.0,
288 U[2], V[2], -N[2], 0.0,
289 0.0, 0.0, 0.0, 1.0
292 P[0] = Listener->Position.v[0];
293 P[1] = Listener->Position.v[1];
294 P[2] = Listener->Position.v[2];
295 aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix);
296 aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
298 Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity);
301 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
303 static const struct ChanMap MonoMap[1] = {
304 { FrontCenter, 0.0f, 0.0f }
305 }, StereoMap[2] = {
306 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
307 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
308 }, RearMap[2] = {
309 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
310 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
311 }, QuadMap[4] = {
312 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
313 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
314 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
315 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
316 }, X51Map[6] = {
317 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
318 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
319 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
320 { LFE, 0.0f, 0.0f },
321 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
322 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
323 }, X61Map[7] = {
324 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
325 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
326 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
327 { LFE, 0.0f, 0.0f },
328 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
329 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
330 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
331 }, X71Map[8] = {
332 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
333 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
334 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
335 { LFE, 0.0f, 0.0f },
336 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
337 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
338 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
339 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
342 const ALCdevice *Device = ALContext->Device;
343 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
344 ALbufferlistitem *BufferListItem;
345 enum FmtChannels Channels;
346 ALfloat DryGain, DryGainHF, DryGainLF;
347 ALfloat WetGain[MAX_SENDS];
348 ALfloat WetGainHF[MAX_SENDS];
349 ALfloat WetGainLF[MAX_SENDS];
350 ALeffectslot *SendSlots[MAX_SENDS];
351 ALuint NumSends, Frequency;
352 ALboolean Relative;
353 const struct ChanMap *chans = NULL;
354 ALuint num_channels = 0;
355 ALboolean DirectChannels;
356 ALboolean isbformat = AL_FALSE;
357 ALfloat Pitch;
358 ALuint i, j, c;
360 /* Get device properties */
361 NumSends = Device->NumAuxSends;
362 Frequency = Device->Frequency;
364 /* Get listener properties */
365 ListenerGain = ALContext->Listener->Gain;
367 /* Get source properties */
368 SourceVolume = ALSource->Gain;
369 MinVolume = ALSource->MinGain;
370 MaxVolume = ALSource->MaxGain;
371 Pitch = ALSource->Pitch;
372 Relative = ALSource->HeadRelative;
373 DirectChannels = ALSource->DirectChannels;
375 voice->Direct.OutBuffer = Device->Dry.Buffer;
376 voice->Direct.OutChannels = Device->Dry.NumChannels;
377 for(i = 0;i < NumSends;i++)
379 SendSlots[i] = ALSource->Send[i].Slot;
380 if(!SendSlots[i] && i == 0)
381 SendSlots[i] = Device->DefaultSlot;
382 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
384 SendSlots[i] = NULL;
385 voice->Send[i].OutBuffer = NULL;
386 voice->Send[i].OutChannels = 0;
388 else
390 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
391 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
395 /* Calculate the stepping value */
396 Channels = FmtMono;
397 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
398 while(BufferListItem != NULL)
400 ALbuffer *ALBuffer;
401 if((ALBuffer=BufferListItem->buffer) != NULL)
403 Pitch = Pitch * ALBuffer->Frequency / Frequency;
404 if(Pitch > (ALfloat)MAX_PITCH)
405 voice->Step = MAX_PITCH<<FRACTIONBITS;
406 else
407 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
408 BsincPrepare(voice->Step, &voice->SincState);
410 Channels = ALBuffer->FmtChannels;
411 break;
413 BufferListItem = BufferListItem->next;
416 /* Calculate gains */
417 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
418 DryGain *= ALSource->Direct.Gain * ListenerGain;
419 DryGainHF = ALSource->Direct.GainHF;
420 DryGainLF = ALSource->Direct.GainLF;
421 for(i = 0;i < NumSends;i++)
423 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
424 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
425 WetGainHF[i] = ALSource->Send[i].GainHF;
426 WetGainLF[i] = ALSource->Send[i].GainLF;
429 switch(Channels)
431 case FmtMono:
432 chans = MonoMap;
433 num_channels = 1;
434 break;
436 case FmtStereo:
437 chans = StereoMap;
438 num_channels = 2;
439 break;
441 case FmtRear:
442 chans = RearMap;
443 num_channels = 2;
444 break;
446 case FmtQuad:
447 chans = QuadMap;
448 num_channels = 4;
449 break;
451 case FmtX51:
452 chans = X51Map;
453 num_channels = 6;
454 break;
456 case FmtX61:
457 chans = X61Map;
458 num_channels = 7;
459 break;
461 case FmtX71:
462 chans = X71Map;
463 num_channels = 8;
464 break;
466 case FmtBFormat2D:
467 num_channels = 3;
468 isbformat = AL_TRUE;
469 DirectChannels = AL_FALSE;
470 break;
472 case FmtBFormat3D:
473 num_channels = 4;
474 isbformat = AL_TRUE;
475 DirectChannels = AL_FALSE;
476 break;
479 if(isbformat)
481 ALfloat N[3], V[3], U[3];
482 aluMatrixf matrix;
483 ALfloat scale;
485 /* AT then UP */
486 N[0] = ALSource->Orientation[0][0];
487 N[1] = ALSource->Orientation[0][1];
488 N[2] = ALSource->Orientation[0][2];
489 aluNormalize(N);
490 V[0] = ALSource->Orientation[1][0];
491 V[1] = ALSource->Orientation[1][1];
492 V[2] = ALSource->Orientation[1][2];
493 aluNormalize(V);
494 if(!Relative)
496 const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
497 aluMatrixdFloat3(N, 0.0f, lmatrix);
498 aluMatrixdFloat3(V, 0.0f, lmatrix);
500 /* Build and normalize right-vector */
501 aluCrossproduct(N, V, U);
502 aluNormalize(U);
504 /* Build a rotate + conversion matrix (B-Format -> N3D), and include
505 * scaling for first-order content on second- or third-order output.
507 scale = Device->Dry.AmbiScale * 1.732050808f;
508 aluMatrixfSet(&matrix,
509 1.414213562f, 0.0f, 0.0f, 0.0f,
510 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
511 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
512 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
515 for(c = 0;c < num_channels;c++)
516 ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, matrix.m[c],
517 DryGain, voice->Direct.Gains[c].Target);
519 /* Rebuild the matrix, without the second- or third-order output
520 * scaling (effects take first-order content, and will do the scaling
521 * themselves when mixing to the output).
523 scale = 1.732050808f;
524 aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale);
525 aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale);
526 aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale);
527 for(i = 0;i < NumSends;i++)
529 if(!SendSlots[i])
531 for(c = 0;c < num_channels;c++)
533 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
534 voice->Send[i].Gains[c].Target[j] = 0.0f;
537 else
539 for(c = 0;c < num_channels;c++)
541 const ALeffectslot *Slot = SendSlots[i];
542 ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c],
543 WetGain[i], voice->Send[i].Gains[c].Target);
548 voice->IsHrtf = AL_FALSE;
550 else
552 ALfloat coeffs[MAX_AMBI_COEFFS];
554 if(DirectChannels)
556 if(Device->Hrtf || Device->Uhj_Encoder)
558 /* DirectChannels with HRTF or UHJ enabled. Skip the virtual
559 * channels and write FrontLeft and FrontRight inputs to the
560 * first and second outputs.
562 voice->Direct.OutBuffer = Device->RealOut.Buffer;
563 voice->Direct.OutChannels = Device->RealOut.NumChannels;
564 for(c = 0;c < num_channels;c++)
566 int idx;
567 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
568 voice->Direct.Gains[c].Target[j] = 0.0f;
569 if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1)
570 voice->Direct.Gains[c].Target[idx] = DryGain;
573 else for(c = 0;c < num_channels;c++)
575 int idx;
576 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
577 voice->Direct.Gains[c].Target[j] = 0.0f;
578 if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1)
579 voice->Direct.Gains[c].Target[idx] = DryGain;
582 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
583 * channel-match. */
584 for(c = 0;c < num_channels;c++)
586 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
588 for(i = 0;i < NumSends;i++)
590 if(!SendSlots[i])
592 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
593 voice->Send[i].Gains[c].Target[j] = 0.0f;
595 else
597 const ALeffectslot *Slot = SendSlots[i];
598 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
599 WetGain[i], voice->Send[i].Gains[c].Target);
604 voice->IsHrtf = AL_FALSE;
606 else if(Device->Render_Mode == HrtfRender)
608 /* Full HRTF rendering. Skip the virtual channels and render each
609 * input channel to the real outputs.
611 voice->Direct.OutBuffer = Device->RealOut.Buffer;
612 voice->Direct.OutChannels = Device->RealOut.NumChannels;
613 for(c = 0;c < num_channels;c++)
615 if(chans[c].channel == LFE)
617 /* Skip LFE */
618 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
619 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
620 for(i = 0;i < HRIR_LENGTH;i++)
622 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
623 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
626 for(i = 0;i < NumSends;i++)
628 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
629 voice->Send[i].Gains[c].Target[j] = 0.0f;
632 continue;
635 /* Get the static HRIR coefficients and delays for this channel. */
636 GetLerpedHrtfCoeffs(Device->Hrtf,
637 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
638 voice->Direct.Hrtf[c].Target.Coeffs,
639 voice->Direct.Hrtf[c].Target.Delay
642 /* Normal panning for auxiliary sends. */
643 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
645 for(i = 0;i < NumSends;i++)
647 if(!SendSlots[i])
649 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
650 voice->Send[i].Gains[c].Target[j] = 0.0f;
652 else
654 const ALeffectslot *Slot = SendSlots[i];
655 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
656 WetGain[i], voice->Send[i].Gains[c].Target);
661 voice->IsHrtf = AL_TRUE;
663 else
665 /* Non-HRTF rendering. Use normal panning to the output. */
666 for(c = 0;c < num_channels;c++)
668 /* Special-case LFE */
669 if(chans[c].channel == LFE)
671 int idx;
672 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
673 voice->Direct.Gains[c].Target[j] = 0.0f;
674 if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1)
675 voice->Direct.Gains[c].Target[idx] = DryGain;
677 for(i = 0;i < NumSends;i++)
679 ALuint j;
680 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
681 voice->Send[i].Gains[c].Target[j] = 0.0f;
683 continue;
686 if(Device->Render_Mode == StereoPair)
688 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
689 ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation);
690 coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5;
691 voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain;
692 voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain;
693 for(j = 2;j < MAX_OUTPUT_CHANNELS;j++)
694 voice->Direct.Gains[c].Target[j] = 0.0f;
696 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
698 else
700 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
701 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
702 DryGain, voice->Direct.Gains[c].Target);
705 for(i = 0;i < NumSends;i++)
707 if(!SendSlots[i])
709 ALuint j;
710 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
711 voice->Send[i].Gains[c].Target[j] = 0.0f;
713 else
715 const ALeffectslot *Slot = SendSlots[i];
716 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
717 WetGain[i], voice->Send[i].Gains[c].Target);
722 voice->IsHrtf = AL_FALSE;
727 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
728 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
729 DryGainHF = maxf(DryGainHF, 0.0001f);
730 DryGainLF = maxf(DryGainLF, 0.0001f);
731 for(c = 0;c < num_channels;c++)
733 voice->Direct.Filters[c].ActiveType = AF_None;
734 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
735 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
736 ALfilterState_setParams(
737 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
738 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
740 ALfilterState_setParams(
741 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
742 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
746 for(i = 0;i < NumSends;i++)
748 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
749 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
750 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
751 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
752 for(c = 0;c < num_channels;c++)
754 voice->Send[i].Filters[c].ActiveType = AF_None;
755 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
756 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
757 ALfilterState_setParams(
758 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
759 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
761 ALfilterState_setParams(
762 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
763 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
769 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
771 const ALCdevice *Device = ALContext->Device;
772 aluVector Position, Velocity, Direction, SourceToListener;
773 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
774 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
775 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
776 ALfloat DopplerFactor, SpeedOfSound;
777 ALfloat AirAbsorptionFactor;
778 ALfloat RoomAirAbsorption[MAX_SENDS];
779 ALbufferlistitem *BufferListItem;
780 ALeffectslot *SendSlots[MAX_SENDS];
781 ALfloat Attenuation;
782 ALfloat RoomAttenuation[MAX_SENDS];
783 ALfloat MetersPerUnit;
784 ALfloat RoomRolloffBase;
785 ALfloat RoomRolloff[MAX_SENDS];
786 ALfloat DecayDistance[MAX_SENDS];
787 ALfloat DryGain;
788 ALfloat DryGainHF;
789 ALfloat DryGainLF;
790 ALboolean DryGainHFAuto;
791 ALfloat WetGain[MAX_SENDS];
792 ALfloat WetGainHF[MAX_SENDS];
793 ALfloat WetGainLF[MAX_SENDS];
794 ALboolean WetGainAuto;
795 ALboolean WetGainHFAuto;
796 ALfloat Pitch;
797 ALuint Frequency;
798 ALint NumSends;
799 ALint i;
801 DryGainHF = 1.0f;
802 DryGainLF = 1.0f;
803 for(i = 0;i < MAX_SENDS;i++)
805 WetGainHF[i] = 1.0f;
806 WetGainLF[i] = 1.0f;
809 /* Get context/device properties */
810 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
811 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
812 NumSends = Device->NumAuxSends;
813 Frequency = Device->Frequency;
815 /* Get listener properties */
816 ListenerGain = ALContext->Listener->Gain;
817 MetersPerUnit = ALContext->Listener->MetersPerUnit;
819 /* Get source properties */
820 SourceVolume = ALSource->Gain;
821 MinVolume = ALSource->MinGain;
822 MaxVolume = ALSource->MaxGain;
823 Pitch = ALSource->Pitch;
824 Position = ALSource->Position;
825 Direction = ALSource->Direction;
826 Velocity = ALSource->Velocity;
827 MinDist = ALSource->RefDistance;
828 MaxDist = ALSource->MaxDistance;
829 Rolloff = ALSource->RollOffFactor;
830 InnerAngle = ALSource->InnerAngle;
831 OuterAngle = ALSource->OuterAngle;
832 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
833 DryGainHFAuto = ALSource->DryGainHFAuto;
834 WetGainAuto = ALSource->WetGainAuto;
835 WetGainHFAuto = ALSource->WetGainHFAuto;
836 RoomRolloffBase = ALSource->RoomRolloffFactor;
838 voice->Direct.OutBuffer = Device->Dry.Buffer;
839 voice->Direct.OutChannels = Device->Dry.NumChannels;
840 for(i = 0;i < NumSends;i++)
842 SendSlots[i] = ALSource->Send[i].Slot;
844 if(!SendSlots[i] && i == 0)
845 SendSlots[i] = Device->DefaultSlot;
846 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
848 SendSlots[i] = NULL;
849 RoomRolloff[i] = 0.0f;
850 DecayDistance[i] = 0.0f;
851 RoomAirAbsorption[i] = 1.0f;
853 else if(SendSlots[i]->AuxSendAuto)
855 RoomRolloff[i] = RoomRolloffBase;
856 if(IsReverbEffect(SendSlots[i]->EffectType))
858 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
859 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
860 SPEEDOFSOUNDMETRESPERSEC;
861 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
863 else
865 DecayDistance[i] = 0.0f;
866 RoomAirAbsorption[i] = 1.0f;
869 else
871 /* If the slot's auxiliary send auto is off, the data sent to the
872 * effect slot is the same as the dry path, sans filter effects */
873 RoomRolloff[i] = Rolloff;
874 DecayDistance[i] = 0.0f;
875 RoomAirAbsorption[i] = AIRABSORBGAINHF;
878 if(!SendSlots[i])
880 voice->Send[i].OutBuffer = NULL;
881 voice->Send[i].OutChannels = 0;
883 else
885 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
886 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
890 /* Transform source to listener space (convert to head relative) */
891 if(ALSource->HeadRelative == AL_FALSE)
893 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
894 /* Transform source vectors */
895 Position = aluMatrixdVector(Matrix, &Position);
896 Velocity = aluMatrixdVector(Matrix, &Velocity);
897 Direction = aluMatrixdVector(Matrix, &Direction);
899 else
901 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
902 /* Offset the source velocity to be relative of the listener velocity */
903 Velocity.v[0] += lvelocity->v[0];
904 Velocity.v[1] += lvelocity->v[1];
905 Velocity.v[2] += lvelocity->v[2];
908 aluNormalize(Direction.v);
909 SourceToListener.v[0] = -Position.v[0];
910 SourceToListener.v[1] = -Position.v[1];
911 SourceToListener.v[2] = -Position.v[2];
912 SourceToListener.v[3] = 0.0f;
913 Distance = aluNormalize(SourceToListener.v);
915 /* Calculate distance attenuation */
916 ClampedDist = Distance;
918 Attenuation = 1.0f;
919 for(i = 0;i < NumSends;i++)
920 RoomAttenuation[i] = 1.0f;
921 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
922 ALContext->DistanceModel)
924 case InverseDistanceClamped:
925 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
926 if(MaxDist < MinDist)
927 break;
928 /*fall-through*/
929 case InverseDistance:
930 if(MinDist > 0.0f)
932 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
933 if(dist > 0.0f) Attenuation = MinDist / dist;
934 for(i = 0;i < NumSends;i++)
936 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
937 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
940 break;
942 case LinearDistanceClamped:
943 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
944 if(MaxDist < MinDist)
945 break;
946 /*fall-through*/
947 case LinearDistance:
948 if(MaxDist != MinDist)
950 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
951 Attenuation = maxf(Attenuation, 0.0f);
952 for(i = 0;i < NumSends;i++)
954 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
955 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
958 break;
960 case ExponentDistanceClamped:
961 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
962 if(MaxDist < MinDist)
963 break;
964 /*fall-through*/
965 case ExponentDistance:
966 if(ClampedDist > 0.0f && MinDist > 0.0f)
968 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
969 for(i = 0;i < NumSends;i++)
970 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
972 break;
974 case DisableDistance:
975 ClampedDist = MinDist;
976 break;
979 /* Source Gain + Attenuation */
980 DryGain = SourceVolume * Attenuation;
981 for(i = 0;i < NumSends;i++)
982 WetGain[i] = SourceVolume * RoomAttenuation[i];
984 /* Distance-based air absorption */
985 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
987 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
988 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
989 for(i = 0;i < NumSends;i++)
990 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
993 if(WetGainAuto)
995 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
997 /* Apply a decay-time transformation to the wet path, based on the
998 * attenuation of the dry path.
1000 * Using the apparent distance, based on the distance attenuation, the
1001 * initial decay of the reverb effect is calculated and applied to the
1002 * wet path.
1004 for(i = 0;i < NumSends;i++)
1006 if(DecayDistance[i] > 0.0f)
1007 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1011 /* Calculate directional soundcones */
1012 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1013 if(Angle > InnerAngle && Angle <= OuterAngle)
1015 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1016 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1017 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1019 else if(Angle > OuterAngle)
1021 ConeVolume = ALSource->OuterGain;
1022 ConeHF = ALSource->OuterGainHF;
1024 else
1026 ConeVolume = 1.0f;
1027 ConeHF = 1.0f;
1030 DryGain *= ConeVolume;
1031 if(WetGainAuto)
1033 for(i = 0;i < NumSends;i++)
1034 WetGain[i] *= ConeVolume;
1036 if(DryGainHFAuto)
1037 DryGainHF *= ConeHF;
1038 if(WetGainHFAuto)
1040 for(i = 0;i < NumSends;i++)
1041 WetGainHF[i] *= ConeHF;
1044 /* Clamp to Min/Max Gain */
1045 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1046 for(i = 0;i < NumSends;i++)
1047 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1049 /* Apply gain and frequency filters */
1050 DryGain *= ALSource->Direct.Gain * ListenerGain;
1051 DryGainHF *= ALSource->Direct.GainHF;
1052 DryGainLF *= ALSource->Direct.GainLF;
1053 for(i = 0;i < NumSends;i++)
1055 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1056 WetGainHF[i] *= ALSource->Send[i].GainHF;
1057 WetGainLF[i] *= ALSource->Send[i].GainLF;
1060 /* Calculate velocity-based doppler effect */
1061 if(DopplerFactor > 0.0f)
1063 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1064 ALfloat VSS, VLS;
1066 if(SpeedOfSound < 1.0f)
1068 DopplerFactor *= 1.0f/SpeedOfSound;
1069 SpeedOfSound = 1.0f;
1072 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1073 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1075 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1076 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1079 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1080 while(BufferListItem != NULL)
1082 ALbuffer *ALBuffer;
1083 if((ALBuffer=BufferListItem->buffer) != NULL)
1085 /* Calculate fixed-point stepping value, based on the pitch, buffer
1086 * frequency, and output frequency. */
1087 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1088 if(Pitch > (ALfloat)MAX_PITCH)
1089 voice->Step = MAX_PITCH<<FRACTIONBITS;
1090 else
1091 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1092 BsincPrepare(voice->Step, &voice->SincState);
1094 break;
1096 BufferListItem = BufferListItem->next;
1099 if(Device->Render_Mode == HrtfRender)
1101 /* Full HRTF rendering. Skip the virtual channels and render to the
1102 * real outputs.
1104 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1105 ALfloat ev = 0.0f, az = 0.0f;
1106 ALfloat radius = ALSource->Radius;
1107 ALfloat dirfact = 1.0f;
1108 ALfloat coeffs[MAX_AMBI_COEFFS];
1110 voice->Direct.OutBuffer = Device->RealOut.Buffer;
1111 voice->Direct.OutChannels = Device->RealOut.NumChannels;
1113 if(Distance > FLT_EPSILON)
1115 dir.v[0] = -SourceToListener.v[0];
1116 dir.v[1] = -SourceToListener.v[1];
1117 dir.v[2] = -SourceToListener.v[2] * ZScale;
1119 /* Calculate elevation and azimuth only when the source is not at
1120 * the listener. This prevents +0 and -0 Z from producing
1121 * inconsistent panning. Also, clamp Y in case FP precision errors
1122 * cause it to land outside of -1..+1. */
1123 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1124 az = atan2f(dir.v[0], -dir.v[2]);
1126 if(radius > 0.0f)
1128 if(radius >= Distance)
1129 dirfact *= Distance / radius * 0.5f;
1130 else
1131 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1134 /* Get the HRIR coefficients and delays. */
1135 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1136 voice->Direct.Hrtf[0].Target.Coeffs,
1137 voice->Direct.Hrtf[0].Target.Delay);
1139 dir.v[0] *= dirfact;
1140 dir.v[1] *= dirfact;
1141 dir.v[2] *= dirfact;
1142 CalcDirectionCoeffs(dir.v, coeffs);
1144 for(i = 0;i < NumSends;i++)
1146 if(!SendSlots[i])
1148 ALuint j;
1149 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1150 voice->Send[i].Gains[0].Target[j] = 0.0f;
1152 else
1154 const ALeffectslot *Slot = SendSlots[i];
1155 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1156 WetGain[i], voice->Send[i].Gains[0].Target);
1160 voice->IsHrtf = AL_TRUE;
1162 else
1164 /* Non-HRTF rendering. */
1165 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1166 ALfloat radius = ALSource->Radius;
1167 ALfloat coeffs[MAX_AMBI_COEFFS];
1169 /* Get the localized direction, and compute panned gains. */
1170 if(Distance > FLT_EPSILON)
1172 dir[0] = -SourceToListener.v[0];
1173 dir[1] = -SourceToListener.v[1];
1174 dir[2] = -SourceToListener.v[2] * ZScale;
1176 if(radius > 0.0f)
1178 ALfloat dirfact;
1179 if(radius >= Distance)
1180 dirfact = Distance / radius * 0.5f;
1181 else
1182 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1183 dir[0] *= dirfact;
1184 dir[1] *= dirfact;
1185 dir[2] *= dirfact;
1188 if(Device->Render_Mode == StereoPair)
1190 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
1191 coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5;
1192 voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain;
1193 voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain;
1194 for(i = 2;i < MAX_OUTPUT_CHANNELS;i++)
1195 voice->Direct.Gains[0].Target[i] = 0.0f;
1197 CalcDirectionCoeffs(dir, coeffs);
1199 else
1201 CalcDirectionCoeffs(dir, coeffs);
1202 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
1203 DryGain, voice->Direct.Gains[0].Target);
1206 for(i = 0;i < NumSends;i++)
1208 if(!SendSlots[i])
1210 ALuint j;
1211 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1212 voice->Send[i].Gains[0].Target[j] = 0.0f;
1214 else
1216 const ALeffectslot *Slot = SendSlots[i];
1217 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1218 WetGain[i], voice->Send[i].Gains[0].Target);
1222 voice->IsHrtf = AL_FALSE;
1226 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1227 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1228 DryGainHF = maxf(DryGainHF, 0.0001f);
1229 DryGainLF = maxf(DryGainLF, 0.0001f);
1230 voice->Direct.Filters[0].ActiveType = AF_None;
1231 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1232 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1233 ALfilterState_setParams(
1234 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1235 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1237 ALfilterState_setParams(
1238 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1239 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1242 for(i = 0;i < NumSends;i++)
1244 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1245 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1246 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1247 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1248 voice->Send[i].Filters[0].ActiveType = AF_None;
1249 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1250 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1251 ALfilterState_setParams(
1252 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1253 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1255 ALfilterState_setParams(
1256 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1257 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1263 void UpdateContextSources(ALCcontext *ctx)
1265 ALvoice *voice, *voice_end;
1266 ALsource *source;
1268 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1270 CalcListenerParams(ctx->Listener);
1272 voice = ctx->Voices;
1273 voice_end = voice + ctx->VoiceCount;
1274 for(;voice != voice_end;++voice)
1276 if(!(source=voice->Source)) continue;
1277 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1278 voice->Source = NULL;
1279 else
1281 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1282 voice->Update(voice, source, ctx);
1286 else
1288 voice = ctx->Voices;
1289 voice_end = voice + ctx->VoiceCount;
1290 for(;voice != voice_end;++voice)
1292 if(!(source=voice->Source)) continue;
1293 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1294 voice->Source = NULL;
1295 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1296 voice->Update(voice, source, ctx);
1302 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1303 * converts NaN to 0. */
1304 static inline ALfloat aluClampf(ALfloat val)
1306 if(fabsf(val) <= 1.0f) return val;
1307 return (ALfloat)((0.0f < val) - (val < 0.0f));
1310 static inline ALfloat aluF2F(ALfloat val)
1311 { return val; }
1313 static inline ALint aluF2I(ALfloat val)
1315 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1316 * integer range normalized floats can be safely converted to.
1318 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1320 static inline ALuint aluF2UI(ALfloat val)
1321 { return aluF2I(val)+2147483648u; }
1323 static inline ALshort aluF2S(ALfloat val)
1324 { return fastf2i(aluClampf(val)*32767.0f); }
1325 static inline ALushort aluF2US(ALfloat val)
1326 { return aluF2S(val)+32768; }
1328 static inline ALbyte aluF2B(ALfloat val)
1329 { return fastf2i(aluClampf(val)*127.0f); }
1330 static inline ALubyte aluF2UB(ALfloat val)
1331 { return aluF2B(val)+128; }
1333 #define DECL_TEMPLATE(T, func) \
1334 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1335 ALuint SamplesToDo, ALuint numchans) \
1337 ALuint i, j; \
1338 for(j = 0;j < numchans;j++) \
1340 const ALfloat *in = InBuffer[j]; \
1341 T *restrict out = (T*)OutBuffer + j; \
1342 for(i = 0;i < SamplesToDo;i++) \
1343 out[i*numchans] = func(in[i]); \
1347 DECL_TEMPLATE(ALfloat, aluF2F)
1348 DECL_TEMPLATE(ALuint, aluF2UI)
1349 DECL_TEMPLATE(ALint, aluF2I)
1350 DECL_TEMPLATE(ALushort, aluF2US)
1351 DECL_TEMPLATE(ALshort, aluF2S)
1352 DECL_TEMPLATE(ALubyte, aluF2UB)
1353 DECL_TEMPLATE(ALbyte, aluF2B)
1355 #undef DECL_TEMPLATE
1358 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1360 ALuint SamplesToDo;
1361 ALvoice *voice, *voice_end;
1362 ALeffectslot *slot;
1363 ALsource *source;
1364 ALCcontext *ctx;
1365 FPUCtl oldMode;
1366 ALuint i, c;
1368 SetMixerFPUMode(&oldMode);
1370 while(size > 0)
1372 IncrementRef(&device->MixCount);
1374 SamplesToDo = minu(size, BUFFERSIZE);
1375 for(c = 0;c < device->VirtOut.NumChannels;c++)
1376 memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1377 for(c = 0;c < device->RealOut.NumChannels;c++)
1378 memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1380 V0(device->Backend,lock)();
1382 if((slot=device->DefaultSlot) != NULL)
1384 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1385 V(slot->EffectState,update)(device, slot);
1386 for(i = 0;i < slot->NumChannels;i++)
1387 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1390 ctx = ATOMIC_LOAD(&device->ContextList);
1391 while(ctx)
1393 if(!ctx->DeferUpdates)
1395 UpdateContextSources(ctx);
1396 #define UPDATE_SLOT(iter) do { \
1397 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1398 V((*iter)->EffectState,update)(device, *iter); \
1399 for(i = 0;i < (*iter)->NumChannels;i++) \
1400 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1401 } while(0)
1402 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1403 #undef UPDATE_SLOT
1405 else
1407 #define CLEAR_WET_BUFFER(iter) do { \
1408 for(i = 0;i < (*iter)->NumChannels;i++) \
1409 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1410 } while(0)
1411 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1412 #undef CLEAR_WET_BUFFER
1415 /* source processing */
1416 voice = ctx->Voices;
1417 voice_end = voice + ctx->VoiceCount;
1418 for(;voice != voice_end;++voice)
1420 source = voice->Source;
1421 if(source && source->state == AL_PLAYING)
1422 MixSource(voice, source, device, SamplesToDo);
1425 /* effect slot processing */
1426 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1427 for(i = 0;i < c;i++)
1429 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1430 ALeffectState *state = slot->EffectState;
1431 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1432 device->Dry.NumChannels);
1435 ctx = ctx->next;
1438 if(device->DefaultSlot != NULL)
1440 const ALeffectslot *slot = device->DefaultSlot;
1441 ALeffectState *state = slot->EffectState;
1442 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1443 device->Dry.NumChannels);
1446 /* Increment the clock time. Every second's worth of samples is
1447 * converted and added to clock base so that large sample counts don't
1448 * overflow during conversion. This also guarantees an exact, stable
1449 * conversion. */
1450 device->SamplesDone += SamplesToDo;
1451 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1452 device->SamplesDone %= device->Frequency;
1453 V0(device->Backend,unlock)();
1455 if(device->Hrtf)
1457 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1458 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1459 MixHrtfParams hrtfparams;
1460 memset(&hrtfparams, 0, sizeof(hrtfparams));
1461 for(c = 0;c < device->VirtOut.NumChannels;c++)
1463 hrtfparams.Current = &device->Hrtf_Params[c];
1464 hrtfparams.Target = &device->Hrtf_Params[c];
1465 HrtfMix(device->RealOut.Buffer, device->VirtOut.Buffer[c], 0,
1466 device->Hrtf_Offset, 0, irsize, &hrtfparams,
1467 &device->Hrtf_State[c], SamplesToDo
1470 device->Hrtf_Offset += SamplesToDo;
1472 else
1474 if(device->Uhj_Encoder)
1476 int lidx = GetChannelIdxByName(device->RealOut, FrontLeft);
1477 int ridx = GetChannelIdxByName(device->RealOut, FrontRight);
1478 if(lidx != -1 && ridx != -1)
1480 /* Encode to stereo-compatible 2-channel UHJ output. */
1481 EncodeUhj2(device->Uhj_Encoder,
1482 device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx],
1483 device->VirtOut.Buffer, SamplesToDo
1487 if(device->Bs2b)
1489 /* Apply binaural/crossfeed filter */
1490 for(i = 0;i < SamplesToDo;i++)
1492 float samples[2];
1493 samples[0] = device->RealOut.Buffer[0][i];
1494 samples[1] = device->RealOut.Buffer[1][i];
1495 bs2b_cross_feed(device->Bs2b, samples);
1496 device->RealOut.Buffer[0][i] = samples[0];
1497 device->RealOut.Buffer[1][i] = samples[1];
1502 if(buffer)
1504 ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
1505 ALuint OutChannels = device->RealOut.NumChannels;;
1507 #define WRITE(T, a, b, c, d) do { \
1508 Write_##T((a), (b), (c), (d)); \
1509 buffer = (T*)buffer + (c)*(d); \
1510 } while(0)
1511 switch(device->FmtType)
1513 case DevFmtByte:
1514 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1515 break;
1516 case DevFmtUByte:
1517 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1518 break;
1519 case DevFmtShort:
1520 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1521 break;
1522 case DevFmtUShort:
1523 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1524 break;
1525 case DevFmtInt:
1526 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1527 break;
1528 case DevFmtUInt:
1529 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1530 break;
1531 case DevFmtFloat:
1532 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1533 break;
1535 #undef WRITE
1538 size -= SamplesToDo;
1539 IncrementRef(&device->MixCount);
1542 RestoreFPUMode(&oldMode);
1546 ALvoid aluHandleDisconnect(ALCdevice *device)
1548 ALCcontext *Context;
1550 device->Connected = ALC_FALSE;
1552 Context = ATOMIC_LOAD(&device->ContextList);
1553 while(Context)
1555 ALvoice *voice, *voice_end;
1557 voice = Context->Voices;
1558 voice_end = voice + Context->VoiceCount;
1559 while(voice != voice_end)
1561 ALsource *source = voice->Source;
1562 voice->Source = NULL;
1564 if(source && source->state == AL_PLAYING)
1566 source->state = AL_STOPPED;
1567 ATOMIC_STORE(&source->current_buffer, NULL);
1568 source->position = 0;
1569 source->position_fraction = 0;
1572 voice++;
1574 Context->VoiceCount = 0;
1576 Context = Context->next;