Update a couple comments
[openal-soft.git] / Alc / ALu.c
blob03df0499c5500b868409734834bcbdbc68b57144
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);
96 /* NOTE: HRTF is set up a bit special in the device. By default, the device's
97 * DryBuffer, NumChannels, ChannelName, and Channel fields correspond to the
98 * output mixing format, and the DryBuffer is then converted and written to the
99 * backend's audio buffer.
101 * With HRTF, these fields correspond to a virtual format (typically B-Format),
102 * and the actual output is stored in DryBuffer[NumChannels] for the left
103 * channel and DryBuffer[NumChannels+1] for the right. As a final output step,
104 * the virtual channels will have HRTF applied and written to the actual
105 * output. Things like effects and B-Format decoding will want to write to the
106 * virtual channels so that they can be mixed with HRTF in full 3D.
108 * Sources that get mixed using HRTF directly (or that want to skip HRTF
109 * completely) will need to offset the output buffer so that they skip the
110 * virtual output and write to the actual output channels. This is the reason
111 * you'll see
113 * voice->Direct.OutBuffer += voice->Direct.OutChannels;
114 * voice->Direct.OutChannels = 2;
116 * at various points in the code where HRTF is explicitly used or bypassed.
119 static inline HrtfMixerFunc SelectHrtfMixer(void)
121 #ifdef HAVE_SSE
122 if((CPUCapFlags&CPU_CAP_SSE))
123 return MixHrtf_SSE;
124 #endif
125 #ifdef HAVE_NEON
126 if((CPUCapFlags&CPU_CAP_NEON))
127 return MixHrtf_Neon;
128 #endif
130 return MixHrtf_C;
134 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
136 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
137 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
138 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
141 static inline ALfloat aluDotproduct(const aluVector *vec1, const aluVector *vec2)
143 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
146 static inline void aluNormalize(ALfloat *vec)
148 ALfloat lengthsqr = vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2];
149 if(lengthsqr > 0.0f)
151 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
152 vec[0] *= inv_length;
153 vec[1] *= inv_length;
154 vec[2] *= inv_length;
158 static inline ALvoid aluMatrixVector(aluVector *vec, const aluMatrix *mtx)
160 aluVector v = *vec;
162 vec->v[0] = v.v[0]*mtx->m[0][0] + v.v[1]*mtx->m[1][0] + v.v[2]*mtx->m[2][0] + v.v[3]*mtx->m[3][0];
163 vec->v[1] = v.v[0]*mtx->m[0][1] + v.v[1]*mtx->m[1][1] + v.v[2]*mtx->m[2][1] + v.v[3]*mtx->m[3][1];
164 vec->v[2] = v.v[0]*mtx->m[0][2] + v.v[1]*mtx->m[1][2] + v.v[2]*mtx->m[2][2] + v.v[3]*mtx->m[3][2];
165 vec->v[3] = v.v[0]*mtx->m[0][3] + v.v[1]*mtx->m[1][3] + v.v[2]*mtx->m[2][3] + v.v[3]*mtx->m[3][3];
169 /* Calculates the fade time from the changes in gain and listener to source
170 * angle between updates. The result is a the time, in seconds, for the
171 * transition to complete.
173 static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *olddir, const aluVector *newdir)
175 ALfloat gainChange, angleChange, change;
177 /* Calculate the normalized dB gain change. */
178 newGain = maxf(newGain, 0.0001f);
179 oldGain = maxf(oldGain, 0.0001f);
180 gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
182 /* Calculate the angle change only when there is enough gain to notice it. */
183 angleChange = 0.0f;
184 if(gainChange > 0.0001f || newGain > 0.0001f)
186 /* No angle change when the directions are equal or degenerate (when
187 * both have zero length).
189 if(newdir->v[0] != olddir->v[0] || newdir->v[1] != olddir->v[1] || newdir->v[2] != olddir->v[2])
191 ALfloat dotp = aluDotproduct(olddir, newdir);
192 angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
196 /* Use the largest of the two changes, and apply a significance shaping
197 * function to it. The result is then scaled to cover a 15ms transition
198 * range.
200 change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
201 return minf(change, 1.0f) * 0.015f;
205 static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps)
207 ALfloat delta;
208 ALuint i, j;
210 if(steps < 2)
212 for(i = 0;i < num_chans;i++)
214 MixGains *gains = params->Gains[i];
215 for(j = 0;j < params->OutChannels;j++)
217 gains[j].Current = gains[j].Target;
218 gains[j].Step = 0.0f;
221 params->Counter = 0;
222 return;
225 delta = 1.0f / (ALfloat)steps;
226 for(i = 0;i < num_chans;i++)
228 MixGains *gains = params->Gains[i];
229 for(j = 0;j < params->OutChannels;j++)
231 ALfloat diff = gains[j].Target - gains[j].Current;
232 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
233 gains[j].Step = diff * delta;
234 else
235 gains[j].Step = 0.0f;
238 params->Counter = steps;
241 static void UpdateWetStepping(SendParams *params, ALuint steps)
243 ALfloat delta;
245 if(steps < 2)
247 params->Gain.Current = params->Gain.Target;
248 params->Gain.Step = 0.0f;
250 params->Counter = 0;
251 return;
254 delta = 1.0f / (ALfloat)steps;
256 ALfloat diff = params->Gain.Target - params->Gain.Current;
257 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
258 params->Gain.Step = diff * delta;
259 else
260 params->Gain.Step = 0.0f;
262 params->Counter = steps;
266 static ALvoid CalcListenerParams(ALlistener *Listener)
268 ALfloat N[3], V[3], U[3];
269 aluVector P;
271 /* AT then UP */
272 N[0] = Listener->Forward[0];
273 N[1] = Listener->Forward[1];
274 N[2] = Listener->Forward[2];
275 aluNormalize(N);
276 V[0] = Listener->Up[0];
277 V[1] = Listener->Up[1];
278 V[2] = Listener->Up[2];
279 aluNormalize(V);
280 /* Build and normalize right-vector */
281 aluCrossproduct(N, V, U);
282 aluNormalize(U);
284 P = Listener->Position;
286 aluMatrixSet(&Listener->Params.Matrix,
287 U[0], V[0], -N[0], 0.0f,
288 U[1], V[1], -N[1], 0.0f,
289 U[2], V[2], -N[2], 0.0f,
290 0.0f, 0.0f, 0.0f, 1.0f
292 aluMatrixVector(&P, &Listener->Params.Matrix);
293 aluMatrixSetRow(&Listener->Params.Matrix, 3, -P.v[0], -P.v[1], -P.v[2], 1.0f);
295 Listener->Params.Velocity = Listener->Velocity;
296 aluMatrixVector(&Listener->Params.Velocity, &Listener->Params.Matrix);
299 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
301 static const struct ChanMap MonoMap[1] = {
302 { FrontCenter, 0.0f, 0.0f }
303 }, StereoMap[2] = {
304 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
305 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
306 }, StereoWideMap[2] = {
307 { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
308 { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
309 }, RearMap[2] = {
310 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
311 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
312 }, QuadMap[4] = {
313 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
314 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
315 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
316 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
317 }, X51Map[6] = {
318 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
319 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
320 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
321 { LFE, 0.0f, 0.0f },
322 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
323 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
324 }, X61Map[7] = {
325 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
326 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
327 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
328 { LFE, 0.0f, 0.0f },
329 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
330 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
331 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
332 }, X71Map[8] = {
333 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
334 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
335 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
336 { LFE, 0.0f, 0.0f },
337 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
338 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
339 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
340 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
343 ALCdevice *Device = ALContext->Device;
344 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
345 ALbufferlistitem *BufferListItem;
346 enum FmtChannels Channels;
347 ALfloat DryGain, DryGainHF, DryGainLF;
348 ALfloat WetGain[MAX_SENDS];
349 ALfloat WetGainHF[MAX_SENDS];
350 ALfloat WetGainLF[MAX_SENDS];
351 ALuint NumSends, Frequency;
352 ALboolean Relative;
353 const struct ChanMap *chans = NULL;
354 ALuint num_channels = 0;
355 ALboolean DirectChannels;
356 ALboolean isbformat = AL_FALSE;
357 ALfloat Pitch;
358 ALuint i, j, c;
360 /* Get device properties */
361 NumSends = Device->NumAuxSends;
362 Frequency = Device->Frequency;
364 /* Get listener properties */
365 ListenerGain = ALContext->Listener->Gain;
367 /* Get source properties */
368 SourceVolume = ALSource->Gain;
369 MinVolume = ALSource->MinGain;
370 MaxVolume = ALSource->MaxGain;
371 Pitch = ALSource->Pitch;
372 Relative = ALSource->HeadRelative;
373 DirectChannels = ALSource->DirectChannels;
375 voice->Direct.OutBuffer = Device->DryBuffer;
376 voice->Direct.OutChannels = Device->NumChannels;
377 for(i = 0;i < NumSends;i++)
379 ALeffectslot *Slot = ALSource->Send[i].Slot;
380 if(!Slot && i == 0)
381 Slot = Device->DefaultSlot;
382 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
383 voice->Send[i].OutBuffer = NULL;
384 else
385 voice->Send[i].OutBuffer = Slot->WetBuffer;
388 /* Calculate the stepping value */
389 Channels = FmtMono;
390 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
391 while(BufferListItem != NULL)
393 ALbuffer *ALBuffer;
394 if((ALBuffer=BufferListItem->buffer) != NULL)
396 Pitch = Pitch * ALBuffer->Frequency / Frequency;
397 if(Pitch > (ALfloat)MAX_PITCH)
398 voice->Step = MAX_PITCH<<FRACTIONBITS;
399 else
401 voice->Step = fastf2i(Pitch*FRACTIONONE);
402 if(voice->Step == 0)
403 voice->Step = 1;
406 Channels = ALBuffer->FmtChannels;
407 break;
409 BufferListItem = BufferListItem->next;
412 /* Calculate gains */
413 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
414 DryGain *= ALSource->Direct.Gain * ListenerGain;
415 DryGainHF = ALSource->Direct.GainHF;
416 DryGainLF = ALSource->Direct.GainLF;
417 for(i = 0;i < NumSends;i++)
419 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
420 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
421 WetGainHF[i] = ALSource->Send[i].GainHF;
422 WetGainLF[i] = ALSource->Send[i].GainLF;
425 switch(Channels)
427 case FmtMono:
428 chans = MonoMap;
429 num_channels = 1;
430 break;
432 case FmtStereo:
433 /* HACK: Place the stereo channels at +/-90 degrees when using non-
434 * HRTF stereo output. This helps reduce the "monoization" caused
435 * by them panning towards the center. */
436 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
437 chans = StereoWideMap;
438 else
439 chans = StereoMap;
440 num_channels = 2;
441 break;
443 case FmtRear:
444 chans = RearMap;
445 num_channels = 2;
446 break;
448 case FmtQuad:
449 chans = QuadMap;
450 num_channels = 4;
451 break;
453 case FmtX51:
454 chans = X51Map;
455 num_channels = 6;
456 break;
458 case FmtX61:
459 chans = X61Map;
460 num_channels = 7;
461 break;
463 case FmtX71:
464 chans = X71Map;
465 num_channels = 8;
466 break;
468 case FmtBFormat2D:
469 num_channels = 3;
470 isbformat = AL_TRUE;
471 DirectChannels = AL_FALSE;
472 break;
474 case FmtBFormat3D:
475 num_channels = 4;
476 isbformat = AL_TRUE;
477 DirectChannels = AL_FALSE;
478 break;
481 if(isbformat)
483 ALfloat N[3], V[3], U[3];
484 aluMatrix matrix;
486 /* AT then UP */
487 N[0] = ALSource->Orientation[0][0];
488 N[1] = ALSource->Orientation[0][1];
489 N[2] = ALSource->Orientation[0][2];
490 aluNormalize(N);
491 V[0] = ALSource->Orientation[1][0];
492 V[1] = ALSource->Orientation[1][1];
493 V[2] = ALSource->Orientation[1][2];
494 aluNormalize(V);
495 if(!Relative)
497 const aluMatrix *lmatrix = &ALContext->Listener->Params.Matrix;
498 aluVector at, up;
499 aluVectorSet(&at, N[0], N[1], N[2], 0.0f);
500 aluVectorSet(&up, V[0], V[1], V[2], 0.0f);
501 aluMatrixVector(&at, lmatrix);
502 aluMatrixVector(&up, lmatrix);
503 N[0] = at.v[0]; N[1] = at.v[1]; N[2] = at.v[2];
504 V[0] = up.v[0]; V[1] = up.v[1]; V[2] = up.v[2];
506 /* Build and normalize right-vector */
507 aluCrossproduct(N, V, U);
508 aluNormalize(U);
510 aluMatrixSet(&matrix,
511 1.0f, 0.0f, 0.0f, 0.0f,
512 0.0f, -N[2], -N[0], N[1],
513 0.0f, U[2], U[0], -U[1],
514 0.0f, -V[2], -V[0], V[1]
517 for(c = 0;c < num_channels;c++)
519 MixGains *gains = voice->Direct.Gains[c];
520 ALfloat Target[MAX_OUTPUT_CHANNELS];
522 ComputeBFormatGains(Device, matrix.m[c], DryGain, Target);
523 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
524 gains[i].Target = Target[i];
526 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
527 voice->Direct.Moving = AL_TRUE;
529 voice->IsHrtf = AL_FALSE;
530 for(i = 0;i < NumSends;i++)
531 WetGain[i] *= 1.4142f;
533 else if(DirectChannels != AL_FALSE)
535 if(Device->Hrtf)
537 voice->Direct.OutBuffer += voice->Direct.OutChannels;
538 voice->Direct.OutChannels = 2;
539 for(c = 0;c < num_channels;c++)
541 MixGains *gains = voice->Direct.Gains[c];
543 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
544 gains[j].Target = 0.0f;
546 if(chans[c].channel == FrontLeft)
547 gains[0].Target = DryGain;
548 else if(chans[c].channel == FrontRight)
549 gains[1].Target = DryGain;
552 else for(c = 0;c < num_channels;c++)
554 MixGains *gains = voice->Direct.Gains[c];
555 int idx;
557 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
558 gains[j].Target = 0.0f;
559 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
560 gains[idx].Target = DryGain;
562 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
563 voice->Direct.Moving = AL_TRUE;
565 voice->IsHrtf = AL_FALSE;
567 else if(Device->Hrtf_Mode == FullHrtf)
569 voice->Direct.OutBuffer += voice->Direct.OutChannels;
570 voice->Direct.OutChannels = 2;
571 for(c = 0;c < num_channels;c++)
573 if(chans[c].channel == LFE)
575 /* Skip LFE */
576 voice->Direct.Hrtf[c].Params.Delay[0] = 0;
577 voice->Direct.Hrtf[c].Params.Delay[1] = 0;
578 for(i = 0;i < HRIR_LENGTH;i++)
580 voice->Direct.Hrtf[c].Params.Coeffs[i][0] = 0.0f;
581 voice->Direct.Hrtf[c].Params.Coeffs[i][1] = 0.0f;
584 else
586 /* Get the static HRIR coefficients and delays for this
587 * channel. */
588 GetLerpedHrtfCoeffs(Device->Hrtf,
589 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
590 voice->Direct.Hrtf[c].Params.Coeffs,
591 voice->Direct.Hrtf[c].Params.Delay);
594 voice->Direct.Counter = 0;
595 voice->Direct.Moving = AL_TRUE;
597 voice->IsHrtf = AL_TRUE;
599 else
601 for(c = 0;c < num_channels;c++)
603 MixGains *gains = voice->Direct.Gains[c];
604 ALfloat Target[MAX_OUTPUT_CHANNELS];
606 /* Special-case LFE */
607 if(chans[c].channel == LFE)
609 int idx;
610 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
611 gains[i].Target = 0.0f;
612 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
613 gains[idx].Target = DryGain;
614 continue;
617 ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
618 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
619 gains[i].Target = Target[i];
621 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
622 voice->Direct.Moving = AL_TRUE;
624 voice->IsHrtf = AL_FALSE;
626 for(i = 0;i < NumSends;i++)
628 voice->Send[i].Gain.Target = WetGain[i];
629 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
630 voice->Send[i].Moving = AL_TRUE;
634 ALfloat gainhf = maxf(0.01f, DryGainHF);
635 ALfloat gainlf = maxf(0.01f, DryGainLF);
636 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
637 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
638 for(c = 0;c < num_channels;c++)
640 voice->Direct.Filters[c].ActiveType = AF_None;
641 if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
642 if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
643 ALfilterState_setParams(
644 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
645 hfscale, 0.0f
647 ALfilterState_setParams(
648 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
649 lfscale, 0.0f
653 for(i = 0;i < NumSends;i++)
655 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
656 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
657 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
658 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
659 for(c = 0;c < num_channels;c++)
661 voice->Send[i].Filters[c].ActiveType = AF_None;
662 if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
663 if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
664 ALfilterState_setParams(
665 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
666 hfscale, 0.0f
668 ALfilterState_setParams(
669 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
670 lfscale, 0.0f
676 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
678 ALCdevice *Device = ALContext->Device;
679 aluVector Position, Velocity, Direction, SourceToListener;
680 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
681 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
682 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
683 ALfloat DopplerFactor, SpeedOfSound;
684 ALfloat AirAbsorptionFactor;
685 ALfloat RoomAirAbsorption[MAX_SENDS];
686 ALbufferlistitem *BufferListItem;
687 ALfloat Attenuation;
688 ALfloat RoomAttenuation[MAX_SENDS];
689 ALfloat MetersPerUnit;
690 ALfloat RoomRolloffBase;
691 ALfloat RoomRolloff[MAX_SENDS];
692 ALfloat DecayDistance[MAX_SENDS];
693 ALfloat DryGain;
694 ALfloat DryGainHF;
695 ALfloat DryGainLF;
696 ALboolean DryGainHFAuto;
697 ALfloat WetGain[MAX_SENDS];
698 ALfloat WetGainHF[MAX_SENDS];
699 ALfloat WetGainLF[MAX_SENDS];
700 ALboolean WetGainAuto;
701 ALboolean WetGainHFAuto;
702 ALfloat Pitch;
703 ALuint Frequency;
704 ALint NumSends;
705 ALint i, j;
707 DryGainHF = 1.0f;
708 DryGainLF = 1.0f;
709 for(i = 0;i < MAX_SENDS;i++)
711 WetGainHF[i] = 1.0f;
712 WetGainLF[i] = 1.0f;
715 /* Get context/device properties */
716 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
717 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
718 NumSends = Device->NumAuxSends;
719 Frequency = Device->Frequency;
721 /* Get listener properties */
722 ListenerGain = ALContext->Listener->Gain;
723 MetersPerUnit = ALContext->Listener->MetersPerUnit;
725 /* Get source properties */
726 SourceVolume = ALSource->Gain;
727 MinVolume = ALSource->MinGain;
728 MaxVolume = ALSource->MaxGain;
729 Pitch = ALSource->Pitch;
730 Position = ALSource->Position;
731 Direction = ALSource->Direction;
732 Velocity = ALSource->Velocity;
733 MinDist = ALSource->RefDistance;
734 MaxDist = ALSource->MaxDistance;
735 Rolloff = ALSource->RollOffFactor;
736 InnerAngle = ALSource->InnerAngle;
737 OuterAngle = ALSource->OuterAngle;
738 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
739 DryGainHFAuto = ALSource->DryGainHFAuto;
740 WetGainAuto = ALSource->WetGainAuto;
741 WetGainHFAuto = ALSource->WetGainHFAuto;
742 RoomRolloffBase = ALSource->RoomRolloffFactor;
744 voice->Direct.OutBuffer = Device->DryBuffer;
745 voice->Direct.OutChannels = Device->NumChannels;
746 for(i = 0;i < NumSends;i++)
748 ALeffectslot *Slot = ALSource->Send[i].Slot;
750 if(!Slot && i == 0)
751 Slot = Device->DefaultSlot;
752 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
754 Slot = NULL;
755 RoomRolloff[i] = 0.0f;
756 DecayDistance[i] = 0.0f;
757 RoomAirAbsorption[i] = 1.0f;
759 else if(Slot->AuxSendAuto)
761 RoomRolloff[i] = RoomRolloffBase;
762 if(IsReverbEffect(Slot->EffectType))
764 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
765 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
766 SPEEDOFSOUNDMETRESPERSEC;
767 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
769 else
771 DecayDistance[i] = 0.0f;
772 RoomAirAbsorption[i] = 1.0f;
775 else
777 /* If the slot's auxiliary send auto is off, the data sent to the
778 * effect slot is the same as the dry path, sans filter effects */
779 RoomRolloff[i] = Rolloff;
780 DecayDistance[i] = 0.0f;
781 RoomAirAbsorption[i] = AIRABSORBGAINHF;
784 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
785 voice->Send[i].OutBuffer = NULL;
786 else
787 voice->Send[i].OutBuffer = Slot->WetBuffer;
790 /* Transform source to listener space (convert to head relative) */
791 if(ALSource->HeadRelative == AL_FALSE)
793 const aluMatrix *Matrix = &ALContext->Listener->Params.Matrix;
794 /* Transform source vectors */
795 aluMatrixVector(&Position, Matrix);
796 aluMatrixVector(&Velocity, Matrix);
797 aluMatrixVector(&Direction, Matrix);
799 else
801 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
802 /* Offset the source velocity to be relative of the listener velocity */
803 Velocity.v[0] += lvelocity->v[0];
804 Velocity.v[1] += lvelocity->v[1];
805 Velocity.v[2] += lvelocity->v[2];
808 SourceToListener.v[0] = -Position.v[0];
809 SourceToListener.v[1] = -Position.v[1];
810 SourceToListener.v[2] = -Position.v[2];
811 SourceToListener.v[3] = 0.0f;
812 aluNormalize(SourceToListener.v);
813 aluNormalize(Direction.v);
815 /* Calculate distance attenuation */
816 Distance = sqrtf(aluDotproduct(&Position, &Position));
817 ClampedDist = Distance;
819 Attenuation = 1.0f;
820 for(i = 0;i < NumSends;i++)
821 RoomAttenuation[i] = 1.0f;
822 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
823 ALContext->DistanceModel)
825 case InverseDistanceClamped:
826 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
827 if(MaxDist < MinDist)
828 break;
829 /*fall-through*/
830 case InverseDistance:
831 if(MinDist > 0.0f)
833 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
834 if(dist > 0.0f) Attenuation = MinDist / dist;
835 for(i = 0;i < NumSends;i++)
837 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
838 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
841 break;
843 case LinearDistanceClamped:
844 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
845 if(MaxDist < MinDist)
846 break;
847 /*fall-through*/
848 case LinearDistance:
849 if(MaxDist != MinDist)
851 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
852 Attenuation = maxf(Attenuation, 0.0f);
853 for(i = 0;i < NumSends;i++)
855 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
856 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
859 break;
861 case ExponentDistanceClamped:
862 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
863 if(MaxDist < MinDist)
864 break;
865 /*fall-through*/
866 case ExponentDistance:
867 if(ClampedDist > 0.0f && MinDist > 0.0f)
869 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
870 for(i = 0;i < NumSends;i++)
871 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
873 break;
875 case DisableDistance:
876 ClampedDist = MinDist;
877 break;
880 /* Source Gain + Attenuation */
881 DryGain = SourceVolume * Attenuation;
882 for(i = 0;i < NumSends;i++)
883 WetGain[i] = SourceVolume * RoomAttenuation[i];
885 /* Distance-based air absorption */
886 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
888 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
889 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
890 for(i = 0;i < NumSends;i++)
891 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
894 if(WetGainAuto)
896 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
898 /* Apply a decay-time transformation to the wet path, based on the
899 * attenuation of the dry path.
901 * Using the apparent distance, based on the distance attenuation, the
902 * initial decay of the reverb effect is calculated and applied to the
903 * wet path.
905 for(i = 0;i < NumSends;i++)
907 if(DecayDistance[i] > 0.0f)
908 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
912 /* Calculate directional soundcones */
913 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
914 if(Angle > InnerAngle && Angle <= OuterAngle)
916 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
917 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
918 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
920 else if(Angle > OuterAngle)
922 ConeVolume = ALSource->OuterGain;
923 ConeHF = ALSource->OuterGainHF;
925 else
927 ConeVolume = 1.0f;
928 ConeHF = 1.0f;
931 DryGain *= ConeVolume;
932 if(WetGainAuto)
934 for(i = 0;i < NumSends;i++)
935 WetGain[i] *= ConeVolume;
937 if(DryGainHFAuto)
938 DryGainHF *= ConeHF;
939 if(WetGainHFAuto)
941 for(i = 0;i < NumSends;i++)
942 WetGainHF[i] *= ConeHF;
945 /* Clamp to Min/Max Gain */
946 DryGain = clampf(DryGain, MinVolume, MaxVolume);
947 for(i = 0;i < NumSends;i++)
948 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
950 /* Apply gain and frequency filters */
951 DryGain *= ALSource->Direct.Gain * ListenerGain;
952 DryGainHF *= ALSource->Direct.GainHF;
953 DryGainLF *= ALSource->Direct.GainLF;
954 for(i = 0;i < NumSends;i++)
956 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
957 WetGainHF[i] *= ALSource->Send[i].GainHF;
958 WetGainLF[i] *= ALSource->Send[i].GainLF;
961 /* Calculate velocity-based doppler effect */
962 if(DopplerFactor > 0.0f)
964 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
965 ALfloat VSS, VLS;
967 if(SpeedOfSound < 1.0f)
969 DopplerFactor *= 1.0f/SpeedOfSound;
970 SpeedOfSound = 1.0f;
973 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
974 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
976 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
977 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
980 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
981 while(BufferListItem != NULL)
983 ALbuffer *ALBuffer;
984 if((ALBuffer=BufferListItem->buffer) != NULL)
986 /* Calculate fixed-point stepping value, based on the pitch, buffer
987 * frequency, and output frequency. */
988 Pitch = Pitch * ALBuffer->Frequency / Frequency;
989 if(Pitch > (ALfloat)MAX_PITCH)
990 voice->Step = MAX_PITCH<<FRACTIONBITS;
991 else
993 voice->Step = fastf2i(Pitch*FRACTIONONE);
994 if(voice->Step == 0)
995 voice->Step = 1;
998 break;
1000 BufferListItem = BufferListItem->next;
1003 if(Device->Hrtf_Mode == FullHrtf)
1005 /* Use a binaural HRTF algorithm for stereo headphone playback */
1006 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
1007 ALfloat ev = 0.0f, az = 0.0f;
1008 ALfloat radius = ALSource->Radius;
1009 ALfloat dirfact = 1.0f;
1011 voice->Direct.OutBuffer += voice->Direct.OutChannels;
1012 voice->Direct.OutChannels = 2;
1014 if(Distance > FLT_EPSILON)
1016 ALfloat invlen = 1.0f/Distance;
1017 dir.v[0] = Position.v[0] * invlen;
1018 dir.v[1] = Position.v[1] * invlen;
1019 dir.v[2] = Position.v[2] * invlen * ZScale;
1021 /* Calculate elevation and azimuth only when the source is not at
1022 * the listener. This prevents +0 and -0 Z from producing
1023 * inconsistent panning. Also, clamp Y in case FP precision errors
1024 * cause it to land outside of -1..+1. */
1025 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1026 az = atan2f(dir.v[0], -dir.v[2]);
1028 if(radius > Distance)
1029 dirfact *= Distance / radius;
1031 /* Check to see if the HRIR is already moving. */
1032 if(voice->Direct.Moving)
1034 ALfloat delta;
1035 delta = CalcFadeTime(voice->Direct.LastGain, DryGain,
1036 &voice->Direct.LastDir, &dir);
1037 /* If the delta is large enough, get the moving HRIR target
1038 * coefficients, target delays, steppping values, and counter. */
1039 if(delta > 0.000015f)
1041 ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
1042 ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
1043 voice->Direct.Hrtf[0].Params.Coeffs, voice->Direct.Hrtf[0].Params.Delay,
1044 voice->Direct.Hrtf[0].Params.CoeffStep, voice->Direct.Hrtf[0].Params.DelayStep
1046 voice->Direct.Counter = counter;
1047 voice->Direct.LastGain = DryGain;
1048 voice->Direct.LastDir = dir;
1051 else
1053 /* Get the initial (static) HRIR coefficients and delays. */
1054 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1055 voice->Direct.Hrtf[0].Params.Coeffs,
1056 voice->Direct.Hrtf[0].Params.Delay);
1057 voice->Direct.Counter = 0;
1058 voice->Direct.Moving = AL_TRUE;
1059 voice->Direct.LastGain = DryGain;
1060 voice->Direct.LastDir = dir;
1063 voice->IsHrtf = AL_TRUE;
1065 else
1067 MixGains *gains = voice->Direct.Gains[0];
1068 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1069 ALfloat radius = ALSource->Radius;
1070 ALfloat Target[MAX_OUTPUT_CHANNELS];
1072 /* Normalize the length, and compute panned gains. */
1073 if(Distance > FLT_EPSILON || radius > FLT_EPSILON)
1075 ALfloat invlen = 1.0f/maxf(Distance, radius);
1076 dir[0] = Position.v[0] * invlen;
1077 dir[1] = Position.v[1] * invlen;
1078 dir[2] = Position.v[2] * invlen * ZScale;
1080 ComputeDirectionalGains(Device, dir, DryGain, Target);
1082 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
1083 gains[j].Target = Target[j];
1084 UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0));
1085 voice->Direct.Moving = AL_TRUE;
1087 voice->IsHrtf = AL_FALSE;
1089 for(i = 0;i < NumSends;i++)
1091 voice->Send[i].Gain.Target = WetGain[i];
1092 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
1093 voice->Send[i].Moving = AL_TRUE;
1097 ALfloat gainhf = maxf(0.01f, DryGainHF);
1098 ALfloat gainlf = maxf(0.01f, DryGainLF);
1099 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1100 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1101 voice->Direct.Filters[0].ActiveType = AF_None;
1102 if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1103 if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1104 ALfilterState_setParams(
1105 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1106 hfscale, 0.0f
1108 ALfilterState_setParams(
1109 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1110 lfscale, 0.0f
1113 for(i = 0;i < NumSends;i++)
1115 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
1116 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
1117 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1118 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1119 voice->Send[i].Filters[0].ActiveType = AF_None;
1120 if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1121 if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1122 ALfilterState_setParams(
1123 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1124 hfscale, 0.0f
1126 ALfilterState_setParams(
1127 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1128 lfscale, 0.0f
1134 static inline ALint aluF2I25(ALfloat val)
1136 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1137 if(fabsf(val) > 1.0f)
1138 val = (ALfloat)((0.0f < val) - (val < 0.0f));
1139 /* Convert to a signed integer, between -16777215 and +16777215. */
1140 return fastf2i(val*16777215.0f);
1143 static inline ALfloat aluF2F(ALfloat val)
1144 { return val; }
1145 static inline ALint aluF2I(ALfloat val)
1146 { return aluF2I25(val)<<7; }
1147 static inline ALuint aluF2UI(ALfloat val)
1148 { return aluF2I(val)+2147483648u; }
1149 static inline ALshort aluF2S(ALfloat val)
1150 { return aluF2I25(val)>>9; }
1151 static inline ALushort aluF2US(ALfloat val)
1152 { return aluF2S(val)+32768; }
1153 static inline ALbyte aluF2B(ALfloat val)
1154 { return aluF2I25(val)>>17; }
1155 static inline ALubyte aluF2UB(ALfloat val)
1156 { return aluF2B(val)+128; }
1158 #define DECL_TEMPLATE(T, func) \
1159 static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1160 ALuint SamplesToDo, ALuint numchans) \
1162 ALuint i, j; \
1163 for(j = 0;j < numchans;j++) \
1165 const ALfloat *in = InBuffer[j]; \
1166 T *restrict out = (T*)OutBuffer + j; \
1167 for(i = 0;i < SamplesToDo;i++) \
1168 out[i*numchans] = func(in[i]); \
1172 DECL_TEMPLATE(ALfloat, aluF2F)
1173 DECL_TEMPLATE(ALuint, aluF2UI)
1174 DECL_TEMPLATE(ALint, aluF2I)
1175 DECL_TEMPLATE(ALushort, aluF2US)
1176 DECL_TEMPLATE(ALshort, aluF2S)
1177 DECL_TEMPLATE(ALubyte, aluF2UB)
1178 DECL_TEMPLATE(ALbyte, aluF2B)
1180 #undef DECL_TEMPLATE
1183 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1185 ALuint SamplesToDo;
1186 ALeffectslot **slot, **slot_end;
1187 ALvoice *voice, *voice_end;
1188 ALCcontext *ctx;
1189 FPUCtl oldMode;
1190 ALuint i, c;
1192 SetMixerFPUMode(&oldMode);
1194 while(size > 0)
1196 ALfloat (*OutBuffer)[BUFFERSIZE];
1197 ALuint OutChannels;
1199 IncrementRef(&device->MixCount);
1201 OutBuffer = device->DryBuffer;
1202 OutChannels = device->NumChannels;
1204 SamplesToDo = minu(size, BUFFERSIZE);
1205 for(c = 0;c < OutChannels;c++)
1206 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1207 if(device->Hrtf)
1209 /* Set OutBuffer/OutChannels to correspond to the actual output
1210 * with HRTF. Make sure to clear them too. */
1211 OutBuffer += OutChannels;
1212 OutChannels = 2;
1213 for(c = 0;c < OutChannels;c++)
1214 memset(OutBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1217 V0(device->Backend,lock)();
1218 V(device->Synth,process)(SamplesToDo, OutBuffer, OutChannels);
1220 ctx = ATOMIC_LOAD(&device->ContextList);
1221 while(ctx)
1223 ALenum DeferUpdates = ctx->DeferUpdates;
1224 ALenum UpdateSources = AL_FALSE;
1226 if(!DeferUpdates)
1227 UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
1229 if(UpdateSources)
1230 CalcListenerParams(ctx->Listener);
1232 /* source processing */
1233 voice = ctx->Voices;
1234 voice_end = voice + ctx->VoiceCount;
1235 while(voice != voice_end)
1237 ALsource *source = voice->Source;
1238 if(!source) goto next;
1240 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1242 voice->Source = NULL;
1243 goto next;
1246 if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
1247 UpdateSources))
1248 voice->Update(voice, source, ctx);
1250 if(source->state != AL_PAUSED)
1251 MixSource(voice, source, device, SamplesToDo);
1252 next:
1253 voice++;
1256 /* effect slot processing */
1257 slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
1258 slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
1259 while(slot != slot_end)
1261 if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1262 V((*slot)->EffectState,update)(device, *slot);
1264 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1265 device->DryBuffer, device->NumChannels);
1267 for(i = 0;i < SamplesToDo;i++)
1268 (*slot)->WetBuffer[0][i] = 0.0f;
1270 slot++;
1273 ctx = ctx->next;
1276 slot = &device->DefaultSlot;
1277 if(*slot != NULL)
1279 if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1280 V((*slot)->EffectState,update)(device, *slot);
1282 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1283 device->DryBuffer, device->NumChannels);
1285 for(i = 0;i < SamplesToDo;i++)
1286 (*slot)->WetBuffer[0][i] = 0.0f;
1289 /* Increment the clock time. Every second's worth of samples is
1290 * converted and added to clock base so that large sample counts don't
1291 * overflow during conversion. This also guarantees an exact, stable
1292 * conversion. */
1293 device->SamplesDone += SamplesToDo;
1294 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1295 device->SamplesDone %= device->Frequency;
1296 V0(device->Backend,unlock)();
1298 if(device->Hrtf)
1300 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1301 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1302 for(c = 0;c < device->NumChannels;c++)
1303 HrtfMix(OutBuffer, device->DryBuffer[c], 0, device->Hrtf_Offset,
1304 0, irsize, &device->Hrtf_Params[c], &device->Hrtf_State[c],
1305 SamplesToDo
1307 device->Hrtf_Offset += SamplesToDo;
1309 else if(device->Bs2b)
1311 /* Apply binaural/crossfeed filter */
1312 for(i = 0;i < SamplesToDo;i++)
1314 float samples[2];
1315 samples[0] = device->DryBuffer[0][i];
1316 samples[1] = device->DryBuffer[1][i];
1317 bs2b_cross_feed(device->Bs2b, samples);
1318 device->DryBuffer[0][i] = samples[0];
1319 device->DryBuffer[1][i] = samples[1];
1323 if(buffer)
1325 #define WRITE(T, a, b, c, d) do { \
1326 Write_##T((a), (b), (c), (d)); \
1327 buffer = (T*)buffer + (c)*(d); \
1328 } while(0)
1329 switch(device->FmtType)
1331 case DevFmtByte:
1332 WRITE(ALbyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1333 break;
1334 case DevFmtUByte:
1335 WRITE(ALubyte, OutBuffer, buffer, SamplesToDo, OutChannels);
1336 break;
1337 case DevFmtShort:
1338 WRITE(ALshort, OutBuffer, buffer, SamplesToDo, OutChannels);
1339 break;
1340 case DevFmtUShort:
1341 WRITE(ALushort, OutBuffer, buffer, SamplesToDo, OutChannels);
1342 break;
1343 case DevFmtInt:
1344 WRITE(ALint, OutBuffer, buffer, SamplesToDo, OutChannels);
1345 break;
1346 case DevFmtUInt:
1347 WRITE(ALuint, OutBuffer, buffer, SamplesToDo, OutChannels);
1348 break;
1349 case DevFmtFloat:
1350 WRITE(ALfloat, OutBuffer, buffer, SamplesToDo, OutChannels);
1351 break;
1353 #undef WRITE
1356 size -= SamplesToDo;
1357 IncrementRef(&device->MixCount);
1360 RestoreFPUMode(&oldMode);
1364 ALvoid aluHandleDisconnect(ALCdevice *device)
1366 ALCcontext *Context;
1368 device->Connected = ALC_FALSE;
1370 Context = ATOMIC_LOAD(&device->ContextList);
1371 while(Context)
1373 ALvoice *voice, *voice_end;
1375 voice = Context->Voices;
1376 voice_end = voice + Context->VoiceCount;
1377 while(voice != voice_end)
1379 ALsource *source = voice->Source;
1380 voice->Source = NULL;
1382 if(source && source->state == AL_PLAYING)
1384 source->state = AL_STOPPED;
1385 ATOMIC_STORE(&source->current_buffer, NULL);
1386 source->position = 0;
1387 source->position_fraction = 0;
1390 voice++;
1392 Context->VoiceCount = 0;
1394 Context = Context->next;