Add a dual-band ambisonic decoder
[openal-soft.git] / Alc / ALu.c
blob5064a588fc0835c2e6549d44e46992affd3adec2
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 }, StereoMap[2] = {
307 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
308 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
309 }, RearMap[2] = {
310 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
311 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
312 }, QuadMap[4] = {
313 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
314 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
315 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
316 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
317 }, X51Map[6] = {
318 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
319 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
320 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
321 { LFE, 0.0f, 0.0f },
322 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
323 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
324 }, X61Map[7] = {
325 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
326 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
327 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
328 { LFE, 0.0f, 0.0f },
329 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
330 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
331 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
332 }, X71Map[8] = {
333 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
334 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
335 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
336 { LFE, 0.0f, 0.0f },
337 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
338 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
339 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
340 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
343 const ALCdevice *Device = ALContext->Device;
344 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
345 ALbufferlistitem *BufferListItem;
346 enum FmtChannels Channels;
347 ALfloat DryGain, DryGainHF, DryGainLF;
348 ALfloat WetGain[MAX_SENDS];
349 ALfloat WetGainHF[MAX_SENDS];
350 ALfloat WetGainLF[MAX_SENDS];
351 ALeffectslot *SendSlots[MAX_SENDS];
352 ALuint NumSends, Frequency;
353 ALboolean Relative;
354 const struct ChanMap *chans = NULL;
355 ALuint num_channels = 0;
356 ALboolean DirectChannels;
357 ALboolean isbformat = AL_FALSE;
358 ALfloat Pitch;
359 ALuint i, j, c;
361 /* Get device properties */
362 NumSends = Device->NumAuxSends;
363 Frequency = Device->Frequency;
365 /* Get listener properties */
366 ListenerGain = ALContext->Listener->Gain;
368 /* Get source properties */
369 SourceVolume = ALSource->Gain;
370 MinVolume = ALSource->MinGain;
371 MaxVolume = ALSource->MaxGain;
372 Pitch = ALSource->Pitch;
373 Relative = ALSource->HeadRelative;
374 DirectChannels = ALSource->DirectChannels;
376 voice->Direct.OutBuffer = Device->Dry.Buffer;
377 voice->Direct.OutChannels = Device->Dry.NumChannels;
378 for(i = 0;i < NumSends;i++)
380 SendSlots[i] = ALSource->Send[i].Slot;
381 if(!SendSlots[i] && i == 0)
382 SendSlots[i] = Device->DefaultSlot;
383 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
385 SendSlots[i] = NULL;
386 voice->Send[i].OutBuffer = NULL;
387 voice->Send[i].OutChannels = 0;
389 else
391 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
392 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
396 /* Calculate the stepping value */
397 Channels = FmtMono;
398 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
399 while(BufferListItem != NULL)
401 ALbuffer *ALBuffer;
402 if((ALBuffer=BufferListItem->buffer) != NULL)
404 Pitch = Pitch * ALBuffer->Frequency / Frequency;
405 if(Pitch > (ALfloat)MAX_PITCH)
406 voice->Step = MAX_PITCH<<FRACTIONBITS;
407 else
408 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
409 BsincPrepare(voice->Step, &voice->SincState);
411 Channels = ALBuffer->FmtChannels;
412 break;
414 BufferListItem = BufferListItem->next;
417 /* Calculate gains */
418 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
419 DryGain *= ALSource->Direct.Gain * ListenerGain;
420 DryGainHF = ALSource->Direct.GainHF;
421 DryGainLF = ALSource->Direct.GainLF;
422 for(i = 0;i < NumSends;i++)
424 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
425 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
426 WetGainHF[i] = ALSource->Send[i].GainHF;
427 WetGainLF[i] = ALSource->Send[i].GainLF;
430 switch(Channels)
432 case FmtMono:
433 chans = MonoMap;
434 num_channels = 1;
435 break;
437 case FmtStereo:
438 chans = StereoMap;
439 num_channels = 2;
440 break;
442 case FmtRear:
443 chans = RearMap;
444 num_channels = 2;
445 break;
447 case FmtQuad:
448 chans = QuadMap;
449 num_channels = 4;
450 break;
452 case FmtX51:
453 chans = X51Map;
454 num_channels = 6;
455 break;
457 case FmtX61:
458 chans = X61Map;
459 num_channels = 7;
460 break;
462 case FmtX71:
463 chans = X71Map;
464 num_channels = 8;
465 break;
467 case FmtBFormat2D:
468 num_channels = 3;
469 isbformat = AL_TRUE;
470 DirectChannels = AL_FALSE;
471 break;
473 case FmtBFormat3D:
474 num_channels = 4;
475 isbformat = AL_TRUE;
476 DirectChannels = AL_FALSE;
477 break;
480 if(isbformat)
482 ALfloat N[3], V[3], U[3];
483 aluMatrixf matrix;
484 ALfloat scale;
486 /* AT then UP */
487 N[0] = ALSource->Orientation[0][0];
488 N[1] = ALSource->Orientation[0][1];
489 N[2] = ALSource->Orientation[0][2];
490 aluNormalize(N);
491 V[0] = ALSource->Orientation[1][0];
492 V[1] = ALSource->Orientation[1][1];
493 V[2] = ALSource->Orientation[1][2];
494 aluNormalize(V);
495 if(!Relative)
497 const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
498 aluMatrixdFloat3(N, 0.0f, lmatrix);
499 aluMatrixdFloat3(V, 0.0f, lmatrix);
501 /* Build and normalize right-vector */
502 aluCrossproduct(N, V, U);
503 aluNormalize(U);
505 /* Build a rotate + conversion matrix (B-Format -> N3D), and include
506 * scaling for first-order content on second- or third-order output.
508 scale = Device->Dry.AmbiScale * 1.732050808f;
509 aluMatrixfSet(&matrix,
510 1.414213562f, 0.0f, 0.0f, 0.0f,
511 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
512 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
513 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
516 for(c = 0;c < num_channels;c++)
517 ComputeFirstOrderGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, matrix.m[c],
518 DryGain, voice->Direct.Gains[c].Target);
520 /* Rebuild the matrix, without the second- or third-order output
521 * scaling (effects take first-order content, and will do the scaling
522 * themselves when mixing to the output).
524 scale = 1.732050808f;
525 aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale);
526 aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale);
527 aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale);
528 for(i = 0;i < NumSends;i++)
530 if(!SendSlots[i])
532 for(c = 0;c < num_channels;c++)
534 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
535 voice->Send[i].Gains[c].Target[j] = 0.0f;
538 else
540 for(c = 0;c < num_channels;c++)
542 const ALeffectslot *Slot = SendSlots[i];
543 ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c],
544 WetGain[i], voice->Send[i].Gains[c].Target);
549 voice->IsHrtf = AL_FALSE;
551 else
553 ALfloat coeffs[MAX_AMBI_COEFFS];
555 if(DirectChannels)
557 /* Skip the virtual channels and write FrontLeft and FrontRight
558 * inputs to the real output.
560 voice->Direct.OutBuffer = Device->RealOut.Buffer;
561 voice->Direct.OutChannels = Device->RealOut.NumChannels;
562 for(c = 0;c < num_channels;c++)
564 int idx;
565 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
566 voice->Direct.Gains[c].Target[j] = 0.0f;
567 if((idx=GetChannelIdxByName(Device->RealOut, chans[c].channel)) != -1)
568 voice->Direct.Gains[c].Target[idx] = DryGain;
571 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
572 * channel-match. */
573 for(c = 0;c < num_channels;c++)
575 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
577 for(i = 0;i < NumSends;i++)
579 if(!SendSlots[i])
581 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
582 voice->Send[i].Gains[c].Target[j] = 0.0f;
584 else
586 const ALeffectslot *Slot = SendSlots[i];
587 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
588 WetGain[i], voice->Send[i].Gains[c].Target);
593 voice->IsHrtf = AL_FALSE;
595 else if(Device->Render_Mode == HrtfRender)
597 /* Full HRTF rendering. Skip the virtual channels and render each
598 * input channel to the real outputs.
600 voice->Direct.OutBuffer = Device->RealOut.Buffer;
601 voice->Direct.OutChannels = Device->RealOut.NumChannels;
602 for(c = 0;c < num_channels;c++)
604 if(chans[c].channel == LFE)
606 /* Skip LFE */
607 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
608 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
609 for(i = 0;i < HRIR_LENGTH;i++)
611 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
612 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
615 for(i = 0;i < NumSends;i++)
617 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
618 voice->Send[i].Gains[c].Target[j] = 0.0f;
621 continue;
624 /* Get the static HRIR coefficients and delays for this channel. */
625 GetLerpedHrtfCoeffs(Device->Hrtf,
626 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
627 voice->Direct.Hrtf[c].Target.Coeffs,
628 voice->Direct.Hrtf[c].Target.Delay
631 /* Normal panning for auxiliary sends. */
632 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
634 for(i = 0;i < NumSends;i++)
636 if(!SendSlots[i])
638 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
639 voice->Send[i].Gains[c].Target[j] = 0.0f;
641 else
643 const ALeffectslot *Slot = SendSlots[i];
644 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
645 WetGain[i], voice->Send[i].Gains[c].Target);
650 voice->IsHrtf = AL_TRUE;
652 else
654 /* Non-HRTF rendering. Use normal panning to the output. */
655 for(c = 0;c < num_channels;c++)
657 /* Special-case LFE */
658 if(chans[c].channel == LFE)
660 int idx;
661 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
662 voice->Direct.Gains[c].Target[j] = 0.0f;
663 if((idx=GetChannelIdxByName(Device->Dry, chans[c].channel)) != -1)
664 voice->Direct.Gains[c].Target[idx] = DryGain;
666 for(i = 0;i < NumSends;i++)
668 ALuint j;
669 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
670 voice->Send[i].Gains[c].Target[j] = 0.0f;
672 continue;
675 if(Device->Render_Mode == StereoPair)
677 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
678 ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation);
679 coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5;
680 voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain;
681 voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain;
682 for(j = 2;j < MAX_OUTPUT_CHANNELS;j++)
683 voice->Direct.Gains[c].Target[j] = 0.0f;
685 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
687 else
689 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
690 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
691 DryGain, voice->Direct.Gains[c].Target);
694 for(i = 0;i < NumSends;i++)
696 if(!SendSlots[i])
698 ALuint j;
699 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
700 voice->Send[i].Gains[c].Target[j] = 0.0f;
702 else
704 const ALeffectslot *Slot = SendSlots[i];
705 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
706 WetGain[i], voice->Send[i].Gains[c].Target);
711 voice->IsHrtf = AL_FALSE;
716 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
717 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
718 DryGainHF = maxf(DryGainHF, 0.0001f);
719 DryGainLF = maxf(DryGainLF, 0.0001f);
720 for(c = 0;c < num_channels;c++)
722 voice->Direct.Filters[c].ActiveType = AF_None;
723 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
724 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
725 ALfilterState_setParams(
726 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
727 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
729 ALfilterState_setParams(
730 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
731 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
735 for(i = 0;i < NumSends;i++)
737 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
738 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
739 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
740 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
741 for(c = 0;c < num_channels;c++)
743 voice->Send[i].Filters[c].ActiveType = AF_None;
744 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
745 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
746 ALfilterState_setParams(
747 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
748 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
750 ALfilterState_setParams(
751 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
752 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
758 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
760 const ALCdevice *Device = ALContext->Device;
761 aluVector Position, Velocity, Direction, SourceToListener;
762 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
763 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
764 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
765 ALfloat DopplerFactor, SpeedOfSound;
766 ALfloat AirAbsorptionFactor;
767 ALfloat RoomAirAbsorption[MAX_SENDS];
768 ALbufferlistitem *BufferListItem;
769 ALeffectslot *SendSlots[MAX_SENDS];
770 ALfloat Attenuation;
771 ALfloat RoomAttenuation[MAX_SENDS];
772 ALfloat MetersPerUnit;
773 ALfloat RoomRolloffBase;
774 ALfloat RoomRolloff[MAX_SENDS];
775 ALfloat DecayDistance[MAX_SENDS];
776 ALfloat DryGain;
777 ALfloat DryGainHF;
778 ALfloat DryGainLF;
779 ALboolean DryGainHFAuto;
780 ALfloat WetGain[MAX_SENDS];
781 ALfloat WetGainHF[MAX_SENDS];
782 ALfloat WetGainLF[MAX_SENDS];
783 ALboolean WetGainAuto;
784 ALboolean WetGainHFAuto;
785 ALfloat Pitch;
786 ALuint Frequency;
787 ALint NumSends;
788 ALint i;
790 DryGainHF = 1.0f;
791 DryGainLF = 1.0f;
792 for(i = 0;i < MAX_SENDS;i++)
794 WetGainHF[i] = 1.0f;
795 WetGainLF[i] = 1.0f;
798 /* Get context/device properties */
799 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
800 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
801 NumSends = Device->NumAuxSends;
802 Frequency = Device->Frequency;
804 /* Get listener properties */
805 ListenerGain = ALContext->Listener->Gain;
806 MetersPerUnit = ALContext->Listener->MetersPerUnit;
808 /* Get source properties */
809 SourceVolume = ALSource->Gain;
810 MinVolume = ALSource->MinGain;
811 MaxVolume = ALSource->MaxGain;
812 Pitch = ALSource->Pitch;
813 Position = ALSource->Position;
814 Direction = ALSource->Direction;
815 Velocity = ALSource->Velocity;
816 MinDist = ALSource->RefDistance;
817 MaxDist = ALSource->MaxDistance;
818 Rolloff = ALSource->RollOffFactor;
819 InnerAngle = ALSource->InnerAngle;
820 OuterAngle = ALSource->OuterAngle;
821 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
822 DryGainHFAuto = ALSource->DryGainHFAuto;
823 WetGainAuto = ALSource->WetGainAuto;
824 WetGainHFAuto = ALSource->WetGainHFAuto;
825 RoomRolloffBase = ALSource->RoomRolloffFactor;
827 voice->Direct.OutBuffer = Device->Dry.Buffer;
828 voice->Direct.OutChannels = Device->Dry.NumChannels;
829 for(i = 0;i < NumSends;i++)
831 SendSlots[i] = ALSource->Send[i].Slot;
833 if(!SendSlots[i] && i == 0)
834 SendSlots[i] = Device->DefaultSlot;
835 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
837 SendSlots[i] = NULL;
838 RoomRolloff[i] = 0.0f;
839 DecayDistance[i] = 0.0f;
840 RoomAirAbsorption[i] = 1.0f;
842 else if(SendSlots[i]->AuxSendAuto)
844 RoomRolloff[i] = RoomRolloffBase;
845 if(IsReverbEffect(SendSlots[i]->EffectType))
847 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
848 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
849 SPEEDOFSOUNDMETRESPERSEC;
850 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
852 else
854 DecayDistance[i] = 0.0f;
855 RoomAirAbsorption[i] = 1.0f;
858 else
860 /* If the slot's auxiliary send auto is off, the data sent to the
861 * effect slot is the same as the dry path, sans filter effects */
862 RoomRolloff[i] = Rolloff;
863 DecayDistance[i] = 0.0f;
864 RoomAirAbsorption[i] = AIRABSORBGAINHF;
867 if(!SendSlots[i])
869 voice->Send[i].OutBuffer = NULL;
870 voice->Send[i].OutChannels = 0;
872 else
874 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
875 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
879 /* Transform source to listener space (convert to head relative) */
880 if(ALSource->HeadRelative == AL_FALSE)
882 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
883 /* Transform source vectors */
884 Position = aluMatrixdVector(Matrix, &Position);
885 Velocity = aluMatrixdVector(Matrix, &Velocity);
886 Direction = aluMatrixdVector(Matrix, &Direction);
888 else
890 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
891 /* Offset the source velocity to be relative of the listener velocity */
892 Velocity.v[0] += lvelocity->v[0];
893 Velocity.v[1] += lvelocity->v[1];
894 Velocity.v[2] += lvelocity->v[2];
897 aluNormalize(Direction.v);
898 SourceToListener.v[0] = -Position.v[0];
899 SourceToListener.v[1] = -Position.v[1];
900 SourceToListener.v[2] = -Position.v[2];
901 SourceToListener.v[3] = 0.0f;
902 Distance = aluNormalize(SourceToListener.v);
904 /* Calculate distance attenuation */
905 ClampedDist = Distance;
907 Attenuation = 1.0f;
908 for(i = 0;i < NumSends;i++)
909 RoomAttenuation[i] = 1.0f;
910 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
911 ALContext->DistanceModel)
913 case InverseDistanceClamped:
914 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
915 if(MaxDist < MinDist)
916 break;
917 /*fall-through*/
918 case InverseDistance:
919 if(MinDist > 0.0f)
921 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
922 if(dist > 0.0f) Attenuation = MinDist / dist;
923 for(i = 0;i < NumSends;i++)
925 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
926 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
929 break;
931 case LinearDistanceClamped:
932 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
933 if(MaxDist < MinDist)
934 break;
935 /*fall-through*/
936 case LinearDistance:
937 if(MaxDist != MinDist)
939 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
940 Attenuation = maxf(Attenuation, 0.0f);
941 for(i = 0;i < NumSends;i++)
943 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
944 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
947 break;
949 case ExponentDistanceClamped:
950 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
951 if(MaxDist < MinDist)
952 break;
953 /*fall-through*/
954 case ExponentDistance:
955 if(ClampedDist > 0.0f && MinDist > 0.0f)
957 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
958 for(i = 0;i < NumSends;i++)
959 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
961 break;
963 case DisableDistance:
964 ClampedDist = MinDist;
965 break;
968 /* Source Gain + Attenuation */
969 DryGain = SourceVolume * Attenuation;
970 for(i = 0;i < NumSends;i++)
971 WetGain[i] = SourceVolume * RoomAttenuation[i];
973 /* Distance-based air absorption */
974 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
976 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
977 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
978 for(i = 0;i < NumSends;i++)
979 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
982 if(WetGainAuto)
984 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
986 /* Apply a decay-time transformation to the wet path, based on the
987 * attenuation of the dry path.
989 * Using the apparent distance, based on the distance attenuation, the
990 * initial decay of the reverb effect is calculated and applied to the
991 * wet path.
993 for(i = 0;i < NumSends;i++)
995 if(DecayDistance[i] > 0.0f)
996 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1000 /* Calculate directional soundcones */
1001 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1002 if(Angle > InnerAngle && Angle <= OuterAngle)
1004 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1005 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1006 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1008 else if(Angle > OuterAngle)
1010 ConeVolume = ALSource->OuterGain;
1011 ConeHF = ALSource->OuterGainHF;
1013 else
1015 ConeVolume = 1.0f;
1016 ConeHF = 1.0f;
1019 DryGain *= ConeVolume;
1020 if(WetGainAuto)
1022 for(i = 0;i < NumSends;i++)
1023 WetGain[i] *= ConeVolume;
1025 if(DryGainHFAuto)
1026 DryGainHF *= ConeHF;
1027 if(WetGainHFAuto)
1029 for(i = 0;i < NumSends;i++)
1030 WetGainHF[i] *= ConeHF;
1033 /* Clamp to Min/Max Gain */
1034 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1035 for(i = 0;i < NumSends;i++)
1036 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1038 /* Apply gain and frequency filters */
1039 DryGain *= ALSource->Direct.Gain * ListenerGain;
1040 DryGainHF *= ALSource->Direct.GainHF;
1041 DryGainLF *= ALSource->Direct.GainLF;
1042 for(i = 0;i < NumSends;i++)
1044 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1045 WetGainHF[i] *= ALSource->Send[i].GainHF;
1046 WetGainLF[i] *= ALSource->Send[i].GainLF;
1049 /* Calculate velocity-based doppler effect */
1050 if(DopplerFactor > 0.0f)
1052 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1053 ALfloat VSS, VLS;
1055 if(SpeedOfSound < 1.0f)
1057 DopplerFactor *= 1.0f/SpeedOfSound;
1058 SpeedOfSound = 1.0f;
1061 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1062 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1064 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1065 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1068 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1069 while(BufferListItem != NULL)
1071 ALbuffer *ALBuffer;
1072 if((ALBuffer=BufferListItem->buffer) != NULL)
1074 /* Calculate fixed-point stepping value, based on the pitch, buffer
1075 * frequency, and output frequency. */
1076 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1077 if(Pitch > (ALfloat)MAX_PITCH)
1078 voice->Step = MAX_PITCH<<FRACTIONBITS;
1079 else
1080 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1081 BsincPrepare(voice->Step, &voice->SincState);
1083 break;
1085 BufferListItem = BufferListItem->next;
1088 if(Device->Render_Mode == HrtfRender)
1090 /* Full HRTF rendering. Skip the virtual channels and render to the
1091 * real outputs.
1093 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1094 ALfloat ev = 0.0f, az = 0.0f;
1095 ALfloat radius = ALSource->Radius;
1096 ALfloat dirfact = 1.0f;
1097 ALfloat coeffs[MAX_AMBI_COEFFS];
1099 voice->Direct.OutBuffer = Device->RealOut.Buffer;
1100 voice->Direct.OutChannels = Device->RealOut.NumChannels;
1102 if(Distance > FLT_EPSILON)
1104 dir.v[0] = -SourceToListener.v[0];
1105 dir.v[1] = -SourceToListener.v[1];
1106 dir.v[2] = -SourceToListener.v[2] * ZScale;
1108 /* Calculate elevation and azimuth only when the source is not at
1109 * the listener. This prevents +0 and -0 Z from producing
1110 * inconsistent panning. Also, clamp Y in case FP precision errors
1111 * cause it to land outside of -1..+1. */
1112 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1113 az = atan2f(dir.v[0], -dir.v[2]);
1115 if(radius > 0.0f)
1117 if(radius >= Distance)
1118 dirfact *= Distance / radius * 0.5f;
1119 else
1120 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1123 /* Get the HRIR coefficients and delays. */
1124 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1125 voice->Direct.Hrtf[0].Target.Coeffs,
1126 voice->Direct.Hrtf[0].Target.Delay);
1128 dir.v[0] *= dirfact;
1129 dir.v[1] *= dirfact;
1130 dir.v[2] *= dirfact;
1131 CalcDirectionCoeffs(dir.v, coeffs);
1133 for(i = 0;i < NumSends;i++)
1135 if(!SendSlots[i])
1137 ALuint j;
1138 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1139 voice->Send[i].Gains[0].Target[j] = 0.0f;
1141 else
1143 const ALeffectslot *Slot = SendSlots[i];
1144 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1145 WetGain[i], voice->Send[i].Gains[0].Target);
1149 voice->IsHrtf = AL_TRUE;
1151 else
1153 /* Non-HRTF rendering. */
1154 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1155 ALfloat radius = ALSource->Radius;
1156 ALfloat coeffs[MAX_AMBI_COEFFS];
1158 /* Get the localized direction, and compute panned gains. */
1159 if(Distance > FLT_EPSILON)
1161 dir[0] = -SourceToListener.v[0];
1162 dir[1] = -SourceToListener.v[1];
1163 dir[2] = -SourceToListener.v[2] * ZScale;
1165 if(radius > 0.0f)
1167 ALfloat dirfact;
1168 if(radius >= Distance)
1169 dirfact = Distance / radius * 0.5f;
1170 else
1171 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1172 dir[0] *= dirfact;
1173 dir[1] *= dirfact;
1174 dir[2] *= dirfact;
1177 if(Device->Render_Mode == StereoPair)
1179 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
1180 coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5;
1181 voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain;
1182 voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain;
1183 for(i = 2;i < MAX_OUTPUT_CHANNELS;i++)
1184 voice->Direct.Gains[0].Target[i] = 0.0f;
1186 CalcDirectionCoeffs(dir, coeffs);
1188 else
1190 CalcDirectionCoeffs(dir, coeffs);
1191 ComputePanningGains(Device->Dry.AmbiCoeffs, Device->Dry.NumChannels, coeffs,
1192 DryGain, voice->Direct.Gains[0].Target);
1195 for(i = 0;i < NumSends;i++)
1197 if(!SendSlots[i])
1199 ALuint j;
1200 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1201 voice->Send[i].Gains[0].Target[j] = 0.0f;
1203 else
1205 const ALeffectslot *Slot = SendSlots[i];
1206 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1207 WetGain[i], voice->Send[i].Gains[0].Target);
1211 voice->IsHrtf = AL_FALSE;
1215 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1216 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1217 DryGainHF = maxf(DryGainHF, 0.0001f);
1218 DryGainLF = maxf(DryGainLF, 0.0001f);
1219 voice->Direct.Filters[0].ActiveType = AF_None;
1220 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1221 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1222 ALfilterState_setParams(
1223 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1224 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1226 ALfilterState_setParams(
1227 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1228 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1231 for(i = 0;i < NumSends;i++)
1233 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1234 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1235 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1236 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1237 voice->Send[i].Filters[0].ActiveType = AF_None;
1238 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1239 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1240 ALfilterState_setParams(
1241 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1242 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1244 ALfilterState_setParams(
1245 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1246 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1252 void UpdateContextSources(ALCcontext *ctx)
1254 ALvoice *voice, *voice_end;
1255 ALsource *source;
1257 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1259 CalcListenerParams(ctx->Listener);
1261 voice = ctx->Voices;
1262 voice_end = voice + ctx->VoiceCount;
1263 for(;voice != voice_end;++voice)
1265 if(!(source=voice->Source)) continue;
1266 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1267 voice->Source = NULL;
1268 else
1270 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1271 voice->Update(voice, source, ctx);
1275 else
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 if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1285 voice->Update(voice, source, ctx);
1291 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1292 * converts NaN to 0. */
1293 static inline ALfloat aluClampf(ALfloat val)
1295 if(fabsf(val) <= 1.0f) return val;
1296 return (ALfloat)((0.0f < val) - (val < 0.0f));
1299 static inline ALfloat aluF2F(ALfloat val)
1300 { return val; }
1302 static inline ALint aluF2I(ALfloat val)
1304 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1305 * integer range normalized floats can be safely converted to.
1307 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1309 static inline ALuint aluF2UI(ALfloat val)
1310 { return aluF2I(val)+2147483648u; }
1312 static inline ALshort aluF2S(ALfloat val)
1313 { return fastf2i(aluClampf(val)*32767.0f); }
1314 static inline ALushort aluF2US(ALfloat val)
1315 { return aluF2S(val)+32768; }
1317 static inline ALbyte aluF2B(ALfloat val)
1318 { return fastf2i(aluClampf(val)*127.0f); }
1319 static inline ALubyte aluF2UB(ALfloat val)
1320 { return aluF2B(val)+128; }
1322 #define DECL_TEMPLATE(T, func) \
1323 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1324 ALuint SamplesToDo, ALuint numchans) \
1326 ALuint i, j; \
1327 for(j = 0;j < numchans;j++) \
1329 const ALfloat *in = InBuffer[j]; \
1330 T *restrict out = (T*)OutBuffer + j; \
1331 for(i = 0;i < SamplesToDo;i++) \
1332 out[i*numchans] = func(in[i]); \
1336 DECL_TEMPLATE(ALfloat, aluF2F)
1337 DECL_TEMPLATE(ALuint, aluF2UI)
1338 DECL_TEMPLATE(ALint, aluF2I)
1339 DECL_TEMPLATE(ALushort, aluF2US)
1340 DECL_TEMPLATE(ALshort, aluF2S)
1341 DECL_TEMPLATE(ALubyte, aluF2UB)
1342 DECL_TEMPLATE(ALbyte, aluF2B)
1344 #undef DECL_TEMPLATE
1347 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1349 ALuint SamplesToDo;
1350 ALvoice *voice, *voice_end;
1351 ALeffectslot *slot;
1352 ALsource *source;
1353 ALCcontext *ctx;
1354 FPUCtl oldMode;
1355 ALuint i, c;
1357 SetMixerFPUMode(&oldMode);
1359 while(size > 0)
1361 IncrementRef(&device->MixCount);
1363 SamplesToDo = minu(size, BUFFERSIZE);
1364 for(c = 0;c < device->VirtOut.NumChannels;c++)
1365 memset(device->VirtOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1366 for(c = 0;c < device->RealOut.NumChannels;c++)
1367 memset(device->RealOut.Buffer[c], 0, SamplesToDo*sizeof(ALfloat));
1369 V0(device->Backend,lock)();
1371 if((slot=device->DefaultSlot) != NULL)
1373 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1374 V(slot->EffectState,update)(device, slot);
1375 for(i = 0;i < slot->NumChannels;i++)
1376 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1379 ctx = ATOMIC_LOAD(&device->ContextList);
1380 while(ctx)
1382 if(!ctx->DeferUpdates)
1384 UpdateContextSources(ctx);
1385 #define UPDATE_SLOT(iter) do { \
1386 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1387 V((*iter)->EffectState,update)(device, *iter); \
1388 for(i = 0;i < (*iter)->NumChannels;i++) \
1389 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1390 } while(0)
1391 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1392 #undef UPDATE_SLOT
1394 else
1396 #define CLEAR_WET_BUFFER(iter) do { \
1397 for(i = 0;i < (*iter)->NumChannels;i++) \
1398 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1399 } while(0)
1400 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1401 #undef CLEAR_WET_BUFFER
1404 /* source processing */
1405 voice = ctx->Voices;
1406 voice_end = voice + ctx->VoiceCount;
1407 for(;voice != voice_end;++voice)
1409 source = voice->Source;
1410 if(source && source->state == AL_PLAYING)
1411 MixSource(voice, source, device, SamplesToDo);
1414 /* effect slot processing */
1415 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1416 for(i = 0;i < c;i++)
1418 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1419 ALeffectState *state = slot->EffectState;
1420 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1421 device->Dry.NumChannels);
1424 ctx = ctx->next;
1427 if(device->DefaultSlot != NULL)
1429 const ALeffectslot *slot = device->DefaultSlot;
1430 ALeffectState *state = slot->EffectState;
1431 V(state,process)(SamplesToDo, slot->WetBuffer, device->Dry.Buffer,
1432 device->Dry.NumChannels);
1435 /* Increment the clock time. Every second's worth of samples is
1436 * converted and added to clock base so that large sample counts don't
1437 * overflow during conversion. This also guarantees an exact, stable
1438 * conversion. */
1439 device->SamplesDone += SamplesToDo;
1440 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1441 device->SamplesDone %= device->Frequency;
1442 V0(device->Backend,unlock)();
1444 if(device->Hrtf)
1446 int lidx = GetChannelIdxByName(device->RealOut, FrontLeft);
1447 int ridx = GetChannelIdxByName(device->RealOut, FrontRight);
1448 if(lidx != -1 && ridx != -1)
1450 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1451 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1452 MixHrtfParams hrtfparams;
1453 memset(&hrtfparams, 0, sizeof(hrtfparams));
1454 for(c = 0;c < device->VirtOut.NumChannels;c++)
1456 hrtfparams.Current = &device->Hrtf_Params[c];
1457 hrtfparams.Target = &device->Hrtf_Params[c];
1458 HrtfMix(device->RealOut.Buffer, lidx, ridx,
1459 device->VirtOut.Buffer[c], 0, device->Hrtf_Offset, 0,
1460 irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
1463 device->Hrtf_Offset += SamplesToDo;
1466 else if(device->AmbiDecoder)
1468 bformatdec_process(device->AmbiDecoder,
1469 device->RealOut.Buffer, device->RealOut.NumChannels,
1470 device->VirtOut.Buffer, SamplesToDo
1473 else
1475 if(device->Uhj_Encoder)
1477 int lidx = GetChannelIdxByName(device->RealOut, FrontLeft);
1478 int ridx = GetChannelIdxByName(device->RealOut, FrontRight);
1479 if(lidx != -1 && ridx != -1)
1481 /* Encode to stereo-compatible 2-channel UHJ output. */
1482 EncodeUhj2(device->Uhj_Encoder,
1483 device->RealOut.Buffer[lidx], device->RealOut.Buffer[ridx],
1484 device->VirtOut.Buffer, SamplesToDo
1488 if(device->Bs2b)
1490 /* Apply binaural/crossfeed filter */
1491 for(i = 0;i < SamplesToDo;i++)
1493 float samples[2];
1494 samples[0] = device->RealOut.Buffer[0][i];
1495 samples[1] = device->RealOut.Buffer[1][i];
1496 bs2b_cross_feed(device->Bs2b, samples);
1497 device->RealOut.Buffer[0][i] = samples[0];
1498 device->RealOut.Buffer[1][i] = samples[1];
1503 if(buffer)
1505 ALfloat (*OutBuffer)[BUFFERSIZE] = device->RealOut.Buffer;
1506 ALuint OutChannels = device->RealOut.NumChannels;;
1508 #define WRITE(T, a, b, c, d) do { \
1509 Write_##T((a), (b), (c), (d)); \
1510 buffer = (T*)buffer + (c)*(d); \
1511 } while(0)
1512 switch(device->FmtType)
1514 case DevFmtByte:
1515 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1516 break;
1517 case DevFmtUByte:
1518 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1519 break;
1520 case DevFmtShort:
1521 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1522 break;
1523 case DevFmtUShort:
1524 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1525 break;
1526 case DevFmtInt:
1527 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1528 break;
1529 case DevFmtUInt:
1530 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1531 break;
1532 case DevFmtFloat:
1533 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1534 break;
1536 #undef WRITE
1539 size -= SamplesToDo;
1540 IncrementRef(&device->MixCount);
1543 RestoreFPUMode(&oldMode);
1547 ALvoid aluHandleDisconnect(ALCdevice *device)
1549 ALCcontext *Context;
1551 device->Connected = ALC_FALSE;
1553 Context = ATOMIC_LOAD(&device->ContextList);
1554 while(Context)
1556 ALvoice *voice, *voice_end;
1558 voice = Context->Voices;
1559 voice_end = voice + Context->VoiceCount;
1560 while(voice != voice_end)
1562 ALsource *source = voice->Source;
1563 voice->Source = NULL;
1565 if(source && source->state == AL_PLAYING)
1567 source->state = AL_STOPPED;
1568 ATOMIC_STORE(&source->current_buffer, NULL);
1569 source->position = 0;
1570 source->position_fraction = 0;
1573 voice++;
1575 Context->VoiceCount = 0;
1577 Context = Context->next;