Use linear gain stepping
[openal-soft.git] / Alc / ALu.c
blob78578a87e06bcac20c325aea639fcdd07b5feb81
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, ALfloat mu);
88 static inline HrtfMixerFunc SelectHrtfMixer(void)
90 #ifdef HAVE_SSE
91 if((CPUCapFlags&CPU_CAP_SSE))
92 return MixHrtf_SSE;
93 #endif
94 #ifdef HAVE_NEON
95 if((CPUCapFlags&CPU_CAP_NEON))
96 return MixHrtf_Neon;
97 #endif
99 return MixHrtf_C;
103 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
105 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
106 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
107 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
110 static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
112 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
113 inVector1[2]*inVector2[2];
116 static inline void aluNormalize(ALfloat *inVector)
118 ALfloat lengthsqr = aluDotproduct(inVector, inVector);
119 if(lengthsqr > 0.0f)
121 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
122 inVector[0] *= inv_length;
123 inVector[1] *= inv_length;
124 inVector[2] *= inv_length;
128 static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
130 ALfloat temp[4] = {
131 vector[0], vector[1], vector[2], w
134 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
135 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
136 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
140 /* Calculates the fade time from the changes in gain and listener to source
141 * angle between updates. The result is a the time, in seconds, for the
142 * transition to complete.
144 static ALfloat CalcFadeTime(ALfloat oldGain, ALfloat newGain, const ALfloat olddir[3], const ALfloat newdir[3])
146 ALfloat gainChange, angleChange, change;
148 /* Calculate the normalized dB gain change. */
149 newGain = maxf(newGain, 0.0001f);
150 oldGain = maxf(oldGain, 0.0001f);
151 gainChange = fabsf(log10f(newGain / oldGain) / log10f(0.0001f));
153 /* Calculate the angle change only when there is enough gain to notice it. */
154 angleChange = 0.0f;
155 if(gainChange > 0.0001f || newGain > 0.0001f)
157 /* No angle change when the directions are equal or degenerate (when
158 * both have zero length).
160 if(newdir[0] != olddir[0] || newdir[1] != olddir[1] || newdir[2] != olddir[2])
162 ALfloat dotp = aluDotproduct(olddir, newdir);
163 angleChange = acosf(clampf(dotp, -1.0f, 1.0f)) / F_PI;
167 /* Use the largest of the two changes, and apply a significance shaping
168 * function to it. The result is then scaled to cover a 15ms transition
169 * range.
171 change = maxf(angleChange * 25.0f, gainChange) * 2.0f;
172 return minf(change, 1.0f) * 0.015f;
176 static void UpdateDryStepping(DirectParams *params, ALuint num_chans, ALuint steps)
178 ALfloat delta;
179 ALuint i, j;
181 if(steps < 2)
183 for(i = 0;i < num_chans;i++)
185 MixGains *gains = params->Gains[i];
186 for(j = 0;j < params->OutChannels;j++)
188 gains[j].Current = gains[j].Target;
189 gains[j].Step = 0.0f;
192 params->Counter = 0;
193 return;
196 delta = 1.0f / (ALfloat)steps;
197 for(i = 0;i < num_chans;i++)
199 MixGains *gains = params->Gains[i];
200 for(j = 0;j < params->OutChannels;j++)
202 ALfloat diff = gains[j].Target - gains[j].Current;
203 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
204 gains[j].Step = diff * delta;
205 else
206 gains[j].Step = 0.0f;
209 params->Counter = steps;
212 static void UpdateWetStepping(SendParams *params, ALuint steps)
214 ALfloat delta;
216 if(steps < 2)
218 params->Gain.Current = params->Gain.Target;
219 params->Gain.Step = 0.0f;
221 params->Counter = 0;
222 return;
225 delta = 1.0f / (ALfloat)steps;
227 ALfloat diff = params->Gain.Target - params->Gain.Current;
228 if(fabs(diff) >= GAIN_SILENCE_THRESHOLD)
229 params->Gain.Step = diff * delta;
230 else
231 params->Gain.Step = 0.0f;
233 params->Counter = steps;
237 static ALvoid CalcListenerParams(ALlistener *Listener)
239 ALfloat N[3], V[3], U[3], P[3];
241 /* AT then UP */
242 N[0] = Listener->Forward[0];
243 N[1] = Listener->Forward[1];
244 N[2] = Listener->Forward[2];
245 aluNormalize(N);
246 V[0] = Listener->Up[0];
247 V[1] = Listener->Up[1];
248 V[2] = Listener->Up[2];
249 aluNormalize(V);
250 /* Build and normalize right-vector */
251 aluCrossproduct(N, V, U);
252 aluNormalize(U);
254 Listener->Params.Matrix[0][0] = U[0];
255 Listener->Params.Matrix[0][1] = V[0];
256 Listener->Params.Matrix[0][2] = -N[0];
257 Listener->Params.Matrix[0][3] = 0.0f;
258 Listener->Params.Matrix[1][0] = U[1];
259 Listener->Params.Matrix[1][1] = V[1];
260 Listener->Params.Matrix[1][2] = -N[1];
261 Listener->Params.Matrix[1][3] = 0.0f;
262 Listener->Params.Matrix[2][0] = U[2];
263 Listener->Params.Matrix[2][1] = V[2];
264 Listener->Params.Matrix[2][2] = -N[2];
265 Listener->Params.Matrix[2][3] = 0.0f;
266 Listener->Params.Matrix[3][0] = 0.0f;
267 Listener->Params.Matrix[3][1] = 0.0f;
268 Listener->Params.Matrix[3][2] = 0.0f;
269 Listener->Params.Matrix[3][3] = 1.0f;
271 P[0] = Listener->Position[0];
272 P[1] = Listener->Position[1];
273 P[2] = Listener->Position[2];
274 aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
275 Listener->Params.Matrix[3][0] = -P[0];
276 Listener->Params.Matrix[3][1] = -P[1];
277 Listener->Params.Matrix[3][2] = -P[2];
279 Listener->Params.Velocity[0] = Listener->Velocity[0];
280 Listener->Params.Velocity[1] = Listener->Velocity[1];
281 Listener->Params.Velocity[2] = Listener->Velocity[2];
282 aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
285 ALvoid CalcNonAttnSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
287 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f, 0.0f } };
288 static const struct ChanMap StereoMap[2] = {
289 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
290 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) }
292 static const struct ChanMap StereoWideMap[2] = {
293 { FrontLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
294 { FrontRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
296 static const struct ChanMap RearMap[2] = {
297 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
298 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) }
300 static const struct ChanMap QuadMap[4] = {
301 { FrontLeft, DEG2RAD( -45.0f), DEG2RAD(0.0f) },
302 { FrontRight, DEG2RAD( 45.0f), DEG2RAD(0.0f) },
303 { BackLeft, DEG2RAD(-135.0f), DEG2RAD(0.0f) },
304 { BackRight, DEG2RAD( 135.0f), DEG2RAD(0.0f) }
306 static const struct ChanMap X51Map[6] = {
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 { SideLeft, DEG2RAD(-110.0f), DEG2RAD(0.0f) },
312 { SideRight, DEG2RAD( 110.0f), DEG2RAD(0.0f) }
314 static const struct ChanMap X61Map[7] = {
315 { FrontLeft, DEG2RAD(-30.0f), DEG2RAD(0.0f) },
316 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
317 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
318 { LFE, 0.0f, 0.0f },
319 { BackCenter, DEG2RAD(180.0f), DEG2RAD(0.0f) },
320 { SideLeft, DEG2RAD(-90.0f), DEG2RAD(0.0f) },
321 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
323 static const struct ChanMap X71Map[8] = {
324 { FrontLeft, DEG2RAD( -30.0f), DEG2RAD(0.0f) },
325 { FrontRight, DEG2RAD( 30.0f), DEG2RAD(0.0f) },
326 { FrontCenter, DEG2RAD( 0.0f), DEG2RAD(0.0f) },
327 { LFE, 0.0f, 0.0f },
328 { BackLeft, DEG2RAD(-150.0f), DEG2RAD(0.0f) },
329 { BackRight, DEG2RAD( 150.0f), DEG2RAD(0.0f) },
330 { SideLeft, DEG2RAD( -90.0f), DEG2RAD(0.0f) },
331 { SideRight, DEG2RAD( 90.0f), DEG2RAD(0.0f) }
334 ALCdevice *Device = ALContext->Device;
335 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
336 ALbufferlistitem *BufferListItem;
337 enum FmtChannels Channels;
338 ALfloat DryGain, DryGainHF, DryGainLF;
339 ALfloat WetGain[MAX_SENDS];
340 ALfloat WetGainHF[MAX_SENDS];
341 ALfloat WetGainLF[MAX_SENDS];
342 ALuint NumSends, Frequency;
343 ALboolean Relative;
344 const struct ChanMap *chans = NULL;
345 ALuint num_channels = 0;
346 ALboolean DirectChannels;
347 ALboolean isbformat = AL_FALSE;
348 ALfloat Pitch;
349 ALuint i, j, c;
351 /* Get device properties */
352 NumSends = Device->NumAuxSends;
353 Frequency = Device->Frequency;
355 /* Get listener properties */
356 ListenerGain = ALContext->Listener->Gain;
358 /* Get source properties */
359 SourceVolume = ALSource->Gain;
360 MinVolume = ALSource->MinGain;
361 MaxVolume = ALSource->MaxGain;
362 Pitch = ALSource->Pitch;
363 Relative = ALSource->HeadRelative;
364 DirectChannels = ALSource->DirectChannels;
366 voice->Direct.OutBuffer = Device->DryBuffer;
367 voice->Direct.OutChannels = Device->NumChannels;
368 for(i = 0;i < NumSends;i++)
370 ALeffectslot *Slot = ALSource->Send[i].Slot;
371 if(!Slot && i == 0)
372 Slot = Device->DefaultSlot;
373 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
374 voice->Send[i].OutBuffer = NULL;
375 else
376 voice->Send[i].OutBuffer = Slot->WetBuffer;
379 /* Calculate the stepping value */
380 Channels = FmtMono;
381 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
382 while(BufferListItem != NULL)
384 ALbuffer *ALBuffer;
385 if((ALBuffer=BufferListItem->buffer) != NULL)
387 Pitch = Pitch * ALBuffer->Frequency / Frequency;
388 if(Pitch > (ALfloat)MAX_PITCH)
389 voice->Step = MAX_PITCH<<FRACTIONBITS;
390 else
392 voice->Step = fastf2i(Pitch*FRACTIONONE);
393 if(voice->Step == 0)
394 voice->Step = 1;
397 Channels = ALBuffer->FmtChannels;
398 break;
400 BufferListItem = BufferListItem->next;
403 /* Calculate gains */
404 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
405 DryGain *= ALSource->Direct.Gain * ListenerGain;
406 DryGainHF = ALSource->Direct.GainHF;
407 DryGainLF = ALSource->Direct.GainLF;
408 for(i = 0;i < NumSends;i++)
410 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
411 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
412 WetGainHF[i] = ALSource->Send[i].GainHF;
413 WetGainLF[i] = ALSource->Send[i].GainLF;
416 switch(Channels)
418 case FmtMono:
419 chans = MonoMap;
420 num_channels = 1;
421 break;
423 case FmtStereo:
424 /* HACK: Place the stereo channels at +/-90 degrees when using non-
425 * HRTF stereo output. This helps reduce the "monoization" caused
426 * by them panning towards the center. */
427 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
428 chans = StereoWideMap;
429 else
430 chans = StereoMap;
431 num_channels = 2;
432 break;
434 case FmtRear:
435 chans = RearMap;
436 num_channels = 2;
437 break;
439 case FmtQuad:
440 chans = QuadMap;
441 num_channels = 4;
442 break;
444 case FmtX51:
445 chans = X51Map;
446 num_channels = 6;
447 break;
449 case FmtX61:
450 chans = X61Map;
451 num_channels = 7;
452 break;
454 case FmtX71:
455 chans = X71Map;
456 num_channels = 8;
457 break;
459 case FmtBFormat2D:
460 num_channels = 3;
461 isbformat = AL_TRUE;
462 DirectChannels = AL_FALSE;
463 break;
465 case FmtBFormat3D:
466 num_channels = 4;
467 isbformat = AL_TRUE;
468 DirectChannels = AL_FALSE;
469 break;
472 if(isbformat)
474 ALfloat N[3], V[3], U[3];
475 ALfloat matrix[4][4];
477 /* AT then UP */
478 N[0] = ALSource->Orientation[0][0];
479 N[1] = ALSource->Orientation[0][1];
480 N[2] = ALSource->Orientation[0][2];
481 aluNormalize(N);
482 V[0] = ALSource->Orientation[1][0];
483 V[1] = ALSource->Orientation[1][1];
484 V[2] = ALSource->Orientation[1][2];
485 aluNormalize(V);
486 if(!Relative)
488 ALfloat (*restrict lmatrix)[4] = ALContext->Listener->Params.Matrix;
489 aluMatrixVector(N, 0.0f, lmatrix);
490 aluMatrixVector(V, 0.0f, lmatrix);
492 /* Build and normalize right-vector */
493 aluCrossproduct(N, V, U);
494 aluNormalize(U);
496 matrix[0][0] = 1.0f;
497 matrix[0][1] = 0.0f;
498 matrix[0][2] = 0.0f;
499 matrix[0][3] = 0.0f;
500 matrix[1][0] = 0.0f;
501 matrix[1][1] = -N[2];
502 matrix[1][2] = -N[0];
503 matrix[1][3] = N[1];
504 matrix[2][0] = 0.0f;
505 matrix[2][1] = U[2];
506 matrix[2][2] = U[0];
507 matrix[2][3] = -U[1];
508 matrix[3][0] = 0.0f;
509 matrix[3][1] = -V[2];
510 matrix[3][2] = -V[0];
511 matrix[3][3] = V[1];
513 for(c = 0;c < num_channels;c++)
515 MixGains *gains = voice->Direct.Gains[c];
516 ALfloat Target[MAX_OUTPUT_CHANNELS];
518 ComputeBFormatGains(Device, matrix[c], DryGain, Target);
519 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
520 gains[i].Target = Target[i];
522 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
523 voice->Direct.Moving = AL_TRUE;
525 voice->IsHrtf = AL_FALSE;
526 for(i = 0;i < NumSends;i++)
527 WetGain[i] *= 1.4142f;
529 else if(DirectChannels != AL_FALSE)
531 if(Device->Hrtf)
533 voice->Direct.OutBuffer = &voice->Direct.OutBuffer[voice->Direct.OutChannels];
534 voice->Direct.OutChannels = 2;
535 for(c = 0;c < num_channels;c++)
537 MixGains *gains = voice->Direct.Gains[c];
539 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
540 gains[j].Target = 0.0f;
542 if(chans[c].channel == FrontLeft)
543 gains[0].Target = DryGain;
544 else if(chans[c].channel == FrontRight)
545 gains[1].Target = DryGain;
548 else for(c = 0;c < num_channels;c++)
550 MixGains *gains = voice->Direct.Gains[c];
551 int idx;
553 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
554 gains[j].Target = 0.0f;
555 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
556 gains[idx].Target = DryGain;
558 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
559 voice->Direct.Moving = AL_TRUE;
561 voice->IsHrtf = AL_FALSE;
563 else if(Device->Hrtf)
565 voice->Direct.OutBuffer = &voice->Direct.OutBuffer[voice->Direct.OutChannels];
566 voice->Direct.OutChannels = 2;
567 for(c = 0;c < num_channels;c++)
569 if(chans[c].channel == LFE)
571 /* Skip LFE */
572 voice->Direct.Hrtf.Params[c].Delay[0] = 0;
573 voice->Direct.Hrtf.Params[c].Delay[1] = 0;
574 for(i = 0;i < HRIR_LENGTH;i++)
576 voice->Direct.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
577 voice->Direct.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
580 else
582 /* Get the static HRIR coefficients and delays for this
583 * channel. */
584 GetLerpedHrtfCoeffs(Device->Hrtf,
585 chans[c].elevation, chans[c].angle, 1.0f, DryGain,
586 voice->Direct.Hrtf.Params[c].Coeffs,
587 voice->Direct.Hrtf.Params[c].Delay);
590 voice->Direct.Counter = 0;
591 voice->Direct.Moving = AL_TRUE;
592 voice->Direct.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
594 voice->IsHrtf = AL_TRUE;
596 else
598 for(c = 0;c < num_channels;c++)
600 MixGains *gains = voice->Direct.Gains[c];
601 ALfloat Target[MAX_OUTPUT_CHANNELS];
603 /* Special-case LFE */
604 if(chans[c].channel == LFE)
606 int idx;
607 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
608 gains[i].Target = 0.0f;
609 if((idx=GetChannelIdxByName(Device, chans[c].channel)) != -1)
610 gains[idx].Target = DryGain;
611 continue;
614 ComputeAngleGains(Device, chans[c].angle, chans[c].elevation, DryGain, Target);
615 for(i = 0;i < MAX_OUTPUT_CHANNELS;i++)
616 gains[i].Target = Target[i];
618 UpdateDryStepping(&voice->Direct, num_channels, (voice->Direct.Moving ? 64 : 0));
619 voice->Direct.Moving = AL_TRUE;
621 voice->IsHrtf = AL_FALSE;
623 for(i = 0;i < NumSends;i++)
625 voice->Send[i].Gain.Target = WetGain[i];
626 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
627 voice->Send[i].Moving = AL_TRUE;
631 ALfloat gainhf = maxf(0.01f, DryGainHF);
632 ALfloat gainlf = maxf(0.01f, DryGainLF);
633 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
634 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
635 for(c = 0;c < num_channels;c++)
637 voice->Direct.Filters[c].ActiveType = AF_None;
638 if(gainhf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_LowPass;
639 if(gainlf != 1.0f) voice->Direct.Filters[c].ActiveType |= AF_HighPass;
640 ALfilterState_setParams(
641 &voice->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
642 hfscale, 0.0f
644 ALfilterState_setParams(
645 &voice->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
646 lfscale, 0.0f
650 for(i = 0;i < NumSends;i++)
652 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
653 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
654 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
655 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
656 for(c = 0;c < num_channels;c++)
658 voice->Send[i].Filters[c].ActiveType = AF_None;
659 if(gainhf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_LowPass;
660 if(gainlf != 1.0f) voice->Send[i].Filters[c].ActiveType |= AF_HighPass;
661 ALfilterState_setParams(
662 &voice->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
663 hfscale, 0.0f
665 ALfilterState_setParams(
666 &voice->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
667 lfscale, 0.0f
673 ALvoid CalcSourceParams(ALvoice *voice, const ALsource *ALSource, const ALCcontext *ALContext)
675 ALCdevice *Device = ALContext->Device;
676 ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
677 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
678 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
679 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
680 ALfloat DopplerFactor, SpeedOfSound;
681 ALfloat AirAbsorptionFactor;
682 ALfloat RoomAirAbsorption[MAX_SENDS];
683 ALbufferlistitem *BufferListItem;
684 ALfloat Attenuation;
685 ALfloat RoomAttenuation[MAX_SENDS];
686 ALfloat MetersPerUnit;
687 ALfloat RoomRolloffBase;
688 ALfloat RoomRolloff[MAX_SENDS];
689 ALfloat DecayDistance[MAX_SENDS];
690 ALfloat DryGain;
691 ALfloat DryGainHF;
692 ALfloat DryGainLF;
693 ALboolean DryGainHFAuto;
694 ALfloat WetGain[MAX_SENDS];
695 ALfloat WetGainHF[MAX_SENDS];
696 ALfloat WetGainLF[MAX_SENDS];
697 ALboolean WetGainAuto;
698 ALboolean WetGainHFAuto;
699 ALfloat Pitch;
700 ALuint Frequency;
701 ALint NumSends;
702 ALint i, j;
704 DryGainHF = 1.0f;
705 DryGainLF = 1.0f;
706 for(i = 0;i < MAX_SENDS;i++)
708 WetGainHF[i] = 1.0f;
709 WetGainLF[i] = 1.0f;
712 /* Get context/device properties */
713 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
714 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
715 NumSends = Device->NumAuxSends;
716 Frequency = Device->Frequency;
718 /* Get listener properties */
719 ListenerGain = ALContext->Listener->Gain;
720 MetersPerUnit = ALContext->Listener->MetersPerUnit;
722 /* Get source properties */
723 SourceVolume = ALSource->Gain;
724 MinVolume = ALSource->MinGain;
725 MaxVolume = ALSource->MaxGain;
726 Pitch = ALSource->Pitch;
727 Position[0] = ALSource->Position[0];
728 Position[1] = ALSource->Position[1];
729 Position[2] = ALSource->Position[2];
730 Direction[0] = ALSource->Direction[0];
731 Direction[1] = ALSource->Direction[1];
732 Direction[2] = ALSource->Direction[2];
733 Velocity[0] = ALSource->Velocity[0];
734 Velocity[1] = ALSource->Velocity[1];
735 Velocity[2] = ALSource->Velocity[2];
736 MinDist = ALSource->RefDistance;
737 MaxDist = ALSource->MaxDistance;
738 Rolloff = ALSource->RollOffFactor;
739 InnerAngle = ALSource->InnerAngle;
740 OuterAngle = ALSource->OuterAngle;
741 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
742 DryGainHFAuto = ALSource->DryGainHFAuto;
743 WetGainAuto = ALSource->WetGainAuto;
744 WetGainHFAuto = ALSource->WetGainHFAuto;
745 RoomRolloffBase = ALSource->RoomRolloffFactor;
747 voice->Direct.OutBuffer = Device->DryBuffer;
748 voice->Direct.OutChannels = Device->NumChannels;
749 for(i = 0;i < NumSends;i++)
751 ALeffectslot *Slot = ALSource->Send[i].Slot;
753 if(!Slot && i == 0)
754 Slot = Device->DefaultSlot;
755 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
757 Slot = NULL;
758 RoomRolloff[i] = 0.0f;
759 DecayDistance[i] = 0.0f;
760 RoomAirAbsorption[i] = 1.0f;
762 else if(Slot->AuxSendAuto)
764 RoomRolloff[i] = RoomRolloffBase;
765 if(IsReverbEffect(Slot->EffectType))
767 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
768 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
769 SPEEDOFSOUNDMETRESPERSEC;
770 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
772 else
774 DecayDistance[i] = 0.0f;
775 RoomAirAbsorption[i] = 1.0f;
778 else
780 /* If the slot's auxiliary send auto is off, the data sent to the
781 * effect slot is the same as the dry path, sans filter effects */
782 RoomRolloff[i] = Rolloff;
783 DecayDistance[i] = 0.0f;
784 RoomAirAbsorption[i] = AIRABSORBGAINHF;
787 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
788 voice->Send[i].OutBuffer = NULL;
789 else
790 voice->Send[i].OutBuffer = Slot->WetBuffer;
793 /* Transform source to listener space (convert to head relative) */
794 if(ALSource->HeadRelative == AL_FALSE)
796 ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
797 /* Transform source vectors */
798 aluMatrixVector(Position, 1.0f, Matrix);
799 aluMatrixVector(Direction, 0.0f, Matrix);
800 aluMatrixVector(Velocity, 0.0f, Matrix);
802 else
804 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
805 /* Offset the source velocity to be relative of the listener velocity */
806 Velocity[0] += ListenerVel[0];
807 Velocity[1] += ListenerVel[1];
808 Velocity[2] += ListenerVel[2];
811 SourceToListener[0] = -Position[0];
812 SourceToListener[1] = -Position[1];
813 SourceToListener[2] = -Position[2];
814 aluNormalize(SourceToListener);
815 aluNormalize(Direction);
817 /* Calculate distance attenuation */
818 Distance = sqrtf(aluDotproduct(Position, Position));
819 ClampedDist = Distance;
821 Attenuation = 1.0f;
822 for(i = 0;i < NumSends;i++)
823 RoomAttenuation[i] = 1.0f;
824 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
825 ALContext->DistanceModel)
827 case InverseDistanceClamped:
828 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
829 if(MaxDist < MinDist)
830 break;
831 /*fall-through*/
832 case InverseDistance:
833 if(MinDist > 0.0f)
835 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
836 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
837 for(i = 0;i < NumSends;i++)
839 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
840 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
843 break;
845 case LinearDistanceClamped:
846 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
847 if(MaxDist < MinDist)
848 break;
849 /*fall-through*/
850 case LinearDistance:
851 if(MaxDist != MinDist)
853 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
854 Attenuation = maxf(Attenuation, 0.0f);
855 for(i = 0;i < NumSends;i++)
857 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
858 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
861 break;
863 case ExponentDistanceClamped:
864 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
865 if(MaxDist < MinDist)
866 break;
867 /*fall-through*/
868 case ExponentDistance:
869 if(ClampedDist > 0.0f && MinDist > 0.0f)
871 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
872 for(i = 0;i < NumSends;i++)
873 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
875 break;
877 case DisableDistance:
878 ClampedDist = MinDist;
879 break;
882 /* Source Gain + Attenuation */
883 DryGain = SourceVolume * Attenuation;
884 for(i = 0;i < NumSends;i++)
885 WetGain[i] = SourceVolume * RoomAttenuation[i];
887 /* Distance-based air absorption */
888 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
890 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
891 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
892 for(i = 0;i < NumSends;i++)
893 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
896 if(WetGainAuto)
898 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
900 /* Apply a decay-time transformation to the wet path, based on the
901 * attenuation of the dry path.
903 * Using the apparent distance, based on the distance attenuation, the
904 * initial decay of the reverb effect is calculated and applied to the
905 * wet path.
907 for(i = 0;i < NumSends;i++)
909 if(DecayDistance[i] > 0.0f)
910 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
914 /* Calculate directional soundcones */
915 Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
916 if(Angle > InnerAngle && Angle <= OuterAngle)
918 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
919 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
920 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
922 else if(Angle > OuterAngle)
924 ConeVolume = ALSource->OuterGain;
925 ConeHF = ALSource->OuterGainHF;
927 else
929 ConeVolume = 1.0f;
930 ConeHF = 1.0f;
933 DryGain *= ConeVolume;
934 if(WetGainAuto)
936 for(i = 0;i < NumSends;i++)
937 WetGain[i] *= ConeVolume;
939 if(DryGainHFAuto)
940 DryGainHF *= ConeHF;
941 if(WetGainHFAuto)
943 for(i = 0;i < NumSends;i++)
944 WetGainHF[i] *= ConeHF;
947 /* Clamp to Min/Max Gain */
948 DryGain = clampf(DryGain, MinVolume, MaxVolume);
949 for(i = 0;i < NumSends;i++)
950 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
952 /* Apply gain and frequency filters */
953 DryGain *= ALSource->Direct.Gain * ListenerGain;
954 DryGainHF *= ALSource->Direct.GainHF;
955 DryGainLF *= ALSource->Direct.GainLF;
956 for(i = 0;i < NumSends;i++)
958 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
959 WetGainHF[i] *= ALSource->Send[i].GainHF;
960 WetGainLF[i] *= ALSource->Send[i].GainLF;
963 /* Calculate velocity-based doppler effect */
964 if(DopplerFactor > 0.0f)
966 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
967 ALfloat VSS, VLS;
969 if(SpeedOfSound < 1.0f)
971 DopplerFactor *= 1.0f/SpeedOfSound;
972 SpeedOfSound = 1.0f;
975 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
976 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
978 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
979 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
982 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
983 while(BufferListItem != NULL)
985 ALbuffer *ALBuffer;
986 if((ALBuffer=BufferListItem->buffer) != NULL)
988 /* Calculate fixed-point stepping value, based on the pitch, buffer
989 * frequency, and output frequency. */
990 Pitch = Pitch * ALBuffer->Frequency / Frequency;
991 if(Pitch > (ALfloat)MAX_PITCH)
992 voice->Step = MAX_PITCH<<FRACTIONBITS;
993 else
995 voice->Step = fastf2i(Pitch*FRACTIONONE);
996 if(voice->Step == 0)
997 voice->Step = 1;
1000 break;
1002 BufferListItem = BufferListItem->next;
1005 if(Device->Hrtf)
1007 /* Use a binaural HRTF algorithm for stereo headphone playback */
1008 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1009 ALfloat ev = 0.0f, az = 0.0f;
1010 ALfloat radius = ALSource->Radius;
1011 ALfloat dirfact = 1.0f;
1013 voice->Direct.OutBuffer = &voice->Direct.OutBuffer[voice->Direct.OutChannels];
1014 voice->Direct.OutChannels = 2;
1016 if(Distance > FLT_EPSILON)
1018 ALfloat invlen = 1.0f/Distance;
1019 dir[0] = Position[0] * invlen;
1020 dir[1] = Position[1] * invlen;
1021 dir[2] = Position[2] * invlen * ZScale;
1023 /* Calculate elevation and azimuth only when the source is not at
1024 * the listener. This prevents +0 and -0 Z from producing
1025 * inconsistent panning. Also, clamp Y in case FP precision errors
1026 * cause it to land outside of -1..+1. */
1027 ev = asinf(clampf(dir[1], -1.0f, 1.0f));
1028 az = atan2f(dir[0], -dir[2]);
1030 if(radius > Distance)
1031 dirfact *= Distance / radius;
1033 /* Check to see if the HRIR is already moving. */
1034 if(voice->Direct.Moving)
1036 ALfloat delta;
1037 delta = CalcFadeTime(voice->Direct.LastGain, DryGain,
1038 voice->Direct.LastDir, dir);
1039 /* If the delta is large enough, get the moving HRIR target
1040 * coefficients, target delays, steppping values, and counter. */
1041 if(delta > 0.000015f)
1043 ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
1044 ev, az, dirfact, DryGain, delta, voice->Direct.Counter,
1045 voice->Direct.Hrtf.Params[0].Coeffs, voice->Direct.Hrtf.Params[0].Delay,
1046 voice->Direct.Hrtf.Params[0].CoeffStep, voice->Direct.Hrtf.Params[0].DelayStep
1048 voice->Direct.Counter = counter;
1049 voice->Direct.LastGain = DryGain;
1050 voice->Direct.LastDir[0] = dir[0];
1051 voice->Direct.LastDir[1] = dir[1];
1052 voice->Direct.LastDir[2] = dir[2];
1055 else
1057 /* Get the initial (static) HRIR coefficients and delays. */
1058 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
1059 voice->Direct.Hrtf.Params[0].Coeffs,
1060 voice->Direct.Hrtf.Params[0].Delay);
1061 voice->Direct.Counter = 0;
1062 voice->Direct.Moving = AL_TRUE;
1063 voice->Direct.LastGain = DryGain;
1064 voice->Direct.LastDir[0] = dir[0];
1065 voice->Direct.LastDir[1] = dir[1];
1066 voice->Direct.LastDir[2] = dir[2];
1068 voice->Direct.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
1070 voice->IsHrtf = AL_TRUE;
1072 else
1074 MixGains *gains = voice->Direct.Gains[0];
1075 ALfloat dir[3] = { 0.0f, 0.0f, -1.0f };
1076 ALfloat radius = ALSource->Radius;
1077 ALfloat Target[MAX_OUTPUT_CHANNELS];
1079 /* Normalize the length, and compute panned gains. */
1080 if(Distance > FLT_EPSILON || radius > FLT_EPSILON)
1082 ALfloat invlen = 1.0f/maxf(Distance, radius);
1083 dir[0] = Position[0] * invlen;
1084 dir[1] = Position[1] * invlen;
1085 dir[2] = Position[2] * invlen * ZScale;
1087 ComputeDirectionalGains(Device, dir, DryGain, Target);
1089 for(j = 0;j < MAX_OUTPUT_CHANNELS;j++)
1090 gains[j].Target = Target[j];
1091 UpdateDryStepping(&voice->Direct, 1, (voice->Direct.Moving ? 64 : 0));
1092 voice->Direct.Moving = AL_TRUE;
1094 voice->IsHrtf = AL_FALSE;
1096 for(i = 0;i < NumSends;i++)
1098 voice->Send[i].Gain.Target = WetGain[i];
1099 UpdateWetStepping(&voice->Send[i], (voice->Send[i].Moving ? 64 : 0));
1100 voice->Send[i].Moving = AL_TRUE;
1104 ALfloat gainhf = maxf(0.01f, DryGainHF);
1105 ALfloat gainlf = maxf(0.01f, DryGainLF);
1106 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1107 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1108 voice->Direct.Filters[0].ActiveType = AF_None;
1109 if(gainhf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_LowPass;
1110 if(gainlf != 1.0f) voice->Direct.Filters[0].ActiveType |= AF_HighPass;
1111 ALfilterState_setParams(
1112 &voice->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1113 hfscale, 0.0f
1115 ALfilterState_setParams(
1116 &voice->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1117 lfscale, 0.0f
1120 for(i = 0;i < NumSends;i++)
1122 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
1123 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
1124 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1125 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1126 voice->Send[i].Filters[0].ActiveType = AF_None;
1127 if(gainhf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_LowPass;
1128 if(gainlf != 1.0f) voice->Send[i].Filters[0].ActiveType |= AF_HighPass;
1129 ALfilterState_setParams(
1130 &voice->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1131 hfscale, 0.0f
1133 ALfilterState_setParams(
1134 &voice->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1135 lfscale, 0.0f
1141 static inline ALint aluF2I25(ALfloat val)
1143 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1144 if(fabsf(val) > 1.0f)
1145 val = (ALfloat)((0.0f < val) - (val < 0.0f));
1146 /* Convert to a signed integer, between -16777215 and +16777215. */
1147 return fastf2i(val*16777215.0f);
1150 static inline ALfloat aluF2F(ALfloat val)
1151 { return val; }
1152 static inline ALint aluF2I(ALfloat val)
1153 { return aluF2I25(val)<<7; }
1154 static inline ALuint aluF2UI(ALfloat val)
1155 { return aluF2I(val)+2147483648u; }
1156 static inline ALshort aluF2S(ALfloat val)
1157 { return aluF2I25(val)>>9; }
1158 static inline ALushort aluF2US(ALfloat val)
1159 { return aluF2S(val)+32768; }
1160 static inline ALbyte aluF2B(ALfloat val)
1161 { return aluF2I25(val)>>17; }
1162 static inline ALubyte aluF2UB(ALfloat val)
1163 { return aluF2B(val)+128; }
1165 #define DECL_TEMPLATE(T, func) \
1166 static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1167 ALuint SamplesToDo, ALuint numchans) \
1169 ALuint i, j; \
1170 for(j = 0;j < numchans;j++) \
1172 const ALfloat *in = InBuffer[j]; \
1173 T *restrict out = (T*)OutBuffer + j; \
1174 for(i = 0;i < SamplesToDo;i++) \
1175 out[i*numchans] = func(in[i]); \
1179 DECL_TEMPLATE(ALfloat, aluF2F)
1180 DECL_TEMPLATE(ALuint, aluF2UI)
1181 DECL_TEMPLATE(ALint, aluF2I)
1182 DECL_TEMPLATE(ALushort, aluF2US)
1183 DECL_TEMPLATE(ALshort, aluF2S)
1184 DECL_TEMPLATE(ALubyte, aluF2UB)
1185 DECL_TEMPLATE(ALbyte, aluF2B)
1187 #undef DECL_TEMPLATE
1190 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1192 ALuint SamplesToDo;
1193 ALeffectslot **slot, **slot_end;
1194 ALvoice *voice, *voice_end;
1195 ALCcontext *ctx;
1196 FPUCtl oldMode;
1197 ALuint i, c;
1199 SetMixerFPUMode(&oldMode);
1201 while(size > 0)
1203 ALuint outchanoffset = 0;
1204 ALuint outchancount = device->NumChannels;
1206 IncrementRef(&device->MixCount);
1208 SamplesToDo = minu(size, BUFFERSIZE);
1209 for(c = 0;c < device->NumChannels;c++)
1210 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1211 if(device->Hrtf)
1213 outchanoffset = device->NumChannels;
1214 outchancount = 2;
1215 for(c = 0;c < outchancount;c++)
1216 memset(device->DryBuffer[outchanoffset+c], 0, SamplesToDo*sizeof(ALfloat));
1219 V0(device->Backend,lock)();
1220 V(device->Synth,process)(SamplesToDo, &device->DryBuffer[outchanoffset]);
1222 ctx = ATOMIC_LOAD(&device->ContextList);
1223 while(ctx)
1225 ALenum DeferUpdates = ctx->DeferUpdates;
1226 ALenum UpdateSources = AL_FALSE;
1228 if(!DeferUpdates)
1229 UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
1231 if(UpdateSources)
1232 CalcListenerParams(ctx->Listener);
1234 /* source processing */
1235 voice = ctx->Voices;
1236 voice_end = voice + ctx->VoiceCount;
1237 while(voice != voice_end)
1239 ALsource *source = voice->Source;
1240 if(!source) goto next;
1242 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1244 voice->Source = NULL;
1245 goto next;
1248 if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
1249 UpdateSources))
1250 voice->Update(voice, source, ctx);
1252 if(source->state != AL_PAUSED)
1253 MixSource(voice, source, device, SamplesToDo);
1254 next:
1255 voice++;
1258 /* effect slot processing */
1259 slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
1260 slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
1261 while(slot != slot_end)
1263 if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1264 V((*slot)->EffectState,update)(device, *slot);
1266 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1267 device->DryBuffer, device->NumChannels);
1269 for(i = 0;i < SamplesToDo;i++)
1270 (*slot)->WetBuffer[0][i] = 0.0f;
1272 slot++;
1275 ctx = ctx->next;
1278 slot = &device->DefaultSlot;
1279 if(*slot != NULL)
1281 if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1282 V((*slot)->EffectState,update)(device, *slot);
1284 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1285 device->DryBuffer, device->NumChannels);
1287 for(i = 0;i < SamplesToDo;i++)
1288 (*slot)->WetBuffer[0][i] = 0.0f;
1291 /* Increment the clock time. Every second's worth of samples is
1292 * converted and added to clock base so that large sample counts don't
1293 * overflow during conversion. This also guarantees an exact, stable
1294 * conversion. */
1295 device->SamplesDone += SamplesToDo;
1296 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1297 device->SamplesDone %= device->Frequency;
1298 V0(device->Backend,unlock)();
1300 if(device->Hrtf)
1302 HrtfMixerFunc HrtfMix = SelectHrtfMixer();
1303 ALuint irsize = GetHrtfIrSize(device->Hrtf);
1304 for(c = 0;c < device->NumChannels;c++)
1305 HrtfMix(&device->DryBuffer[outchanoffset], device->DryBuffer[c], 0.0f,
1306 device->Hrtf_Offset, 0.0f, irsize, &device->Hrtf_Params[c],
1307 &device->Hrtf_State[c], SamplesToDo
1309 device->Hrtf_Offset += SamplesToDo;
1311 else if(device->Bs2b)
1313 /* Apply binaural/crossfeed filter */
1314 for(i = 0;i < SamplesToDo;i++)
1316 float samples[2];
1317 samples[0] = device->DryBuffer[0][i];
1318 samples[1] = device->DryBuffer[1][i];
1319 bs2b_cross_feed(device->Bs2b, samples);
1320 device->DryBuffer[0][i] = samples[0];
1321 device->DryBuffer[1][i] = samples[1];
1325 if(buffer)
1327 #define WRITE(T, a, b, c, d) do { \
1328 Write_##T((a), (b), (c), (d)); \
1329 buffer = (char*)buffer + (c)*(d)*sizeof(T); \
1330 } while(0)
1331 switch(device->FmtType)
1333 case DevFmtByte:
1334 WRITE(ALbyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1335 break;
1336 case DevFmtUByte:
1337 WRITE(ALubyte, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1338 break;
1339 case DevFmtShort:
1340 WRITE(ALshort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1341 break;
1342 case DevFmtUShort:
1343 WRITE(ALushort, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1344 break;
1345 case DevFmtInt:
1346 WRITE(ALint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1347 break;
1348 case DevFmtUInt:
1349 WRITE(ALuint, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1350 break;
1351 case DevFmtFloat:
1352 WRITE(ALfloat, device->DryBuffer+outchanoffset, buffer, SamplesToDo, outchancount);
1353 break;
1355 #undef WRITE
1358 size -= SamplesToDo;
1359 IncrementRef(&device->MixCount);
1362 RestoreFPUMode(&oldMode);
1366 ALvoid aluHandleDisconnect(ALCdevice *device)
1368 ALCcontext *Context;
1370 device->Connected = ALC_FALSE;
1372 Context = ATOMIC_LOAD(&device->ContextList);
1373 while(Context)
1375 ALvoice *voice, *voice_end;
1377 voice = Context->Voices;
1378 voice_end = voice + Context->VoiceCount;
1379 while(voice != voice_end)
1381 ALsource *source = voice->Source;
1382 voice->Source = NULL;
1384 if(source && source->state == AL_PLAYING)
1386 source->state = AL_STOPPED;
1387 ATOMIC_STORE(&source->current_buffer, NULL);
1388 source->position = 0;
1389 source->position_fraction = 0;
1392 voice++;
1394 Context->VoiceCount = 0;
1396 Context = Context->next;