Keep track of the real output's channel names
[openal-soft.git] / Alc / ALu.c
blob8ea74669675b3570a83bdaabc88cf3866adafd9e
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 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
567 voice->Direct.Gains[c].Target[j] = 0.0f;
568 for(j = 0;j < Device->RealOut.NumChannels;j++)
570 if(chans[c].channel == Device->RealOut.ChannelName[j])
572 voice->Direct.Gains[c].Target[j] = DryGain;
573 break;
578 else for(c = 0;c < num_channels;c++)
580 int idx;
581 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
582 voice->Direct.Gains[c].Target[j] = 0.0f;
583 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
584 voice->Direct.Gains[c].Target[idx] = DryGain;
587 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
588 * channel-match. */
589 for(c = 0;c < num_channels;c++)
591 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
593 for(i = 0;i < NumSends;i++)
595 if(!SendSlots[i])
597 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
598 voice->Send[i].Gains[c].Target[j] = 0.0f;
600 else
602 const ALeffectslot *Slot = SendSlots[i];
603 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
604 WetGain[i], voice->Send[i].Gains[c].Target);
609 voice->IsHrtf = AL_FALSE;
611 else if(Device->Render_Mode == HrtfRender)
613 /* Full HRTF rendering. Skip the virtual channels and render each
614 * input channel to the real outputs.
616 voice->Direct.OutBuffer = Device->RealOut.Buffer;
617 voice->Direct.OutChannels = Device->RealOut.NumChannels;
618 for(c = 0;c < num_channels;c++)
620 if(chans[c].channel == LFE)
622 /* Skip LFE */
623 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
624 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
625 for(i = 0;i < HRIR_LENGTH;i++)
627 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
628 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
631 for(i = 0;i < NumSends;i++)
633 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
634 voice->Send[i].Gains[c].Target[j] = 0.0f;
637 continue;
640 /* Get the static HRIR coefficients and delays for this channel. */
641 GetLerpedHrtfCoeffs(Device->Hrtf,
642 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
643 voice->Direct.Hrtf[c].Target.Coeffs,
644 voice->Direct.Hrtf[c].Target.Delay
647 /* Normal panning for auxiliary sends. */
648 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
650 for(i = 0;i < NumSends;i++)
652 if(!SendSlots[i])
654 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
655 voice->Send[i].Gains[c].Target[j] = 0.0f;
657 else
659 const ALeffectslot *Slot = SendSlots[i];
660 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
661 WetGain[i], voice->Send[i].Gains[c].Target);
666 voice->IsHrtf = AL_TRUE;
668 else
670 /* Non-HRTF rendering. Use normal panning to the output. */
671 for(c = 0;c < num_channels;c++)
673 /* Special-case LFE */
674 if(chans[c].channel == LFE)
676 int idx;
677 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
678 voice->Direct.Gains[c].Target[j] = 0.0f;
679 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
680 voice->Direct.Gains[c].Target[idx] = DryGain;
682 for(i = 0;i < NumSends;i++)
684 ALuint j;
685 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
686 voice->Send[i].Gains[c].Target[j] = 0.0f;
688 continue;
691 if(Device->Render_Mode == StereoPair)
693 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
694 ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation);
695 coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5;
696 voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain;
697 voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain;
698 for(j = 2;j < MAX_OUTPUT_CHANNELS;j++)
699 voice->Direct.Gains[c].Target[j] = 0.0f;
701 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
703 else
705 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
706 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
707 DryGain, voice->Direct.Gains[c].Target);
710 for(i = 0;i < NumSends;i++)
712 if(!SendSlots[i])
714 ALuint j;
715 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
716 voice->Send[i].Gains[c].Target[j] = 0.0f;
718 else
720 const ALeffectslot *Slot = SendSlots[i];
721 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
722 WetGain[i], voice->Send[i].Gains[c].Target);
727 voice->IsHrtf = AL_FALSE;
732 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
733 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
734 DryGainHF = maxf(DryGainHF, 0.0001f);
735 DryGainLF = maxf(DryGainLF, 0.0001f);
736 for(c = 0;c < num_channels;c++)
738 voice->Direct.Filters[c].ActiveType = AF_None;
739 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
740 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
741 ALfilterState_setParams(
742 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
743 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
745 ALfilterState_setParams(
746 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
747 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
751 for(i = 0;i < NumSends;i++)
753 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
754 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
755 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
756 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
757 for(c = 0;c < num_channels;c++)
759 voice->Send[i].Filters[c].ActiveType = AF_None;
760 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
761 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
762 ALfilterState_setParams(
763 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
764 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
766 ALfilterState_setParams(
767 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
768 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
774 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
776 const ALCdevice *Device = ALContext->Device;
777 aluVector Position, Velocity, Direction, SourceToListener;
778 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
779 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
780 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
781 ALfloat DopplerFactor, SpeedOfSound;
782 ALfloat AirAbsorptionFactor;
783 ALfloat RoomAirAbsorption[MAX_SENDS];
784 ALbufferlistitem *BufferListItem;
785 ALeffectslot *SendSlots[MAX_SENDS];
786 ALfloat Attenuation;
787 ALfloat RoomAttenuation[MAX_SENDS];
788 ALfloat MetersPerUnit;
789 ALfloat RoomRolloffBase;
790 ALfloat RoomRolloff[MAX_SENDS];
791 ALfloat DecayDistance[MAX_SENDS];
792 ALfloat DryGain;
793 ALfloat DryGainHF;
794 ALfloat DryGainLF;
795 ALboolean DryGainHFAuto;
796 ALfloat WetGain[MAX_SENDS];
797 ALfloat WetGainHF[MAX_SENDS];
798 ALfloat WetGainLF[MAX_SENDS];
799 ALboolean WetGainAuto;
800 ALboolean WetGainHFAuto;
801 ALfloat Pitch;
802 ALuint Frequency;
803 ALint NumSends;
804 ALint i;
806 DryGainHF = 1.0f;
807 DryGainLF = 1.0f;
808 for(i = 0;i < MAX_SENDS;i++)
810 WetGainHF[i] = 1.0f;
811 WetGainLF[i] = 1.0f;
814 /* Get context/device properties */
815 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
816 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
817 NumSends = Device->NumAuxSends;
818 Frequency = Device->Frequency;
820 /* Get listener properties */
821 ListenerGain = ALContext->Listener->Gain;
822 MetersPerUnit = ALContext->Listener->MetersPerUnit;
824 /* Get source properties */
825 SourceVolume = ALSource->Gain;
826 MinVolume = ALSource->MinGain;
827 MaxVolume = ALSource->MaxGain;
828 Pitch = ALSource->Pitch;
829 Position = ALSource->Position;
830 Direction = ALSource->Direction;
831 Velocity = ALSource->Velocity;
832 MinDist = ALSource->RefDistance;
833 MaxDist = ALSource->MaxDistance;
834 Rolloff = ALSource->RollOffFactor;
835 InnerAngle = ALSource->InnerAngle;
836 OuterAngle = ALSource->OuterAngle;
837 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
838 DryGainHFAuto = ALSource->DryGainHFAuto;
839 WetGainAuto = ALSource->WetGainAuto;
840 WetGainHFAuto = ALSource->WetGainHFAuto;
841 RoomRolloffBase = ALSource->RoomRolloffFactor;
843 voice->Direct.OutBuffer = Device->Dry.Buffer;
844 voice->Direct.OutChannels = Device->Dry.NumChannels;
845 for(i = 0;i < NumSends;i++)
847 SendSlots[i] = ALSource->Send[i].Slot;
849 if(!SendSlots[i] && i == 0)
850 SendSlots[i] = Device->DefaultSlot;
851 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
853 SendSlots[i] = NULL;
854 RoomRolloff[i] = 0.0f;
855 DecayDistance[i] = 0.0f;
856 RoomAirAbsorption[i] = 1.0f;
858 else if(SendSlots[i]->AuxSendAuto)
860 RoomRolloff[i] = RoomRolloffBase;
861 if(IsReverbEffect(SendSlots[i]->EffectType))
863 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
864 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
865 SPEEDOFSOUNDMETRESPERSEC;
866 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
868 else
870 DecayDistance[i] = 0.0f;
871 RoomAirAbsorption[i] = 1.0f;
874 else
876 /* If the slot's auxiliary send auto is off, the data sent to the
877 * effect slot is the same as the dry path, sans filter effects */
878 RoomRolloff[i] = Rolloff;
879 DecayDistance[i] = 0.0f;
880 RoomAirAbsorption[i] = AIRABSORBGAINHF;
883 if(!SendSlots[i])
885 voice->Send[i].OutBuffer = NULL;
886 voice->Send[i].OutChannels = 0;
888 else
890 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
891 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
895 /* Transform source to listener space (convert to head relative) */
896 if(ALSource->HeadRelative == AL_FALSE)
898 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
899 /* Transform source vectors */
900 Position = aluMatrixdVector(Matrix, &Position);
901 Velocity = aluMatrixdVector(Matrix, &Velocity);
902 Direction = aluMatrixdVector(Matrix, &Direction);
904 else
906 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
907 /* Offset the source velocity to be relative of the listener velocity */
908 Velocity.v[0] += lvelocity->v[0];
909 Velocity.v[1] += lvelocity->v[1];
910 Velocity.v[2] += lvelocity->v[2];
913 aluNormalize(Direction.v);
914 SourceToListener.v[0] = -Position.v[0];
915 SourceToListener.v[1] = -Position.v[1];
916 SourceToListener.v[2] = -Position.v[2];
917 SourceToListener.v[3] = 0.0f;
918 Distance = aluNormalize(SourceToListener.v);
920 /* Calculate distance attenuation */
921 ClampedDist = Distance;
923 Attenuation = 1.0f;
924 for(i = 0;i < NumSends;i++)
925 RoomAttenuation[i] = 1.0f;
926 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
927 ALContext->DistanceModel)
929 case InverseDistanceClamped:
930 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
931 if(MaxDist < MinDist)
932 break;
933 /*fall-through*/
934 case InverseDistance:
935 if(MinDist > 0.0f)
937 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
938 if(dist > 0.0f) Attenuation = MinDist / dist;
939 for(i = 0;i < NumSends;i++)
941 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
942 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
945 break;
947 case LinearDistanceClamped:
948 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
949 if(MaxDist < MinDist)
950 break;
951 /*fall-through*/
952 case LinearDistance:
953 if(MaxDist != MinDist)
955 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
956 Attenuation = maxf(Attenuation, 0.0f);
957 for(i = 0;i < NumSends;i++)
959 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
960 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
963 break;
965 case ExponentDistanceClamped:
966 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
967 if(MaxDist < MinDist)
968 break;
969 /*fall-through*/
970 case ExponentDistance:
971 if(ClampedDist > 0.0f && MinDist > 0.0f)
973 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
974 for(i = 0;i < NumSends;i++)
975 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
977 break;
979 case DisableDistance:
980 ClampedDist = MinDist;
981 break;
984 /* Source Gain + Attenuation */
985 DryGain = SourceVolume * Attenuation;
986 for(i = 0;i < NumSends;i++)
987 WetGain[i] = SourceVolume * RoomAttenuation[i];
989 /* Distance-based air absorption */
990 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
992 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
993 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
994 for(i = 0;i < NumSends;i++)
995 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
998 if(WetGainAuto)
1000 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
1002 /* Apply a decay-time transformation to the wet path, based on the
1003 * attenuation of the dry path.
1005 * Using the apparent distance, based on the distance attenuation, the
1006 * initial decay of the reverb effect is calculated and applied to the
1007 * wet path.
1009 for(i = 0;i < NumSends;i++)
1011 if(DecayDistance[i] > 0.0f)
1012 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1016 /* Calculate directional soundcones */
1017 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1018 if(Angle > InnerAngle && Angle <= OuterAngle)
1020 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1021 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1022 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1024 else if(Angle > OuterAngle)
1026 ConeVolume = ALSource->OuterGain;
1027 ConeHF = ALSource->OuterGainHF;
1029 else
1031 ConeVolume = 1.0f;
1032 ConeHF = 1.0f;
1035 DryGain *= ConeVolume;
1036 if(WetGainAuto)
1038 for(i = 0;i < NumSends;i++)
1039 WetGain[i] *= ConeVolume;
1041 if(DryGainHFAuto)
1042 DryGainHF *= ConeHF;
1043 if(WetGainHFAuto)
1045 for(i = 0;i < NumSends;i++)
1046 WetGainHF[i] *= ConeHF;
1049 /* Clamp to Min/Max Gain */
1050 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1051 for(i = 0;i < NumSends;i++)
1052 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1054 /* Apply gain and frequency filters */
1055 DryGain *= ALSource->Direct.Gain * ListenerGain;
1056 DryGainHF *= ALSource->Direct.GainHF;
1057 DryGainLF *= ALSource->Direct.GainLF;
1058 for(i = 0;i < NumSends;i++)
1060 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1061 WetGainHF[i] *= ALSource->Send[i].GainHF;
1062 WetGainLF[i] *= ALSource->Send[i].GainLF;
1065 /* Calculate velocity-based doppler effect */
1066 if(DopplerFactor > 0.0f)
1068 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1069 ALfloat VSS, VLS;
1071 if(SpeedOfSound < 1.0f)
1073 DopplerFactor *= 1.0f/SpeedOfSound;
1074 SpeedOfSound = 1.0f;
1077 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1078 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1080 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1081 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1084 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1085 while(BufferListItem != NULL)
1087 ALbuffer *ALBuffer;
1088 if((ALBuffer=BufferListItem->buffer) != NULL)
1090 /* Calculate fixed-point stepping value, based on the pitch, buffer
1091 * frequency, and output frequency. */
1092 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1093 if(Pitch > (ALfloat)MAX_PITCH)
1094 voice->Step = MAX_PITCH<<FRACTIONBITS;
1095 else
1096 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1097 BsincPrepare(voice->Step, &voice->SincState);
1099 break;
1101 BufferListItem = BufferListItem->next;
1104 if(Device->Render_Mode == HrtfRender)
1106 /* Full HRTF rendering. Skip the virtual channels and render to the
1107 * real outputs.
1109 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1110 ALfloat ev = 0.0f, az = 0.0f;
1111 ALfloat radius = ALSource->Radius;
1112 ALfloat dirfact = 1.0f;
1113 ALfloat coeffs[MAX_AMBI_COEFFS];
1115 voice->Direct.OutBuffer = Device->RealOut.Buffer;
1116 voice->Direct.OutChannels = Device->RealOut.NumChannels;
1118 if(Distance > FLT_EPSILON)
1120 dir.v[0] = -SourceToListener.v[0];
1121 dir.v[1] = -SourceToListener.v[1];
1122 dir.v[2] = -SourceToListener.v[2] * ZScale;
1124 /* Calculate elevation and azimuth only when the source is not at
1125 * the listener. This prevents +0 and -0 Z from producing
1126 * inconsistent panning. Also, clamp Y in case FP precision errors
1127 * cause it to land outside of -1..+1. */
1128 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1129 az = atan2f(dir.v[0], -dir.v[2]);
1131 if(radius > 0.0f)
1133 if(radius >= Distance)
1134 dirfact *= Distance / radius * 0.5f;
1135 else
1136 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1139 /* Get the HRIR coefficients and delays. */
1140 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1141 voice->Direct.Hrtf[0].Target.Coeffs,
1142 voice->Direct.Hrtf[0].Target.Delay);
1144 dir.v[0] *= dirfact;
1145 dir.v[1] *= dirfact;
1146 dir.v[2] *= dirfact;
1147 CalcDirectionCoeffs(dir.v, coeffs);
1149 for(i = 0;i < NumSends;i++)
1151 if(!SendSlots[i])
1153 ALuint j;
1154 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1155 voice->Send[i].Gains[0].Target[j] = 0.0f;
1157 else
1159 const ALeffectslot *Slot = SendSlots[i];
1160 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1161 WetGain[i], voice->Send[i].Gains[0].Target);
1165 voice->IsHrtf = AL_TRUE;
1167 else
1169 /* Non-HRTF rendering. */
1170 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1171 ALfloat radius = ALSource->Radius;
1172 ALfloat coeffs[MAX_AMBI_COEFFS];
1174 /* Get the localized direction, and compute panned gains. */
1175 if(Distance > FLT_EPSILON)
1177 dir[0] = -SourceToListener.v[0];
1178 dir[1] = -SourceToListener.v[1];
1179 dir[2] = -SourceToListener.v[2] * ZScale;
1181 if(radius > 0.0f)
1183 ALfloat dirfact;
1184 if(radius >= Distance)
1185 dirfact = Distance / radius * 0.5f;
1186 else
1187 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1188 dir[0] *= dirfact;
1189 dir[1] *= dirfact;
1190 dir[2] *= dirfact;
1193 if(Device->Render_Mode == StereoPair)
1195 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
1196 coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5;
1197 voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain;
1198 voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain;
1199 for(i = 2;i < MAX_OUTPUT_CHANNELS;i++)
1200 voice->Direct.Gains[0].Target[i] = 0.0f;
1202 CalcDirectionCoeffs(dir, coeffs);
1204 else
1206 CalcDirectionCoeffs(dir, coeffs);
1207 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
1208 DryGain, voice->Direct.Gains[0].Target);
1211 for(i = 0;i < NumSends;i++)
1213 if(!SendSlots[i])
1215 ALuint j;
1216 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1217 voice->Send[i].Gains[0].Target[j] = 0.0f;
1219 else
1221 const ALeffectslot *Slot = SendSlots[i];
1222 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1223 WetGain[i], voice->Send[i].Gains[0].Target);
1227 voice->IsHrtf = AL_FALSE;
1231 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1232 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1233 DryGainHF = maxf(DryGainHF, 0.0001f);
1234 DryGainLF = maxf(DryGainLF, 0.0001f);
1235 voice->Direct.Filters[0].ActiveType = AF_None;
1236 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1237 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1238 ALfilterState_setParams(
1239 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1240 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1242 ALfilterState_setParams(
1243 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1244 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1247 for(i = 0;i < NumSends;i++)
1249 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1250 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1251 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1252 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1253 voice->Send[i].Filters[0].ActiveType = AF_None;
1254 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1255 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1256 ALfilterState_setParams(
1257 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1258 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1260 ALfilterState_setParams(
1261 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1262 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1268 void UpdateContextSources(ALCcontext *ctx)
1270 ALvoice *voice, *voice_end;
1271 ALsource *source;
1273 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1275 CalcListenerParams(ctx->Listener);
1277 voice = ctx->Voices;
1278 voice_end = voice + ctx->VoiceCount;
1279 for(;voice != voice_end;++voice)
1281 if(!(source=voice->Source)) continue;
1282 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1283 voice->Source = NULL;
1284 else
1286 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1287 voice->Update(voice, source, ctx);
1291 else
1293 voice = ctx->Voices;
1294 voice_end = voice + ctx->VoiceCount;
1295 for(;voice != voice_end;++voice)
1297 if(!(source=voice->Source)) continue;
1298 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1299 voice->Source = NULL;
1300 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1301 voice->Update(voice, source, ctx);
1307 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1308 * converts NaN to 0. */
1309 static inline ALfloat aluClampf(ALfloat val)
1311 if(fabsf(val) <= 1.0f) return val;
1312 return (ALfloat)((0.0f < val) - (val < 0.0f));
1315 static inline ALfloat aluF2F(ALfloat val)
1316 { return val; }
1318 static inline ALint aluF2I(ALfloat val)
1320 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1321 * integer range normalized floats can be safely converted to.
1323 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1325 static inline ALuint aluF2UI(ALfloat val)
1326 { return aluF2I(val)+2147483648u; }
1328 static inline ALshort aluF2S(ALfloat val)
1329 { return fastf2i(aluClampf(val)*32767.0f); }
1330 static inline ALushort aluF2US(ALfloat val)
1331 { return aluF2S(val)+32768; }
1333 static inline ALbyte aluF2B(ALfloat val)
1334 { return fastf2i(aluClampf(val)*127.0f); }
1335 static inline ALubyte aluF2UB(ALfloat val)
1336 { return aluF2B(val)+128; }
1338 #define DECL_TEMPLATE(T, func) \
1339 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1340 ALuint SamplesToDo, ALuint numchans) \
1342 ALuint i, j; \
1343 for(j = 0;j < numchans;j++) \
1345 const ALfloat *in = InBuffer[j]; \
1346 T *restrict out = (T*)OutBuffer + j; \
1347 for(i = 0;i < SamplesToDo;i++) \
1348 out[i*numchans] = func(in[i]); \
1352 DECL_TEMPLATE(ALfloat, aluF2F)
1353 DECL_TEMPLATE(ALuint, aluF2UI)
1354 DECL_TEMPLATE(ALint, aluF2I)
1355 DECL_TEMPLATE(ALushort, aluF2US)
1356 DECL_TEMPLATE(ALshort, aluF2S)
1357 DECL_TEMPLATE(ALubyte, aluF2UB)
1358 DECL_TEMPLATE(ALbyte, aluF2B)
1360 #undef DECL_TEMPLATE
1363 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1365 ALuint SamplesToDo;
1366 ALvoice *voice, *voice_end;
1367 ALeffectslot *slot;
1368 ALsource *source;
1369 ALCcontext *ctx;
1370 FPUCtl oldMode;
1371 ALuint i, c;
1373 SetMixerFPUMode(&oldMode);
1375 while(size > 0)
1377 IncrementRef(&device->MixCount);
1379 SamplesToDo = minu(size, BUFFERSIZE);
1380 for(c = 0;c < device->VirtOut.NumChannels;c++)
1381 memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1382 for(c = 0;c < device->RealOut.NumChannels;c++)
1383 memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1385 V0(device->Backend,lock)();
1387 if((slot=device->DefaultSlot) != NULL)
1389 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1390 V(slot->EffectState,update)(device, slot);
1391 for(i = 0;i < slot->NumChannels;i++)
1392 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1395 ctx = ATOMIC_LOAD(&device->ContextList);
1396 while(ctx)
1398 if(!ctx->DeferUpdates)
1400 UpdateContextSources(ctx);
1401 #define UPDATE_SLOT(iter) do { \
1402 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1403 V((*iter)->EffectState,update)(device, *iter); \
1404 for(i = 0;i < (*iter)->NumChannels;i++) \
1405 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1406 } while(0)
1407 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1408 #undef UPDATE_SLOT
1410 else
1412 #define CLEAR_WET_BUFFER(iter) do { \
1413 for(i = 0;i < (*iter)->NumChannels;i++) \
1414 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1415 } while(0)
1416 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1417 #undef CLEAR_WET_BUFFER
1420 /* source processing */
1421 voice = ctx->Voices;
1422 voice_end = voice + ctx->VoiceCount;
1423 for(;voice != voice_end;++voice)
1425 source = voice->Source;
1426 if(source && source->state == AL_PLAYING)
1427 MixSource(voice, source, device, SamplesToDo);
1430 /* effect slot processing */
1431 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1432 for(i = 0;i < c;i++)
1434 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1435 ALeffectState *state = slot->EffectState;
1436 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1437 device->Dry.NumChannels);
1440 ctx = ctx->next;
1443 if(device->DefaultSlot != NULL)
1445 const ALeffectslot *slot = device->DefaultSlot;
1446 ALeffectState *state = slot->EffectState;
1447 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1448 device->Dry.NumChannels);
1451 /* Increment the clock time. Every second's worth of samples is
1452 * converted and added to clock base so that large sample counts don't
1453 * overflow during conversion. This also guarantees an exact, stable
1454 * conversion. */
1455 device->SamplesDone += SamplesToDo;
1456 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1457 device->SamplesDone %= device->Frequency;
1458 V0(device->Backend,unlock)();
1460 if(device->Hrtf)
1462 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1463 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1464 MixHrtfParams hrtfparams;
1465 memset(&hrtfparams, 0, sizeof(hrtfparams));
1466 for(c = 0;c < device->VirtOut.NumChannels;c++)
1468 hrtfparams.Current = &device->Hrtf_Params[c];
1469 hrtfparams.Target = &device->Hrtf_Params[c];
1470 HrtfMix(device->RealOut.Buffer, device->VirtOut.Buffer[c], 0,
1471 device->Hrtf_Offset, 0, irsize, &hrtfparams,
1472 &device->Hrtf_State[c], SamplesToDo
1475 device->Hrtf_Offset += SamplesToDo;
1477 else
1479 if(device->Uhj_Encoder)
1481 /* Encode to stereo-compatible 2-channel UHJ output. */
1482 EncodeUhj2(device->Uhj_Encoder, device->RealOut.Buffer,
1483 device->VirtOut.Buffer, SamplesToDo);
1485 if(device->Bs2b)
1487 /* Apply binaural/crossfeed filter */
1488 for(i = 0;i < SamplesToDo;i++)
1490 float samples[2];
1491 samples[0] = device->RealOut.Buffer[0][i];
1492 samples[1] = device->RealOut.Buffer[1][i];
1493 bs2b_cross_feed(device->Bs2b, samples);
1494 device->RealOut.Buffer[0][i] = samples[0];
1495 device->RealOut.Buffer[1][i] = samples[1];
1500 if(buffer)
1502 ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
1503 ALuint OutChannels = device->RealOut.NumChannels;;
1505 #define WRITE(T, a, b, c, d) do { \
1506 Write_##T((a), (b), (c), (d)); \
1507 buffer = (T*)buffer + (c)*(d); \
1508 } while(0)
1509 switch(device->FmtType)
1511 case DevFmtByte:
1512 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1513 break;
1514 case DevFmtUByte:
1515 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1516 break;
1517 case DevFmtShort:
1518 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1519 break;
1520 case DevFmtUShort:
1521 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1522 break;
1523 case DevFmtInt:
1524 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1525 break;
1526 case DevFmtUInt:
1527 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1528 break;
1529 case DevFmtFloat:
1530 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1531 break;
1533 #undef WRITE
1536 size -= SamplesToDo;
1537 IncrementRef(&device->MixCount);
1540 RestoreFPUMode(&oldMode);
1544 ALvoid aluHandleDisconnect(ALCdevice *device)
1546 ALCcontext *Context;
1548 device->Connected = ALC_FALSE;
1550 Context = ATOMIC_LOAD(&device->ContextList);
1551 while(Context)
1553 ALvoice *voice, *voice_end;
1555 voice = Context->Voices;
1556 voice_end = voice + Context->VoiceCount;
1557 while(voice != voice_end)
1559 ALsource *source = voice->Source;
1560 voice->Source = NULL;
1562 if(source && source->state == AL_PLAYING)
1564 source->state = AL_STOPPED;
1565 ATOMIC_STORE(&source->current_buffer, NULL);
1566 source->position = 0;
1567 source->position_fraction = 0;
1570 voice++;
1572 Context->VoiceCount = 0;
1574 Context = Context->next;