Fix reverb with UHJ encoding
[openal-soft.git] / Alc / ALu.c
blob38a4ef715d29297bf2ad725ad1b43f129c8b4733
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 or UHJ enabled. Skip the virtual
581 * channels and write FrontLeft and FrontRight inputs to the
582 * first and 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->Render_Mode == HrtfRender)
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 /* Non-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 if(Device->Render_Mode == StereoPair)
712 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
713 ALfloat x = sinf(chans[c].angle) * cosf(chans[c].elevation);
714 coeffs[0] = clampf(-x, -0.5f, 0.5f) + 0.5;
715 voice->Direct.Gains[c].Target[0] = coeffs[0] * DryGain;
716 voice->Direct.Gains[c].Target[1] = (1.0f-coeffs[0]) * DryGain;
717 for(j = 2;j < MAX_OUTPUT_CHANNELS;j++)
718 voice->Direct.Gains[c].Target[j] = 0.0f;
720 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
722 else
724 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
725 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain,
726 voice->Direct.Gains[c].Target);
729 for(i = 0;i < NumSends;i++)
731 if(!SendSlots[i])
733 ALuint j;
734 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
735 voice->Send[i].Gains[c].Target[j] = 0.0f;
737 else
739 const ALeffectslot *Slot = SendSlots[i];
740 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
741 WetGain[i], voice->Send[i].Gains[c].Target);
746 voice->IsHrtf = AL_FALSE;
751 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
752 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
753 DryGainHF = maxf(DryGainHF, 0.0001f);
754 DryGainLF = maxf(DryGainLF, 0.0001f);
755 for(c = 0;c < num_channels;c++)
757 voice->Direct.Filters[c].ActiveType = AF_None;
758 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
759 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
760 ALfilterState_setParams(
761 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
762 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
764 ALfilterState_setParams(
765 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
766 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
770 for(i = 0;i < NumSends;i++)
772 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
773 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
774 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
775 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
776 for(c = 0;c < num_channels;c++)
778 voice->Send[i].Filters[c].ActiveType = AF_None;
779 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
780 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
781 ALfilterState_setParams(
782 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
783 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
785 ALfilterState_setParams(
786 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
787 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
793 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
795 const ALCdevice *Device = ALContext->Device;
796 aluVector Position, Velocity, Direction, SourceToListener;
797 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
798 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
799 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
800 ALfloat DopplerFactor, SpeedOfSound;
801 ALfloat AirAbsorptionFactor;
802 ALfloat RoomAirAbsorption[MAX_SENDS];
803 ALbufferlistitem *BufferListItem;
804 ALeffectslot *SendSlots[MAX_SENDS];
805 ALfloat Attenuation;
806 ALfloat RoomAttenuation[MAX_SENDS];
807 ALfloat MetersPerUnit;
808 ALfloat RoomRolloffBase;
809 ALfloat RoomRolloff[MAX_SENDS];
810 ALfloat DecayDistance[MAX_SENDS];
811 ALfloat DryGain;
812 ALfloat DryGainHF;
813 ALfloat DryGainLF;
814 ALboolean DryGainHFAuto;
815 ALfloat WetGain[MAX_SENDS];
816 ALfloat WetGainHF[MAX_SENDS];
817 ALfloat WetGainLF[MAX_SENDS];
818 ALboolean WetGainAuto;
819 ALboolean WetGainHFAuto;
820 ALfloat Pitch;
821 ALuint Frequency;
822 ALint NumSends;
823 ALint i;
825 DryGainHF = 1.0f;
826 DryGainLF = 1.0f;
827 for(i = 0;i < MAX_SENDS;i++)
829 WetGainHF[i] = 1.0f;
830 WetGainLF[i] = 1.0f;
833 /* Get context/device properties */
834 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
835 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
836 NumSends = Device->NumAuxSends;
837 Frequency = Device->Frequency;
839 /* Get listener properties */
840 ListenerGain = ALContext->Listener->Gain;
841 MetersPerUnit = ALContext->Listener->MetersPerUnit;
843 /* Get source properties */
844 SourceVolume = ALSource->Gain;
845 MinVolume = ALSource->MinGain;
846 MaxVolume = ALSource->MaxGain;
847 Pitch = ALSource->Pitch;
848 Position = ALSource->Position;
849 Direction = ALSource->Direction;
850 Velocity = ALSource->Velocity;
851 MinDist = ALSource->RefDistance;
852 MaxDist = ALSource->MaxDistance;
853 Rolloff = ALSource->RollOffFactor;
854 InnerAngle = ALSource->InnerAngle;
855 OuterAngle = ALSource->OuterAngle;
856 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
857 DryGainHFAuto = ALSource->DryGainHFAuto;
858 WetGainAuto = ALSource->WetGainAuto;
859 WetGainHFAuto = ALSource->WetGainHFAuto;
860 RoomRolloffBase = ALSource->RoomRolloffFactor;
862 voice->Direct.OutBuffer = Device->DryBuffer;
863 voice->Direct.OutChannels = Device->NumChannels;
864 for(i = 0;i < NumSends;i++)
866 SendSlots[i] = ALSource->Send[i].Slot;
868 if(!SendSlots[i] && i == 0)
869 SendSlots[i] = Device->DefaultSlot;
870 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
872 SendSlots[i] = NULL;
873 RoomRolloff[i] = 0.0f;
874 DecayDistance[i] = 0.0f;
875 RoomAirAbsorption[i] = 1.0f;
877 else if(SendSlots[i]->AuxSendAuto)
879 RoomRolloff[i] = RoomRolloffBase;
880 if(IsReverbEffect(SendSlots[i]->EffectType))
882 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
883 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
884 SPEEDOFSOUNDMETRESPERSEC;
885 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
887 else
889 DecayDistance[i] = 0.0f;
890 RoomAirAbsorption[i] = 1.0f;
893 else
895 /* If the slot's auxiliary send auto is off, the data sent to the
896 * effect slot is the same as the dry path, sans filter effects */
897 RoomRolloff[i] = Rolloff;
898 DecayDistance[i] = 0.0f;
899 RoomAirAbsorption[i] = AIRABSORBGAINHF;
902 if(!SendSlots[i])
904 voice->Send[i].OutBuffer = NULL;
905 voice->Send[i].OutChannels = 0;
907 else
909 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
910 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
914 /* Transform source to listener space (convert to head relative) */
915 if(ALSource->HeadRelative == AL_FALSE)
917 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
918 /* Transform source vectors */
919 Position = aluMatrixdVector(Matrix, &Position);
920 Velocity = aluMatrixdVector(Matrix, &Velocity);
921 Direction = aluMatrixdVector(Matrix, &Direction);
923 else
925 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
926 /* Offset the source velocity to be relative of the listener velocity */
927 Velocity.v[0] += lvelocity->v[0];
928 Velocity.v[1] += lvelocity->v[1];
929 Velocity.v[2] += lvelocity->v[2];
932 aluNormalize(Direction.v);
933 SourceToListener.v[0] = -Position.v[0];
934 SourceToListener.v[1] = -Position.v[1];
935 SourceToListener.v[2] = -Position.v[2];
936 SourceToListener.v[3] = 0.0f;
937 Distance = aluNormalize(SourceToListener.v);
939 /* Calculate distance attenuation */
940 ClampedDist = Distance;
942 Attenuation = 1.0f;
943 for(i = 0;i < NumSends;i++)
944 RoomAttenuation[i] = 1.0f;
945 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
946 ALContext->DistanceModel)
948 case InverseDistanceClamped:
949 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
950 if(MaxDist < MinDist)
951 break;
952 /*fall-through*/
953 case InverseDistance:
954 if(MinDist > 0.0f)
956 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
957 if(dist > 0.0f) Attenuation = MinDist / dist;
958 for(i = 0;i < NumSends;i++)
960 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
961 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
964 break;
966 case LinearDistanceClamped:
967 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
968 if(MaxDist < MinDist)
969 break;
970 /*fall-through*/
971 case LinearDistance:
972 if(MaxDist != MinDist)
974 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
975 Attenuation = maxf(Attenuation, 0.0f);
976 for(i = 0;i < NumSends;i++)
978 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
979 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
982 break;
984 case ExponentDistanceClamped:
985 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
986 if(MaxDist < MinDist)
987 break;
988 /*fall-through*/
989 case ExponentDistance:
990 if(ClampedDist > 0.0f && MinDist > 0.0f)
992 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
993 for(i = 0;i < NumSends;i++)
994 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
996 break;
998 case DisableDistance:
999 ClampedDist = MinDist;
1000 break;
1003 /* Source Gain + Attenuation */
1004 DryGain = SourceVolume * Attenuation;
1005 for(i = 0;i < NumSends;i++)
1006 WetGain[i] = SourceVolume * RoomAttenuation[i];
1008 /* Distance-based air absorption */
1009 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
1011 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
1012 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
1013 for(i = 0;i < NumSends;i++)
1014 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
1017 if(WetGainAuto)
1019 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
1021 /* Apply a decay-time transformation to the wet path, based on the
1022 * attenuation of the dry path.
1024 * Using the apparent distance, based on the distance attenuation, the
1025 * initial decay of the reverb effect is calculated and applied to the
1026 * wet path.
1028 for(i = 0;i < NumSends;i++)
1030 if(DecayDistance[i] > 0.0f)
1031 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1035 /* Calculate directional soundcones */
1036 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1037 if(Angle > InnerAngle && Angle <= OuterAngle)
1039 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1040 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1041 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1043 else if(Angle > OuterAngle)
1045 ConeVolume = ALSource->OuterGain;
1046 ConeHF = ALSource->OuterGainHF;
1048 else
1050 ConeVolume = 1.0f;
1051 ConeHF = 1.0f;
1054 DryGain *= ConeVolume;
1055 if(WetGainAuto)
1057 for(i = 0;i < NumSends;i++)
1058 WetGain[i] *= ConeVolume;
1060 if(DryGainHFAuto)
1061 DryGainHF *= ConeHF;
1062 if(WetGainHFAuto)
1064 for(i = 0;i < NumSends;i++)
1065 WetGainHF[i] *= ConeHF;
1068 /* Clamp to Min/Max Gain */
1069 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1070 for(i = 0;i < NumSends;i++)
1071 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1073 /* Apply gain and frequency filters */
1074 DryGain *= ALSource->Direct.Gain * ListenerGain;
1075 DryGainHF *= ALSource->Direct.GainHF;
1076 DryGainLF *= ALSource->Direct.GainLF;
1077 for(i = 0;i < NumSends;i++)
1079 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1080 WetGainHF[i] *= ALSource->Send[i].GainHF;
1081 WetGainLF[i] *= ALSource->Send[i].GainLF;
1084 /* Calculate velocity-based doppler effect */
1085 if(DopplerFactor > 0.0f)
1087 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1088 ALfloat VSS, VLS;
1090 if(SpeedOfSound < 1.0f)
1092 DopplerFactor *= 1.0f/SpeedOfSound;
1093 SpeedOfSound = 1.0f;
1096 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1097 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1099 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1100 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1103 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1104 while(BufferListItem != NULL)
1106 ALbuffer *ALBuffer;
1107 if((ALBuffer=BufferListItem->buffer) != NULL)
1109 /* Calculate fixed-point stepping value, based on the pitch, buffer
1110 * frequency, and output frequency. */
1111 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1112 if(Pitch > (ALfloat)MAX_PITCH)
1113 voice->Step = MAX_PITCH<<FRACTIONBITS;
1114 else
1115 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1116 BsincPrepare(voice->Step, &voice->SincState);
1118 break;
1120 BufferListItem = BufferListItem->next;
1123 if(Device->Render_Mode == HrtfRender)
1125 /* Full HRTF rendering. Skip the virtual channels and render to the
1126 * real outputs.
1128 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1129 ALfloat ev = 0.0f, az = 0.0f;
1130 ALfloat radius = ALSource->Radius;
1131 ALfloat dirfact = 1.0f;
1132 ALfloat coeffs[MAX_AMBI_COEFFS];
1134 voice->Direct.OutBuffer += voice->Direct.OutChannels;
1135 voice->Direct.OutChannels = 2;
1137 if(Distance > FLT_EPSILON)
1139 dir.v[0] = -SourceToListener.v[0];
1140 dir.v[1] = -SourceToListener.v[1];
1141 dir.v[2] = -SourceToListener.v[2] * ZScale;
1143 /* Calculate elevation and azimuth only when the source is not at
1144 * the listener. This prevents +0 and -0 Z from producing
1145 * inconsistent panning. Also, clamp Y in case FP precision errors
1146 * cause it to land outside of -1..+1. */
1147 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1148 az = atan2f(dir.v[0], -dir.v[2]);
1150 if(radius > 0.0f)
1152 if(radius >= Distance)
1153 dirfact *= Distance / radius * 0.5f;
1154 else
1155 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1158 /* Get the HRIR coefficients and delays. */
1159 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1160 voice->Direct.Hrtf[0].Target.Coeffs,
1161 voice->Direct.Hrtf[0].Target.Delay);
1163 dir.v[0] *= dirfact;
1164 dir.v[1] *= dirfact;
1165 dir.v[2] *= dirfact;
1166 CalcDirectionCoeffs(dir.v, coeffs);
1168 for(i = 0;i < NumSends;i++)
1170 if(!SendSlots[i])
1172 ALuint j;
1173 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1174 voice->Send[i].Gains[0].Target[j] = 0.0f;
1176 else
1178 const ALeffectslot *Slot = SendSlots[i];
1179 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1180 WetGain[i], voice->Send[i].Gains[0].Target);
1184 voice->IsHrtf = AL_TRUE;
1186 else
1188 /* Non-HRTF rendering. */
1189 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1190 ALfloat radius = ALSource->Radius;
1191 ALfloat coeffs[MAX_AMBI_COEFFS];
1193 /* Get the localized direction, and compute panned gains. */
1194 if(Distance > FLT_EPSILON)
1196 dir[0] = -SourceToListener.v[0];
1197 dir[1] = -SourceToListener.v[1];
1198 dir[2] = -SourceToListener.v[2] * ZScale;
1200 if(radius > 0.0f)
1202 ALfloat dirfact;
1203 if(radius >= Distance)
1204 dirfact = Distance / radius * 0.5f;
1205 else
1206 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1207 dir[0] *= dirfact;
1208 dir[1] *= dirfact;
1209 dir[2] *= dirfact;
1212 if(Device->Render_Mode == StereoPair)
1214 /* Clamp X so it remains within 30 degrees of 0 or 180 degree azimuth. */
1215 coeffs[0] = clampf(-dir[0], -0.5f, 0.5f) + 0.5;
1216 voice->Direct.Gains[0].Target[0] = coeffs[0] * DryGain;
1217 voice->Direct.Gains[0].Target[1] = (1.0f-coeffs[0]) * DryGain;
1218 for(i = 2;i < MAX_OUTPUT_CHANNELS;i++)
1219 voice->Direct.Gains[0].Target[i] = 0.0f;
1221 CalcDirectionCoeffs(dir, coeffs);
1223 else
1225 CalcDirectionCoeffs(dir, coeffs);
1226 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain,
1227 voice->Direct.Gains[0].Target);
1230 for(i = 0;i < NumSends;i++)
1232 if(!SendSlots[i])
1234 ALuint j;
1235 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1236 voice->Send[i].Gains[0].Target[j] = 0.0f;
1238 else
1240 const ALeffectslot *Slot = SendSlots[i];
1241 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1242 WetGain[i], voice->Send[i].Gains[0].Target);
1246 voice->IsHrtf = AL_FALSE;
1250 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1251 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1252 DryGainHF = maxf(DryGainHF, 0.0001f);
1253 DryGainLF = maxf(DryGainLF, 0.0001f);
1254 voice->Direct.Filters[0].ActiveType = AF_None;
1255 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1256 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1257 ALfilterState_setParams(
1258 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1259 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1261 ALfilterState_setParams(
1262 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1263 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1266 for(i = 0;i < NumSends;i++)
1268 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1269 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1270 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1271 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1272 voice->Send[i].Filters[0].ActiveType = AF_None;
1273 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1274 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1275 ALfilterState_setParams(
1276 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1277 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1279 ALfilterState_setParams(
1280 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1281 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1287 void UpdateContextSources(ALCcontext *ctx)
1289 ALvoice *voice, *voice_end;
1290 ALsource *source;
1292 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1294 CalcListenerParams(ctx->Listener);
1296 voice = ctx->Voices;
1297 voice_end = voice + ctx->VoiceCount;
1298 for(;voice != voice_end;++voice)
1300 if(!(source=voice->Source)) continue;
1301 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1302 voice->Source = NULL;
1303 else
1305 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1306 voice->Update(voice, source, ctx);
1310 else
1312 voice = ctx->Voices;
1313 voice_end = voice + ctx->VoiceCount;
1314 for(;voice != voice_end;++voice)
1316 if(!(source=voice->Source)) continue;
1317 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1318 voice->Source = NULL;
1319 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1320 voice->Update(voice, source, ctx);
1326 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1327 * converts NaN to 0. */
1328 static inline ALfloat aluClampf(ALfloat val)
1330 if(fabsf(val) <= 1.0f) return val;
1331 return (ALfloat)((0.0f < val) - (val < 0.0f));
1334 static inline ALfloat aluF2F(ALfloat val)
1335 { return val; }
1337 static inline ALint aluF2I(ALfloat val)
1339 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1340 * integer range normalized floats can be safely converted to.
1342 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1344 static inline ALuint aluF2UI(ALfloat val)
1345 { return aluF2I(val)+2147483648u; }
1347 static inline ALshort aluF2S(ALfloat val)
1348 { return fastf2i(aluClampf(val)*32767.0f); }
1349 static inline ALushort aluF2US(ALfloat val)
1350 { return aluF2S(val)+32768; }
1352 static inline ALbyte aluF2B(ALfloat val)
1353 { return fastf2i(aluClampf(val)*127.0f); }
1354 static inline ALubyte aluF2UB(ALfloat val)
1355 { return aluF2B(val)+128; }
1357 #define DECL_TEMPLATE(T, func) \
1358 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1359 ALuint SamplesToDo, ALuint numchans) \
1361 ALuint i, j; \
1362 for(j = 0;j < numchans;j++) \
1364 const ALfloat *in = InBuffer[j]; \
1365 T *restrict out = (T*)OutBuffer + j; \
1366 for(i = 0;i < SamplesToDo;i++) \
1367 out[i*numchans] = func(in[i]); \
1371 DECL_TEMPLATE(ALfloat, aluF2F)
1372 DECL_TEMPLATE(ALuint, aluF2UI)
1373 DECL_TEMPLATE(ALint, aluF2I)
1374 DECL_TEMPLATE(ALushort, aluF2US)
1375 DECL_TEMPLATE(ALshort, aluF2S)
1376 DECL_TEMPLATE(ALubyte, aluF2UB)
1377 DECL_TEMPLATE(ALbyte, aluF2B)
1379 #undef DECL_TEMPLATE
1382 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1384 ALuint SamplesToDo;
1385 ALvoice *voice, *voice_end;
1386 ALeffectslot *slot;
1387 ALsource *source;
1388 ALCcontext *ctx;
1389 FPUCtl oldMode;
1390 ALuint i, c;
1392 SetMixerFPUMode(&oldMode);
1394 while(size > 0)
1396 ALfloat (*OutBuffer)[BUFFERSIZE];
1397 ALuint OutChannels;
1399 IncrementRef(&device->MixCount);
1401 OutBuffer = device->DryBuffer;
1402 OutChannels = device->NumChannels;
1404 SamplesToDo = minu(size, BUFFERSIZE);
1405 for(c = 0;c < OutChannels;c++)
1406 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1407 if(device->Hrtf || device->Uhj_Encoder)
1409 /* Set OutBuffer/OutChannels to correspond to the actual output
1410 * with HRTF. Make sure to clear them too. */
1411 OutBuffer += OutChannels;
1412 OutChannels = 2;
1413 for(c = 0;c < OutChannels;c++)
1414 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1417 V0(device->Backend,lock)();
1419 if((slot=device->DefaultSlot) != NULL)
1421 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1422 V(slot->EffectState,update)(device, slot);
1423 for(i = 0;i < slot->NumChannels;i++)
1424 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1427 ctx = ATOMIC_LOAD(&device->ContextList);
1428 while(ctx)
1430 if(!ctx->DeferUpdates)
1432 UpdateContextSources(ctx);
1433 #define UPDATE_SLOT(iter) do { \
1434 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1435 V((*iter)->EffectState,update)(device, *iter); \
1436 for(i = 0;i < (*iter)->NumChannels;i++) \
1437 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1438 } while(0)
1439 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, UPDATE_SLOT);
1440 #undef UPDATE_SLOT
1442 else
1444 #define CLEAR_WET_BUFFER(iter) do { \
1445 for(i = 0;i < (*iter)->NumChannels;i++) \
1446 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1447 } while(0)
1448 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1449 #undef CLEAR_WET_BUFFER
1452 /* source processing */
1453 voice = ctx->Voices;
1454 voice_end = voice + ctx->VoiceCount;
1455 for(;voice != voice_end;++voice)
1457 source = voice->Source;
1458 if(source && source->state == AL_PLAYING)
1459 MixSource(voice, source, device, SamplesToDo);
1462 /* effect slot processing */
1463 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1464 for(i = 0;i < c;i++)
1466 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1467 ALeffectState *state = slot->EffectState;
1468 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1469 device->NumChannels);
1472 ctx = ctx->next;
1475 if(device->DefaultSlot != NULL)
1477 const ALeffectslot *slot = device->DefaultSlot;
1478 ALeffectState *state = slot->EffectState;
1479 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1480 device->NumChannels);
1483 /* Increment the clock time. Every second's worth of samples is
1484 * converted and added to clock base so that large sample counts don't
1485 * overflow during conversion. This also guarantees an exact, stable
1486 * conversion. */
1487 device->SamplesDone += SamplesToDo;
1488 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1489 device->SamplesDone %= device->Frequency;
1490 V0(device->Backend,unlock)();
1492 if(device->Hrtf)
1494 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1495 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1496 MixHrtfParams hrtfparams;
1497 memset(&hrtfparams, 0, sizeof(hrtfparams));
1498 for(c = 0;c < device->NumChannels;c++)
1500 hrtfparams.Current = &device->Hrtf_Params[c];
1501 hrtfparams.Target = &device->Hrtf_Params[c];
1502 HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
1503 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
1506 device->Hrtf_Offset += SamplesToDo;
1508 else
1510 if(device->Uhj_Encoder)
1512 /* Encode to stereo-compatible 2-channel UHJ output. */
1513 EncodeUhj2(device->Uhj_Encoder, OutBuffer, device->DryBuffer, SamplesToDo);
1515 if(device->Bs2b)
1517 /* Apply binaural/crossfeed filter */
1518 for(i = 0;i < SamplesToDo;i++)
1520 float samples[2];
1521 samples[0] = OutBuffer[0][i];
1522 samples[1] = OutBuffer[1][i];
1523 bs2b_cross_feed(device->Bs2b, samples);
1524 OutBuffer[0][i] = samples[0];
1525 OutBuffer[1][i] = samples[1];
1530 if(buffer)
1532 #define WRITE(T, a, b, c, d) do { \
1533 Write_##T((a), (b), (c), (d)); \
1534 buffer = (T*)buffer + (c)*(d); \
1535 } while(0)
1536 switch(device->FmtType)
1538 case DevFmtByte:
1539 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1540 break;
1541 case DevFmtUByte:
1542 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1543 break;
1544 case DevFmtShort:
1545 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1546 break;
1547 case DevFmtUShort:
1548 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1549 break;
1550 case DevFmtInt:
1551 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1552 break;
1553 case DevFmtUInt:
1554 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1555 break;
1556 case DevFmtFloat:
1557 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1558 break;
1560 #undef WRITE
1563 size -= SamplesToDo;
1564 IncrementRef(&device->MixCount);
1567 RestoreFPUMode(&oldMode);
1571 ALvoid aluHandleDisconnect(ALCdevice *device)
1573 ALCcontext *Context;
1575 device->Connected = ALC_FALSE;
1577 Context = ATOMIC_LOAD(&device->ContextList);
1578 while(Context)
1580 ALvoice *voice, *voice_end;
1582 voice = Context->Voices;
1583 voice_end = voice + Context->VoiceCount;
1584 while(voice != voice_end)
1586 ALsource *source = voice->Source;
1587 voice->Source = NULL;
1589 if(source && source->state == AL_PLAYING)
1591 source->state = AL_STOPPED;
1592 ATOMIC_STORE(&source->current_buffer, NULL);
1593 source->position = 0;
1594 source->position_fraction = 0;
1597 voice++;
1599 Context->VoiceCount = 0;
1601 Context = Context->next;