Use 2-channel UHJ for stereo output
[openal-soft.git] / Alc / ALu.c
blob41d9a3fbe39277db9995df895521f64dd2e7b1c6
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 1999-2007 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alListener.h"
33 #include "alAuxEffectSlot.h"
34 #include "alu.h"
35 #include "bs2b.h"
36 #include "hrtf.h"
37 #include "uhjfilter.h"
38 #include "static_assert.h"
40 #include "mixer_defs.h"
42 #include "backends/base.h"
45 struct ChanMap {
46 enum Channel channel;
47 ALfloat angle;
48 ALfloat elevation;
51 /* Cone scalar */
52 ALfloat ConeScale = 1.0f;
54 /* Localized Z scalar for mono sources */
55 ALfloat ZScale = 1.0f;
57 extern inline ALfloat minf(ALfloat a, ALfloat b);
58 extern inline ALfloat maxf(ALfloat a, ALfloat b);
59 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
61 extern inline ALdouble mind(ALdouble a, ALdouble b);
62 extern inline ALdouble maxd(ALdouble a, ALdouble b);
63 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
65 extern inline ALuint minu(ALuint a, ALuint b);
66 extern inline ALuint maxu(ALuint a, ALuint b);
67 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
69 extern inline ALint mini(ALint a, ALint b);
70 extern inline ALint maxi(ALint a, ALint b);
71 extern inline ALint clampi(ALint val, ALint min, ALint max);
73 extern inline ALint64 mini64(ALint64 a, ALint64 b);
74 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
75 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
77 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
78 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
79 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
81 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
82 extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
83 extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac);
85 extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
87 extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
88 ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
89 extern inline void aluMatrixfSet(aluMatrixf *matrix,
90 ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
91 ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
92 ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
93 ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
95 extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
96 ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3);
97 extern inline void aluMatrixdSet(aluMatrixd *matrix,
98 ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
99 ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
100 ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
101 ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
104 /* NOTE: HRTF and UHJ are set up a bit special in the device. Normally the
105 * device's DryBuffer, NumChannels, ChannelName, and Channel fields correspond
106 * to the output format, and the DryBuffer is then converted and written to the
107 * backend's audio buffer.
109 * With HRTF or UHJ, these fields correspond to a virtual format, and the
110 * actual output is stored in DryBuffer[NumChannels] for the left channel and
111 * DryBuffer[NumChannels+1] for the right. As a final output step,
112 * the virtual channels will have HRTF filters or UHJ encoding applied and
113 * written to the actual output.
115 * Sources that get mixed using HRTF directly (or that want to skip HRTF or UHJ
116 * completely) will need to offset the output buffer so that they skip the
117 * virtual output and write to the actual output channels. This is the reason
118 * you'll see
120 * voice->Direct.OutBuffer += voice->Direct.OutChannels;
121 * voice->Direct.OutChannels = 2;
123 * at various points in the code where HRTF is explicitly used or bypassed.
126 static inline HrtfMixerFunc SelectHrtfMixer(void)
128 #ifdef HAVE_SSE
129 if((CPUCapFlags&CPU_CAP_SSE))
130 return MixHrtf_SSE;
131 #endif
132 #ifdef HAVE_NEON
133 if((CPUCapFlags&CPU_CAP_NEON))
134 return MixHrtf_Neon;
135 #endif
137 return MixHrtf_C;
141 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
143 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
144 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
145 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
148 static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2)
150 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
153 static inline ALfloat aluNormalize(ALfloat *vec)
155 ALfloat length = sqrtf(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
156 if(length > 0.0f)
158 ALfloat inv_length = 1.0f/length;
159 vec[0] *= inv_length;
160 vec[1] *= inv_length;
161 vec[2] *= inv_length;
163 return length;
167 static inline void aluCrossproductd(const ALdouble *inVector1, const ALdouble *inVector2, ALdouble *outVector)
169 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
170 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
171 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
174 static inline ALdouble aluNormalized(ALdouble *vec)
176 ALdouble length = sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
177 if(length > 0.0)
179 ALdouble inv_length = 1.0/length;
180 vec[0] *= inv_length;
181 vec[1] *= inv_length;
182 vec[2] *= inv_length;
184 return length;
187 static inline ALvoid aluMatrixdFloat3(ALfloat *vec, ALfloat w, const aluMatrixd *mtx)
189 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
191 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]);
192 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]);
193 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]);
196 static inline ALvoid aluMatrixdDouble3(ALdouble *vec, ALdouble w, const aluMatrixd *mtx)
198 ALdouble v[4] = { vec[0], vec[1], vec[2], w };
200 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];
201 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];
202 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];
205 static inline aluVector aluMatrixdVector(const aluMatrixd *mtx, const aluVector *vec)
207 aluVector v;
208 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]);
209 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]);
210 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]);
211 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]);
212 return v;
216 /* Prepares the interpolator for a given rate (determined by increment). A
217 * result of AL_FALSE indicates that the filter output will completely cut
218 * the input signal.
220 * With a bit of work, and a trade of memory for CPU cost, this could be
221 * modified for use with an interpolated increment for buttery-smooth pitch
222 * changes.
224 static ALboolean BsincPrepare(const ALuint increment, BsincState *state)
226 static const ALfloat scaleBase = 1.510578918e-01f, scaleRange = 1.177936623e+00f;
227 static const ALuint m[BSINC_SCALE_COUNT] = { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 };
228 static const ALuint to[4][BSINC_SCALE_COUNT] =
230 { 0, 24, 408, 792, 1176, 1560, 1944, 2328, 2648, 2968, 3288, 3544, 3800, 4056, 4248, 4440 },
231 { 4632, 5016, 5400, 5784, 6168, 6552, 6936, 7320, 7640, 7960, 8280, 8536, 8792, 9048, 9240, 0 },
232 { 0, 9432, 9816, 10200, 10584, 10968, 11352, 11736, 12056, 12376, 12696, 12952, 13208, 13464, 13656, 13848 },
233 { 14040, 14424, 14808, 15192, 15576, 15960, 16344, 16728, 17048, 17368, 17688, 17944, 18200, 18456, 18648, 0 }
235 static const ALuint tm[2][BSINC_SCALE_COUNT] =
237 { 0, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 12 },
238 { 24, 24, 24, 24, 24, 24, 24, 20, 20, 20, 16, 16, 16, 12, 12, 0 }
240 ALfloat sf;
241 ALuint si, pi;
242 ALboolean uncut = AL_TRUE;
244 if(increment > FRACTIONONE)
246 sf = (ALfloat)FRACTIONONE / increment;
247 if(sf < scaleBase)
249 /* Signal has been completely cut. The return result can be used
250 * to skip the filter (and output zeros) as an optimization.
252 sf = 0.0f;
253 si = 0;
254 uncut = AL_FALSE;
256 else
258 sf = (BSINC_SCALE_COUNT - 1) * (sf - scaleBase) * scaleRange;
259 si = fastf2u(sf);
260 /* The interpolation factor is fit to this diagonally-symmetric
261 * curve to reduce the transition ripple caused by interpolating
262 * different scales of the sinc function.
264 sf = 1.0f - cosf(asinf(sf - si));
267 else
269 sf = 0.0f;
270 si = BSINC_SCALE_COUNT - 1;
273 state->sf = sf;
274 state->m = m[si];
275 state->l = -(ALint)((m[si] / 2) - 1);
276 /* The CPU cost of this table re-mapping could be traded for the memory
277 * cost of a complete table map (1024 elements large).
279 for(pi = 0;pi < BSINC_PHASE_COUNT;pi++)
281 state->coeffs[pi].filter = &bsincTab[to[0][si] + tm[0][si]*pi];
282 state->coeffs[pi].scDelta = &bsincTab[to[1][si] + tm[1][si]*pi];
283 state->coeffs[pi].phDelta = &bsincTab[to[2][si] + tm[0][si]*pi];
284 state->coeffs[pi].spDelta = &bsincTab[to[3][si] + tm[1][si]*pi];
286 return uncut;
290 static ALvoid CalcListenerParams(ALlistener *Listener)
292 ALdouble N[3], V[3], U[3], P[3];
294 /* AT then UP */
295 N[0] = Listener->Forward[0];
296 N[1] = Listener->Forward[1];
297 N[2] = Listener->Forward[2];
298 aluNormalized(N);
299 V[0] = Listener->Up[0];
300 V[1] = Listener->Up[1];
301 V[2] = Listener->Up[2];
302 aluNormalized(V);
303 /* Build and normalize right-vector */
304 aluCrossproductd(N, V, U);
305 aluNormalized(U);
307 aluMatrixdSet(&Listener->Params.Matrix,
308 U[0], V[0], -N[0], 0.0,
309 U[1], V[1], -N[1], 0.0,
310 U[2], V[2], -N[2], 0.0,
311 0.0, 0.0, 0.0, 1.0
314 P[0] = Listener->Position.v[0];
315 P[1] = Listener->Position.v[1];
316 P[2] = Listener->Position.v[2];
317 aluMatrixdDouble3(P, 1.0, &Listener->Params.Matrix);
318 aluMatrixdSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
320 Listener->Params.Velocity = aluMatrixdVector(&Listener->Params.Matrix, &Listener->Velocity);
323 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
325 static const struct ChanMap MonoMap[1] = {
326 { FrontCenter, 0.0f, 0.0f }
327 }, StereoMap[2] = {
328 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
329 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
330 }, RearMap[2] = {
331 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
332 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
333 }, QuadMap[4] = {
334 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
335 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
336 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
337 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
338 }, X51Map[6] = {
339 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
340 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
341 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
342 { LFE, 0.0f, 0.0f },
343 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
344 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
345 }, X61Map[7] = {
346 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
347 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
348 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
349 { LFE, 0.0f, 0.0f },
350 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
351 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
352 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
353 }, X71Map[8] = {
354 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
355 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
356 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
357 { LFE, 0.0f, 0.0f },
358 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
359 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
360 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
361 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
364 const ALCdevice *Device = ALContext->Device;
365 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
366 ALbufferlistitem *BufferListItem;
367 enum FmtChannels Channels;
368 ALfloat DryGain, DryGainHF, DryGainLF;
369 ALfloat WetGain[MAX_SENDS];
370 ALfloat WetGainHF[MAX_SENDS];
371 ALfloat WetGainLF[MAX_SENDS];
372 ALeffectslot *SendSlots[MAX_SENDS];
373 ALuint NumSends, Frequency;
374 ALboolean Relative;
375 const struct ChanMap *chans = NULL;
376 ALuint num_channels = 0;
377 ALboolean DirectChannels;
378 ALboolean isbformat = AL_FALSE;
379 ALfloat Pitch;
380 ALuint i, j, c;
382 /* Get device properties */
383 NumSends = Device->NumAuxSends;
384 Frequency = Device->Frequency;
386 /* Get listener properties */
387 ListenerGain = ALContext->Listener->Gain;
389 /* Get source properties */
390 SourceVolume = ALSource->Gain;
391 MinVolume = ALSource->MinGain;
392 MaxVolume = ALSource->MaxGain;
393 Pitch = ALSource->Pitch;
394 Relative = ALSource->HeadRelative;
395 DirectChannels = ALSource->DirectChannels;
397 voice->Direct.OutBuffer = Device->DryBuffer;
398 voice->Direct.OutChannels = Device->NumChannels;
399 for(i = 0;i < NumSends;i++)
401 SendSlots[i] = ALSource->Send[i].Slot;
402 if(!SendSlots[i] && i == 0)
403 SendSlots[i] = Device->DefaultSlot;
404 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
406 SendSlots[i] = NULL;
407 voice->Send[i].OutBuffer = NULL;
408 voice->Send[i].OutChannels = 0;
410 else
412 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
413 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
417 /* Calculate the stepping value */
418 Channels = FmtMono;
419 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
420 while(BufferListItem != NULL)
422 ALbuffer *ALBuffer;
423 if((ALBuffer=BufferListItem->buffer) != NULL)
425 Pitch = Pitch * ALBuffer->Frequency / Frequency;
426 if(Pitch > (ALfloat)MAX_PITCH)
427 voice->Step = MAX_PITCH<<FRACTIONBITS;
428 else
429 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
430 BsincPrepare(voice->Step, &voice->SincState);
432 Channels = ALBuffer->FmtChannels;
433 break;
435 BufferListItem = BufferListItem->next;
438 /* Calculate gains */
439 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
440 DryGain *= ALSource->Direct.Gain * ListenerGain;
441 DryGainHF = ALSource->Direct.GainHF;
442 DryGainLF = ALSource->Direct.GainLF;
443 for(i = 0;i < NumSends;i++)
445 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
446 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
447 WetGainHF[i] = ALSource->Send[i].GainHF;
448 WetGainLF[i] = ALSource->Send[i].GainLF;
451 switch(Channels)
453 case FmtMono:
454 chans = MonoMap;
455 num_channels = 1;
456 break;
458 case FmtStereo:
459 chans = StereoMap;
460 num_channels = 2;
461 break;
463 case FmtRear:
464 chans = RearMap;
465 num_channels = 2;
466 break;
468 case FmtQuad:
469 chans = QuadMap;
470 num_channels = 4;
471 break;
473 case FmtX51:
474 chans = X51Map;
475 num_channels = 6;
476 break;
478 case FmtX61:
479 chans = X61Map;
480 num_channels = 7;
481 break;
483 case FmtX71:
484 chans = X71Map;
485 num_channels = 8;
486 break;
488 case FmtBFormat2D:
489 num_channels = 3;
490 isbformat = AL_TRUE;
491 DirectChannels = AL_FALSE;
492 break;
494 case FmtBFormat3D:
495 num_channels = 4;
496 isbformat = AL_TRUE;
497 DirectChannels = AL_FALSE;
498 break;
501 if(isbformat)
503 ALfloat N[3], V[3], U[3];
504 aluMatrixf matrix;
505 ALfloat scale;
507 /* AT then UP */
508 N[0] = ALSource->Orientation[0][0];
509 N[1] = ALSource->Orientation[0][1];
510 N[2] = ALSource->Orientation[0][2];
511 aluNormalize(N);
512 V[0] = ALSource->Orientation[1][0];
513 V[1] = ALSource->Orientation[1][1];
514 V[2] = ALSource->Orientation[1][2];
515 aluNormalize(V);
516 if(!Relative)
518 const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
519 aluMatrixdFloat3(N, 0.0f, lmatrix);
520 aluMatrixdFloat3(V, 0.0f, lmatrix);
522 /* Build and normalize right-vector */
523 aluCrossproduct(N, V, U);
524 aluNormalize(U);
526 /* Build a rotate + conversion matrix (B-Format -> N3D), and include
527 * scaling for first-order content on second- or third-order output.
529 scale = Device->AmbiScale * 1.732050808f;
530 aluMatrixfSet(&matrix,
531 1.414213562f, 0.0f, 0.0f, 0.0f,
532 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
533 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
534 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
537 for(c = 0;c < num_channels;c++)
538 ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain,
539 voice->Direct.Gains[c].Target);
541 /* Rebuild the matrix, without the second- or third-order output
542 * scaling (effects take first-order content, and will do the scaling
543 * themselves when mixing to the output).
545 scale = 1.732050808f;
546 aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale);
547 aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale);
548 aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale);
549 for(i = 0;i < NumSends;i++)
551 if(!SendSlots[i])
553 for(c = 0;c < num_channels;c++)
555 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
556 voice->Send[i].Gains[c].Target[j] = 0.0f;
559 else
561 for(c = 0;c < num_channels;c++)
563 const ALeffectslot *Slot = SendSlots[i];
564 ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c],
565 WetGain[i], voice->Send[i].Gains[c].Target);
570 voice->IsHrtf = AL_FALSE;
572 else
574 ALfloat coeffs[MAX_AMBI_COEFFS];
576 if(DirectChannels)
578 if(Device->Hrtf || Device->Uhj_Encoder)
580 /* DirectChannels with HRTF enabled. Skip the virtual channels
581 * and write FrontLeft and FrontRight inputs to the first and
582 * second outputs.
584 voice->Direct.OutBuffer += voice->Direct.OutChannels;
585 voice->Direct.OutChannels = 2;
586 for(c = 0;c < num_channels;c++)
588 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
589 voice->Direct.Gains[c].Target[j] = 0.0f;
591 if(chans[c].channel == FrontLeft)
592 voice->Direct.Gains[c].Target[0] = DryGain;
593 else if(chans[c].channel == FrontRight)
594 voice->Direct.Gains[c].Target[1] = DryGain;
597 else for(c = 0;c < num_channels;c++)
599 int idx;
600 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
601 voice->Direct.Gains[c].Target[j] = 0.0f;
602 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
603 voice->Direct.Gains[c].Target[idx] = DryGain;
606 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
607 * channel-match. */
608 for(c = 0;c < num_channels;c++)
610 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
612 for(i = 0;i < NumSends;i++)
614 if(!SendSlots[i])
616 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
617 voice->Send[i].Gains[c].Target[j] = 0.0f;
619 else
621 const ALeffectslot *Slot = SendSlots[i];
622 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
623 WetGain[i], voice->Send[i].Gains[c].Target);
628 voice->IsHrtf = AL_FALSE;
630 else if(Device->Hrtf_Mode == FullHrtf)
632 /* Full HRTF rendering. Skip the virtual channels and render each
633 * input channel to the real outputs.
635 voice->Direct.OutBuffer += voice->Direct.OutChannels;
636 voice->Direct.OutChannels = 2;
637 for(c = 0;c < num_channels;c++)
639 if(chans[c].channel == LFE)
641 /* Skip LFE */
642 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
643 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
644 for(i = 0;i < HRIR_LENGTH;i++)
646 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
647 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
650 for(i = 0;i < NumSends;i++)
652 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
653 voice->Send[i].Gains[c].Target[j] = 0.0f;
656 continue;
659 /* Get the static HRIR coefficients and delays for this channel. */
660 GetLerpedHrtfCoeffs(Device->Hrtf,
661 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
662 voice->Direct.Hrtf[c].Target.Coeffs,
663 voice->Direct.Hrtf[c].Target.Delay
666 /* Normal panning for auxiliary sends. */
667 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
669 for(i = 0;i < NumSends;i++)
671 if(!SendSlots[i])
673 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
674 voice->Send[i].Gains[c].Target[j] = 0.0f;
676 else
678 const ALeffectslot *Slot = SendSlots[i];
679 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
680 WetGain[i], voice->Send[i].Gains[c].Target);
685 voice->IsHrtf = AL_TRUE;
687 else
689 /* Basic or no HRTF rendering. Use normal panning to the output. */
690 for(c = 0;c < num_channels;c++)
692 /* Special-case LFE */
693 if(chans[c].channel == LFE)
695 int idx;
696 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
697 voice->Direct.Gains[c].Target[j] = 0.0f;
698 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
699 voice->Direct.Gains[c].Target[idx] = DryGain;
701 for(i = 0;i < NumSends;i++)
703 ALuint j;
704 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
705 voice->Send[i].Gains[c].Target[j] = 0.0f;
707 continue;
710 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
712 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, voice->Direct.Gains[c].Target);
714 for(i = 0;i < NumSends;i++)
716 if(!SendSlots[i])
718 ALuint j;
719 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
720 voice->Send[i].Gains[c].Target[j] = 0.0f;
722 else
724 const ALeffectslot *Slot = SendSlots[i];
725 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
726 WetGain[i], voice->Send[i].Gains[c].Target);
731 voice->IsHrtf = AL_FALSE;
736 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
737 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
738 DryGainHF = maxf(DryGainHF, 0.0001f);
739 DryGainLF = maxf(DryGainLF, 0.0001f);
740 for(c = 0;c < num_channels;c++)
742 voice->Direct.Filters[c].ActiveType = AF_None;
743 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
744 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
745 ALfilterState_setParams(
746 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
747 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
749 ALfilterState_setParams(
750 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
751 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
755 for(i = 0;i < NumSends;i++)
757 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
758 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
759 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
760 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
761 for(c = 0;c < num_channels;c++)
763 voice->Send[i].Filters[c].ActiveType = AF_None;
764 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
765 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
766 ALfilterState_setParams(
767 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
768 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
770 ALfilterState_setParams(
771 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
772 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
778 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
780 const ALCdevice *Device = ALContext->Device;
781 aluVector Position, Velocity, Direction, SourceToListener;
782 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
783 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
784 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
785 ALfloat DopplerFactor, SpeedOfSound;
786 ALfloat AirAbsorptionFactor;
787 ALfloat RoomAirAbsorption[MAX_SENDS];
788 ALbufferlistitem *BufferListItem;
789 ALeffectslot *SendSlots[MAX_SENDS];
790 ALfloat Attenuation;
791 ALfloat RoomAttenuation[MAX_SENDS];
792 ALfloat MetersPerUnit;
793 ALfloat RoomRolloffBase;
794 ALfloat RoomRolloff[MAX_SENDS];
795 ALfloat DecayDistance[MAX_SENDS];
796 ALfloat DryGain;
797 ALfloat DryGainHF;
798 ALfloat DryGainLF;
799 ALboolean DryGainHFAuto;
800 ALfloat WetGain[MAX_SENDS];
801 ALfloat WetGainHF[MAX_SENDS];
802 ALfloat WetGainLF[MAX_SENDS];
803 ALboolean WetGainAuto;
804 ALboolean WetGainHFAuto;
805 ALfloat Pitch;
806 ALuint Frequency;
807 ALint NumSends;
808 ALint i;
810 DryGainHF = 1.0f;
811 DryGainLF = 1.0f;
812 for(i = 0;i < MAX_SENDS;i++)
814 WetGainHF[i] = 1.0f;
815 WetGainLF[i] = 1.0f;
818 /* Get context/device properties */
819 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
820 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
821 NumSends = Device->NumAuxSends;
822 Frequency = Device->Frequency;
824 /* Get listener properties */
825 ListenerGain = ALContext->Listener->Gain;
826 MetersPerUnit = ALContext->Listener->MetersPerUnit;
828 /* Get source properties */
829 SourceVolume = ALSource->Gain;
830 MinVolume = ALSource->MinGain;
831 MaxVolume = ALSource->MaxGain;
832 Pitch = ALSource->Pitch;
833 Position = ALSource->Position;
834 Direction = ALSource->Direction;
835 Velocity = ALSource->Velocity;
836 MinDist = ALSource->RefDistance;
837 MaxDist = ALSource->MaxDistance;
838 Rolloff = ALSource->RollOffFactor;
839 InnerAngle = ALSource->InnerAngle;
840 OuterAngle = ALSource->OuterAngle;
841 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
842 DryGainHFAuto = ALSource->DryGainHFAuto;
843 WetGainAuto = ALSource->WetGainAuto;
844 WetGainHFAuto = ALSource->WetGainHFAuto;
845 RoomRolloffBase = ALSource->RoomRolloffFactor;
847 voice->Direct.OutBuffer = Device->DryBuffer;
848 voice->Direct.OutChannels = Device->NumChannels;
849 for(i = 0;i < NumSends;i++)
851 SendSlots[i] = ALSource->Send[i].Slot;
853 if(!SendSlots[i] && i == 0)
854 SendSlots[i] = Device->DefaultSlot;
855 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
857 SendSlots[i] = NULL;
858 RoomRolloff[i] = 0.0f;
859 DecayDistance[i] = 0.0f;
860 RoomAirAbsorption[i] = 1.0f;
862 else if(SendSlots[i]->AuxSendAuto)
864 RoomRolloff[i] = RoomRolloffBase;
865 if(IsReverbEffect(SendSlots[i]->EffectType))
867 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
868 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
869 SPEEDOFSOUNDMETRESPERSEC;
870 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
872 else
874 DecayDistance[i] = 0.0f;
875 RoomAirAbsorption[i] = 1.0f;
878 else
880 /* If the slot's auxiliary send auto is off, the data sent to the
881 * effect slot is the same as the dry path, sans filter effects */
882 RoomRolloff[i] = Rolloff;
883 DecayDistance[i] = 0.0f;
884 RoomAirAbsorption[i] = AIRABSORBGAINHF;
887 if(!SendSlots[i])
889 voice->Send[i].OutBuffer = NULL;
890 voice->Send[i].OutChannels = 0;
892 else
894 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
895 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
899 /* Transform source to listener space (convert to head relative) */
900 if(ALSource->HeadRelative == AL_FALSE)
902 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
903 /* Transform source vectors */
904 Position = aluMatrixdVector(Matrix, &Position);
905 Velocity = aluMatrixdVector(Matrix, &Velocity);
906 Direction = aluMatrixdVector(Matrix, &Direction);
908 else
910 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
911 /* Offset the source velocity to be relative of the listener velocity */
912 Velocity.v[0] += lvelocity->v[0];
913 Velocity.v[1] += lvelocity->v[1];
914 Velocity.v[2] += lvelocity->v[2];
917 aluNormalize(Direction.v);
918 SourceToListener.v[0] = -Position.v[0];
919 SourceToListener.v[1] = -Position.v[1];
920 SourceToListener.v[2] = -Position.v[2];
921 SourceToListener.v[3] = 0.0f;
922 Distance = aluNormalize(SourceToListener.v);
924 /* Calculate distance attenuation */
925 ClampedDist = Distance;
927 Attenuation = 1.0f;
928 for(i = 0;i < NumSends;i++)
929 RoomAttenuation[i] = 1.0f;
930 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
931 ALContext->DistanceModel)
933 case InverseDistanceClamped:
934 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
935 if(MaxDist < MinDist)
936 break;
937 /*fall-through*/
938 case InverseDistance:
939 if(MinDist > 0.0f)
941 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
942 if(dist > 0.0f) Attenuation = MinDist / dist;
943 for(i = 0;i < NumSends;i++)
945 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
946 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
949 break;
951 case LinearDistanceClamped:
952 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
953 if(MaxDist < MinDist)
954 break;
955 /*fall-through*/
956 case LinearDistance:
957 if(MaxDist != MinDist)
959 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
960 Attenuation = maxf(Attenuation, 0.0f);
961 for(i = 0;i < NumSends;i++)
963 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
964 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
967 break;
969 case ExponentDistanceClamped:
970 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
971 if(MaxDist < MinDist)
972 break;
973 /*fall-through*/
974 case ExponentDistance:
975 if(ClampedDist > 0.0f && MinDist > 0.0f)
977 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
978 for(i = 0;i < NumSends;i++)
979 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
981 break;
983 case DisableDistance:
984 ClampedDist = MinDist;
985 break;
988 /* Source Gain + Attenuation */
989 DryGain = SourceVolume * Attenuation;
990 for(i = 0;i < NumSends;i++)
991 WetGain[i] = SourceVolume * RoomAttenuation[i];
993 /* Distance-based air absorption */
994 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
996 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
997 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
998 for(i = 0;i < NumSends;i++)
999 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
1002 if(WetGainAuto)
1004 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
1006 /* Apply a decay-time transformation to the wet path, based on the
1007 * attenuation of the dry path.
1009 * Using the apparent distance, based on the distance attenuation, the
1010 * initial decay of the reverb effect is calculated and applied to the
1011 * wet path.
1013 for(i = 0;i < NumSends;i++)
1015 if(DecayDistance[i] > 0.0f)
1016 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1020 /* Calculate directional soundcones */
1021 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1022 if(Angle > InnerAngle && Angle <= OuterAngle)
1024 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1025 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1026 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1028 else if(Angle > OuterAngle)
1030 ConeVolume = ALSource->OuterGain;
1031 ConeHF = ALSource->OuterGainHF;
1033 else
1035 ConeVolume = 1.0f;
1036 ConeHF = 1.0f;
1039 DryGain *= ConeVolume;
1040 if(WetGainAuto)
1042 for(i = 0;i < NumSends;i++)
1043 WetGain[i] *= ConeVolume;
1045 if(DryGainHFAuto)
1046 DryGainHF *= ConeHF;
1047 if(WetGainHFAuto)
1049 for(i = 0;i < NumSends;i++)
1050 WetGainHF[i] *= ConeHF;
1053 /* Clamp to Min/Max Gain */
1054 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1055 for(i = 0;i < NumSends;i++)
1056 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1058 /* Apply gain and frequency filters */
1059 DryGain *= ALSource->Direct.Gain * ListenerGain;
1060 DryGainHF *= ALSource->Direct.GainHF;
1061 DryGainLF *= ALSource->Direct.GainLF;
1062 for(i = 0;i < NumSends;i++)
1064 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1065 WetGainHF[i] *= ALSource->Send[i].GainHF;
1066 WetGainLF[i] *= ALSource->Send[i].GainLF;
1069 /* Calculate velocity-based doppler effect */
1070 if(DopplerFactor > 0.0f)
1072 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1073 ALfloat VSS, VLS;
1075 if(SpeedOfSound < 1.0f)
1077 DopplerFactor *= 1.0f/SpeedOfSound;
1078 SpeedOfSound = 1.0f;
1081 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1082 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1084 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1085 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1088 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1089 while(BufferListItem != NULL)
1091 ALbuffer *ALBuffer;
1092 if((ALBuffer=BufferListItem->buffer) != NULL)
1094 /* Calculate fixed-point stepping value, based on the pitch, buffer
1095 * frequency, and output frequency. */
1096 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1097 if(Pitch > (ALfloat)MAX_PITCH)
1098 voice->Step = MAX_PITCH<<FRACTIONBITS;
1099 else
1100 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1101 BsincPrepare(voice->Step, &voice->SincState);
1103 break;
1105 BufferListItem = BufferListItem->next;
1108 if(Device->Hrtf_Mode == FullHrtf)
1110 /* Full HRTF rendering. Skip the virtual channels and render to the
1111 * real outputs.
1113 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1114 ALfloat ev = 0.0f, az = 0.0f;
1115 ALfloat radius = ALSource->Radius;
1116 ALfloat dirfact = 1.0f;
1117 ALfloat coeffs[MAX_AMBI_COEFFS];
1119 voice->Direct.OutBuffer += voice->Direct.OutChannels;
1120 voice->Direct.OutChannels = 2;
1122 if(Distance > FLT_EPSILON)
1124 dir.v[0] = -SourceToListener.v[0];
1125 dir.v[1] = -SourceToListener.v[1];
1126 dir.v[2] = -SourceToListener.v[2] * ZScale;
1128 /* Calculate elevation and azimuth only when the source is not at
1129 * the listener. This prevents +0 and -0 Z from producing
1130 * inconsistent panning. Also, clamp Y in case FP precision errors
1131 * cause it to land outside of -1..+1. */
1132 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1133 az = atan2f(dir.v[0], -dir.v[2]);
1135 if(radius > 0.0f)
1137 if(radius >= Distance)
1138 dirfact *= Distance / radius * 0.5f;
1139 else
1140 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1143 /* Get the HRIR coefficients and delays. */
1144 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1145 voice->Direct.Hrtf[0].Target.Coeffs,
1146 voice->Direct.Hrtf[0].Target.Delay);
1148 dir.v[0] *= dirfact;
1149 dir.v[1] *= dirfact;
1150 dir.v[2] *= dirfact;
1151 CalcDirectionCoeffs(dir.v, coeffs);
1153 for(i = 0;i < NumSends;i++)
1155 if(!SendSlots[i])
1157 ALuint j;
1158 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1159 voice->Send[i].Gains[0].Target[j] = 0.0f;
1161 else
1163 const ALeffectslot *Slot = SendSlots[i];
1164 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1165 WetGain[i], voice->Send[i].Gains[0].Target);
1169 voice->IsHrtf = AL_TRUE;
1171 else
1173 /* Basic or no HRTF rendering. Use normal panning to the output. */
1174 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1175 ALfloat radius = ALSource->Radius;
1176 ALfloat coeffs[MAX_AMBI_COEFFS];
1178 /* Get the localized direction, and compute panned gains. */
1179 if(Distance > FLT_EPSILON)
1181 dir[0] = -SourceToListener.v[0];
1182 dir[1] = -SourceToListener.v[1];
1183 dir[2] = -SourceToListener.v[2] * ZScale;
1185 if(radius > 0.0f)
1187 ALfloat dirfact;
1188 if(radius >= Distance)
1189 dirfact = Distance / radius * 0.5f;
1190 else
1191 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1192 dir[0] *= dirfact;
1193 dir[1] *= dirfact;
1194 dir[2] *= dirfact;
1196 CalcDirectionCoeffs(dir, coeffs);
1198 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain,
1199 voice->Direct.Gains[0].Target);
1201 for(i = 0;i < NumSends;i++)
1203 if(!SendSlots[i])
1205 ALuint j;
1206 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1207 voice->Send[i].Gains[0].Target[j] = 0.0f;
1209 else
1211 const ALeffectslot *Slot = SendSlots[i];
1212 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1213 WetGain[i], voice->Send[i].Gains[0].Target);
1217 voice->IsHrtf = AL_FALSE;
1221 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1222 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1223 DryGainHF = maxf(DryGainHF, 0.0001f);
1224 DryGainLF = maxf(DryGainLF, 0.0001f);
1225 voice->Direct.Filters[0].ActiveType = AF_None;
1226 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1227 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1228 ALfilterState_setParams(
1229 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1230 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1232 ALfilterState_setParams(
1233 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1234 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1237 for(i = 0;i < NumSends;i++)
1239 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1240 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1241 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1242 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1243 voice->Send[i].Filters[0].ActiveType = AF_None;
1244 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1245 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1246 ALfilterState_setParams(
1247 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1248 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1250 ALfilterState_setParams(
1251 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1252 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1258 void UpdateContextSources(ALCcontext *ctx)
1260 ALvoice *voice, *voice_end;
1261 ALsource *source;
1263 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1265 CalcListenerParams(ctx->Listener);
1267 voice = ctx->Voices;
1268 voice_end = voice + ctx->VoiceCount;
1269 for(;voice != voice_end;++voice)
1271 if(!(source=voice->Source)) continue;
1272 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1273 voice->Source = NULL;
1274 else
1276 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1277 voice->Update(voice, source, ctx);
1281 else
1283 voice = ctx->Voices;
1284 voice_end = voice + ctx->VoiceCount;
1285 for(;voice != voice_end;++voice)
1287 if(!(source=voice->Source)) continue;
1288 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1289 voice->Source = NULL;
1290 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1291 voice->Update(voice, source, ctx);
1297 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1298 * converts NaN to 0. */
1299 static inline ALfloat aluClampf(ALfloat val)
1301 if(fabsf(val) <= 1.0f) return val;
1302 return (ALfloat)((0.0f < val) - (val < 0.0f));
1305 static inline ALfloat aluF2F(ALfloat val)
1306 { return val; }
1308 static inline ALint aluF2I(ALfloat val)
1310 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1311 * integer range normalized floats can be safely converted to.
1313 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1315 static inline ALuint aluF2UI(ALfloat val)
1316 { return aluF2I(val)+2147483648u; }
1318 static inline ALshort aluF2S(ALfloat val)
1319 { return fastf2i(aluClampf(val)*32767.0f); }
1320 static inline ALushort aluF2US(ALfloat val)
1321 { return aluF2S(val)+32768; }
1323 static inline ALbyte aluF2B(ALfloat val)
1324 { return fastf2i(aluClampf(val)*127.0f); }
1325 static inline ALubyte aluF2UB(ALfloat val)
1326 { return aluF2B(val)+128; }
1328 #define DECL_TEMPLATE(T, func) \
1329 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1330 ALuint SamplesToDo, ALuint numchans) \
1332 ALuint i, j; \
1333 for(j = 0;j < numchans;j++) \
1335 const ALfloat *in = InBuffer[j]; \
1336 T *restrict out = (T*)OutBuffer + j; \
1337 for(i = 0;i < SamplesToDo;i++) \
1338 out[i*numchans] = func(in[i]); \
1342 DECL_TEMPLATE(ALfloat, aluF2F)
1343 DECL_TEMPLATE(ALuint, aluF2UI)
1344 DECL_TEMPLATE(ALint, aluF2I)
1345 DECL_TEMPLATE(ALushort, aluF2US)
1346 DECL_TEMPLATE(ALshort, aluF2S)
1347 DECL_TEMPLATE(ALubyte, aluF2UB)
1348 DECL_TEMPLATE(ALbyte, aluF2B)
1350 #undef DECL_TEMPLATE
1353 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1355 ALuint SamplesToDo;
1356 ALvoice *voice, *voice_end;
1357 ALeffectslot *slot;
1358 ALsource *source;
1359 ALCcontext *ctx;
1360 FPUCtl oldMode;
1361 ALuint i, c;
1363 SetMixerFPUMode(&oldMode);
1365 while(size > 0)
1367 ALfloat (*OutBuffer)[BUFFERSIZE];
1368 ALuint OutChannels;
1370 IncrementRef(&device->MixCount);
1372 OutBuffer = device->DryBuffer;
1373 OutChannels = device->NumChannels;
1375 SamplesToDo = minu(size, BUFFERSIZE);
1376 for(c = 0;c < OutChannels;c++)
1377 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1378 if(device->Hrtf || device->Uhj_Encoder)
1380 /* Set OutBuffer/OutChannels to correspond to the actual output
1381 * with HRTF. Make sure to clear them too. */
1382 OutBuffer += OutChannels;
1383 OutChannels = 2;
1384 for(c = 0;c < OutChannels;c++)
1385 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1388 V0(device->Backend,lock)();
1390 if((slot=device->DefaultSlot) != NULL)
1392 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1393 V(slot->EffectState,update)(device, slot);
1394 for(i = 0;i < slot->NumChannels;i++)
1395 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1398 ctx = ATOMIC_LOAD(&device->ContextList);
1399 while(ctx)
1401 if(!ctx->DeferUpdates)
1403 UpdateContextSources(ctx);
1404 #define UPDATE_SLOT(iter) do { \
1405 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1406 V((*iter)->EffectState,update)(device, *iter); \
1407 for(i = 0;i < (*iter)->NumChannels;i++) \
1408 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1409 } while(0)
1410 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1411 #undef UPDATE_SLOT
1413 else
1415 #define CLEAR_WET_BUFFER(iter) do { \
1416 for(i = 0;i < (*iter)->NumChannels;i++) \
1417 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1418 } while(0)
1419 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1420 #undef CLEAR_WET_BUFFER
1423 /* source processing */
1424 voice = ctx->Voices;
1425 voice_end = voice + ctx->VoiceCount;
1426 for(;voice != voice_end;++voice)
1428 source = voice->Source;
1429 if(source && source->state == AL_PLAYING)
1430 MixSource(voice, source, device, SamplesToDo);
1433 /* effect slot processing */
1434 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1435 for(i = 0;i < c;i++)
1437 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1438 ALeffectState *state = slot->EffectState;
1439 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1440 device->NumChannels);
1443 ctx = ctx->next;
1446 if(device->DefaultSlot != NULL)
1448 const ALeffectslot *slot = device->DefaultSlot;
1449 ALeffectState *state = slot->EffectState;
1450 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1451 device->NumChannels);
1454 /* Increment the clock time. Every second's worth of samples is
1455 * converted and added to clock base so that large sample counts don't
1456 * overflow during conversion. This also guarantees an exact, stable
1457 * conversion. */
1458 device->SamplesDone += SamplesToDo;
1459 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1460 device->SamplesDone %= device->Frequency;
1461 V0(device->Backend,unlock)();
1463 if(device->Hrtf)
1465 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1466 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1467 MixHrtfParams hrtfparams;
1468 memset(&hrtfparams, 0, sizeof(hrtfparams));
1469 for(c = 0;c < device->NumChannels;c++)
1471 hrtfparams.Current = &device->Hrtf_Params[c];
1472 hrtfparams.Target = &device->Hrtf_Params[c];
1473 HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
1474 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
1477 device->Hrtf_Offset += SamplesToDo;
1479 else
1481 if(device->Uhj_Encoder)
1483 /* Encode to stereo-compatible 2-channel UHJ output. */
1484 EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo);
1486 if(device->Bs2b)
1488 /* Apply binaural/crossfeed filter */
1489 for(i = 0;i < SamplesToDo;i++)
1491 float samples[2];
1492 samples[0] = OutBuffer[0][i];
1493 samples[1] = OutBuffer[1][i];
1494 bs2b_cross_feed(device->Bs2b, samples);
1495 OutBuffer[0][i] = samples[0];
1496 OutBuffer[1][i] = samples[1];
1501 if(buffer)
1503 #define WRITE(T, a, b, c, d) do { \
1504 Write_##T((a), (b), (c), (d)); \
1505 buffer = (T*)buffer + (c)*(d); \
1506 } while(0)
1507 switch(device->FmtType)
1509 case DevFmtByte:
1510 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1511 break;
1512 case DevFmtUByte:
1513 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1514 break;
1515 case DevFmtShort:
1516 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1517 break;
1518 case DevFmtUShort:
1519 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1520 break;
1521 case DevFmtInt:
1522 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1523 break;
1524 case DevFmtUInt:
1525 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1526 break;
1527 case DevFmtFloat:
1528 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1529 break;
1531 #undef WRITE
1534 size -= SamplesToDo;
1535 IncrementRef(&device->MixCount);
1538 RestoreFPUMode(&oldMode);
1542 ALvoid aluHandleDisconnect(ALCdevice *device)
1544 ALCcontext *Context;
1546 device->Connected = ALC_FALSE;
1548 Context = ATOMIC_LOAD(&device->ContextList);
1549 while(Context)
1551 ALvoice *voice, *voice_end;
1553 voice = Context->Voices;
1554 voice_end = voice + Context->VoiceCount;
1555 while(voice != voice_end)
1557 ALsource *source = voice->Source;
1558 voice->Source = NULL;
1560 if(source && source->state == AL_PLAYING)
1562 source->state = AL_STOPPED;
1563 ATOMIC_STORE(&source->current_buffer, NULL);
1564 source->position = 0;
1565 source->position_fraction = 0;
1568 voice++;
1570 Context->VoiceCount = 0;
1572 Context = Context->next;