Use aluVector in some more places
[openal-soft.git] / Alc / ALu.c
blobc10c18a6fe4c537e803a4e8fa0d98d7088a31a50
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"
42 #include "midi/base.h"
45 static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
46 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
48 struct ChanMap {
49 enum Channel channel;
50 ALfloat angle;
51 ALfloat elevation;
54 /* Cone scalar */
55 ALfloat ConeScale = 1.0f;
57 /* Localized Z scalar for mono sources */
58 ALfloat ZScale = 1.0f;
60 extern inline ALfloat minf(ALfloat a, ALfloat b);
61 extern inline ALfloat maxf(ALfloat a, ALfloat b);
62 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
64 extern inline ALdouble mind(ALdouble a, ALdouble b);
65 extern inline ALdouble maxd(ALdouble a, ALdouble b);
66 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
68 extern inline ALuint minu(ALuint a, ALuint b);
69 extern inline ALuint maxu(ALuint a, ALuint b);
70 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
72 extern inline ALint mini(ALint a, ALint b);
73 extern inline ALint maxi(ALint a, ALint b);
74 extern inline ALint clampi(ALint val, ALint min, ALint max);
76 extern inline ALint64 mini64(ALint64 a, ALint64 b);
77 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
78 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
80 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
81 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
82 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
84 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
85 extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALuint frac);
87 extern inline void aluVectorSet(aluVector *restrict vector, ALfloat x, ALfloat y, ALfloat z, ALfloat w);
89 extern inline void aluMatrixSetRow(aluMatrix *restrict matrix, ALuint row,
90 ALfloat m0, ALfloat m1, ALfloat m2, ALfloat m3);
91 extern inline void aluMatrixSet(aluMatrix *restrict matrix, ALfloat m00, ALfloat m01, ALfloat m02, ALfloat m03,
92 ALfloat m10, ALfloat m11, ALfloat m12, ALfloat m13,
93 ALfloat m20, ALfloat m21, ALfloat m22, ALfloat m23,
94 ALfloat m30, ALfloat m31, ALfloat m32, ALfloat m33);
97 static inline HrtfMixerFunc SelectHrtfMixer(void)
99 #ifdef HAVE_SSE
100 if((CPUCapFlags&CPU_CAP_SSE))
101 return MixHrtf_SSE;
102 #endif
103 #ifdef HAVE_NEON
104 if((CPUCapFlags&CPU_CAP_NEON))
105 return MixHrtf_Neon;
106 #endif
108 return MixHrtf_C;
112 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
114 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
115 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
116 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
119 static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
121 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
122 inVector1[2]*inVector2[2];
125 static inline void aluNormalize(ALfloat *inVector)
127 ALfloat lengthsqr = aluDotproduct(inVector, inVector);
128 if(lengthsqr > 0.0f)
130 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
131 inVector[0] *= inv_length;
132 inVector[1] *= inv_length;
133 inVector[2] *= inv_length;
137 static inline ALvoid aluMatrixVector(ALfloat *vec, ALfloat w, const aluMatrix *mtx)
139 ALfloat v[4] = {
140 vec[0], vec[1], vec[2], w
143 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];
144 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];
145 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];
149 /* Calculates the fade time from the changes in gain and listener to source
150 * angle between updates. The result is a the time, in seconds, for the
151 * transition to complete.
153 static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
155 ALfloat gainChange, angleChange, change;
157 /* Calculate the normalized dB gain change. */
158 newGain = maxf(newGain, 0.0001f);
159 oldGain = maxf(oldGain, 0.0001f);
160 gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
162 /* Calculate the angle change only when there is enough gain to notice it. */
163 angleChange = 0.0f;
164 if(gainChange > 0.0001f || newGain > 0.0001f)
166 /* No angle change when the directions are equal or degenerate (when
167 * both have zero length).
169 if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2])
171 ALfloat dotp = aluDotproduct(olddir, newdir);
172 angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
176 /* Use the largest of the two changes, and apply a significance shaping
177 * function to it. The result is then scaled to cover a 15ms transition
178 * range.
180 change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
181 return minf(change, 1.0f) * 0.015f;
185 static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps)
187 ALfloat delta;
188 ALuint i, j;
190 if(steps < 2)
192 for(i = 0;i < num_chans;i++)
194 MixGains *gains = params->Gains[i];
195 for(j = 0;j < params->OutChannels;j++)
197 gains[j].Current = gains[j].Target;
198 gains[j].Step = 0.0f;
201 params->Counter = 0;
202 return;
205 delta = 1.0f / (ALfloat)steps;
206 for(i = 0;i < num_chans;i++)
208 MixGains *gains = params->Gains[i];
209 for(j = 0;j < params->OutChannels;j++)
211 ALfloat diff = gains[j].Target - gains[j].Current;
212 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
213 gains[j].Step = diff * delta;
214 else
215 gains[j].Step = 0.0f;
218 params->Counter = steps;
221 static void UpdateWetStepping(SendParams *params, ALuint steps)
223 ALfloat delta;
225 if(steps < 2)
227 params->Gain.Current = params->Gain.Target;
228 params->Gain.Step = 0.0f;
230 params->Counter = 0;
231 return;
234 delta = 1.0f / (ALfloat)steps;
236 ALfloat diff = params->Gain.Target - params->Gain.Current;
237 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
238 params->Gain.Step = diff * delta;
239 else
240 params->Gain.Step = 0.0f;
242 params->Counter = steps;
246 static ALvoid CalcListenerParams(ALlistener *Listener)
248 ALfloat N[3], V[3], U[3], P[3];
250 /* AT then UP */
251 N[0] = Listener->Forward[0];
252 N[1] = Listener->Forward[1];
253 N[2] = Listener->Forward[2];
254 aluNormalize(N);
255 V[0] = Listener->Up[0];
256 V[1] = Listener->Up[1];
257 V[2] = Listener->Up[2];
258 aluNormalize(V);
259 /* Build and normalize right-vector */
260 aluCrossproduct(N, V, U);
261 aluNormalize(U);
263 P[0] = Listener->Position.v[0];
264 P[1] = Listener->Position.v[1];
265 P[2] = Listener->Position.v[2];
267 aluMatrixSet(&Listener->Params.Matrix,
268 U[0], V[0], -N[0], 0.0f,
269 U[1], V[1], -N[1], 0.0f,
270 U[2], V[2], -N[2], 0.0f,
271 0.0f, 0.0f, 0.0f, 1.0f
273 aluMatrixVector(P, 1.0f, &Listener->Params.Matrix);
274 aluMatrixSetRow(&Listener->Params.Matrix, 3, -P[0], -P[1], -P[2], 1.0f);
276 Listener->Params.Velocity = Listener->Velocity;
277 aluMatrixVector(Listener->Params.Velocity.v, 0.0f, &Listener->Params.Matrix);
280 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
282 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } };
283 static const struct ChanMap StereoMap[2] = {
284 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
285 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
287 static const struct ChanMap StereoWideMap[2] = {
288 { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
289 { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
291 static const struct ChanMap RearMap[2] = {
292 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
293 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
295 static const struct ChanMap QuadMap[4] = {
296 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
297 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
298 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
299 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
301 static const struct ChanMap X51Map[6] = {
302 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
303 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
304 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
305 { LFE, 0.0f, 0.0f },
306 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
307 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
309 static const struct ChanMap X61Map[7] = {
310 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
311 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
312 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
313 { LFE, 0.0f, 0.0f },
314 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
315 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
316 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
318 static const struct ChanMap X71Map[8] = {
319 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
320 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
321 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
322 { LFE, 0.0f, 0.0f },
323 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
324 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
325 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
326 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
329 ALCdevice *Device = ALContext->Device;
330 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
331 ALbufferlistitem *BufferListItem;
332 enum FmtChannels Channels;
333 ALfloat DryGain, DryGainHF, DryGainLF;
334 ALfloat WetGain[MAX_SENDS];
335 ALfloat WetGainHF[MAX_SENDS];
336 ALfloat WetGainLF[MAX_SENDS];
337 ALuint NumSends, Frequency;
338 ALboolean Relative;
339 const struct ChanMap *chans = NULL;
340 ALuint num_channels = 0;
341 ALboolean DirectChannels;
342 ALboolean isbformat = AL_FALSE;
343 ALfloat Pitch;
344 ALuint i, j, c;
346 /* Get device properties */
347 NumSends = Device->NumAuxSends;
348 Frequency = Device->Frequency;
350 /* Get listener properties */
351 ListenerGain = ALContext->Listener->Gain;
353 /* Get source properties */
354 SourceVolume = ALSource->Gain;
355 MinVolume = ALSource->MinGain;
356 MaxVolume = ALSource->MaxGain;
357 Pitch = ALSource->Pitch;
358 Relative = ALSource->HeadRelative;
359 DirectChannels = ALSource->DirectChannels;
361 voice->Direct.OutBuffer = Device->DryBuffer;
362 voice->Direct.OutChannels = Device->NumChannels;
363 for(i = 0;i < NumSends;i++)
365 ALeffectslot *Slot = ALSource->Send[i].Slot;
366 if(!Slot && i == 0)
367 Slot = Device->DefaultSlot;
368 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
369 voice->Send[i].OutBuffer = NULL;
370 else
371 voice->Send[i].OutBuffer = Slot->WetBuffer;
374 /* Calculate the stepping value */
375 Channels = FmtMono;
376 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
377 while(BufferListItem != NULL)
379 ALbuffer *ALBuffer;
380 if((ALBuffer=BufferListItem->buffer) != NULL)
382 Pitch = Pitch * ALBuffer->Frequency / Frequency;
383 if(Pitch > (ALfloat)MAX_PITCH)
384 voice->Step = MAX_PITCH<<FRACTIONBITS;
385 else
387 voice->Step = fastf2i(Pitch*FRACTIONONE);
388 if(voice->Step == 0)
389 voice->Step = 1;
392 Channels = ALBuffer->FmtChannels;
393 break;
395 BufferListItem = BufferListItem->next;
398 /* Calculate gains */
399 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
400 DryGain *= ALSource->Direct.Gain * ListenerGain;
401 DryGainHF = ALSource->Direct.GainHF;
402 DryGainLF = ALSource->Direct.GainLF;
403 for(i = 0;i < NumSends;i++)
405 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
406 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
407 WetGainHF[i] = ALSource->Send[i].GainHF;
408 WetGainLF[i] = ALSource->Send[i].GainLF;
411 switch(Channels)
413 case FmtMono:
414 chans = MonoMap;
415 num_channels = 1;
416 break;
418 case FmtStereo:
419 /* HACK: Place the stereo channels at +/-90 degrees when using non-
420 * HRTF stereo output. This helps reduce the "monoization" caused
421 * by them panning towards the center. */
422 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
423 chans = StereoWideMap;
424 else
425 chans = StereoMap;
426 num_channels = 2;
427 break;
429 case FmtRear:
430 chans = RearMap;
431 num_channels = 2;
432 break;
434 case FmtQuad:
435 chans = QuadMap;
436 num_channels = 4;
437 break;
439 case FmtX51:
440 chans = X51Map;
441 num_channels = 6;
442 break;
444 case FmtX61:
445 chans = X61Map;
446 num_channels = 7;
447 break;
449 case FmtX71:
450 chans = X71Map;
451 num_channels = 8;
452 break;
454 case FmtBFormat2D:
455 num_channels = 3;
456 isbformat = AL_TRUE;
457 DirectChannels = AL_FALSE;
458 break;
460 case FmtBFormat3D:
461 num_channels = 4;
462 isbformat = AL_TRUE;
463 DirectChannels = AL_FALSE;
464 break;
467 if(isbformat)
469 ALfloat N[3], V[3], U[3];
470 ALfloat matrix[4][4];
472 /* AT then UP */
473 N[0] = ALSource->Orientation[0][0];
474 N[1] = ALSource->Orientation[0][1];
475 N[2] = ALSource->Orientation[0][2];
476 aluNormalize(N);
477 V[0] = ALSource->Orientation[1][0];
478 V[1] = ALSource->Orientation[1][1];
479 V[2] = ALSource->Orientation[1][2];
480 aluNormalize(V);
481 if(!Relative)
483 const aluMatrix *lmatrix = &ALContext->Listener->Params.Matrix;
484 aluMatrixVector(N, 0.0f, lmatrix);
485 aluMatrixVector(V, 0.0f, lmatrix);
487 /* Build and normalize right-vector */
488 aluCrossproduct(N, V, U);
489 aluNormalize(U);
491 matrix[0][0] = 1.0f;
492 matrix[0][1] = 0.0f;
493 matrix[0][2] = 0.0f;
494 matrix[0][3] = 0.0f;
495 matrix[1][0] = 0.0f;
496 matrix[1][1] = -N[2];
497 matrix[1][2] = -N[0];
498 matrix[1][3] = N[1];
499 matrix[2][0] = 0.0f;
500 matrix[2][1] = U[2];
501 matrix[2][2] = U[0];
502 matrix[2][3] = -U[1];
503 matrix[3][0] = 0.0f;
504 matrix[3][1] = -V[2];
505 matrix[3][2] = -V[0];
506 matrix[3][3] = V[1];
508 for(c = 0;c < num_channels;c++)
510 MixGains *gains = voice->Direct.Gains[c];
511 ALfloat Target[MAX_OUTPUT_CHANNELS];
513 ComputeBFormatGains(Device, matrix[c], DryGain, Target);
514 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
515 gains[i].Target = Target[i];
517 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
518 voice->Direct.Moving = AL_TRUE;
520 voice->IsHrtf = AL_FALSE;
521 for(i = 0;i < NumSends;i++)
522 WetGain[i] *= 1.4142f;
524 else if(DirectChannels != AL_FALSE)
526 if(Device->Hrtf)
528 voice->Direct.OutBuffer += voice->Direct.OutChannels;
529 voice->Direct.OutChannels = 2;
530 for(c = 0;c < num_channels;c++)
532 MixGains *gains = voice->Direct.Gains[c];
534 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
535 gains[j].Target = 0.0f;
537 if(chans[c].channel == FrontLeft)
538 gains[0].Target = DryGain;
539 else if(chans[c].channel == FrontRight)
540 gains[1].Target = DryGain;
543 else for(c = 0;c < num_channels;c++)
545 MixGains *gains = voice->Direct.Gains[c];
546 int idx;
548 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
549 gains[j].Target = 0.0f;
550 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
551 gains[idx].Target = DryGain;
553 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
554 voice->Direct.Moving = AL_TRUE;
556 voice->IsHrtf = AL_FALSE;
558 else if(Device->Hrtf)
560 voice->Direct.OutBuffer += voice->Direct.OutChannels;
561 voice->Direct.OutChannels = 2;
562 for(c = 0;c < num_channels;c++)
564 if(chans[c].channel == LFE)
566 /* Skip LFE */
567 voice->Direct.Hrtf.Params[c].Delay[0] = 0;
568 voice->Direct.Hrtf.Params[c].Delay[1] = 0;
569 for(i = 0;i < HRIR_LENGTH;i++)
571 voice->Direct.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
572 voice->Direct.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
575 else
577 /* Get the static HRIR coefficients and delays for this
578 * channel. */
579 GetLerpedHrtfCoeffs(Device->Hrtf,
580 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
581 voice->Direct.Hrtf.Params[c].Coeffs,
582 voice->Direct.Hrtf.Params[c].Delay);
585 voice->Direct.Counter = 0;
586 voice->Direct.Moving = AL_TRUE;
588 voice->IsHrtf = AL_TRUE;
590 else
592 for(c = 0;c < num_channels;c++)
594 MixGains *gains = voice->Direct.Gains[c];
595 ALfloat Target[MAX_OUTPUT_CHANNELS];
597 /* Special-case LFE */
598 if(chans[c].channel == LFE)
600 int idx;
601 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
602 gains[i].Target = 0.0f;
603 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
604 gains[idx].Target = DryGain;
605 continue;
608 ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
609 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
610 gains[i].Target = Target[i];
612 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
613 voice->Direct.Moving = AL_TRUE;
615 voice->IsHrtf = AL_FALSE;
617 for(i = 0;i < NumSends;i++)
619 voice->Send[i].Gain.Target = WetGain[i];
620 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
621 voice->Send[i].Moving = AL_TRUE;
625 ALfloat gainhf = maxf(0.01f, DryGainHF);
626 ALfloat gainlf = maxf(0.01f, DryGainLF);
627 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
628 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
629 for(c = 0;c < num_channels;c++)
631 voice->Direct.Filters[c].ActiveType = AF_None;
632 if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
633 if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
634 ALfilterState_setParams(
635 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
636 hfscale, 0.0f
638 ALfilterState_setParams(
639 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
640 lfscale, 0.0f
644 for(i = 0;i < NumSends;i++)
646 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
647 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
648 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
649 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
650 for(c = 0;c < num_channels;c++)
652 voice->Send[i].Filters[c].ActiveType = AF_None;
653 if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
654 if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
655 ALfilterState_setParams(
656 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
657 hfscale, 0.0f
659 ALfilterState_setParams(
660 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
661 lfscale, 0.0f
667 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
669 ALCdevice *Device = ALContext->Device;
670 aluVector Position, Velocity, Direction, SourceToListener;
671 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
672 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
673 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
674 ALfloat DopplerFactor, SpeedOfSound;
675 ALfloat AirAbsorptionFactor;
676 ALfloat RoomAirAbsorption[MAX_SENDS];
677 ALbufferlistitem *BufferListItem;
678 ALfloat Attenuation;
679 ALfloat RoomAttenuation[MAX_SENDS];
680 ALfloat MetersPerUnit;
681 ALfloat RoomRolloffBase;
682 ALfloat RoomRolloff[MAX_SENDS];
683 ALfloat DecayDistance[MAX_SENDS];
684 ALfloat DryGain;
685 ALfloat DryGainHF;
686 ALfloat DryGainLF;
687 ALboolean DryGainHFAuto;
688 ALfloat WetGain[MAX_SENDS];
689 ALfloat WetGainHF[MAX_SENDS];
690 ALfloat WetGainLF[MAX_SENDS];
691 ALboolean WetGainAuto;
692 ALboolean WetGainHFAuto;
693 ALfloat Pitch;
694 ALuint Frequency;
695 ALint NumSends;
696 ALint i, j;
698 DryGainHF = 1.0f;
699 DryGainLF = 1.0f;
700 for(i = 0;i < MAX_SENDS;i++)
702 WetGainHF[i] = 1.0f;
703 WetGainLF[i] = 1.0f;
706 /* Get context/device properties */
707 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
708 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
709 NumSends = Device->NumAuxSends;
710 Frequency = Device->Frequency;
712 /* Get listener properties */
713 ListenerGain = ALContext->Listener->Gain;
714 MetersPerUnit = ALContext->Listener->MetersPerUnit;
716 /* Get source properties */
717 SourceVolume = ALSource->Gain;
718 MinVolume = ALSource->MinGain;
719 MaxVolume = ALSource->MaxGain;
720 Pitch = ALSource->Pitch;
721 Position = ALSource->Position;
722 Direction = ALSource->Direction;
723 Velocity = ALSource->Velocity;
724 MinDist = ALSource->RefDistance;
725 MaxDist = ALSource->MaxDistance;
726 Rolloff = ALSource->RollOffFactor;
727 InnerAngle = ALSource->InnerAngle;
728 OuterAngle = ALSource->OuterAngle;
729 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
730 DryGainHFAuto = ALSource->DryGainHFAuto;
731 WetGainAuto = ALSource->WetGainAuto;
732 WetGainHFAuto = ALSource->WetGainHFAuto;
733 RoomRolloffBase = ALSource->RoomRolloffFactor;
735 voice->Direct.OutBuffer = Device->DryBuffer;
736 voice->Direct.OutChannels = Device->NumChannels;
737 for(i = 0;i < NumSends;i++)
739 ALeffectslot *Slot = ALSource->Send[i].Slot;
741 if(!Slot && i == 0)
742 Slot = Device->DefaultSlot;
743 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
745 Slot = NULL;
746 RoomRolloff[i] = 0.0f;
747 DecayDistance[i] = 0.0f;
748 RoomAirAbsorption[i] = 1.0f;
750 else if(Slot->AuxSendAuto)
752 RoomRolloff[i] = RoomRolloffBase;
753 if(IsReverbEffect(Slot->EffectType))
755 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
756 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
757 SPEEDOFSOUNDMETRESPERSEC;
758 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
760 else
762 DecayDistance[i] = 0.0f;
763 RoomAirAbsorption[i] = 1.0f;
766 else
768 /* If the slot's auxiliary send auto is off, the data sent to the
769 * effect slot is the same as the dry path, sans filter effects */
770 RoomRolloff[i] = Rolloff;
771 DecayDistance[i] = 0.0f;
772 RoomAirAbsorption[i] = AIRABSORBGAINHF;
775 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
776 voice->Send[i].OutBuffer = NULL;
777 else
778 voice->Send[i].OutBuffer = Slot->WetBuffer;
781 /* Transform source to listener space (convert to head relative) */
782 if(ALSource->HeadRelative == AL_FALSE)
784 const aluMatrix *Matrix = &ALContext->Listener->Params.Matrix;
785 /* Transform source vectors */
786 aluMatrixVector(Position.v, 1.0f, Matrix);
787 aluMatrixVector(Direction.v, 0.0f, Matrix);
788 aluMatrixVector(Velocity.v, 0.0f, Matrix);
790 else
792 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
793 /* Offset the source velocity to be relative of the listener velocity */
794 Velocity.v[0] += lvelocity->v[0];
795 Velocity.v[1] += lvelocity->v[1];
796 Velocity.v[2] += lvelocity->v[2];
799 SourceToListener.v[0] = -Position.v[0];
800 SourceToListener.v[1] = -Position.v[1];
801 SourceToListener.v[2] = -Position.v[2];
802 SourceToListener.v[2] = 0.0f;
803 aluNormalize(SourceToListener.v);
804 aluNormalize(Direction.v);
806 /* Calculate distance attenuation */
807 Distance = sqrtf(aluDotproduct(Position.v, Position.v));
808 ClampedDist = Distance;
810 Attenuation = 1.0f;
811 for(i = 0;i < NumSends;i++)
812 RoomAttenuation[i] = 1.0f;
813 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
814 ALContext->DistanceModel)
816 case InverseDistanceClamped:
817 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
818 if(MaxDist < MinDist)
819 break;
820 /*fall-through*/
821 case InverseDistance:
822 if(MinDist > 0.0f)
824 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
825 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
826 for(i = 0;i < NumSends;i++)
828 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
829 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
832 break;
834 case LinearDistanceClamped:
835 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
836 if(MaxDist < MinDist)
837 break;
838 /*fall-through*/
839 case LinearDistance:
840 if(MaxDist != MinDist)
842 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
843 Attenuation = maxf(Attenuation, 0.0f);
844 for(i = 0;i < NumSends;i++)
846 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
847 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
850 break;
852 case ExponentDistanceClamped:
853 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
854 if(MaxDist < MinDist)
855 break;
856 /*fall-through*/
857 case ExponentDistance:
858 if(ClampedDist > 0.0f && MinDist > 0.0f)
860 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
861 for(i = 0;i < NumSends;i++)
862 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
864 break;
866 case DisableDistance:
867 ClampedDist = MinDist;
868 break;
871 /* Source Gain + Attenuation */
872 DryGain = SourceVolume * Attenuation;
873 for(i = 0;i < NumSends;i++)
874 WetGain[i] = SourceVolume * RoomAttenuation[i];
876 /* Distance-based air absorption */
877 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
879 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
880 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
881 for(i = 0;i < NumSends;i++)
882 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
885 if(WetGainAuto)
887 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
889 /* Apply a decay-time transformation to the wet path, based on the
890 * attenuation of the dry path.
892 * Using the apparent distance, based on the distance attenuation, the
893 * initial decay of the reverb effect is calculated and applied to the
894 * wet path.
896 for(i = 0;i < NumSends;i++)
898 if(DecayDistance[i] > 0.0f)
899 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
903 /* Calculate directional soundcones */
904 Angle = RAD2DEG(acosf(aluDotproduct(Direction.v,SourceToListener.v)) * ConeScale) * 2.0f;
905 if(Angle > InnerAngle && Angle <= OuterAngle)
907 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
908 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
909 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
911 else if(Angle > OuterAngle)
913 ConeVolume = ALSource->OuterGain;
914 ConeHF = ALSource->OuterGainHF;
916 else
918 ConeVolume = 1.0f;
919 ConeHF = 1.0f;
922 DryGain *= ConeVolume;
923 if(WetGainAuto)
925 for(i = 0;i < NumSends;i++)
926 WetGain[i] *= ConeVolume;
928 if(DryGainHFAuto)
929 DryGainHF *= ConeHF;
930 if(WetGainHFAuto)
932 for(i = 0;i < NumSends;i++)
933 WetGainHF[i] *= ConeHF;
936 /* Clamp to Min/Max Gain */
937 DryGain = clampf(DryGain, MinVolume, MaxVolume);
938 for(i = 0;i < NumSends;i++)
939 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
941 /* Apply gain and frequency filters */
942 DryGain *= ALSource->Direct.Gain * ListenerGain;
943 DryGainHF *= ALSource->Direct.GainHF;
944 DryGainLF *= ALSource->Direct.GainLF;
945 for(i = 0;i < NumSends;i++)
947 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
948 WetGainHF[i] *= ALSource->Send[i].GainHF;
949 WetGainLF[i] *= ALSource->Send[i].GainLF;
952 /* Calculate velocity-based doppler effect */
953 if(DopplerFactor > 0.0f)
955 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
956 ALfloat VSS, VLS;
958 if(SpeedOfSound < 1.0f)
960 DopplerFactor *= 1.0f/SpeedOfSound;
961 SpeedOfSound = 1.0f;
964 VSS = aluDotproduct(Velocity.v, SourceToListener.v) * DopplerFactor;
965 VLS = aluDotproduct(lvelocity->v, SourceToListener.v) * DopplerFactor;
967 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
968 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
971 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
972 while(BufferListItem != NULL)
974 ALbuffer *ALBuffer;
975 if((ALBuffer=BufferListItem->buffer) != NULL)
977 /* Calculate fixed-point stepping value, based on the pitch, buffer
978 * frequency, and output frequency. */
979 Pitch = Pitch * ALBuffer->Frequency / Frequency;
980 if(Pitch > (ALfloat)MAX_PITCH)
981 voice->Step = MAX_PITCH<<FRACTIONBITS;
982 else
984 voice->Step = fastf2i(Pitch*FRACTIONONE);
985 if(voice->Step == 0)
986 voice->Step = 1;
989 break;
991 BufferListItem = BufferListItem->next;
994 if(Device->Hrtf)
996 /* Use a binaural HRTF algorithm for stereo headphone playback */
997 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
998 ALfloat ev = 0.0f, az = 0.0f;
999 ALfloat radius = ALSource->Radius;
1000 ALfloat dirfact = 1.0f;
1002 voice->Direct.OutBuffer += voice->Direct.OutChannels;
1003 voice->Direct.OutChannels = 2;
1005 if(Distance > FLT_EPSILON)
1007 ALfloat invlen = 1.0f/Distance;
1008 dir[0] = Position.v[0] * invlen;
1009 dir[1] = Position.v[1] * invlen;
1010 dir[2] = Position.v[2] * invlen * ZScale;
1012 /* Calculate elevation and azimuth only when the source is not at
1013 * the listener. This prevents +0 and -0 Z from producing
1014 * inconsistent panning. Also, clamp Y in case FP precision errors
1015 * cause it to land outside of -1..+1. */
1016 ev = asinf(clampf(dir[1], -1.0f, 1.0f));
1017 az = atan2f(dir[0], -dir[2]);
1019 if(radius > Distance)
1020 dirfact *= Distance / radius;
1022 /* Check to see if the HRIR is already moving. */
1023 if(voice->Direct.Moving)
1025 ALfloat delta;
1026 delta = CalcFadeTime(voice->Direct.LastGain, DryGain,
1027 voice->Direct.LastDir, dir);
1028 /* If the delta is large enough, get the moving HRIR target
1029 * coefficients, target delays, steppping values, and counter. */
1030 if(delta > 0.000015f)
1032 ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
1033 ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
1034 voice->Direct.Hrtf.Params[0].Coeffs, voice->Direct.Hrtf.Params[0].Delay,
1035 voice->Direct.Hrtf.Params[0].CoeffStep, voice->Direct.Hrtf.Params[0].DelayStep
1037 voice->Direct.Counter = counter;
1038 voice->Direct.LastGain = DryGain;
1039 voice->Direct.LastDir[0] = dir[0];
1040 voice->Direct.LastDir[1] = dir[1];
1041 voice->Direct.LastDir[2] = dir[2];
1044 else
1046 /* Get the initial (static) HRIR coefficients and delays. */
1047 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1048 voice->Direct.Hrtf.Params[0].Coeffs,
1049 voice->Direct.Hrtf.Params[0].Delay);
1050 voice->Direct.Counter = 0;
1051 voice->Direct.Moving = AL_TRUE;
1052 voice->Direct.LastGain = DryGain;
1053 voice->Direct.LastDir[0] = dir[0];
1054 voice->Direct.LastDir[1] = dir[1];
1055 voice->Direct.LastDir[2] = dir[2];
1058 voice->IsHrtf = AL_TRUE;
1060 else
1062 MixGains *gains = voice->Direct.Gains[0];
1063 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1064 ALfloat radius = ALSource->Radius;
1065 ALfloat Target[MAX_OUTPUT_CHANNELS];
1067 /* Normalize the length, and compute panned gains. */
1068 if(Distance > FLT_EPSILON || radius > FLT_EPSILON)
1070 ALfloat invlen = 1.0f/maxf(Distance, radius);
1071 dir[0] = Position.v[0] * invlen;
1072 dir[1] = Position.v[1] * invlen;
1073 dir[2] = Position.v[2] * invlen * ZScale;
1075 ComputeDirectionalGains(Device, dir, DryGain, Target);
1077 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
1078 gains[j].Target = Target[j];
1079 UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0));
1080 voice->Direct.Moving = AL_TRUE;
1082 voice->IsHrtf = AL_FALSE;
1084 for(i = 0;i < NumSends;i++)
1086 voice->Send[i].Gain.Target = WetGain[i];
1087 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
1088 voice->Send[i].Moving = AL_TRUE;
1092 ALfloat gainhf = maxf(0.01f, DryGainHF);
1093 ALfloat gainlf = maxf(0.01f, DryGainLF);
1094 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1095 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1096 voice->Direct.Filters[0].ActiveType = AF_None;
1097 if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1098 if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1099 ALfilterState_setParams(
1100 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1101 hfscale, 0.0f
1103 ALfilterState_setParams(
1104 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1105 lfscale, 0.0f
1108 for(i = 0;i < NumSends;i++)
1110 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
1111 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
1112 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1113 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1114 voice->Send[i].Filters[0].ActiveType = AF_None;
1115 if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1116 if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1117 ALfilterState_setParams(
1118 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1119 hfscale, 0.0f
1121 ALfilterState_setParams(
1122 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1123 lfscale, 0.0f
1129 static inline ALint aluF2I25(ALfloat val)
1131 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1132 if(fabsf(val) > 1.0f)
1133 val = (ALfloat)((0.0f < val) - (val < 0.0f));
1134 /* Convert to a signed integer, between -16777215 and +16777215. */
1135 return fastf2i(val*16777215.0f);
1138 static inline ALfloat aluF2F(ALfloat val)
1139 { return val; }
1140 static inline ALint aluF2I(ALfloat val)
1141 { return aluF2I25(val)<<7; }
1142 static inline ALuint aluF2UI(ALfloat val)
1143 { return aluF2I(val)+2147483648u; }
1144 static inline ALshort aluF2S(ALfloat val)
1145 { return aluF2I25(val)>>9; }
1146 static inline ALushort aluF2US(ALfloat val)
1147 { return aluF2S(val)+32768; }
1148 static inline ALbyte aluF2B(ALfloat val)
1149 { return aluF2I25(val)>>17; }
1150 static inline ALubyte aluF2UB(ALfloat val)
1151 { return aluF2B(val)+128; }
1153 #define DECL_TEMPLATE(T, func) \
1154 static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1155 ALuint SamplesToDo, ALuint numchans) \
1157 ALuint i, j; \
1158 for(j = 0;j < numchans;j++) \
1160 const ALfloat *in = InBuffer[j]; \
1161 T *restrict out = (T*)OutBuffer + j; \
1162 for(i = 0;i < SamplesToDo;i++) \
1163 out[i*numchans] = func(in[i]); \
1167 DECL_TEMPLATE(ALfloat, aluF2F)
1168 DECL_TEMPLATE(ALuint, aluF2UI)
1169 DECL_TEMPLATE(ALint, aluF2I)
1170 DECL_TEMPLATE(ALushort, aluF2US)
1171 DECL_TEMPLATE(ALshort, aluF2S)
1172 DECL_TEMPLATE(ALubyte, aluF2UB)
1173 DECL_TEMPLATE(ALbyte, aluF2B)
1175 #undef DECL_TEMPLATE
1178 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1180 ALuint SamplesToDo;
1181 ALeffectslot **slot, **slot_end;
1182 ALvoice *voice, *voice_end;
1183 ALCcontext *ctx;
1184 FPUCtl oldMode;
1185 ALuint i, c;
1187 SetMixerFPUMode(&oldMode);
1189 while(size > 0)
1191 ALuint outchanoffset = 0;
1192 ALuint outchancount = device->NumChannels;
1194 IncrementRef(&device->MixCount);
1196 SamplesToDo = minu(size, BUFFERSIZE);
1197 for(c = 0;c < device->NumChannels;c++)
1198 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1199 if(device->Hrtf)
1201 outchanoffset = device->NumChannels;
1202 outchancount = 2;
1203 for(c = 0;c < outchancount;c++)
1204 memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat));
1207 V0(device->Backend,lock)();
1208 V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]);
1210 ctx = ATOMIC_LOAD(&device->ContextList);
1211 while(ctx)
1213 ALenum DeferUpdates = ctx->DeferUpdates;
1214 ALenum UpdateSources = AL_FALSE;
1216 if(!DeferUpdates)
1217 UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
1219 if(UpdateSources)
1220 CalcListenerParams(ctx->Listener);
1222 /* source processing */
1223 voice = ctx->Voices;
1224 voice_end = voice + ctx->VoiceCount;
1225 while(voice != voice_end)
1227 ALsource *source = voice->Source;
1228 if(!source) goto next;
1230 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1232 voice->Source = NULL;
1233 goto next;
1236 if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
1237 UpdateSources))
1238 voice->Update(voice, source, ctx);
1240 if(source->state != AL_PAUSED)
1241 MixSource(voice, source, device, SamplesToDo);
1242 next:
1243 voice++;
1246 /* effect slot processing */
1247 slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
1248 slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
1249 while(slot != slot_end)
1251 if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1252 V((*slot)->EffectState,update)(device, *slot);
1254 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1255 device->DryBuffer, device->NumChannels);
1257 for(i = 0;i < SamplesToDo;i++)
1258 (*slot)->WetBuffer[0][i] = 0.0f;
1260 slot++;
1263 ctx = ctx->next;
1266 slot = &device->DefaultSlot;
1267 if(*slot != NULL)
1269 if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1270 V((*slot)->EffectState,update)(device, *slot);
1272 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1273 device->DryBuffer, device->NumChannels);
1275 for(i = 0;i < SamplesToDo;i++)
1276 (*slot)->WetBuffer[0][i] = 0.0f;
1279 /* Increment the clock time. Every second's worth of samples is
1280 * converted and added to clock base so that large sample counts don't
1281 * overflow during conversion. This also guarantees an exact, stable
1282 * conversion. */
1283 device->SamplesDone += SamplesToDo;
1284 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1285 device->SamplesDone %= device->Frequency;
1286 V0(device->Backend,unlock)();
1288 if(device->Hrtf)
1290 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1291 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1292 for(c = 0;c < device->NumChannels;c++)
1293 HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], 0,
1294 device->Hrtf_Offset, 0, irsize, &device->Hrtf_Params[c],
1295 &device->Hrtf_State[c], SamplesToDo
1297 device->Hrtf_Offset += SamplesToDo;
1299 else if(device->Bs2b)
1301 /* Apply binaural/crossfeed filter */
1302 for(i = 0;i < SamplesToDo;i++)
1304 float samples[2];
1305 samples[0] = device->DryBuffer[0][i];
1306 samples[1] = device->DryBuffer[1][i];
1307 bs2b_cross_feed(device->Bs2b, samples);
1308 device->DryBuffer[0][i] = samples[0];
1309 device->DryBuffer[1][i] = samples[1];
1313 if(buffer)
1315 #define WRITE(T, a, b, c, d) do { \
1316 Write_##T((a), (b), (c), (d)); \
1317 buffer = (char*)buffer + (c)*(d)*sizeof(T); \
1318 } while(0)
1319 switch(device->FmtType)
1321 case DevFmtByte:
1322 WRITE(ALbyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1323 break;
1324 case DevFmtUByte:
1325 WRITE(ALubyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1326 break;
1327 case DevFmtShort:
1328 WRITE(ALshort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1329 break;
1330 case DevFmtUShort:
1331 WRITE(ALushort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1332 break;
1333 case DevFmtInt:
1334 WRITE(ALint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1335 break;
1336 case DevFmtUInt:
1337 WRITE(ALuint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1338 break;
1339 case DevFmtFloat:
1340 WRITE(ALfloat, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1341 break;
1343 #undef WRITE
1346 size -= SamplesToDo;
1347 IncrementRef(&device->MixCount);
1350 RestoreFPUMode(&oldMode);
1354 ALvoid aluHandleDisconnect(ALCdevice *device)
1356 ALCcontext *Context;
1358 device->Connected = ALC_FALSE;
1360 Context = ATOMIC_LOAD(&device->ContextList);
1361 while(Context)
1363 ALvoice *voice, *voice_end;
1365 voice = Context->Voices;
1366 voice_end = voice + Context->VoiceCount;
1367 while(voice != voice_end)
1369 ALsource *source = voice->Source;
1370 voice->Source = NULL;
1372 if(source && source->state == AL_PLAYING)
1374 source->state = AL_STOPPED;
1375 ATOMIC_STORE(&source->current_buffer, NULL);
1376 source->position = 0;
1377 source->position_fraction = 0;
1380 voice++;
1382 Context->VoiceCount = 0;
1384 Context = Context->next;