Use an 8-channel cube for HRTF's virtual format.
[openal-soft.git] / Alc / ALu.c
blobd4dac1ab0ce48c0ca86c8aa61d4cc02c8ea89ba2
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 "static_assert.h"
39 #include "mixer_defs.h"
41 #include "backends/base.h"
44 struct ChanMap {
45 enum Channel channel;
46 ALfloat angle;
47 ALfloat elevation;
50 /* Cone scalar */
51 ALfloat ConeScale = 1.0f;
53 /* Localized Z scalar for mono sources */
54 ALfloat ZScale = 1.0f;
56 extern inline ALfloat minf(ALfloat a, ALfloat b);
57 extern inline ALfloat maxf(ALfloat a, ALfloat b);
58 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
60 extern inline ALdouble mind(ALdouble a, ALdouble b);
61 extern inline ALdouble maxd(ALdouble a, ALdouble b);
62 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
64 extern inline ALuint minu(ALuint a, ALuint b);
65 extern inline ALuint maxu(ALuint a, ALuint b);
66 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
68 extern inline ALint mini(ALint a, ALint b);
69 extern inline ALint maxi(ALint a, ALint b);
70 extern inline ALint clampi(ALint val, ALint min, ALint max);
72 extern inline ALint64 mini64(ALint64 a, ALint64 b);
73 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
74 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
76 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
77 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
78 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
80 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
81 extern inline ALfloat resample_fir4(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
82 extern inline ALfloat resample_fir8(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat val4, ALfloat val5, ALfloat val6, ALfloat val7, ALuint frac);
84 extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
86 extern inline void aluMatrixfSetRow(aluMatrixf *matrix, ALuint row,
87 ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
88 extern inline void aluMatrixfSet(aluMatrixf *matrix,
89 ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
90 ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
91 ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
92 ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
94 extern inline void aluMatrixdSetRow(aluMatrixd *matrix, ALuint row,
95 ALdouble m0, ALdouble m1, ALdouble m2, ALdouble m3);
96 extern inline void aluMatrixdSet(aluMatrixd *matrix,
97 ALdouble m00, ALdouble m01, ALdouble m02, ALdouble m03,
98 ALdouble m10, ALdouble m11, ALdouble m12, ALdouble m13,
99 ALdouble m20, ALdouble m21, ALdouble m22, ALdouble m23,
100 ALdouble m30, ALdouble m31, ALdouble m32, ALdouble m33);
103 /* NOTE: HRTF is set up a bit special in the device. By default, without HRTF,
104 * the device's DryBuffer, NumChannels, ChannelName, and Channel fields
105 * correspond to the output format, and the DryBuffer is then converted and
106 * written to the backend's audio buffer.
108 * With HRTF, these fields correspond to a virtual format, and the actual
109 * output is stored in DryBuffer[NumChannels] for the left channel and
110 * DryBuffer[NumChannels+1] for the right. As a final output step,
111 * the virtual channels will have HRTF applied and written to the actual
112 * output. Things like effects and B-Format decoding will want to write to the
113 * virtual channels so that they can be mixed with HRTF in full 3D.
115 * Sources that get mixed using HRTF directly (or that want to skip HRTF
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 }, StereoWideMap[2] = {
331 { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
332 { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
333 }, RearMap[2] = {
334 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
335 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
336 }, QuadMap[4] = {
337 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
338 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
339 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
340 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
341 }, X51Map[6] = {
342 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
343 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
344 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
345 { LFE, 0.0f, 0.0f },
346 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
347 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
348 }, X61Map[7] = {
349 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
350 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
351 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
352 { LFE, 0.0f, 0.0f },
353 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
354 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
355 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
356 }, X71Map[8] = {
357 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
358 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
359 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
360 { LFE, 0.0f, 0.0f },
361 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
362 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
363 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
364 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
367 const ALCdevice *Device = ALContext->Device;
368 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
369 ALbufferlistitem *BufferListItem;
370 enum FmtChannels Channels;
371 ALfloat DryGain, DryGainHF, DryGainLF;
372 ALfloat WetGain[MAX_SENDS];
373 ALfloat WetGainHF[MAX_SENDS];
374 ALfloat WetGainLF[MAX_SENDS];
375 ALeffectslot *SendSlots[MAX_SENDS];
376 ALuint NumSends, Frequency;
377 ALboolean Relative;
378 const struct ChanMap *chans = NULL;
379 ALuint num_channels = 0;
380 ALboolean DirectChannels;
381 ALboolean isbformat = AL_FALSE;
382 ALfloat Pitch;
383 ALuint i, j, c;
385 /* Get device properties */
386 NumSends = Device->NumAuxSends;
387 Frequency = Device->Frequency;
389 /* Get listener properties */
390 ListenerGain = ALContext->Listener->Gain;
392 /* Get source properties */
393 SourceVolume = ALSource->Gain;
394 MinVolume = ALSource->MinGain;
395 MaxVolume = ALSource->MaxGain;
396 Pitch = ALSource->Pitch;
397 Relative = ALSource->HeadRelative;
398 DirectChannels = ALSource->DirectChannels;
400 voice->Direct.OutBuffer = Device->DryBuffer;
401 voice->Direct.OutChannels = Device->NumChannels;
402 for(i = 0;i < NumSends;i++)
404 SendSlots[i] = ALSource->Send[i].Slot;
405 if(!SendSlots[i] && i == 0)
406 SendSlots[i] = Device->DefaultSlot;
407 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
409 SendSlots[i] = NULL;
410 voice->Send[i].OutBuffer = NULL;
411 voice->Send[i].OutChannels = 0;
413 else
415 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
416 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
420 /* Calculate the stepping value */
421 Channels = FmtMono;
422 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
423 while(BufferListItem != NULL)
425 ALbuffer *ALBuffer;
426 if((ALBuffer=BufferListItem->buffer) != NULL)
428 Pitch = Pitch * ALBuffer->Frequency / Frequency;
429 if(Pitch > (ALfloat)MAX_PITCH)
430 voice->Step = MAX_PITCH<<FRACTIONBITS;
431 else
432 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
433 BsincPrepare(voice->Step, &voice->SincState);
435 Channels = ALBuffer->FmtChannels;
436 break;
438 BufferListItem = BufferListItem->next;
441 /* Calculate gains */
442 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
443 DryGain *= ALSource->Direct.Gain * ListenerGain;
444 DryGainHF = ALSource->Direct.GainHF;
445 DryGainLF = ALSource->Direct.GainLF;
446 for(i = 0;i < NumSends;i++)
448 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
449 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
450 WetGainHF[i] = ALSource->Send[i].GainHF;
451 WetGainLF[i] = ALSource->Send[i].GainLF;
454 switch(Channels)
456 case FmtMono:
457 chans = MonoMap;
458 num_channels = 1;
459 break;
461 case FmtStereo:
462 /* HACK: Place the stereo channels at +/-90 degrees when using non-
463 * HRTF stereo output. This helps reduce the "monoization" caused
464 * by them panning towards the center. */
465 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
466 chans = StereoWideMap;
467 else
468 chans = StereoMap;
469 num_channels = 2;
470 break;
472 case FmtRear:
473 chans = RearMap;
474 num_channels = 2;
475 break;
477 case FmtQuad:
478 chans = QuadMap;
479 num_channels = 4;
480 break;
482 case FmtX51:
483 chans = X51Map;
484 num_channels = 6;
485 break;
487 case FmtX61:
488 chans = X61Map;
489 num_channels = 7;
490 break;
492 case FmtX71:
493 chans = X71Map;
494 num_channels = 8;
495 break;
497 case FmtBFormat2D:
498 num_channels = 3;
499 isbformat = AL_TRUE;
500 DirectChannels = AL_FALSE;
501 break;
503 case FmtBFormat3D:
504 num_channels = 4;
505 isbformat = AL_TRUE;
506 DirectChannels = AL_FALSE;
507 break;
510 if(isbformat)
512 ALfloat N[3], V[3], U[3];
513 aluMatrixf matrix;
514 ALfloat scale;
516 /* AT then UP */
517 N[0] = ALSource->Orientation[0][0];
518 N[1] = ALSource->Orientation[0][1];
519 N[2] = ALSource->Orientation[0][2];
520 aluNormalize(N);
521 V[0] = ALSource->Orientation[1][0];
522 V[1] = ALSource->Orientation[1][1];
523 V[2] = ALSource->Orientation[1][2];
524 aluNormalize(V);
525 if(!Relative)
527 const aluMatrixd *lmatrix = &ALContext->Listener->Params.Matrix;
528 aluMatrixdFloat3(N, 0.0f, lmatrix);
529 aluMatrixdFloat3(V, 0.0f, lmatrix);
531 /* Build and normalize right-vector */
532 aluCrossproduct(N, V, U);
533 aluNormalize(U);
535 /* Build a rotate + conversion matrix (B-Format -> N3D), and include
536 * scaling for first-order content on second- or third-order output.
538 scale = Device->AmbiScale * 1.732050808f;
539 aluMatrixfSet(&matrix,
540 1.414213562f, 0.0f, 0.0f, 0.0f,
541 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale,
542 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale,
543 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale
546 for(c = 0;c < num_channels;c++)
547 ComputeFirstOrderGains(Device->AmbiCoeffs, Device->NumChannels, matrix.m[c], DryGain,
548 voice->Direct.Gains[c].Target);
550 /* Rebuild the matrix, without the second- or third-order output
551 * scaling (effects take first-order content, and will do the scaling
552 * themselves when mixing to the output).
554 scale = 1.732050808f;
555 aluMatrixfSetRow(&matrix, 1, 0.0f, -N[0]*scale, N[1]*scale, -N[2]*scale);
556 aluMatrixfSetRow(&matrix, 2, 0.0f, U[0]*scale, -U[1]*scale, U[2]*scale);
557 aluMatrixfSetRow(&matrix, 3, 0.0f, -V[0]*scale, V[1]*scale, -V[2]*scale);
558 for(i = 0;i < NumSends;i++)
560 if(!SendSlots[i])
562 for(c = 0;c < num_channels;c++)
564 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
565 voice->Send[i].Gains[c].Target[j] = 0.0f;
568 else
570 for(c = 0;c < num_channels;c++)
572 const ALeffectslot *Slot = SendSlots[i];
573 ComputeFirstOrderGains(Slot->AmbiCoeffs, Slot->NumChannels, matrix.m[c],
574 WetGain[i], voice->Send[i].Gains[c].Target);
579 voice->IsHrtf = AL_FALSE;
581 else
583 ALfloat coeffs[MAX_AMBI_COEFFS];
585 if(DirectChannels)
587 if(Device->Hrtf)
589 /* DirectChannels with HRTF enabled. Skip the virtual channels
590 * and write FrontLeft and FrontRight inputs to the first and
591 * second outputs.
593 voice->Direct.OutBuffer += voice->Direct.OutChannels;
594 voice->Direct.OutChannels = 2;
595 for(c = 0;c < num_channels;c++)
597 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
598 voice->Direct.Gains[c].Target[j] = 0.0f;
600 if(chans[c].channel == FrontLeft)
601 voice->Direct.Gains[c].Target[0] = DryGain;
602 else if(chans[c].channel == FrontRight)
603 voice->Direct.Gains[c].Target[1] = DryGain;
606 else for(c = 0;c < num_channels;c++)
608 int idx;
609 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
610 voice->Direct.Gains[c].Target[j] = 0.0f;
611 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
612 voice->Direct.Gains[c].Target[idx] = DryGain;
615 /* Auxiliary sends still use normal panning since they mix to B-Format, which can't
616 * channel-match. */
617 for(c = 0;c < num_channels;c++)
619 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
621 for(i = 0;i < NumSends;i++)
623 if(!SendSlots[i])
625 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
626 voice->Send[i].Gains[c].Target[j] = 0.0f;
628 else
630 const ALeffectslot *Slot = SendSlots[i];
631 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
632 WetGain[i], voice->Send[i].Gains[c].Target);
637 voice->IsHrtf = AL_FALSE;
639 else if(Device->Hrtf_Mode == FullHrtf)
641 /* Full HRTF rendering. Skip the virtual channels and render each
642 * input channel to the real outputs.
644 voice->Direct.OutBuffer += voice->Direct.OutChannels;
645 voice->Direct.OutChannels = 2;
646 for(c = 0;c < num_channels;c++)
648 if(chans[c].channel == LFE)
650 /* Skip LFE */
651 voice->Direct.Hrtf[c].Target.Delay[0] = 0;
652 voice->Direct.Hrtf[c].Target.Delay[1] = 0;
653 for(i = 0;i < HRIR_LENGTH;i++)
655 voice->Direct.Hrtf[c].Target.Coeffs[i][0] = 0.0f;
656 voice->Direct.Hrtf[c].Target.Coeffs[i][1] = 0.0f;
659 for(i = 0;i < NumSends;i++)
661 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
662 voice->Send[i].Gains[c].Target[j] = 0.0f;
665 continue;
668 /* Get the static HRIR coefficients and delays for this channel. */
669 GetLerpedHrtfCoeffs(Device->Hrtf,
670 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
671 voice->Direct.Hrtf[c].Target.Coeffs,
672 voice->Direct.Hrtf[c].Target.Delay
675 /* Normal panning for auxiliary sends. */
676 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
678 for(i = 0;i < NumSends;i++)
680 if(!SendSlots[i])
682 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
683 voice->Send[i].Gains[c].Target[j] = 0.0f;
685 else
687 const ALeffectslot *Slot = SendSlots[i];
688 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
689 WetGain[i], voice->Send[i].Gains[c].Target);
694 voice->IsHrtf = AL_TRUE;
696 else
698 /* Basic or no HRTF rendering. Use normal panning to the output. */
699 for(c = 0;c < num_channels;c++)
701 /* Special-case LFE */
702 if(chans[c].channel == LFE)
704 int idx;
705 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
706 voice->Direct.Gains[c].Target[j] = 0.0f;
707 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
708 voice->Direct.Gains[c].Target[idx] = DryGain;
710 for(i = 0;i < NumSends;i++)
712 ALuint j;
713 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
714 voice->Send[i].Gains[c].Target[j] = 0.0f;
716 continue;
719 CalcAngleCoeffs(chans[c].angle, chans[c].elevation, coeffs);
721 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain, voice->Direct.Gains[c].Target);
723 for(i = 0;i < NumSends;i++)
725 if(!SendSlots[i])
727 ALuint j;
728 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
729 voice->Send[i].Gains[c].Target[j] = 0.0f;
731 else
733 const ALeffectslot *Slot = SendSlots[i];
734 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
735 WetGain[i], voice->Send[i].Gains[c].Target);
740 voice->IsHrtf = AL_FALSE;
745 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
746 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
747 DryGainHF = maxf(DryGainHF, 0.0001f);
748 DryGainLF = maxf(DryGainLF, 0.0001f);
749 for(c = 0;c < num_channels;c++)
751 voice->Direct.Filters[c].ActiveType = AF_None;
752 if(DryGainHF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
753 if(DryGainLF != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
754 ALfilterState_setParams(
755 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf,
756 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
758 ALfilterState_setParams(
759 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf,
760 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
764 for(i = 0;i < NumSends;i++)
766 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
767 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
768 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
769 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
770 for(c = 0;c < num_channels;c++)
772 voice->Send[i].Filters[c].ActiveType = AF_None;
773 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
774 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
775 ALfilterState_setParams(
776 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf,
777 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
779 ALfilterState_setParams(
780 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf,
781 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
787 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
789 const ALCdevice *Device = ALContext->Device;
790 aluVector Position, Velocity, Direction, SourceToListener;
791 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
792 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
793 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
794 ALfloat DopplerFactor, SpeedOfSound;
795 ALfloat AirAbsorptionFactor;
796 ALfloat RoomAirAbsorption[MAX_SENDS];
797 ALbufferlistitem *BufferListItem;
798 ALeffectslot *SendSlots[MAX_SENDS];
799 ALfloat Attenuation;
800 ALfloat RoomAttenuation[MAX_SENDS];
801 ALfloat MetersPerUnit;
802 ALfloat RoomRolloffBase;
803 ALfloat RoomRolloff[MAX_SENDS];
804 ALfloat DecayDistance[MAX_SENDS];
805 ALfloat DryGain;
806 ALfloat DryGainHF;
807 ALfloat DryGainLF;
808 ALboolean DryGainHFAuto;
809 ALfloat WetGain[MAX_SENDS];
810 ALfloat WetGainHF[MAX_SENDS];
811 ALfloat WetGainLF[MAX_SENDS];
812 ALboolean WetGainAuto;
813 ALboolean WetGainHFAuto;
814 ALfloat Pitch;
815 ALuint Frequency;
816 ALint NumSends;
817 ALint i;
819 DryGainHF = 1.0f;
820 DryGainLF = 1.0f;
821 for(i = 0;i < MAX_SENDS;i++)
823 WetGainHF[i] = 1.0f;
824 WetGainLF[i] = 1.0f;
827 /* Get context/device properties */
828 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
829 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
830 NumSends = Device->NumAuxSends;
831 Frequency = Device->Frequency;
833 /* Get listener properties */
834 ListenerGain = ALContext->Listener->Gain;
835 MetersPerUnit = ALContext->Listener->MetersPerUnit;
837 /* Get source properties */
838 SourceVolume = ALSource->Gain;
839 MinVolume = ALSource->MinGain;
840 MaxVolume = ALSource->MaxGain;
841 Pitch = ALSource->Pitch;
842 Position = ALSource->Position;
843 Direction = ALSource->Direction;
844 Velocity = ALSource->Velocity;
845 MinDist = ALSource->RefDistance;
846 MaxDist = ALSource->MaxDistance;
847 Rolloff = ALSource->RollOffFactor;
848 InnerAngle = ALSource->InnerAngle;
849 OuterAngle = ALSource->OuterAngle;
850 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
851 DryGainHFAuto = ALSource->DryGainHFAuto;
852 WetGainAuto = ALSource->WetGainAuto;
853 WetGainHFAuto = ALSource->WetGainHFAuto;
854 RoomRolloffBase = ALSource->RoomRolloffFactor;
856 voice->Direct.OutBuffer = Device->DryBuffer;
857 voice->Direct.OutChannels = Device->NumChannels;
858 for(i = 0;i < NumSends;i++)
860 SendSlots[i] = ALSource->Send[i].Slot;
862 if(!SendSlots[i] && i == 0)
863 SendSlots[i] = Device->DefaultSlot;
864 if(!SendSlots[i] || SendSlots[i]->EffectType == AL_EFFECT_NULL)
866 SendSlots[i] = NULL;
867 RoomRolloff[i] = 0.0f;
868 DecayDistance[i] = 0.0f;
869 RoomAirAbsorption[i] = 1.0f;
871 else if(SendSlots[i]->AuxSendAuto)
873 RoomRolloff[i] = RoomRolloffBase;
874 if(IsReverbEffect(SendSlots[i]->EffectType))
876 RoomRolloff[i] += SendSlots[i]->EffectProps.Reverb.RoomRolloffFactor;
877 DecayDistance[i] = SendSlots[i]->EffectProps.Reverb.DecayTime *
878 SPEEDOFSOUNDMETRESPERSEC;
879 RoomAirAbsorption[i] = SendSlots[i]->EffectProps.Reverb.AirAbsorptionGainHF;
881 else
883 DecayDistance[i] = 0.0f;
884 RoomAirAbsorption[i] = 1.0f;
887 else
889 /* If the slot's auxiliary send auto is off, the data sent to the
890 * effect slot is the same as the dry path, sans filter effects */
891 RoomRolloff[i] = Rolloff;
892 DecayDistance[i] = 0.0f;
893 RoomAirAbsorption[i] = AIRABSORBGAINHF;
896 if(!SendSlots[i])
898 voice->Send[i].OutBuffer = NULL;
899 voice->Send[i].OutChannels = 0;
901 else
903 voice->Send[i].OutBuffer = SendSlots[i]->WetBuffer;
904 voice->Send[i].OutChannels = SendSlots[i]->NumChannels;
908 /* Transform source to listener space (convert to head relative) */
909 if(ALSource->HeadRelative == AL_FALSE)
911 const aluMatrixd *Matrix = &ALContext->Listener->Params.Matrix;
912 /* Transform source vectors */
913 Position = aluMatrixdVector(Matrix, &Position);
914 Velocity = aluMatrixdVector(Matrix, &Velocity);
915 Direction = aluMatrixdVector(Matrix, &Direction);
917 else
919 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
920 /* Offset the source velocity to be relative of the listener velocity */
921 Velocity.v[0] += lvelocity->v[0];
922 Velocity.v[1] += lvelocity->v[1];
923 Velocity.v[2] += lvelocity->v[2];
926 aluNormalize(Direction.v);
927 SourceToListener.v[0] = -Position.v[0];
928 SourceToListener.v[1] = -Position.v[1];
929 SourceToListener.v[2] = -Position.v[2];
930 SourceToListener.v[3] = 0.0f;
931 Distance = aluNormalize(SourceToListener.v);
933 /* Calculate distance attenuation */
934 ClampedDist = Distance;
936 Attenuation = 1.0f;
937 for(i = 0;i < NumSends;i++)
938 RoomAttenuation[i] = 1.0f;
939 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
940 ALContext->DistanceModel)
942 case InverseDistanceClamped:
943 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
944 if(MaxDist < MinDist)
945 break;
946 /*fall-through*/
947 case InverseDistance:
948 if(MinDist > 0.0f)
950 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
951 if(dist > 0.0f) Attenuation = MinDist / dist;
952 for(i = 0;i < NumSends;i++)
954 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
955 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
958 break;
960 case LinearDistanceClamped:
961 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
962 if(MaxDist < MinDist)
963 break;
964 /*fall-through*/
965 case LinearDistance:
966 if(MaxDist != MinDist)
968 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
969 Attenuation = maxf(Attenuation, 0.0f);
970 for(i = 0;i < NumSends;i++)
972 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
973 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
976 break;
978 case ExponentDistanceClamped:
979 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
980 if(MaxDist < MinDist)
981 break;
982 /*fall-through*/
983 case ExponentDistance:
984 if(ClampedDist > 0.0f && MinDist > 0.0f)
986 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
987 for(i = 0;i < NumSends;i++)
988 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
990 break;
992 case DisableDistance:
993 ClampedDist = MinDist;
994 break;
997 /* Source Gain + Attenuation */
998 DryGain = SourceVolume * Attenuation;
999 for(i = 0;i < NumSends;i++)
1000 WetGain[i] = SourceVolume * RoomAttenuation[i];
1002 /* Distance-based air absorption */
1003 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
1005 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
1006 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
1007 for(i = 0;i < NumSends;i++)
1008 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
1011 if(WetGainAuto)
1013 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
1015 /* Apply a decay-time transformation to the wet path, based on the
1016 * attenuation of the dry path.
1018 * Using the apparent distance, based on the distance attenuation, the
1019 * initial decay of the reverb effect is calculated and applied to the
1020 * wet path.
1022 for(i = 0;i < NumSends;i++)
1024 if(DecayDistance[i] > 0.0f)
1025 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
1029 /* Calculate directional soundcones */
1030 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
1031 if(Angle > InnerAngle && Angle <= OuterAngle)
1033 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
1034 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
1035 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
1037 else if(Angle > OuterAngle)
1039 ConeVolume = ALSource->OuterGain;
1040 ConeHF = ALSource->OuterGainHF;
1042 else
1044 ConeVolume = 1.0f;
1045 ConeHF = 1.0f;
1048 DryGain *= ConeVolume;
1049 if(WetGainAuto)
1051 for(i = 0;i < NumSends;i++)
1052 WetGain[i] *= ConeVolume;
1054 if(DryGainHFAuto)
1055 DryGainHF *= ConeHF;
1056 if(WetGainHFAuto)
1058 for(i = 0;i < NumSends;i++)
1059 WetGainHF[i] *= ConeHF;
1062 /* Clamp to Min/Max Gain */
1063 DryGain = clampf(DryGain, MinVolume, MaxVolume);
1064 for(i = 0;i < NumSends;i++)
1065 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
1067 /* Apply gain and frequency filters */
1068 DryGain *= ALSource->Direct.Gain * ListenerGain;
1069 DryGainHF *= ALSource->Direct.GainHF;
1070 DryGainLF *= ALSource->Direct.GainLF;
1071 for(i = 0;i < NumSends;i++)
1073 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
1074 WetGainHF[i] *= ALSource->Send[i].GainHF;
1075 WetGainLF[i] *= ALSource->Send[i].GainLF;
1078 /* Calculate velocity-based doppler effect */
1079 if(DopplerFactor > 0.0f)
1081 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
1082 ALfloat VSS, VLS;
1084 if(SpeedOfSound < 1.0f)
1086 DopplerFactor *= 1.0f/SpeedOfSound;
1087 SpeedOfSound = 1.0f;
1090 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
1091 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
1093 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
1094 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
1097 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
1098 while(BufferListItem != NULL)
1100 ALbuffer *ALBuffer;
1101 if((ALBuffer=BufferListItem->buffer) != NULL)
1103 /* Calculate fixed-point stepping value, based on the pitch, buffer
1104 * frequency, and output frequency. */
1105 Pitch = Pitch * ALBuffer->Frequency / Frequency;
1106 if(Pitch > (ALfloat)MAX_PITCH)
1107 voice->Step = MAX_PITCH<<FRACTIONBITS;
1108 else
1109 voice->Step = maxi(fastf2i(Pitch*FRACTIONONE + 0.5f), 1);
1110 BsincPrepare(voice->Step, &voice->SincState);
1112 break;
1114 BufferListItem = BufferListItem->next;
1117 if(Device->Hrtf_Mode == FullHrtf)
1119 /* Full HRTF rendering. Skip the virtual channels and render to the
1120 * real outputs.
1122 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1123 ALfloat ev = 0.0f, az = 0.0f;
1124 ALfloat radius = ALSource->Radius;
1125 ALfloat dirfact = 1.0f;
1126 ALfloat coeffs[MAX_AMBI_COEFFS];
1128 voice->Direct.OutBuffer += voice->Direct.OutChannels;
1129 voice->Direct.OutChannels = 2;
1131 if(Distance > FLT_EPSILON)
1133 dir.v[0] = -SourceToListener.v[0];
1134 dir.v[1] = -SourceToListener.v[1];
1135 dir.v[2] = -SourceToListener.v[2] * ZScale;
1137 /* Calculate elevation and azimuth only when the source is not at
1138 * the listener. This prevents +0 and -0 Z from producing
1139 * inconsistent panning. Also, clamp Y in case FP precision errors
1140 * cause it to land outside of -1..+1. */
1141 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1142 az = atan2f(dir.v[0], -dir.v[2]);
1144 if(radius > 0.0f)
1146 if(radius >= Distance)
1147 dirfact *= Distance / radius * 0.5f;
1148 else
1149 dirfact *= 1.0f - (asinf(radius / Distance) / F_PI);
1152 /* Get the HRIR coefficients and delays. */
1153 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1154 voice->Direct.Hrtf[0].Target.Coeffs,
1155 voice->Direct.Hrtf[0].Target.Delay);
1157 dir.v[0] *= dirfact;
1158 dir.v[1] *= dirfact;
1159 dir.v[2] *= dirfact;
1160 CalcDirectionCoeffs(dir.v, coeffs);
1162 for(i = 0;i < NumSends;i++)
1164 if(!SendSlots[i])
1166 ALuint j;
1167 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1168 voice->Send[i].Gains[0].Target[j] = 0.0f;
1170 else
1172 const ALeffectslot *Slot = SendSlots[i];
1173 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1174 WetGain[i], voice->Send[i].Gains[0].Target);
1178 voice->IsHrtf = AL_TRUE;
1180 else
1182 /* Basic or no HRTF rendering. Use normal panning to the output. */
1183 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1184 ALfloat radius = ALSource->Radius;
1185 ALfloat coeffs[MAX_AMBI_COEFFS];
1187 /* Get the localized direction, and compute panned gains. */
1188 if(Distance > FLT_EPSILON)
1190 dir[0] = -SourceToListener.v[0];
1191 dir[1] = -SourceToListener.v[1];
1192 dir[2] = -SourceToListener.v[2] * ZScale;
1194 if(radius > 0.0f)
1196 ALfloat dirfact;
1197 if(radius >= Distance)
1198 dirfact = Distance / radius * 0.5f;
1199 else
1200 dirfact = 1.0f - (asinf(radius / Distance) / F_PI);
1201 dir[0] *= dirfact;
1202 dir[1] *= dirfact;
1203 dir[2] *= dirfact;
1205 CalcDirectionCoeffs(dir, coeffs);
1207 ComputePanningGains(Device->AmbiCoeffs, Device->NumChannels, coeffs, DryGain,
1208 voice->Direct.Gains[0].Target);
1210 for(i = 0;i < NumSends;i++)
1212 if(!SendSlots[i])
1214 ALuint j;
1215 for(j = 0;j < MAX_EFFECT_CHANNELS;j++)
1216 voice->Send[i].Gains[0].Target[j] = 0.0f;
1218 else
1220 const ALeffectslot *Slot = SendSlots[i];
1221 ComputePanningGains(Slot->AmbiCoeffs, Slot->NumChannels, coeffs,
1222 WetGain[i], voice->Send[i].Gains[0].Target);
1226 voice->IsHrtf = AL_FALSE;
1230 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1231 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1232 DryGainHF = maxf(DryGainHF, 0.0001f);
1233 DryGainLF = maxf(DryGainLF, 0.0001f);
1234 voice->Direct.Filters[0].ActiveType = AF_None;
1235 if(DryGainHF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1236 if(DryGainLF != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1237 ALfilterState_setParams(
1238 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf,
1239 DryGainHF, hfscale, calc_rcpQ_from_slope(DryGainHF, 0.75f)
1241 ALfilterState_setParams(
1242 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf,
1243 DryGainLF, lfscale, calc_rcpQ_from_slope(DryGainLF, 0.75f)
1246 for(i = 0;i < NumSends;i++)
1248 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1249 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1250 WetGainHF[i] = maxf(WetGainHF[i], 0.0001f);
1251 WetGainLF[i] = maxf(WetGainLF[i], 0.0001f);
1252 voice->Send[i].Filters[0].ActiveType = AF_None;
1253 if(WetGainHF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1254 if(WetGainLF[i] != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1255 ALfilterState_setParams(
1256 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf,
1257 WetGainHF[i], hfscale, calc_rcpQ_from_slope(WetGainHF[i], 0.75f)
1259 ALfilterState_setParams(
1260 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf,
1261 WetGainLF[i], lfscale, calc_rcpQ_from_slope(WetGainLF[i], 0.75f)
1267 void UpdateContextSources(ALCcontext *ctx)
1269 ALvoice *voice, *voice_end;
1270 ALsource *source;
1272 if(ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE))
1274 CalcListenerParams(ctx->Listener);
1276 voice = ctx->Voices;
1277 voice_end = voice + ctx->VoiceCount;
1278 for(;voice != voice_end;++voice)
1280 if(!(source=voice->Source)) continue;
1281 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1282 voice->Source = NULL;
1283 else
1285 ATOMIC_STORE(&source->NeedsUpdate, AL_FALSE);
1286 voice->Update(voice, source, ctx);
1290 else
1292 voice = ctx->Voices;
1293 voice_end = voice + ctx->VoiceCount;
1294 for(;voice != voice_end;++voice)
1296 if(!(source=voice->Source)) continue;
1297 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1298 voice->Source = NULL;
1299 else if(ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE))
1300 voice->Update(voice, source, ctx);
1306 /* Specialized function to clamp to [-1, +1] with only one branch. This also
1307 * converts NaN to 0. */
1308 static inline ALfloat aluClampf(ALfloat val)
1310 if(fabsf(val) <= 1.0f) return val;
1311 return (ALfloat)((0.0f < val) - (val < 0.0f));
1314 static inline ALfloat aluF2F(ALfloat val)
1315 { return val; }
1317 static inline ALint aluF2I(ALfloat val)
1319 /* Floats only have a 24-bit mantissa, so [-16777215, +16777215] is the max
1320 * integer range normalized floats can be safely converted to.
1322 return fastf2i(aluClampf(val)*16777215.0f)<<7;
1324 static inline ALuint aluF2UI(ALfloat val)
1325 { return aluF2I(val)+2147483648u; }
1327 static inline ALshort aluF2S(ALfloat val)
1328 { return fastf2i(aluClampf(val)*32767.0f); }
1329 static inline ALushort aluF2US(ALfloat val)
1330 { return aluF2S(val)+32768; }
1332 static inline ALbyte aluF2B(ALfloat val)
1333 { return fastf2i(aluClampf(val)*127.0f); }
1334 static inline ALubyte aluF2UB(ALfloat val)
1335 { return aluF2B(val)+128; }
1337 #define DECL_TEMPLATE(T, func) \
1338 static void Write_##T(ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1339 ALuint SamplesToDo, ALuint numchans) \
1341 ALuint i, j; \
1342 for(j = 0;j < numchans;j++) \
1344 const ALfloat *in = InBuffer[j]; \
1345 T *restrict out = (T*)OutBuffer + j; \
1346 for(i = 0;i < SamplesToDo;i++) \
1347 out[i*numchans] = func(in[i]); \
1351 DECL_TEMPLATE(ALfloat, aluF2F)
1352 DECL_TEMPLATE(ALuint, aluF2UI)
1353 DECL_TEMPLATE(ALint, aluF2I)
1354 DECL_TEMPLATE(ALushort, aluF2US)
1355 DECL_TEMPLATE(ALshort, aluF2S)
1356 DECL_TEMPLATE(ALubyte, aluF2UB)
1357 DECL_TEMPLATE(ALbyte, aluF2B)
1359 #undef DECL_TEMPLATE
1362 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1364 ALuint SamplesToDo;
1365 ALvoice *voice, *voice_end;
1366 ALeffectslot *slot;
1367 ALsource *source;
1368 ALCcontext *ctx;
1369 FPUCtl oldMode;
1370 ALuint i, c;
1372 SetMixerFPUMode(&oldMode);
1374 while(size > 0)
1376 ALfloat (*OutBuffer)[BUFFERSIZE];
1377 ALuint OutChannels;
1379 IncrementRef(&device->MixCount);
1381 OutBuffer = device->DryBuffer;
1382 OutChannels = device->NumChannels;
1384 SamplesToDo = minu(size, BUFFERSIZE);
1385 for(c = 0;c < OutChannels;c++)
1386 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1387 if(device->Hrtf)
1389 /* Set OutBuffer/OutChannels to correspond to the actual output
1390 * with HRTF. Make sure to clear them too. */
1391 OutBuffer += OutChannels;
1392 OutChannels = 2;
1393 for(c = 0;c < OutChannels;c++)
1394 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1397 V0(device->Backend,lock)();
1399 if((slot=device->DefaultSlot) != NULL)
1401 if(ATOMIC_EXCHANGE(ALenum, &slot->NeedsUpdate, AL_FALSE))
1402 V(slot->EffectState,update)(device, slot);
1403 for(i = 0;i < slot->NumChannels;i++)
1404 memset(slot->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat));
1407 ctx = ATOMIC_LOAD(&device->ContextList);
1408 while(ctx)
1410 if(!ctx->DeferUpdates)
1412 UpdateContextSources(ctx);
1413 #define UPDATE_SLOT(iter) do { \
1414 if(ATOMIC_EXCHANGE(ALenum, &(*iter)->NeedsUpdate, AL_FALSE)) \
1415 V((*iter)->EffectState,update)(device, *iter); \
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, UPDATE_SLOT);
1420 #undef UPDATE_SLOT
1422 else
1424 #define CLEAR_WET_BUFFER(iter) do { \
1425 for(i = 0;i < (*iter)->NumChannels;i++) \
1426 memset((*iter)->WetBuffer[i], 0, SamplesToDo*sizeof(ALfloat)); \
1427 } while(0)
1428 VECTOR_FOR_EACH(ALeffectslot*, ctx->ActiveAuxSlots, CLEAR_WET_BUFFER);
1429 #undef CLEAR_WET_BUFFER
1432 /* source processing */
1433 voice = ctx->Voices;
1434 voice_end = voice + ctx->VoiceCount;
1435 for(;voice != voice_end;++voice)
1437 source = voice->Source;
1438 if(source && source->state == AL_PLAYING)
1439 MixSource(voice, source, device, SamplesToDo);
1442 /* effect slot processing */
1443 c = VECTOR_SIZE(ctx->ActiveAuxSlots);
1444 for(i = 0;i < c;i++)
1446 const ALeffectslot *slot = VECTOR_ELEM(ctx->ActiveAuxSlots, i);
1447 ALeffectState *state = slot->EffectState;
1448 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1449 device->NumChannels);
1452 ctx = ctx->next;
1455 if(device->DefaultSlot != NULL)
1457 const ALeffectslot *slot = device->DefaultSlot;
1458 ALeffectState *state = slot->EffectState;
1459 V(state,process)(SamplesToDo, slot->WetBuffer, device->DryBuffer,
1460 device->NumChannels);
1463 /* Increment the clock time. Every second's worth of samples is
1464 * converted and added to clock base so that large sample counts don't
1465 * overflow during conversion. This also guarantees an exact, stable
1466 * conversion. */
1467 device->SamplesDone += SamplesToDo;
1468 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1469 device->SamplesDone %= device->Frequency;
1470 V0(device->Backend,unlock)();
1472 if(device->Hrtf)
1474 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1475 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1476 MixHrtfParams hrtfparams;
1477 memset(&hrtfparams, 0, sizeof(hrtfparams));
1478 for(c = 0;c < device->NumChannels;c++)
1480 hrtfparams.Current = &device->Hrtf_Params[c];
1481 hrtfparams.Target = &device->Hrtf_Params[c];
1482 HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
1483 0, irsize, &hrtfparams, &device->Hrtf_State[c], SamplesToDo
1486 device->Hrtf_Offset += SamplesToDo;
1488 else if(device->Bs2b)
1490 /* Apply binaural/crossfeed filter */
1491 for(i = 0;i < SamplesToDo;i++)
1493 float samples[2];
1494 samples[0] = device->DryBuffer[0][i];
1495 samples[1] = device->DryBuffer[1][i];
1496 bs2b_cross_feed(device->Bs2b, samples);
1497 device->DryBuffer[0][i] = samples[0];
1498 device->DryBuffer[1][i] = samples[1];
1502 if(buffer)
1504 #define WRITE(T, a, b, c, d) do { \
1505 Write_##T((a), (b), (c), (d)); \
1506 buffer = (T*)buffer + (c)*(d); \
1507 } while(0)
1508 switch(device->FmtType)
1510 case DevFmtByte:
1511 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1512 break;
1513 case DevFmtUByte:
1514 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1515 break;
1516 case DevFmtShort:
1517 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1518 break;
1519 case DevFmtUShort:
1520 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1521 break;
1522 case DevFmtInt:
1523 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1524 break;
1525 case DevFmtUInt:
1526 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1527 break;
1528 case DevFmtFloat:
1529 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1530 break;
1532 #undef WRITE
1535 size -= SamplesToDo;
1536 IncrementRef(&device->MixCount);
1539 RestoreFPUMode(&oldMode);
1543 ALvoid aluHandleDisconnect(ALCdevice *device)
1545 ALCcontext *Context;
1547 device->Connected = ALC_FALSE;
1549 Context = ATOMIC_LOAD(&device->ContextList);
1550 while(Context)
1552 ALvoice *voice, *voice_end;
1554 voice = Context->Voices;
1555 voice_end = voice + Context->VoiceCount;
1556 while(voice != voice_end)
1558 ALsource *source = voice->Source;
1559 voice->Source = NULL;
1561 if(source && source->state == AL_PLAYING)
1563 source->state = AL_STOPPED;
1564 ATOMIC_STORE(&source->current_buffer, NULL);
1565 source->position = 0;
1566 source->position_fraction = 0;
1569 voice++;
1571 Context->VoiceCount = 0;
1573 Context = Context->next;