Avoid tracing wide-char strings
[openal-soft.git] / Alc / ALu.c
blobaf7ca616bb58d96b16e73f6cba97cbb83e6bceed
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 aluVector *vec1, const aluVector *vec2)
121 return vec1->v[0]*vec2->v[0] + vec1->v[1]*vec2->v[1] + vec1->v[2]*vec2->v[2];
124 static inline void aluNormalize(ALfloat *vec)
126 ALfloat lengthsqr = vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2];
127 if(lengthsqr > 0.0f)
129 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
130 vec[0] *= inv_length;
131 vec[1] *= inv_length;
132 vec[2] *= inv_length;
136 static inline ALvoid aluMatrixVector(aluVector *vec, const aluMatrix *mtx)
138 aluVector v = *vec;
140 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];
141 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];
142 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];
143 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];
147 /* Calculates the fade time from the changes in gain and listener to source
148 * angle between updates. The result is a the time, in seconds, for the
149 * transition to complete.
151 static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const aluVector *olddir, const aluVector *newdir)
153 ALfloat gainChange, angleChange, change;
155 /* Calculate the normalized dB gain change. */
156 newGain = maxf(newGain, 0.0001f);
157 oldGain = maxf(oldGain, 0.0001f);
158 gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
160 /* Calculate the angle change only when there is enough gain to notice it. */
161 angleChange = 0.0f;
162 if(gainChange > 0.0001f || newGain > 0.0001f)
164 /* No angle change when the directions are equal or degenerate (when
165 * both have zero length).
167 if(newdir->v[0] != olddir->v[0] || newdir->v[1] != olddir->v[1] || newdir->v[2] != olddir->v[2])
169 ALfloat dotp = aluDotproduct(olddir, newdir);
170 angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
174 /* Use the largest of the two changes, and apply a significance shaping
175 * function to it. The result is then scaled to cover a 15ms transition
176 * range.
178 change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
179 return minf(change, 1.0f) * 0.015f;
183 static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps)
185 ALfloat delta;
186 ALuint i, j;
188 if(steps < 2)
190 for(i = 0;i < num_chans;i++)
192 MixGains *gains = params->Gains[i];
193 for(j = 0;j < params->OutChannels;j++)
195 gains[j].Current = gains[j].Target;
196 gains[j].Step = 0.0f;
199 params->Counter = 0;
200 return;
203 delta = 1.0f / (ALfloat)steps;
204 for(i = 0;i < num_chans;i++)
206 MixGains *gains = params->Gains[i];
207 for(j = 0;j < params->OutChannels;j++)
209 ALfloat diff = gains[j].Target - gains[j].Current;
210 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
211 gains[j].Step = diff * delta;
212 else
213 gains[j].Step = 0.0f;
216 params->Counter = steps;
219 static void UpdateWetStepping(SendParams *params, ALuint steps)
221 ALfloat delta;
223 if(steps < 2)
225 params->Gain.Current = params->Gain.Target;
226 params->Gain.Step = 0.0f;
228 params->Counter = 0;
229 return;
232 delta = 1.0f / (ALfloat)steps;
234 ALfloat diff = params->Gain.Target - params->Gain.Current;
235 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
236 params->Gain.Step = diff * delta;
237 else
238 params->Gain.Step = 0.0f;
240 params->Counter = steps;
244 static ALvoid CalcListenerParams(ALlistener *Listener)
246 ALfloat N[3], V[3], U[3];
247 aluVector P;
249 /* AT then UP */
250 N[0] = Listener->Forward[0];
251 N[1] = Listener->Forward[1];
252 N[2] = Listener->Forward[2];
253 aluNormalize(N);
254 V[0] = Listener->Up[0];
255 V[1] = Listener->Up[1];
256 V[2] = Listener->Up[2];
257 aluNormalize(V);
258 /* Build and normalize right-vector */
259 aluCrossproduct(N, V, U);
260 aluNormalize(U);
262 P = Listener->Position;
264 aluMatrixSet(&Listener->Params.Matrix,
265 U[0], V[0], -N[0], 0.0f,
266 U[1], V[1], -N[1], 0.0f,
267 U[2], V[2], -N[2], 0.0f,
268 0.0f, 0.0f, 0.0f, 1.0f
270 aluMatrixVector(&P, &Listener->Params.Matrix);
271 aluMatrixSetRow(&Listener->Params.Matrix, 3, -P.v[0], -P.v[1], -P.v[2], 1.0f);
273 Listener->Params.Velocity = Listener->Velocity;
274 aluMatrixVector(&Listener->Params.Velocity, &Listener->Params.Matrix);
277 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
279 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } };
280 static const struct ChanMap StereoMap[2] = {
281 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
282 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
284 static const struct ChanMap StereoWideMap[2] = {
285 { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
286 { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
288 static const struct ChanMap RearMap[2] = {
289 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
290 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
292 static const struct ChanMap QuadMap[4] = {
293 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
294 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
295 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
296 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
298 static const struct ChanMap X51Map[6] = {
299 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
300 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
301 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
302 { LFE, 0.0f, 0.0f },
303 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
304 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
306 static const struct ChanMap X61Map[7] = {
307 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
308 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
309 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
310 { LFE, 0.0f, 0.0f },
311 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
312 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
313 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
315 static const struct ChanMap X71Map[8] = {
316 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
317 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
318 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
319 { LFE, 0.0f, 0.0f },
320 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
321 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
322 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
323 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
326 ALCdevice *Device = ALContext->Device;
327 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
328 ALbufferlistitem *BufferListItem;
329 enum FmtChannels Channels;
330 ALfloat DryGain, DryGainHF, DryGainLF;
331 ALfloat WetGain[MAX_SENDS];
332 ALfloat WetGainHF[MAX_SENDS];
333 ALfloat WetGainLF[MAX_SENDS];
334 ALuint NumSends, Frequency;
335 ALboolean Relative;
336 const struct ChanMap *chans = NULL;
337 ALuint num_channels = 0;
338 ALboolean DirectChannels;
339 ALboolean isbformat = AL_FALSE;
340 ALfloat Pitch;
341 ALuint i, j, c;
343 /* Get device properties */
344 NumSends = Device->NumAuxSends;
345 Frequency = Device->Frequency;
347 /* Get listener properties */
348 ListenerGain = ALContext->Listener->Gain;
350 /* Get source properties */
351 SourceVolume = ALSource->Gain;
352 MinVolume = ALSource->MinGain;
353 MaxVolume = ALSource->MaxGain;
354 Pitch = ALSource->Pitch;
355 Relative = ALSource->HeadRelative;
356 DirectChannels = ALSource->DirectChannels;
358 voice->Direct.OutBuffer = Device->DryBuffer;
359 voice->Direct.OutChannels = Device->NumChannels;
360 for(i = 0;i < NumSends;i++)
362 ALeffectslot *Slot = ALSource->Send[i].Slot;
363 if(!Slot && i == 0)
364 Slot = Device->DefaultSlot;
365 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
366 voice->Send[i].OutBuffer = NULL;
367 else
368 voice->Send[i].OutBuffer = Slot->WetBuffer;
371 /* Calculate the stepping value */
372 Channels = FmtMono;
373 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
374 while(BufferListItem != NULL)
376 ALbuffer *ALBuffer;
377 if((ALBuffer=BufferListItem->buffer) != NULL)
379 Pitch = Pitch * ALBuffer->Frequency / Frequency;
380 if(Pitch > (ALfloat)MAX_PITCH)
381 voice->Step = MAX_PITCH<<FRACTIONBITS;
382 else
384 voice->Step = fastf2i(Pitch*FRACTIONONE);
385 if(voice->Step == 0)
386 voice->Step = 1;
389 Channels = ALBuffer->FmtChannels;
390 break;
392 BufferListItem = BufferListItem->next;
395 /* Calculate gains */
396 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
397 DryGain *= ALSource->Direct.Gain * ListenerGain;
398 DryGainHF = ALSource->Direct.GainHF;
399 DryGainLF = ALSource->Direct.GainLF;
400 for(i = 0;i < NumSends;i++)
402 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
403 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
404 WetGainHF[i] = ALSource->Send[i].GainHF;
405 WetGainLF[i] = ALSource->Send[i].GainLF;
408 switch(Channels)
410 case FmtMono:
411 chans = MonoMap;
412 num_channels = 1;
413 break;
415 case FmtStereo:
416 /* HACK: Place the stereo channels at +/-90 degrees when using non-
417 * HRTF stereo output. This helps reduce the "monoization" caused
418 * by them panning towards the center. */
419 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
420 chans = StereoWideMap;
421 else
422 chans = StereoMap;
423 num_channels = 2;
424 break;
426 case FmtRear:
427 chans = RearMap;
428 num_channels = 2;
429 break;
431 case FmtQuad:
432 chans = QuadMap;
433 num_channels = 4;
434 break;
436 case FmtX51:
437 chans = X51Map;
438 num_channels = 6;
439 break;
441 case FmtX61:
442 chans = X61Map;
443 num_channels = 7;
444 break;
446 case FmtX71:
447 chans = X71Map;
448 num_channels = 8;
449 break;
451 case FmtBFormat2D:
452 num_channels = 3;
453 isbformat = AL_TRUE;
454 DirectChannels = AL_FALSE;
455 break;
457 case FmtBFormat3D:
458 num_channels = 4;
459 isbformat = AL_TRUE;
460 DirectChannels = AL_FALSE;
461 break;
464 if(isbformat)
466 ALfloat N[3], V[3], U[3];
467 aluMatrix matrix;
469 /* AT then UP */
470 N[0] = ALSource->Orientation[0][0];
471 N[1] = ALSource->Orientation[0][1];
472 N[2] = ALSource->Orientation[0][2];
473 aluNormalize(N);
474 V[0] = ALSource->Orientation[1][0];
475 V[1] = ALSource->Orientation[1][1];
476 V[2] = ALSource->Orientation[1][2];
477 aluNormalize(V);
478 if(!Relative)
480 const aluMatrix *lmatrix = &ALContext->Listener->Params.Matrix;
481 aluVector at, up;
482 aluVectorSet(&at, N[0], N[1], N[2], 0.0f);
483 aluVectorSet(&up, V[0], V[1], V[2], 0.0f);
484 aluMatrixVector(&at, lmatrix);
485 aluMatrixVector(&up, lmatrix);
486 N[0] = at.v[0]; N[1] = at.v[1]; N[2] = at.v[2];
487 V[0] = up.v[0]; V[1] = up.v[1]; V[2] = up.v[2];
489 /* Build and normalize right-vector */
490 aluCrossproduct(N, V, U);
491 aluNormalize(U);
493 aluMatrixSet(&matrix,
494 1.0f, 0.0f, 0.0f, 0.0f,
495 0.0f, -N[2], -N[0], N[1],
496 0.0f, U[2], U[0], -U[1],
497 0.0f, -V[2], -V[0], V[1]
500 for(c = 0;c < num_channels;c++)
502 MixGains *gains = voice->Direct.Gains[c];
503 ALfloat Target[MAX_OUTPUT_CHANNELS];
505 ComputeBFormatGains(Device, matrix.m[c], DryGain, Target);
506 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
507 gains[i].Target = Target[i];
509 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
510 voice->Direct.Moving = AL_TRUE;
512 voice->IsHrtf = AL_FALSE;
513 for(i = 0;i < NumSends;i++)
514 WetGain[i] *= 1.4142f;
516 else if(DirectChannels != AL_FALSE)
518 if(Device->Hrtf)
520 voice->Direct.OutBuffer += voice->Direct.OutChannels;
521 voice->Direct.OutChannels = 2;
522 for(c = 0;c < num_channels;c++)
524 MixGains *gains = voice->Direct.Gains[c];
526 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
527 gains[j].Target = 0.0f;
529 if(chans[c].channel == FrontLeft)
530 gains[0].Target = DryGain;
531 else if(chans[c].channel == FrontRight)
532 gains[1].Target = DryGain;
535 else for(c = 0;c < num_channels;c++)
537 MixGains *gains = voice->Direct.Gains[c];
538 int idx;
540 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
541 gains[j].Target = 0.0f;
542 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
543 gains[idx].Target = DryGain;
545 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
546 voice->Direct.Moving = AL_TRUE;
548 voice->IsHrtf = AL_FALSE;
550 else if(Device->Hrtf)
552 voice->Direct.OutBuffer += voice->Direct.OutChannels;
553 voice->Direct.OutChannels = 2;
554 for(c = 0;c < num_channels;c++)
556 if(chans[c].channel == LFE)
558 /* Skip LFE */
559 voice->Direct.Hrtf.Params[c].Delay[0] = 0;
560 voice->Direct.Hrtf.Params[c].Delay[1] = 0;
561 for(i = 0;i < HRIR_LENGTH;i++)
563 voice->Direct.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
564 voice->Direct.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
567 else
569 /* Get the static HRIR coefficients and delays for this
570 * channel. */
571 GetLerpedHrtfCoeffs(Device->Hrtf,
572 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
573 voice->Direct.Hrtf.Params[c].Coeffs,
574 voice->Direct.Hrtf.Params[c].Delay);
577 voice->Direct.Counter = 0;
578 voice->Direct.Moving = AL_TRUE;
580 voice->IsHrtf = AL_TRUE;
582 else
584 for(c = 0;c < num_channels;c++)
586 MixGains *gains = voice->Direct.Gains[c];
587 ALfloat Target[MAX_OUTPUT_CHANNELS];
589 /* Special-case LFE */
590 if(chans[c].channel == LFE)
592 int idx;
593 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
594 gains[i].Target = 0.0f;
595 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
596 gains[idx].Target = DryGain;
597 continue;
600 ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
601 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
602 gains[i].Target = Target[i];
604 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
605 voice->Direct.Moving = AL_TRUE;
607 voice->IsHrtf = AL_FALSE;
609 for(i = 0;i < NumSends;i++)
611 voice->Send[i].Gain.Target = WetGain[i];
612 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
613 voice->Send[i].Moving = AL_TRUE;
617 ALfloat gainhf = maxf(0.01f, DryGainHF);
618 ALfloat gainlf = maxf(0.01f, DryGainLF);
619 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
620 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
621 for(c = 0;c < num_channels;c++)
623 voice->Direct.Filters[c].ActiveType = AF_None;
624 if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
625 if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
626 ALfilterState_setParams(
627 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
628 hfscale, 0.0f
630 ALfilterState_setParams(
631 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
632 lfscale, 0.0f
636 for(i = 0;i < NumSends;i++)
638 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
639 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
640 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
641 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
642 for(c = 0;c < num_channels;c++)
644 voice->Send[i].Filters[c].ActiveType = AF_None;
645 if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
646 if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
647 ALfilterState_setParams(
648 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
649 hfscale, 0.0f
651 ALfilterState_setParams(
652 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
653 lfscale, 0.0f
659 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
661 ALCdevice *Device = ALContext->Device;
662 aluVector Position, Velocity, Direction, SourceToListener;
663 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
664 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
665 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
666 ALfloat DopplerFactor, SpeedOfSound;
667 ALfloat AirAbsorptionFactor;
668 ALfloat RoomAirAbsorption[MAX_SENDS];
669 ALbufferlistitem *BufferListItem;
670 ALfloat Attenuation;
671 ALfloat RoomAttenuation[MAX_SENDS];
672 ALfloat MetersPerUnit;
673 ALfloat RoomRolloffBase;
674 ALfloat RoomRolloff[MAX_SENDS];
675 ALfloat DecayDistance[MAX_SENDS];
676 ALfloat DryGain;
677 ALfloat DryGainHF;
678 ALfloat DryGainLF;
679 ALboolean DryGainHFAuto;
680 ALfloat WetGain[MAX_SENDS];
681 ALfloat WetGainHF[MAX_SENDS];
682 ALfloat WetGainLF[MAX_SENDS];
683 ALboolean WetGainAuto;
684 ALboolean WetGainHFAuto;
685 ALfloat Pitch;
686 ALuint Frequency;
687 ALint NumSends;
688 ALint i, j;
690 DryGainHF = 1.0f;
691 DryGainLF = 1.0f;
692 for(i = 0;i < MAX_SENDS;i++)
694 WetGainHF[i] = 1.0f;
695 WetGainLF[i] = 1.0f;
698 /* Get context/device properties */
699 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
700 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
701 NumSends = Device->NumAuxSends;
702 Frequency = Device->Frequency;
704 /* Get listener properties */
705 ListenerGain = ALContext->Listener->Gain;
706 MetersPerUnit = ALContext->Listener->MetersPerUnit;
708 /* Get source properties */
709 SourceVolume = ALSource->Gain;
710 MinVolume = ALSource->MinGain;
711 MaxVolume = ALSource->MaxGain;
712 Pitch = ALSource->Pitch;
713 Position = ALSource->Position;
714 Direction = ALSource->Direction;
715 Velocity = ALSource->Velocity;
716 MinDist = ALSource->RefDistance;
717 MaxDist = ALSource->MaxDistance;
718 Rolloff = ALSource->RollOffFactor;
719 InnerAngle = ALSource->InnerAngle;
720 OuterAngle = ALSource->OuterAngle;
721 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
722 DryGainHFAuto = ALSource->DryGainHFAuto;
723 WetGainAuto = ALSource->WetGainAuto;
724 WetGainHFAuto = ALSource->WetGainHFAuto;
725 RoomRolloffBase = ALSource->RoomRolloffFactor;
727 voice->Direct.OutBuffer = Device->DryBuffer;
728 voice->Direct.OutChannels = Device->NumChannels;
729 for(i = 0;i < NumSends;i++)
731 ALeffectslot *Slot = ALSource->Send[i].Slot;
733 if(!Slot && i == 0)
734 Slot = Device->DefaultSlot;
735 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
737 Slot = NULL;
738 RoomRolloff[i] = 0.0f;
739 DecayDistance[i] = 0.0f;
740 RoomAirAbsorption[i] = 1.0f;
742 else if(Slot->AuxSendAuto)
744 RoomRolloff[i] = RoomRolloffBase;
745 if(IsReverbEffect(Slot->EffectType))
747 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
748 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
749 SPEEDOFSOUNDMETRESPERSEC;
750 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
752 else
754 DecayDistance[i] = 0.0f;
755 RoomAirAbsorption[i] = 1.0f;
758 else
760 /* If the slot's auxiliary send auto is off, the data sent to the
761 * effect slot is the same as the dry path, sans filter effects */
762 RoomRolloff[i] = Rolloff;
763 DecayDistance[i] = 0.0f;
764 RoomAirAbsorption[i] = AIRABSORBGAINHF;
767 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
768 voice->Send[i].OutBuffer = NULL;
769 else
770 voice->Send[i].OutBuffer = Slot->WetBuffer;
773 /* Transform source to listener space (convert to head relative) */
774 if(ALSource->HeadRelative == AL_FALSE)
776 const aluMatrix *Matrix = &ALContext->Listener->Params.Matrix;
777 /* Transform source vectors */
778 aluMatrixVector(&Position, Matrix);
779 aluMatrixVector(&Velocity, Matrix);
780 aluMatrixVector(&Direction, Matrix);
782 else
784 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
785 /* Offset the source velocity to be relative of the listener velocity */
786 Velocity.v[0] += lvelocity->v[0];
787 Velocity.v[1] += lvelocity->v[1];
788 Velocity.v[2] += lvelocity->v[2];
791 SourceToListener.v[0] = -Position.v[0];
792 SourceToListener.v[1] = -Position.v[1];
793 SourceToListener.v[2] = -Position.v[2];
794 SourceToListener.v[3] = 0.0f;
795 aluNormalize(SourceToListener.v);
796 aluNormalize(Direction.v);
798 /* Calculate distance attenuation */
799 Distance = sqrtf(aluDotproduct(&Position, &Position));
800 ClampedDist = Distance;
802 Attenuation = 1.0f;
803 for(i = 0;i < NumSends;i++)
804 RoomAttenuation[i] = 1.0f;
805 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
806 ALContext->DistanceModel)
808 case InverseDistanceClamped:
809 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
810 if(MaxDist < MinDist)
811 break;
812 /*fall-through*/
813 case InverseDistance:
814 if(MinDist > 0.0f)
816 ALfloat dist = lerp(MinDist, ClampedDist, Rolloff);
817 if(dist > 0.0f) Attenuation = MinDist / dist;
818 for(i = 0;i < NumSends;i++)
820 dist = lerp(MinDist, ClampedDist, RoomRolloff[i]);
821 if(dist > 0.0f) RoomAttenuation[i] = MinDist / dist;
824 break;
826 case LinearDistanceClamped:
827 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
828 if(MaxDist < MinDist)
829 break;
830 /*fall-through*/
831 case LinearDistance:
832 if(MaxDist != MinDist)
834 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
835 Attenuation = maxf(Attenuation, 0.0f);
836 for(i = 0;i < NumSends;i++)
838 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
839 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
842 break;
844 case ExponentDistanceClamped:
845 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
846 if(MaxDist < MinDist)
847 break;
848 /*fall-through*/
849 case ExponentDistance:
850 if(ClampedDist > 0.0f && MinDist > 0.0f)
852 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
853 for(i = 0;i < NumSends;i++)
854 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
856 break;
858 case DisableDistance:
859 ClampedDist = MinDist;
860 break;
863 /* Source Gain + Attenuation */
864 DryGain = SourceVolume * Attenuation;
865 for(i = 0;i < NumSends;i++)
866 WetGain[i] = SourceVolume * RoomAttenuation[i];
868 /* Distance-based air absorption */
869 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
871 ALfloat meters = (ClampedDist-MinDist) * MetersPerUnit;
872 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
873 for(i = 0;i < NumSends;i++)
874 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
877 if(WetGainAuto)
879 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
881 /* Apply a decay-time transformation to the wet path, based on the
882 * attenuation of the dry path.
884 * Using the apparent distance, based on the distance attenuation, the
885 * initial decay of the reverb effect is calculated and applied to the
886 * wet path.
888 for(i = 0;i < NumSends;i++)
890 if(DecayDistance[i] > 0.0f)
891 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
895 /* Calculate directional soundcones */
896 Angle = RAD2DEG(acosf(aluDotproduct(&Direction, &SourceToListener)) * ConeScale) * 2.0f;
897 if(Angle > InnerAngle && Angle <= OuterAngle)
899 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
900 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
901 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
903 else if(Angle > OuterAngle)
905 ConeVolume = ALSource->OuterGain;
906 ConeHF = ALSource->OuterGainHF;
908 else
910 ConeVolume = 1.0f;
911 ConeHF = 1.0f;
914 DryGain *= ConeVolume;
915 if(WetGainAuto)
917 for(i = 0;i < NumSends;i++)
918 WetGain[i] *= ConeVolume;
920 if(DryGainHFAuto)
921 DryGainHF *= ConeHF;
922 if(WetGainHFAuto)
924 for(i = 0;i < NumSends;i++)
925 WetGainHF[i] *= ConeHF;
928 /* Clamp to Min/Max Gain */
929 DryGain = clampf(DryGain, MinVolume, MaxVolume);
930 for(i = 0;i < NumSends;i++)
931 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
933 /* Apply gain and frequency filters */
934 DryGain *= ALSource->Direct.Gain * ListenerGain;
935 DryGainHF *= ALSource->Direct.GainHF;
936 DryGainLF *= ALSource->Direct.GainLF;
937 for(i = 0;i < NumSends;i++)
939 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
940 WetGainHF[i] *= ALSource->Send[i].GainHF;
941 WetGainLF[i] *= ALSource->Send[i].GainLF;
944 /* Calculate velocity-based doppler effect */
945 if(DopplerFactor > 0.0f)
947 const aluVector *lvelocity = &ALContext->Listener->Params.Velocity;
948 ALfloat VSS, VLS;
950 if(SpeedOfSound < 1.0f)
952 DopplerFactor *= 1.0f/SpeedOfSound;
953 SpeedOfSound = 1.0f;
956 VSS = aluDotproduct(&Velocity, &SourceToListener) * DopplerFactor;
957 VLS = aluDotproduct(lvelocity, &SourceToListener) * DopplerFactor;
959 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
960 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
963 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
964 while(BufferListItem != NULL)
966 ALbuffer *ALBuffer;
967 if((ALBuffer=BufferListItem->buffer) != NULL)
969 /* Calculate fixed-point stepping value, based on the pitch, buffer
970 * frequency, and output frequency. */
971 Pitch = Pitch * ALBuffer->Frequency / Frequency;
972 if(Pitch > (ALfloat)MAX_PITCH)
973 voice->Step = MAX_PITCH<<FRACTIONBITS;
974 else
976 voice->Step = fastf2i(Pitch*FRACTIONONE);
977 if(voice->Step == 0)
978 voice->Step = 1;
981 break;
983 BufferListItem = BufferListItem->next;
986 if(Device->Hrtf)
988 /* Use a binaural HRTF algorithm for stereo headphone playback */
989 aluVector dir = {{ 0.0f, 0.0f, -1.0f, 0.0f }};
990 ALfloat ev = 0.0f, az = 0.0f;
991 ALfloat radius = ALSource->Radius;
992 ALfloat dirfact = 1.0f;
994 voice->Direct.OutBuffer += voice->Direct.OutChannels;
995 voice->Direct.OutChannels = 2;
997 if(Distance > FLT_EPSILON)
999 ALfloat invlen = 1.0f/Distance;
1000 dir.v[0] = Position.v[0] * invlen;
1001 dir.v[1] = Position.v[1] * invlen;
1002 dir.v[2] = Position.v[2] * invlen * ZScale;
1004 /* Calculate elevation and azimuth only when the source is not at
1005 * the listener. This prevents +0 and -0 Z from producing
1006 * inconsistent panning. Also, clamp Y in case FP precision errors
1007 * cause it to land outside of -1..+1. */
1008 ev = asinf(clampf(dir.v[1], -1.0f, 1.0f));
1009 az = atan2f(dir.v[0], -dir.v[2]);
1011 if(radius > Distance)
1012 dirfact *= Distance / radius;
1014 /* Check to see if the HRIR is already moving. */
1015 if(voice->Direct.Moving)
1017 ALfloat delta;
1018 delta = CalcFadeTime(voice->Direct.LastGain, DryGain,
1019 &voice->Direct.LastDir, &dir);
1020 /* If the delta is large enough, get the moving HRIR target
1021 * coefficients, target delays, steppping values, and counter. */
1022 if(delta > 0.000015f)
1024 ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
1025 ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
1026 voice->Direct.Hrtf.Params[0].Coeffs, voice->Direct.Hrtf.Params[0].Delay,
1027 voice->Direct.Hrtf.Params[0].CoeffStep, voice->Direct.Hrtf.Params[0].DelayStep
1029 voice->Direct.Counter = counter;
1030 voice->Direct.LastGain = DryGain;
1031 voice->Direct.LastDir = dir;
1034 else
1036 /* Get the initial (static) HRIR coefficients and delays. */
1037 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1038 voice->Direct.Hrtf.Params[0].Coeffs,
1039 voice->Direct.Hrtf.Params[0].Delay);
1040 voice->Direct.Counter = 0;
1041 voice->Direct.Moving = AL_TRUE;
1042 voice->Direct.LastGain = DryGain;
1043 voice->Direct.LastDir = dir;
1046 voice->IsHrtf = AL_TRUE;
1048 else
1050 MixGains *gains = voice->Direct.Gains[0];
1051 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1052 ALfloat radius = ALSource->Radius;
1053 ALfloat Target[MAX_OUTPUT_CHANNELS];
1055 /* Normalize the length, and compute panned gains. */
1056 if(Distance > FLT_EPSILON || radius > FLT_EPSILON)
1058 ALfloat invlen = 1.0f/maxf(Distance, radius);
1059 dir[0] = Position.v[0] * invlen;
1060 dir[1] = Position.v[1] * invlen;
1061 dir[2] = Position.v[2] * invlen * ZScale;
1063 ComputeDirectionalGains(Device, dir, DryGain, Target);
1065 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
1066 gains[j].Target = Target[j];
1067 UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0));
1068 voice->Direct.Moving = AL_TRUE;
1070 voice->IsHrtf = AL_FALSE;
1072 for(i = 0;i < NumSends;i++)
1074 voice->Send[i].Gain.Target = WetGain[i];
1075 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
1076 voice->Send[i].Moving = AL_TRUE;
1080 ALfloat gainhf = maxf(0.01f, DryGainHF);
1081 ALfloat gainlf = maxf(0.01f, DryGainLF);
1082 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1083 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1084 voice->Direct.Filters[0].ActiveType = AF_None;
1085 if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1086 if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1087 ALfilterState_setParams(
1088 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1089 hfscale, 0.0f
1091 ALfilterState_setParams(
1092 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1093 lfscale, 0.0f
1096 for(i = 0;i < NumSends;i++)
1098 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
1099 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
1100 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1101 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1102 voice->Send[i].Filters[0].ActiveType = AF_None;
1103 if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1104 if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1105 ALfilterState_setParams(
1106 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1107 hfscale, 0.0f
1109 ALfilterState_setParams(
1110 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1111 lfscale, 0.0f
1117 static inline ALint aluF2I25(ALfloat val)
1119 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1120 if(fabsf(val) > 1.0f)
1121 val = (ALfloat)((0.0f < val) - (val < 0.0f));
1122 /* Convert to a signed integer, between -16777215 and +16777215. */
1123 return fastf2i(val*16777215.0f);
1126 static inline ALfloat aluF2F(ALfloat val)
1127 { return val; }
1128 static inline ALint aluF2I(ALfloat val)
1129 { return aluF2I25(val)<<7; }
1130 static inline ALuint aluF2UI(ALfloat val)
1131 { return aluF2I(val)+2147483648u; }
1132 static inline ALshort aluF2S(ALfloat val)
1133 { return aluF2I25(val)>>9; }
1134 static inline ALushort aluF2US(ALfloat val)
1135 { return aluF2S(val)+32768; }
1136 static inline ALbyte aluF2B(ALfloat val)
1137 { return aluF2I25(val)>>17; }
1138 static inline ALubyte aluF2UB(ALfloat val)
1139 { return aluF2B(val)+128; }
1141 #define DECL_TEMPLATE(T, func) \
1142 static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1143 ALuint SamplesToDo, ALuint numchans) \
1145 ALuint i, j; \
1146 for(j = 0;j < numchans;j++) \
1148 const ALfloat *in = InBuffer[j]; \
1149 T *restrict out = (T*)OutBuffer + j; \
1150 for(i = 0;i < SamplesToDo;i++) \
1151 out[i*numchans] = func(in[i]); \
1155 DECL_TEMPLATE(ALfloat, aluF2F)
1156 DECL_TEMPLATE(ALuint, aluF2UI)
1157 DECL_TEMPLATE(ALint, aluF2I)
1158 DECL_TEMPLATE(ALushort, aluF2US)
1159 DECL_TEMPLATE(ALshort, aluF2S)
1160 DECL_TEMPLATE(ALubyte, aluF2UB)
1161 DECL_TEMPLATE(ALbyte, aluF2B)
1163 #undef DECL_TEMPLATE
1166 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1168 ALuint SamplesToDo;
1169 ALeffectslot **slot, **slot_end;
1170 ALvoice *voice, *voice_end;
1171 ALCcontext *ctx;
1172 FPUCtl oldMode;
1173 ALuint i, c;
1175 SetMixerFPUMode(&oldMode);
1177 while(size > 0)
1179 ALuint outchanoffset = 0;
1180 ALuint outchancount = device->NumChannels;
1182 IncrementRef(&device->MixCount);
1184 SamplesToDo = minu(size, BUFFERSIZE);
1185 for(c = 0;c < device->NumChannels;c++)
1186 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1187 if(device->Hrtf)
1189 outchanoffset = device->NumChannels;
1190 outchancount = 2;
1191 for(c = 0;c < outchancount;c++)
1192 memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat));
1195 V0(device->Backend,lock)();
1196 V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]);
1198 ctx = ATOMIC_LOAD(&device->ContextList);
1199 while(ctx)
1201 ALenum DeferUpdates = ctx->DeferUpdates;
1202 ALenum UpdateSources = AL_FALSE;
1204 if(!DeferUpdates)
1205 UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
1207 if(UpdateSources)
1208 CalcListenerParams(ctx->Listener);
1210 /* source processing */
1211 voice = ctx->Voices;
1212 voice_end = voice + ctx->VoiceCount;
1213 while(voice != voice_end)
1215 ALsource *source = voice->Source;
1216 if(!source) goto next;
1218 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1220 voice->Source = NULL;
1221 goto next;
1224 if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
1225 UpdateSources))
1226 voice->Update(voice, source, ctx);
1228 if(source->state != AL_PAUSED)
1229 MixSource(voice, source, device, SamplesToDo);
1230 next:
1231 voice++;
1234 /* effect slot processing */
1235 slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
1236 slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
1237 while(slot != slot_end)
1239 if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1240 V((*slot)->EffectState,update)(device, *slot);
1242 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1243 device->DryBuffer, device->NumChannels);
1245 for(i = 0;i < SamplesToDo;i++)
1246 (*slot)->WetBuffer[0][i] = 0.0f;
1248 slot++;
1251 ctx = ctx->next;
1254 slot = &device->DefaultSlot;
1255 if(*slot != NULL)
1257 if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1258 V((*slot)->EffectState,update)(device, *slot);
1260 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1261 device->DryBuffer, device->NumChannels);
1263 for(i = 0;i < SamplesToDo;i++)
1264 (*slot)->WetBuffer[0][i] = 0.0f;
1267 /* Increment the clock time. Every second's worth of samples is
1268 * converted and added to clock base so that large sample counts don't
1269 * overflow during conversion. This also guarantees an exact, stable
1270 * conversion. */
1271 device->SamplesDone += SamplesToDo;
1272 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1273 device->SamplesDone %= device->Frequency;
1274 V0(device->Backend,unlock)();
1276 if(device->Hrtf)
1278 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1279 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1280 for(c = 0;c < device->NumChannels;c++)
1281 HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], 0,
1282 device->Hrtf_Offset, 0, irsize, &device->Hrtf_Params[c],
1283 &device->Hrtf_State[c], SamplesToDo
1285 device->Hrtf_Offset += SamplesToDo;
1287 else if(device->Bs2b)
1289 /* Apply binaural/crossfeed filter */
1290 for(i = 0;i < SamplesToDo;i++)
1292 float samples[2];
1293 samples[0] = device->DryBuffer[0][i];
1294 samples[1] = device->DryBuffer[1][i];
1295 bs2b_cross_feed(device->Bs2b, samples);
1296 device->DryBuffer[0][i] = samples[0];
1297 device->DryBuffer[1][i] = samples[1];
1301 if(buffer)
1303 #define WRITE(T, a, b, c, d) do { \
1304 Write_##T((a), (b), (c), (d)); \
1305 buffer = (T*)buffer + (c)*(d); \
1306 } while(0)
1307 switch(device->FmtType)
1309 case DevFmtByte:
1310 WRITE(ALbyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1311 break;
1312 case DevFmtUByte:
1313 WRITE(ALubyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1314 break;
1315 case DevFmtShort:
1316 WRITE(ALshort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1317 break;
1318 case DevFmtUShort:
1319 WRITE(ALushort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1320 break;
1321 case DevFmtInt:
1322 WRITE(ALint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1323 break;
1324 case DevFmtUInt:
1325 WRITE(ALuint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1326 break;
1327 case DevFmtFloat:
1328 WRITE(ALfloat, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1329 break;
1331 #undef WRITE
1334 size -= SamplesToDo;
1335 IncrementRef(&device->MixCount);
1338 RestoreFPUMode(&oldMode);
1342 ALvoid aluHandleDisconnect(ALCdevice *device)
1344 ALCcontext *Context;
1346 device->Connected = ALC_FALSE;
1348 Context = ATOMIC_LOAD(&device->ContextList);
1349 while(Context)
1351 ALvoice *voice, *voice_end;
1353 voice = Context->Voices;
1354 voice_end = voice + Context->VoiceCount;
1355 while(voice != voice_end)
1357 ALsource *source = voice->Source;
1358 voice->Source = NULL;
1360 if(source && source->state == AL_PLAYING)
1362 source->state = AL_STOPPED;
1363 ATOMIC_STORE(&source->current_buffer, NULL);
1364 source->position = 0;
1365 source->position_fraction = 0;
1368 voice++;
1370 Context->VoiceCount = 0;
1372 Context = Context->next;