Remove unnecessary code for the now-unused write offset
[openal-soft.git] / Alc / ALu.c
blobadc72416e922c7f643ddfdc900eea38a2b89b744
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 "bformatdec.h"
39 #include "static_assert.h"
41 #include "mixer_defs.h"
43 #include "backends/base.h"
46 struct ChanMap {
47 enum Channel channel;
48 ALfloat angle;
49 ALfloat elevation;
52 /* Cone scalar */
53 ALfloat ConeScale = 1.0f;
55 /* Localized Z scalar for mono sources */
56 ALfloat ZScale = 1.0f;
58 extern inline ALfloat minf(ALfloat a, ALfloat b);
59 extern inline ALfloat maxf(ALfloat a, ALfloat b);
60 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
62 extern inline ALdouble mind(ALdouble a, ALdouble b);
63 extern inline ALdouble maxd(ALdouble a, ALdouble b);
64 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
66 extern inline ALuint minu(ALuint a, ALuint b);
67 extern inline ALuint maxu(ALuint a, ALuint b);
68 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
70 extern inline ALint mini(ALint a, ALint b);
71 extern inline ALint maxi(ALint a, ALint b);
72 extern inline ALint clampi(ALint val, ALint min, ALint max);
74 extern inline ALint64 mini64(ALint64 a, ALint64 b);
75 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
76 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
78 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
79 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
80 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
82 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
83 extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
84 extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac);
86 extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
88 extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
89 ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
90 extern inline void aluMatrixfSet(aluMatrixf *matrix,
91 ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
92 ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
93 ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
94 ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
96 extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
97 ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3);
98 extern inline void aluMatrixdSet(aluMatrixd *matrix,
99 ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
100 ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
101 ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
102 ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
105 static inline HrtfMixerFunc SelectHrtfMixer(void)
107 #ifdef HAVE_SSE
108 if((CPUCapFlags&CPU_CAP_SSE))
109 return MixHrtf_SSE;
110 #endif
111 #ifdef HAVE_NEON
112 if((CPUCapFlags&CPU_CAP_NEON))
113 return MixHrtf_Neon;
114 #endif
116 return MixHrtf_C;
120 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
122 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
123 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
124 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
127 static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2)
129 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
132 static inline ALfloat aluNormalize(ALfloat *vec)
134 ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
135 if(length > 0.0f)
137 ALfloat inv_length = 1.0f/length;
138 vec[0] *= inv_length;
139 vec[1] *= inv_length;
140 vec[2] *= inv_length;
142 return length;
146 static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *outVector)
148 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
149 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
150 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
153 static inline ALdouble aluNormalized(ALdouble *vec)
155 ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
156 if(length > 0.0)
158 ALdouble inv_length = 1.0/length;
159 vec[0] *= inv_length;
160 vec[1] *= inv_length;
161 vec[2] *= inv_length;
163 return length;
166 static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx)
168 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
170 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]);
171 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]);
172 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]);
175 static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx)
177 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
179 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];
180 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];
181 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];
184 static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec)
186 aluVector v;
187 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]);
188 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]);
189 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]);
190 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]);
191 return v;
195 /* Prepares the interpolator for a given rate (determined by increment). A
196 * result of AL_FALSE indicates that the filter output will completely cut
197 * the input signal.
199 * With a bit of work, and a trade of memory for CPU cost, this could be
200 * modified for use with an interpolated increment for buttery-smooth pitch
201 * changes.
203 static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
205 static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f;
206 static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 };
207 static const ALuint to[4][BSINC_SCALE_COUNT] =
209 { 0, 24, 408, 792, 1176, 1560, 1944, 2328, 2648, 2968, 3288, 3544, 3800, 4056, 4248, 4440 },
210 { 4632, 5016, 5400, 5784, 6168, 6552, 6936, 7320, 7640, 7960, 8280, 8536, 8792, 9048, 9240, 0 },
211 { 0, 9432, 9816, 10200, 10584, 10968, 11352, 11736, 12056, 12376, 12696, 12952, 13208, 13464, 13656, 13848 },
212 { 14040, 14424, 14808, 15192, 15576, 15960, 16344, 16728, 17048, 17368, 17688, 17944, 18200, 18456, 18648, 0 }
214 static const ALuint tm[2][BSINC_SCALE_COUNT] =
216 { 0, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 },
217 { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 }
219 ALfloat sf;
220 ALuint si, pi;
221 ALboolean uncut = AL_TRUE;
223 if(increment > FRACTIONONE)
225 sf = (ALfloat)FRACTIONONE / increment;
226 if(sf < scaleBase)
228 /* Signal has been completely cut. The return result can be used
229 * to skip the filter (and output zeros) as an optimization.
231 sf = 0.0f;
232 si = 0;
233 uncut = AL_FALSE;
235 else
237 sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange;
238 si = fastf2u(sf);
239 /* The interpolation factor is fit to this diagonally-symmetric
240 * curve to reduce the transition ripple caused by interpolating
241 * different scales of the sinc function.
243 sf = 1.0f - cosf(asinf(sf - si));
246 else
248 sf = 0.0f;
249 si = BSINC_SCALE_COUNT - 1;
252 state->sf = sf;
253 state->m = m[si];
254 state->l = -(ALint)((m[si] / 2) - 1);
255 /* The CPU cost of this table re-mapping could be traded for the memory
256 * cost of a complete table map (1024 elements large).
258 for(pi = 0;pi < BSINC_PHASE_COUNT;pi++)
260 state->coeffs[pi].filter = &bsincTab[to[0][si] + tm[0][si]*pi];
261 state->coeffs[pi].scDelta = &bsincTab[to[1][si] + tm[1][si]*pi];
262 state->coeffs[pi].phDelta = &bsincTab[to[2][si] + tm[0][si]*pi];
263 state->coeffs[pi].spDelta = &bsincTab[to[3][si] + tm[1][si]*pi];
265 return uncut;
269 static ALvoid CalcListenerParams(ALlistener *Listener)
271 ALdouble N[3], V[3], U[3], P[3];
273 /* AT then UP */
274 N[0] = Listener->Forward[0];
275 N[1] = Listener->Forward[1];
276 N[2] = Listener->Forward[2];
277 aluNormalized(N);
278 V[0] = Listener->Up[0];
279 V[1] = Listener->Up[1];
280 V[2] = Listener->Up[2];
281 aluNormalized(V);
282 /* Build and normalize right-vector */
283 aluCrossproductd(N, V, U);
284 aluNormalized(U);
286 aluMatrixdSet(&Listener->Params.Matrix,
287 U[0], V[0], -N[0], 0.0,
288 U[1], V[1], -N[1], 0.0,
289 U[2], V[2], -N[2], 0.0,
290 0.0, 0.0, 0.0, 1.0
293 P[0] = Listener->Position.v[0];
294 P[1] = Listener->Position.v[1];
295 P[2] = Listener->Position.v[2];
296 aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix);
297 aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
299 Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity);
302 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
304 static const struct ChanMap MonoMap[1] = {
305 { FrontCenter, 0.0f, 0.0f }
306 }, RearMap[2] = {
307 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
308 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
309 }, QuadMap[4] = {
310 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
311 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
312 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
313 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
314 }, X51Map[6] = {
315 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
316 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
317 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
318 { LFE, 0.0f, 0.0f },
319 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
320 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
321 }, X61Map[7] = {
322 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
323 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
324 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
325 { LFE, 0.0f, 0.0f },
326 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
327 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
328 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
329 }, X71Map[8] = {
330 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
331 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
332 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
333 { LFE, 0.0f, 0.0f },
334 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
335 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
336 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
337 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
340 const ALCdevice *Device = ALContext->Device;
341 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
342 ALbufferlistitem *BufferListItem;
343 enum FmtChannels Channels;
344 ALfloat DryGain, DryGainHF, DryGainLF;
345 ALfloat WetGain[MAX_SENDS];
346 ALfloat WetGainHF[MAX_SENDS];
347 ALfloat WetGainLF[MAX_SENDS];
348 ALeffectslot *SendSlots[MAX_SENDS];
349 ALuint NumSends, Frequency;
350 ALboolean Relative;
351 const struct ChanMap *chans = NULL;
352 struct ChanMap StereoMap[2] = {
353 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
354 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
356 ALuint num_channels = 0;
357 ALboolean DirectChannels;
358 ALboolean isbformat = AL_FALSE;
359 ALfloat Pitch;
360 ALuint i, j, c;
362 /* Get device properties */
363 NumSends = Device->NumAuxSends;
364 Frequency = Device->Frequency;
366 /* Get listener properties */
367 ListenerGain = ALContext->Listener->Gain;
369 /* Get source properties */
370 SourceVolume = ALSource->Gain;
371 MinVolume = ALSource->MinGain;
372 MaxVolume = ALSource->MaxGain;
373 Pitch = ALSource->Pitch;
374 Relative = ALSource->HeadRelative;
375 DirectChannels = ALSource->DirectChannels;
377 /* Convert counter-clockwise to clockwise. */
378 StereoMap[0].angle = -ALSource->StereoPan[0];
379 StereoMap[1].angle = -ALSource->StereoPan[1];
381 voice->Direct.OutBuffer = Device->Dry.Buffer;
382 voice->Direct.OutChannels = Device->Dry.NumChannels;
383 for(i = 0;i < NumSends;i++)
385 SendSlots[i] = ALSource->Send[i].Slot;
386 if(!SendSlots[i] && i == 0)
387 SendSlots[i] = Device->DefaultSlot;
388 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
390 SendSlots[i] = NULL;
391 voice->Send[i].OutBuffer = NULL;
392 voice->Send[i].OutChannels = 0;
394 else
396 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
397 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
401 /* Calculate the stepping value */
402 Channels = FmtMono;
403 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
404 while(BufferListItem != NULL)
406 ALbuffer *ALBuffer;
407 if((ALBuffer=BufferListItem->buffer) != NULL)
409 Pitch = Pitch * ALBuffer->Frequency / Frequency;
410 if(Pitch > (ALfloat)MAX_PITCH)
411 voice->Step = MAX_PITCH<<FRACTIONBITS;
412 else
413 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
414 BsincPrepare(voice->Step, &voice->SincState);
416 Channels = ALBuffer->FmtChannels;
417 break;
419 BufferListItem = BufferListItem->next;
422 /* Calculate gains */
423 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
424 DryGain *= ALSource->Direct.Gain * ListenerGain;
425 DryGainHF = ALSource->Direct.GainHF;
426 DryGainLF = ALSource->Direct.GainLF;
427 for(i = 0;i < NumSends;i++)
429 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
430 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
431 WetGainHF[i] = ALSource->Send[i].GainHF;
432 WetGainLF[i] = ALSource->Send[i].GainLF;
435 switch(Channels)
437 case FmtMono:
438 chans = MonoMap;
439 num_channels = 1;
440 break;
442 case FmtStereo:
443 chans = StereoMap;
444 num_channels = 2;
445 break;
447 case FmtRear:
448 chans = RearMap;
449 num_channels = 2;
450 break;
452 case FmtQuad:
453 chans = QuadMap;
454 num_channels = 4;
455 break;
457 case FmtX51:
458 chans = X51Map;
459 num_channels = 6;
460 break;
462 case FmtX61:
463 chans = X61Map;
464 num_channels = 7;
465 break;
467 case FmtX71:
468 chans = X71Map;
469 num_channels = 8;
470 break;
472 case FmtBFormat2D:
473 num_channels = 3;
474 isbformat = AL_TRUE;
475 DirectChannels = AL_FALSE;
476 break;
478 case FmtBFormat3D:
479 num_channels = 4;
480 isbformat = AL_TRUE;
481 DirectChannels = AL_FALSE;
482 break;
485 if(isbformat)
487 ALfloat N[3], V[3], U[3];
488 aluMatrixf matrix;
489 ALfloat scale;
491 /* AT then UP */
492 N[0] = ALSource->Orientation[0][0];
493 N[1] = ALSource->Orientation[0][1];
494 N[2] = ALSource->Orientation[0][2];
495 aluNormalize(N);
496 V[0] = ALSource->Orientation[1][0];
497 V[1] = ALSource->Orientation[1][1];
498 V[2] = ALSource->Orientation[1][2];
499 aluNormalize(V);
500 if(!Relative)
502 const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
503 aluMatrixdFloat3(N, 0.0f, lmatrix);
504 aluMatrixdFloat3(V, 0.0f, lmatrix);
506 /* Build and normalize right-vector */
507 aluCrossproduct(N, V, U);
508 aluNormalize(U);
510 /* Build a rotate + conversion matrix (B-Format -> N3D). */
511 scale = 1.732050808f;
512 aluMatrixfSet(&matrix,
513 1.414213562f, 0.0f, 0.0f, 0.0f,
514 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
515 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
516 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
519 voice->Direct.OutBuffer = Device->FOAOut.Buffer;
520 voice->Direct.OutChannels = Device->FOAOut.NumChannels;
521 for(c = 0;c < num_channels;c++)
522 ComputeFirstOrderGains(Device->FOAOut, matrix.m[c], DryGain,
523 voice->Direct.Gains[c].Target);
525 for(i = 0;i < NumSends;i++)
527 if(!SendSlots[i])
529 for(c = 0;c < num_channels;c++)
531 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
532 voice->Send[i].Gains[c].Target[j] = 0.0f;
535 else
537 for(c = 0;c < num_channels;c++)
539 const ALeffectslot *Slot = SendSlots[i];
540 ComputeFirstOrderGainsBF(Slot->ChanMap, Slot->NumChannels, matrix.m[c],
541 WetGain[i], voice->Send[i].Gains[c].Target);
546 voice->IsHrtf = AL_FALSE;
548 else
550 ALfloat coeffs[MAX_AMBI_COEFFS];
552 if(DirectChannels)
554 /* Skip the virtual channels and write inputs to the real output. */
555 voice->Direct.OutBuffer = Device->RealOut.Buffer;
556 voice->Direct.OutChannels = Device->RealOut.NumChannels;
557 for(c = 0;c < num_channels;c++)
559 int idx;
560 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
561 voice->Direct.Gains[c].Target[j] = 0.0f;
562 if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1)
563 voice->Direct.Gains[c].Target[idx] = DryGain;
566 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
567 * channel-match. */
568 for(c = 0;c < num_channels;c++)
570 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs);
572 for(i = 0;i < NumSends;i++)
574 if(!SendSlots[i])
576 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
577 voice->Send[i].Gains[c].Target[j] = 0.0f;
579 else
581 const ALeffectslot *Slot = SendSlots[i];
582 ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs,
583 WetGain[i], voice->Send[i].Gains[c].Target);
588 voice->IsHrtf = AL_FALSE;
590 else if(Device->Render_Mode == HrtfRender)
592 /* Full HRTF rendering. Skip the virtual channels and render each
593 * input channel to the real outputs.
595 voice->Direct.OutBuffer = Device->RealOut.Buffer;
596 voice->Direct.OutChannels = Device->RealOut.NumChannels;
597 for(c = 0;c < num_channels;c++)
599 if(chans[c].channel == LFE)
601 /* Skip LFE */
602 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
603 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
604 for(i = 0;i < HRIR_LENGTH;i++)
606 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
607 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
610 for(i = 0;i < NumSends;i++)
612 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
613 voice->Send[i].Gains[c].Target[j] = 0.0f;
616 continue;
619 /* Get the static HRIR coefficients and delays for this channel. */
620 GetLerpedHrtfCoeffs(Device->Hrtf,
621 chans[c].elevation, chans[c].angle, 0.0f, DryGain,
622 voice->Direct.Hrtf[c].Target.Coeffs,
623 voice->Direct.Hrtf[c].Target.Delay
626 /* Normal panning for auxiliary sends. */
627 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs);
629 for(i = 0;i < NumSends;i++)
631 if(!SendSlots[i])
633 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
634 voice->Send[i].Gains[c].Target[j] = 0.0f;
636 else
638 const ALeffectslot *Slot = SendSlots[i];
639 ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs,
640 WetGain[i], voice->Send[i].Gains[c].Target);
645 voice->IsHrtf = AL_TRUE;
647 else
649 /* Non-HRTF rendering. Use normal panning to the output. */
650 for(c = 0;c < num_channels;c++)
652 /* Special-case LFE */
653 if(chans[c].channel == LFE)
655 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
656 voice->Direct.Gains[c].Target[j] = 0.0f;
657 if(Device->Dry.Buffer == Device->RealOut.Buffer)
659 int idx;
660 if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1)
661 voice->Direct.Gains[c].Target[idx] = DryGain;
664 for(i = 0;i < NumSends;i++)
666 ALuint j;
667 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
668 voice->Send[i].Gains[c].Target[j] = 0.0f;
670 continue;
673 if(Device->Render_Mode == StereoPair)
675 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
676 ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation);
677 coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5f;
678 voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain;
679 voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain;
680 for(j = 2;j < MAX_OUTPUT_CHANNELS;j++)
681 voice->Direct.Gains[c].Target[j] = 0.0f;
683 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs);
685 else
687 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, 0.0f, coeffs);
688 ComputePanningGains(Device->Dry, coeffs, DryGain,
689 voice->Direct.Gains[c].Target);
692 for(i = 0;i < NumSends;i++)
694 if(!SendSlots[i])
696 ALuint j;
697 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
698 voice->Send[i].Gains[c].Target[j] = 0.0f;
700 else
702 const ALeffectslot *Slot = SendSlots[i];
703 ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs,
704 WetGain[i], voice->Send[i].Gains[c].Target);
709 voice->IsHrtf = AL_FALSE;
714 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
715 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
716 DryGainHF = maxf(DryGainHF, 0.0001f);
717 DryGainLF = maxf(DryGainLF, 0.0001f);
718 for(c = 0;c < num_channels;c++)
720 voice->Direct.Filters[c].ActiveType = AF_None;
721 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
722 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
723 ALfilterState_setParams(
724 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
725 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
727 ALfilterState_setParams(
728 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
729 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
733 for(i = 0;i < NumSends;i++)
735 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
736 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
737 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
738 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
739 for(c = 0;c < num_channels;c++)
741 voice->Send[i].Filters[c].ActiveType = AF_None;
742 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
743 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
744 ALfilterState_setParams(
745 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
746 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
748 ALfilterState_setParams(
749 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
750 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
756 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
758 const ALCdevice *Device = ALContext->Device;
759 aluVector Position, Velocity, Direction, SourceToListener;
760 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
761 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
762 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
763 ALfloat DopplerFactor, SpeedOfSound;
764 ALfloat AirAbsorptionFactor;
765 ALfloat RoomAirAbsorption[MAX_SENDS];
766 ALbufferlistitem *BufferListItem;
767 ALeffectslot *SendSlots[MAX_SENDS];
768 ALfloat Attenuation;
769 ALfloat RoomAttenuation[MAX_SENDS];
770 ALfloat MetersPerUnit;
771 ALfloat RoomRolloffBase;
772 ALfloat RoomRolloff[MAX_SENDS];
773 ALfloat DecayDistance[MAX_SENDS];
774 ALfloat DryGain;
775 ALfloat DryGainHF;
776 ALfloat DryGainLF;
777 ALboolean DryGainHFAuto;
778 ALfloat WetGain[MAX_SENDS];
779 ALfloat WetGainHF[MAX_SENDS];
780 ALfloat WetGainLF[MAX_SENDS];
781 ALboolean WetGainAuto;
782 ALboolean WetGainHFAuto;
783 ALfloat Pitch;
784 ALuint Frequency;
785 ALint NumSends;
786 ALint i;
788 DryGainHF = 1.0f;
789 DryGainLF = 1.0f;
790 for(i = 0;i < MAX_SENDS;i++)
792 WetGainHF[i] = 1.0f;
793 WetGainLF[i] = 1.0f;
796 /* Get context/device properties */
797 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
798 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
799 NumSends = Device->NumAuxSends;
800 Frequency = Device->Frequency;
802 /* Get listener properties */
803 ListenerGain = ALContext->Listener->Gain;
804 MetersPerUnit = ALContext->Listener->MetersPerUnit;
806 /* Get source properties */
807 SourceVolume = ALSource->Gain;
808 MinVolume = ALSource->MinGain;
809 MaxVolume = ALSource->MaxGain;
810 Pitch = ALSource->Pitch;
811 Position = ALSource->Position;
812 Direction = ALSource->Direction;
813 Velocity = ALSource->Velocity;
814 MinDist = ALSource->RefDistance;
815 MaxDist = ALSource->MaxDistance;
816 Rolloff = ALSource->RollOffFactor;
817 InnerAngle = ALSource->InnerAngle;
818 OuterAngle = ALSource->OuterAngle;
819 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
820 DryGainHFAuto = ALSource->DryGainHFAuto;
821 WetGainAuto = ALSource->WetGainAuto;
822 WetGainHFAuto = ALSource->WetGainHFAuto;
823 RoomRolloffBase = ALSource->RoomRolloffFactor;
825 voice->Direct.OutBuffer = Device->Dry.Buffer;
826 voice->Direct.OutChannels = Device->Dry.NumChannels;
827 for(i = 0;i < NumSends;i++)
829 SendSlots[i] = ALSource->Send[i].Slot;
831 if(!SendSlots[i] && i == 0)
832 SendSlots[i] = Device->DefaultSlot;
833 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
835 SendSlots[i] = NULL;
836 RoomRolloff[i] = 0.0f;
837 DecayDistance[i] = 0.0f;
838 RoomAirAbsorption[i] = 1.0f;
840 else if(SendSlots[i]->AuxSendAuto)
842 RoomRolloff[i] = RoomRolloffBase;
843 if(IsReverbEffect(SendSlots[i]->EffectType))
845 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
846 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
847 SPEEDOFSOUNDMETRESPERSEC;
848 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
850 else
852 DecayDistance[i] = 0.0f;
853 RoomAirAbsorption[i] = 1.0f;
856 else
858 /* If the slot's auxiliary send auto is off, the data sent to the
859 * effect slot is the same as the dry path, sans filter effects */
860 RoomRolloff[i] = Rolloff;
861 DecayDistance[i] = 0.0f;
862 RoomAirAbsorption[i] = AIRABSORBGAINHF;
865 if(!SendSlots[i])
867 voice->Send[i].OutBuffer = NULL;
868 voice->Send[i].OutChannels = 0;
870 else
872 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
873 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
877 /* Transform source to listener space (convert to head relative) */
878 if(ALSource->HeadRelative == AL_FALSE)
880 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
881 /* Transform source vectors */
882 Position = aluMatrixdVector(Matrix, &Position);
883 Velocity = aluMatrixdVector(Matrix, &Velocity);
884 Direction = aluMatrixdVector(Matrix, &Direction);
886 else
888 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
889 /* Offset the source velocity to be relative of the listener velocity */
890 Velocity.v[0] += lvelocity->v[0];
891 Velocity.v[1] += lvelocity->v[1];
892 Velocity.v[2] += lvelocity->v[2];
895 aluNormalize(Direction.v);
896 SourceToListener.v[0] = -Position.v[0];
897 SourceToListener.v[1] = -Position.v[1];
898 SourceToListener.v[2] = -Position.v[2];
899 SourceToListener.v[3] = 0.0f;
900 Distance = aluNormalize(SourceToListener.v);
902 /* Calculate distance attenuation */
903 ClampedDist = Distance;
905 Attenuation = 1.0f;
906 for(i = 0;i < NumSends;i++)
907 RoomAttenuation[i] = 1.0f;
908 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
909 ALContext->DistanceModel)
911 case InverseDistanceClamped:
912 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
913 if(MaxDist < MinDist)
914 break;
915 /*fall-through*/
916 case InverseDistance:
917 if(MinDist > 0.0f)
919 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
920 if(dist > 0.0f) Attenuation = MinDist / dist;
921 for(i = 0;i < NumSends;i++)
923 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
924 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
927 break;
929 case LinearDistanceClamped:
930 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
931 if(MaxDist < MinDist)
932 break;
933 /*fall-through*/
934 case LinearDistance:
935 if(MaxDist != MinDist)
937 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
938 Attenuation = maxf(Attenuation, 0.0f);
939 for(i = 0;i < NumSends;i++)
941 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
942 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
945 break;
947 case ExponentDistanceClamped:
948 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
949 if(MaxDist < MinDist)
950 break;
951 /*fall-through*/
952 case ExponentDistance:
953 if(ClampedDist > 0.0f && MinDist > 0.0f)
955 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
956 for(i = 0;i < NumSends;i++)
957 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
959 break;
961 case DisableDistance:
962 ClampedDist = MinDist;
963 break;
966 /* Source Gain + Attenuation */
967 DryGain = SourceVolume * Attenuation;
968 for(i = 0;i < NumSends;i++)
969 WetGain[i] = SourceVolume * RoomAttenuation[i];
971 /* Distance-based air absorption */
972 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
974 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
975 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
976 for(i = 0;i < NumSends;i++)
977 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
980 if(WetGainAuto)
982 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
984 /* Apply a decay-time transformation to the wet path, based on the
985 * attenuation of the dry path.
987 * Using the apparent distance, based on the distance attenuation, the
988 * initial decay of the reverb effect is calculated and applied to the
989 * wet path.
991 for(i = 0;i < NumSends;i++)
993 if(DecayDistance[i] > 0.0f)
994 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
998 /* Calculate directional soundcones */
999 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1000 if(Angle > InnerAngle && Angle <= OuterAngle)
1002 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1003 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1004 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1006 else if(Angle > OuterAngle)
1008 ConeVolume = ALSource->OuterGain;
1009 ConeHF = ALSource->OuterGainHF;
1011 else
1013 ConeVolume = 1.0f;
1014 ConeHF = 1.0f;
1017 DryGain *= ConeVolume;
1018 if(WetGainAuto)
1020 for(i = 0;i < NumSends;i++)
1021 WetGain[i] *= ConeVolume;
1023 if(DryGainHFAuto)
1024 DryGainHF *= ConeHF;
1025 if(WetGainHFAuto)
1027 for(i = 0;i < NumSends;i++)
1028 WetGainHF[i] *= ConeHF;
1031 /* Clamp to Min/Max Gain */
1032 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1033 for(i = 0;i < NumSends;i++)
1034 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1036 /* Apply gain and frequency filters */
1037 DryGain *= ALSource->Direct.Gain * ListenerGain;
1038 DryGainHF *= ALSource->Direct.GainHF;
1039 DryGainLF *= ALSource->Direct.GainLF;
1040 for(i = 0;i < NumSends;i++)
1042 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1043 WetGainHF[i] *= ALSource->Send[i].GainHF;
1044 WetGainLF[i] *= ALSource->Send[i].GainLF;
1047 /* Calculate velocity-based doppler effect */
1048 if(DopplerFactor > 0.0f)
1050 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1051 ALfloat VSS, VLS;
1053 if(SpeedOfSound < 1.0f)
1055 DopplerFactor *= 1.0f/SpeedOfSound;
1056 SpeedOfSound = 1.0f;
1059 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1060 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1062 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1063 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1066 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1067 while(BufferListItem != NULL)
1069 ALbuffer *ALBuffer;
1070 if((ALBuffer=BufferListItem->buffer) != NULL)
1072 /* Calculate fixed-point stepping value, based on the pitch, buffer
1073 * frequency, and output frequency. */
1074 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1075 if(Pitch > (ALfloat)MAX_PITCH)
1076 voice->Step = MAX_PITCH<<FRACTIONBITS;
1077 else
1078 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1079 BsincPrepare(voice->Step, &voice->SincState);
1081 break;
1083 BufferListItem = BufferListItem->next;
1086 if(Device->Render_Mode == HrtfRender)
1088 /* Full HRTF rendering. Skip the virtual channels and render to the
1089 * real outputs.
1091 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1092 ALfloat ev = 0.0f, az = 0.0f;
1093 ALfloat radius = ALSource->Radius;
1094 ALfloat coeffs[MAX_AMBI_COEFFS];
1095 ALfloat spread = 0.0f;
1097 voice->Direct.OutBuffer = Device->RealOut.Buffer;
1098 voice->Direct.OutChannels = Device->RealOut.NumChannels;
1100 if(Distance > FLT_EPSILON)
1102 dir[0] = -SourceToListener.v[0];
1103 dir[1] = -SourceToListener.v[1];
1104 dir[2] = -SourceToListener.v[2] * ZScale;
1106 /* Calculate elevation and azimuth only when the source is not at
1107 * the listener. This prevents +0 and -0 Z from producing
1108 * inconsistent panning. Also, clamp Y in case FP precision errors
1109 * cause it to land outside of -1..+1. */
1110 ev = asinf(clampf(dir[1], -1.0f, 1.0f));
1111 az = atan2f(dir[0], -dir[2]);
1113 if(radius > Distance)
1114 spread = F_TAU - Distance/radius*F_PI;
1115 else if(Distance > FLT_EPSILON)
1116 spread = asinf(radius / Distance) * 2.0f;
1118 /* Get the HRIR coefficients and delays. */
1119 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, spread, DryGain,
1120 voice->Direct.Hrtf[0].Target.Coeffs,
1121 voice->Direct.Hrtf[0].Target.Delay);
1123 CalcDirectionCoeffs(dir, spread, coeffs);
1125 for(i = 0;i < NumSends;i++)
1127 if(!SendSlots[i])
1129 ALuint j;
1130 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1131 voice->Send[i].Gains[0].Target[j] = 0.0f;
1133 else
1135 const ALeffectslot *Slot = SendSlots[i];
1136 ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs,
1137 WetGain[i], voice->Send[i].Gains[0].Target);
1141 voice->IsHrtf = AL_TRUE;
1143 else
1145 /* Non-HRTF rendering. */
1146 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1147 ALfloat radius = ALSource->Radius;
1148 ALfloat coeffs[MAX_AMBI_COEFFS];
1149 ALfloat spread = 0.0f;
1151 /* Get the localized direction, and compute panned gains. */
1152 if(Distance > FLT_EPSILON)
1154 dir[0] = -SourceToListener.v[0];
1155 dir[1] = -SourceToListener.v[1];
1156 dir[2] = -SourceToListener.v[2] * ZScale;
1158 if(radius > Distance)
1159 spread = F_TAU - Distance/radius*F_PI;
1160 else if(Distance > FLT_EPSILON)
1161 spread = asinf(radius / Distance) * 2.0f;
1163 if(Device->Render_Mode == StereoPair)
1165 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
1166 ALfloat x = -dir[0] * (0.5f * (cosf(spread*0.5f) + 1.0f));
1167 x = clampf(x, -0.5f, 0.5f) + 0.5f;
1168 voice->Direct.Gains[0].Target[0] = x * DryGain;
1169 voice->Direct.Gains[0].Target[1] = (1.0f-x) * DryGain;
1170 for(i = 2;i < MAX_OUTPUT_CHANNELS;i++)
1171 voice->Direct.Gains[0].Target[i] = 0.0f;
1173 CalcDirectionCoeffs(dir, spread, coeffs);
1175 else
1177 CalcDirectionCoeffs(dir, spread, coeffs);
1178 ComputePanningGains(Device->Dry, coeffs, DryGain, voice->Direct.Gains[0].Target);
1181 for(i = 0;i < NumSends;i++)
1183 if(!SendSlots[i])
1185 ALuint j;
1186 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1187 voice->Send[i].Gains[0].Target[j] = 0.0f;
1189 else
1191 const ALeffectslot *Slot = SendSlots[i];
1192 ComputePanningGainsBF(Slot->ChanMap, Slot->NumChannels, coeffs,
1193 WetGain[i], voice->Send[i].Gains[0].Target);
1197 voice->IsHrtf = AL_FALSE;
1201 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1202 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1203 DryGainHF = maxf(DryGainHF, 0.0001f);
1204 DryGainLF = maxf(DryGainLF, 0.0001f);
1205 voice->Direct.Filters[0].ActiveType = AF_None;
1206 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1207 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1208 ALfilterState_setParams(
1209 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1210 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1212 ALfilterState_setParams(
1213 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1214 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1217 for(i = 0;i < NumSends;i++)
1219 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1220 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1221 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1222 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1223 voice->Send[i].Filters[0].ActiveType = AF_None;
1224 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1225 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1226 ALfilterState_setParams(
1227 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1228 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1230 ALfilterState_setParams(
1231 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1232 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1238 void UpdateContextSources(ALCcontext *ctx)
1240 ALvoice *voice, *voice_end;
1241 ALsource *source;
1243 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1245 CalcListenerParams(ctx->Listener);
1247 voice = ctx->Voices;
1248 voice_end = voice + ctx->VoiceCount;
1249 for(;voice != voice_end;++voice)
1251 if(!(source=voice->Source)) continue;
1252 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1253 voice->Source = NULL;
1254 else
1256 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1257 voice->Update(voice, source, ctx);
1261 else
1263 voice = ctx->Voices;
1264 voice_end = voice + ctx->VoiceCount;
1265 for(;voice != voice_end;++voice)
1267 if(!(source=voice->Source)) continue;
1268 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1269 voice->Source = NULL;
1270 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1271 voice->Update(voice, source, ctx);
1277 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1278 * converts NaN to 0. */
1279 static inline ALfloat aluClampf(ALfloat val)
1281 if(fabsf(val) <= 1.0f) return val;
1282 return (ALfloat)((0.0f < val) - (val < 0.0f));
1285 static inline ALfloat aluF2F(ALfloat val)
1286 { return val; }
1288 static inline ALint aluF2I(ALfloat val)
1290 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1291 * integer range normalized floats can be safely converted to.
1293 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1295 static inline ALuint aluF2UI(ALfloat val)
1296 { return aluF2I(val)+2147483648u; }
1298 static inline ALshort aluF2S(ALfloat val)
1299 { return fastf2i(aluClampf(val)*32767.0f); }
1300 static inline ALushort aluF2US(ALfloat val)
1301 { return aluF2S(val)+32768; }
1303 static inline ALbyte aluF2B(ALfloat val)
1304 { return fastf2i(aluClampf(val)*127.0f); }
1305 static inline ALubyte aluF2UB(ALfloat val)
1306 { return aluF2B(val)+128; }
1308 #define DECL_TEMPLATE(T, func) \
1309 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1310 ALuint SamplesToDo, ALuint numchans) \
1312 ALuint i, j; \
1313 for(j = 0;j < numchans;j++) \
1315 const ALfloat *in = InBuffer[j]; \
1316 T *restrict out = (T*)OutBuffer + j; \
1317 for(i = 0;i < SamplesToDo;i++) \
1318 out[i*numchans] = func(in[i]); \
1322 DECL_TEMPLATE(ALfloat, aluF2F)
1323 DECL_TEMPLATE(ALuint, aluF2UI)
1324 DECL_TEMPLATE(ALint, aluF2I)
1325 DECL_TEMPLATE(ALushort, aluF2US)
1326 DECL_TEMPLATE(ALshort, aluF2S)
1327 DECL_TEMPLATE(ALubyte, aluF2UB)
1328 DECL_TEMPLATE(ALbyte, aluF2B)
1330 #undef DECL_TEMPLATE
1333 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1335 ALuint SamplesToDo;
1336 ALvoice *voice, *voice_end;
1337 ALeffectslot *slot;
1338 ALsource *source;
1339 ALCcontext *ctx;
1340 FPUCtl oldMode;
1341 ALuint i, c;
1343 SetMixerFPUMode(&oldMode);
1345 while(size > 0)
1347 IncrementRef(&device->MixCount);
1349 SamplesToDo = minu(size, BUFFERSIZE);
1350 for(c = 0;c < device->VirtOut.NumChannels;c++)
1351 memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1352 for(c = 0;c < device->RealOut.NumChannels;c++)
1353 memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1354 if(device->Dry.Buffer != device->FOAOut.Buffer)
1355 for(c = 0;c < device->FOAOut.NumChannels;c++)
1356 memset(device->FOAOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1358 V0(device->Backend,lock)();
1360 if((slot=device->DefaultSlot) != NULL)
1362 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1363 V(slot->EffectState,update)(device, slot);
1364 for(i = 0;i < slot->NumChannels;i++)
1365 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1368 ctx = ATOMIC_LOAD(&device->ContextList);
1369 while(ctx)
1371 if(!ctx->DeferUpdates)
1373 UpdateContextSources(ctx);
1374 #define UPDATE_SLOT(iter) do { \
1375 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1376 V((*iter)->EffectState,update)(device, *iter); \
1377 for(i = 0;i < (*iter)->NumChannels;i++) \
1378 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1379 } while(0)
1380 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1381 #undef UPDATE_SLOT
1383 else
1385 #define CLEAR_WET_BUFFER(iter) do { \
1386 for(i = 0;i < (*iter)->NumChannels;i++) \
1387 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1388 } while(0)
1389 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1390 #undef CLEAR_WET_BUFFER
1393 /* source processing */
1394 voice = ctx->Voices;
1395 voice_end = voice + ctx->VoiceCount;
1396 for(;voice != voice_end;++voice)
1398 source = voice->Source;
1399 if(source && source->state == AL_PLAYING)
1400 MixSource(voice, source, device, SamplesToDo);
1403 /* effect slot processing */
1404 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1405 for(i = 0;i < c;i++)
1407 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1408 ALeffectState *state = slot->EffectState;
1409 V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
1410 state->OutChannels);
1413 ctx = ctx->next;
1416 if(device->DefaultSlot != NULL)
1418 const ALeffectslot *slot = device->DefaultSlot;
1419 ALeffectState *state = slot->EffectState;
1420 V(state,process)(SamplesToDo, slot->WetBuffer, state->OutBuffer,
1421 state->OutChannels);
1424 /* Increment the clock time. Every second's worth of samples is
1425 * converted and added to clock base so that large sample counts don't
1426 * overflow during conversion. This also guarantees an exact, stable
1427 * conversion. */
1428 device->SamplesDone += SamplesToDo;
1429 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1430 device->SamplesDone %= device->Frequency;
1431 V0(device->Backend,unlock)();
1433 if(device->Hrtf)
1435 int lidx = GetChannelIdxByName(device->RealOut, FrontLeft);
1436 int ridx = GetChannelIdxByName(device->RealOut, FrontRight);
1437 if(lidx != -1 && ridx != -1)
1439 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1440 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1441 MixHrtfParams hrtfparams;
1442 memset(&hrtfparams, 0, sizeof(hrtfparams));
1443 for(c = 0;c < device->VirtOut.NumChannels;c++)
1445 hrtfparams.Current = &device->Hrtf_Params[c];
1446 hrtfparams.Target = &device->Hrtf_Params[c];
1447 HrtfMix(device->RealOut.Buffer, lidx, ridx,
1448 device->VirtOut.Buffer[c], 0, device->Hrtf_Offset, 0,
1449 irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
1452 device->Hrtf_Offset += SamplesToDo;
1455 else if(device->AmbiDecoder)
1457 if(device->VirtOut.Buffer != device->FOAOut.Buffer)
1458 bformatdec_upSample(device->AmbiDecoder,
1459 device->VirtOut.Buffer, device->FOAOut.Buffer,
1460 device->FOAOut.NumChannels, SamplesToDo
1462 bformatdec_process(device->AmbiDecoder,
1463 device->RealOut.Buffer, device->RealOut.NumChannels,
1464 device->VirtOut.Buffer, SamplesToDo
1467 else
1469 if(device->Uhj_Encoder)
1471 int lidx = GetChannelIdxByName(device->RealOut, FrontLeft);
1472 int ridx = GetChannelIdxByName(device->RealOut, FrontRight);
1473 if(lidx != -1 && ridx != -1)
1475 /* Encode to stereo-compatible 2-channel UHJ output. */
1476 EncodeUhj2(device->Uhj_Encoder,
1477 device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx],
1478 device->VirtOut.Buffer, SamplesToDo
1482 if(device->Bs2b)
1484 /* Apply binaural/crossfeed filter */
1485 for(i = 0;i < SamplesToDo;i++)
1487 float samples[2];
1488 samples[0] = device->RealOut.Buffer[0][i];
1489 samples[1] = device->RealOut.Buffer[1][i];
1490 bs2b_cross_feed(device->Bs2b, samples);
1491 device->RealOut.Buffer[0][i] = samples[0];
1492 device->RealOut.Buffer[1][i] = samples[1];
1497 if(buffer)
1499 ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
1500 ALuint OutChannels = device->RealOut.NumChannels;
1502 #define WRITE(T, a, b, c, d) do { \
1503 Write_##T((a), (b), (c), (d)); \
1504 buffer = (T*)buffer + (c)*(d); \
1505 } while(0)
1506 switch(device->FmtType)
1508 case DevFmtByte:
1509 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1510 break;
1511 case DevFmtUByte:
1512 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1513 break;
1514 case DevFmtShort:
1515 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1516 break;
1517 case DevFmtUShort:
1518 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1519 break;
1520 case DevFmtInt:
1521 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1522 break;
1523 case DevFmtUInt:
1524 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1525 break;
1526 case DevFmtFloat:
1527 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1528 break;
1530 #undef WRITE
1533 size -= SamplesToDo;
1534 IncrementRef(&device->MixCount);
1537 RestoreFPUMode(&oldMode);
1541 ALvoid aluHandleDisconnect(ALCdevice *device)
1543 ALCcontext *Context;
1545 device->Connected = ALC_FALSE;
1547 Context = ATOMIC_LOAD(&device->ContextList);
1548 while(Context)
1550 ALvoice *voice, *voice_end;
1552 voice = Context->Voices;
1553 voice_end = voice + Context->VoiceCount;
1554 while(voice != voice_end)
1556 ALsource *source = voice->Source;
1557 voice->Source = NULL;
1559 if(source && source->state == AL_PLAYING)
1561 source->state = AL_STOPPED;
1562 ATOMIC_STORE(&source->current_buffer, NULL);
1563 source->position = 0;
1564 source->position_fraction = 0;
1567 voice++;
1569 Context->VoiceCount = 0;
1571 Context = Context->next;