Try the __cpuid intrinsic if GCC's __get_cpuid isn't available
[openal-soft.git] / Alc / ALu.c
bloba85e1aa06e8a63e29c7563db72e9373e79728728
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., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, 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 "midi/base.h"
42 static_assert((INT_MAX>>FRACTIONBITS)/MAX_PITCH > BUFFERSIZE,
43 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
45 struct ChanMap {
46 enum Channel channel;
47 ALfloat angle;
50 /* Cone scalar */
51 ALfloat ConeScale = 1.0f;
53 /* Localized Z scalar for mono sources */
54 ALfloat ZScale = 1.0f;
56 extern inline ALfloat minf(ALfloat a, ALfloat b);
57 extern inline ALfloat maxf(ALfloat a, ALfloat b);
58 extern inline ALfloat clampf(ALfloat val, ALfloat min, ALfloat max);
60 extern inline ALdouble mind(ALdouble a, ALdouble b);
61 extern inline ALdouble maxd(ALdouble a, ALdouble b);
62 extern inline ALdouble clampd(ALdouble val, ALdouble min, ALdouble max);
64 extern inline ALuint minu(ALuint a, ALuint b);
65 extern inline ALuint maxu(ALuint a, ALuint b);
66 extern inline ALuint clampu(ALuint val, ALuint min, ALuint max);
68 extern inline ALint mini(ALint a, ALint b);
69 extern inline ALint maxi(ALint a, ALint b);
70 extern inline ALint clampi(ALint val, ALint min, ALint max);
72 extern inline ALint64 mini64(ALint64 a, ALint64 b);
73 extern inline ALint64 maxi64(ALint64 a, ALint64 b);
74 extern inline ALint64 clampi64(ALint64 val, ALint64 min, ALint64 max);
76 extern inline ALuint64 minu64(ALuint64 a, ALuint64 b);
77 extern inline ALuint64 maxu64(ALuint64 a, ALuint64 b);
78 extern inline ALuint64 clampu64(ALuint64 val, ALuint64 min, ALuint64 max);
80 extern inline ALfloat lerp(ALfloat val1, ALfloat val2, ALfloat mu);
81 extern inline ALfloat cubic(ALfloat val0, ALfloat val1, ALfloat val2, ALfloat val3, ALfloat mu);
84 static inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
86 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
87 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
88 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
91 static inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
93 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
94 inVector1[2]*inVector2[2];
97 static inline void aluNormalize(ALfloat *inVector)
99 ALfloat lengthsqr = aluDotproduct(inVector, inVector);
100 if(lengthsqr > 0.0f)
102 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
103 inVector[0] *= inv_length;
104 inVector[1] *= inv_length;
105 inVector[2] *= inv_length;
109 static inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*restrict matrix)[4])
111 ALfloat temp[4] = {
112 vector[0], vector[1], vector[2], w
115 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
116 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
117 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
121 static ALvoid CalcListenerParams(ALlistener *Listener)
123 ALfloat N[3], V[3], U[3], P[3];
125 /* AT then UP */
126 N[0] = Listener->Forward[0];
127 N[1] = Listener->Forward[1];
128 N[2] = Listener->Forward[2];
129 aluNormalize(N);
130 V[0] = Listener->Up[0];
131 V[1] = Listener->Up[1];
132 V[2] = Listener->Up[2];
133 aluNormalize(V);
134 /* Build and normalize right-vector */
135 aluCrossproduct(N, V, U);
136 aluNormalize(U);
138 Listener->Params.Matrix[0][0] = U[0];
139 Listener->Params.Matrix[0][1] = V[0];
140 Listener->Params.Matrix[0][2] = -N[0];
141 Listener->Params.Matrix[0][3] = 0.0f;
142 Listener->Params.Matrix[1][0] = U[1];
143 Listener->Params.Matrix[1][1] = V[1];
144 Listener->Params.Matrix[1][2] = -N[1];
145 Listener->Params.Matrix[1][3] = 0.0f;
146 Listener->Params.Matrix[2][0] = U[2];
147 Listener->Params.Matrix[2][1] = V[2];
148 Listener->Params.Matrix[2][2] = -N[2];
149 Listener->Params.Matrix[2][3] = 0.0f;
150 Listener->Params.Matrix[3][0] = 0.0f;
151 Listener->Params.Matrix[3][1] = 0.0f;
152 Listener->Params.Matrix[3][2] = 0.0f;
153 Listener->Params.Matrix[3][3] = 1.0f;
155 P[0] = Listener->Position[0];
156 P[1] = Listener->Position[1];
157 P[2] = Listener->Position[2];
158 aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
159 Listener->Params.Matrix[3][0] = -P[0];
160 Listener->Params.Matrix[3][1] = -P[1];
161 Listener->Params.Matrix[3][2] = -P[2];
163 Listener->Params.Velocity[0] = Listener->Velocity[0];
164 Listener->Params.Velocity[1] = Listener->Velocity[1];
165 Listener->Params.Velocity[2] = Listener->Velocity[2];
166 aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
169 ALvoid CalcNonAttnSourceParams(ALactivesource *src, const ALCcontext *ALContext)
171 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
172 static const struct ChanMap StereoMap[2] = {
173 { FrontLeft, DEG2RAD(-30.0f) },
174 { FrontRight, DEG2RAD( 30.0f) }
176 static const struct ChanMap StereoWideMap[2] = {
177 { FrontLeft, DEG2RAD(-90.0f) },
178 { FrontRight, DEG2RAD( 90.0f) }
180 static const struct ChanMap RearMap[2] = {
181 { BackLeft, DEG2RAD(-150.0f) },
182 { BackRight, DEG2RAD( 150.0f) }
184 static const struct ChanMap QuadMap[4] = {
185 { FrontLeft, DEG2RAD( -45.0f) },
186 { FrontRight, DEG2RAD( 45.0f) },
187 { BackLeft, DEG2RAD(-135.0f) },
188 { BackRight, DEG2RAD( 135.0f) }
190 static const struct ChanMap X51Map[6] = {
191 { FrontLeft, DEG2RAD( -30.0f) },
192 { FrontRight, DEG2RAD( 30.0f) },
193 { FrontCenter, DEG2RAD( 0.0f) },
194 { LFE, 0.0f },
195 { BackLeft, DEG2RAD(-110.0f) },
196 { BackRight, DEG2RAD( 110.0f) }
198 static const struct ChanMap X61Map[7] = {
199 { FrontLeft, DEG2RAD(-30.0f) },
200 { FrontRight, DEG2RAD( 30.0f) },
201 { FrontCenter, DEG2RAD( 0.0f) },
202 { LFE, 0.0f },
203 { BackCenter, DEG2RAD(180.0f) },
204 { SideLeft, DEG2RAD(-90.0f) },
205 { SideRight, DEG2RAD( 90.0f) }
207 static const struct ChanMap X71Map[8] = {
208 { FrontLeft, DEG2RAD( -30.0f) },
209 { FrontRight, DEG2RAD( 30.0f) },
210 { FrontCenter, DEG2RAD( 0.0f) },
211 { LFE, 0.0f },
212 { BackLeft, DEG2RAD(-150.0f) },
213 { BackRight, DEG2RAD( 150.0f) },
214 { SideLeft, DEG2RAD( -90.0f) },
215 { SideRight, DEG2RAD( 90.0f) }
218 ALCdevice *Device = ALContext->Device;
219 const ALsource *ALSource = src->Source;
220 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
221 ALbufferlistitem *BufferListItem;
222 enum FmtChannels Channels;
223 ALfloat DryGain, DryGainHF, DryGainLF;
224 ALfloat WetGain[MAX_SENDS];
225 ALfloat WetGainHF[MAX_SENDS];
226 ALfloat WetGainLF[MAX_SENDS];
227 ALint NumSends, Frequency;
228 const struct ChanMap *chans = NULL;
229 ALint num_channels = 0;
230 ALboolean DirectChannels;
231 ALfloat hwidth = 0.0f;
232 ALfloat Pitch;
233 ALint i, j, c;
235 /* Get device properties */
236 NumSends = Device->NumAuxSends;
237 Frequency = Device->Frequency;
239 /* Get listener properties */
240 ListenerGain = ALContext->Listener->Gain;
242 /* Get source properties */
243 SourceVolume = ALSource->Gain;
244 MinVolume = ALSource->MinGain;
245 MaxVolume = ALSource->MaxGain;
246 Pitch = ALSource->Pitch;
247 DirectChannels = ALSource->DirectChannels;
249 src->Direct.OutBuffer = Device->DryBuffer;
250 for(i = 0;i < NumSends;i++)
252 ALeffectslot *Slot = ALSource->Send[i].Slot;
253 if(!Slot && i == 0)
254 Slot = Device->DefaultSlot;
255 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
256 src->Send[i].OutBuffer = NULL;
257 else
258 src->Send[i].OutBuffer = Slot->WetBuffer;
261 /* Calculate the stepping value */
262 Channels = FmtMono;
263 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
264 while(BufferListItem != NULL)
266 ALbuffer *ALBuffer;
267 if((ALBuffer=BufferListItem->buffer) != NULL)
269 Pitch = Pitch * ALBuffer->Frequency / Frequency;
270 if(Pitch > (ALfloat)MAX_PITCH)
271 src->Step = MAX_PITCH<<FRACTIONBITS;
272 else
274 src->Step = fastf2i(Pitch*FRACTIONONE);
275 if(src->Step == 0)
276 src->Step = 1;
279 Channels = ALBuffer->FmtChannels;
280 break;
282 BufferListItem = BufferListItem->next;
285 /* Calculate gains */
286 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
287 DryGain *= ALSource->Direct.Gain * ListenerGain;
288 DryGainHF = ALSource->Direct.GainHF;
289 DryGainLF = ALSource->Direct.GainLF;
290 for(i = 0;i < NumSends;i++)
292 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
293 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
294 WetGainHF[i] = ALSource->Send[i].GainHF;
295 WetGainLF[i] = ALSource->Send[i].GainLF;
298 switch(Channels)
300 case FmtMono:
301 chans = MonoMap;
302 num_channels = 1;
303 break;
305 case FmtStereo:
306 if(!(Device->Flags&DEVICE_WIDE_STEREO))
308 /* HACK: Place the stereo channels at +/-90 degrees when using non-
309 * HRTF stereo output. This helps reduce the "monoization" caused
310 * by them panning towards the center. */
311 if(Device->FmtChans == DevFmtStereo && !Device->Hrtf)
312 chans = StereoWideMap;
313 else
314 chans = StereoMap;
316 else
318 chans = StereoWideMap;
319 hwidth = DEG2RAD(60.0f);
321 num_channels = 2;
322 break;
324 case FmtRear:
325 chans = RearMap;
326 num_channels = 2;
327 break;
329 case FmtQuad:
330 chans = QuadMap;
331 num_channels = 4;
332 break;
334 case FmtX51:
335 chans = X51Map;
336 num_channels = 6;
337 break;
339 case FmtX61:
340 chans = X61Map;
341 num_channels = 7;
342 break;
344 case FmtX71:
345 chans = X71Map;
346 num_channels = 8;
347 break;
350 if(DirectChannels != AL_FALSE)
352 for(c = 0;c < num_channels;c++)
354 MixGains *gains = src->Direct.Mix.Gains[c];
355 for(j = 0;j < MaxChannels;j++)
356 gains[j].Target = 0.0f;
359 for(c = 0;c < num_channels;c++)
361 MixGains *gains = src->Direct.Mix.Gains[c];
362 for(i = 0;i < (ALint)Device->NumChan;i++)
364 enum Channel chan = Device->Speaker2Chan[i];
365 if(chan == chans[c].channel)
367 gains[chan].Target = DryGain;
368 break;
373 if(!src->Direct.Moving)
375 for(i = 0;i < num_channels;i++)
377 MixGains *gains = src->Direct.Mix.Gains[i];
378 for(j = 0;j < MaxChannels;j++)
380 gains[j].Current = gains[j].Target;
381 gains[j].Step = 1.0f;
384 src->Direct.Counter = 0;
385 src->Direct.Moving = AL_TRUE;
387 else
389 for(i = 0;i < num_channels;i++)
391 MixGains *gains = src->Direct.Mix.Gains[i];
392 for(j = 0;j < MaxChannels;j++)
394 ALfloat cur = maxf(gains[j].Current, FLT_EPSILON);
395 ALfloat trg = maxf(gains[j].Target, FLT_EPSILON);
396 if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
397 gains[j].Step = powf(trg/cur, 1.0f/64.0f);
398 else
399 gains[j].Step = 1.0f;
400 gains[j].Current = cur;
403 src->Direct.Counter = 64;
406 src->IsHrtf = AL_FALSE;
408 else if(Device->Hrtf)
410 for(c = 0;c < num_channels;c++)
412 if(chans[c].channel == LFE)
414 /* Skip LFE */
415 src->Direct.Mix.Hrtf.Params[c].Delay[0] = 0;
416 src->Direct.Mix.Hrtf.Params[c].Delay[1] = 0;
417 for(i = 0;i < HRIR_LENGTH;i++)
419 src->Direct.Mix.Hrtf.Params[c].Coeffs[i][0] = 0.0f;
420 src->Direct.Mix.Hrtf.Params[c].Coeffs[i][1] = 0.0f;
423 else
425 /* Get the static HRIR coefficients and delays for this
426 * channel. */
427 GetLerpedHrtfCoeffs(Device->Hrtf,
428 0.0f, chans[c].angle, 1.0f, DryGain,
429 src->Direct.Mix.Hrtf.Params[c].Coeffs,
430 src->Direct.Mix.Hrtf.Params[c].Delay);
433 src->Direct.Counter = 0;
434 src->Direct.Moving = AL_TRUE;
435 src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
437 src->IsHrtf = AL_TRUE;
439 else
441 for(i = 0;i < num_channels;i++)
443 MixGains *gains = src->Direct.Mix.Gains[i];
444 for(j = 0;j < MaxChannels;j++)
445 gains[j].Target = 0.0f;
448 DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
449 for(c = 0;c < num_channels;c++)
451 MixGains *gains = src->Direct.Mix.Gains[c];
452 ALfloat Target[MaxChannels];
454 /* Special-case LFE */
455 if(chans[c].channel == LFE)
457 gains[chans[c].channel].Target = DryGain;
458 continue;
460 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain, Target);
461 for(i = 0;i < MaxChannels;i++)
462 gains[i].Target = Target[i];
465 if(!src->Direct.Moving)
467 for(i = 0;i < num_channels;i++)
469 MixGains *gains = src->Direct.Mix.Gains[i];
470 for(j = 0;j < MaxChannels;j++)
472 gains[j].Current = gains[j].Target;
473 gains[j].Step = 1.0f;
476 src->Direct.Counter = 0;
477 src->Direct.Moving = AL_TRUE;
479 else
481 for(i = 0;i < num_channels;i++)
483 MixGains *gains = src->Direct.Mix.Gains[i];
484 for(j = 0;j < MaxChannels;j++)
486 ALfloat trg = maxf(gains[j].Target, FLT_EPSILON);
487 ALfloat cur = maxf(gains[j].Current, FLT_EPSILON);
488 if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
489 gains[j].Step = powf(trg/cur, 1.0f/64.0f);
490 else
491 gains[j].Step = 1.0f;
492 gains[j].Current = cur;
495 src->Direct.Counter = 64;
498 src->IsHrtf = AL_FALSE;
500 for(i = 0;i < NumSends;i++)
502 src->Send[i].Gain.Target = WetGain[i];
503 if(!src->Send[i].Moving)
505 src->Send[i].Gain.Current = src->Send[i].Gain.Target;
506 src->Send[i].Gain.Step = 1.0f;
507 src->Send[i].Counter = 0;
508 src->Send[i].Moving = AL_TRUE;
510 else
512 ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
513 ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
514 if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
515 src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
516 else
517 src->Send[i].Gain.Step = 1.0f;
518 src->Send[i].Gain.Current = cur;
519 src->Send[i].Counter = 64;
524 ALfloat gainhf = maxf(0.01f, DryGainHF);
525 ALfloat gainlf = maxf(0.01f, DryGainLF);
526 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
527 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
528 for(c = 0;c < num_channels;c++)
530 src->Direct.Filters[c].ActiveType = AF_None;
531 if(gainhf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_LowPass;
532 if(gainlf != 1.0f) src->Direct.Filters[c].ActiveType |= AF_HighPass;
533 ALfilterState_setParams(
534 &src->Direct.Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
535 hfscale, 0.0f
537 ALfilterState_setParams(
538 &src->Direct.Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
539 lfscale, 0.0f
543 for(i = 0;i < NumSends;i++)
545 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
546 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
547 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
548 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
549 for(c = 0;c < num_channels;c++)
551 src->Send[i].Filters[c].ActiveType = AF_None;
552 if(gainhf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_LowPass;
553 if(gainlf != 1.0f) src->Send[i].Filters[c].ActiveType |= AF_HighPass;
554 ALfilterState_setParams(
555 &src->Send[i].Filters[c].LowPass, ALfilterType_HighShelf, gainhf,
556 hfscale, 0.0f
558 ALfilterState_setParams(
559 &src->Send[i].Filters[c].HighPass, ALfilterType_LowShelf, gainlf,
560 lfscale, 0.0f
566 ALvoid CalcSourceParams(ALactivesource *src, const ALCcontext *ALContext)
568 ALCdevice *Device = ALContext->Device;
569 const ALsource *ALSource = src->Source;
570 ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
571 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
572 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
573 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
574 ALfloat DopplerFactor, SpeedOfSound;
575 ALfloat AirAbsorptionFactor;
576 ALfloat RoomAirAbsorption[MAX_SENDS];
577 ALbufferlistitem *BufferListItem;
578 ALfloat Attenuation;
579 ALfloat RoomAttenuation[MAX_SENDS];
580 ALfloat MetersPerUnit;
581 ALfloat RoomRolloffBase;
582 ALfloat RoomRolloff[MAX_SENDS];
583 ALfloat DecayDistance[MAX_SENDS];
584 ALfloat DryGain;
585 ALfloat DryGainHF;
586 ALfloat DryGainLF;
587 ALboolean DryGainHFAuto;
588 ALfloat WetGain[MAX_SENDS];
589 ALfloat WetGainHF[MAX_SENDS];
590 ALfloat WetGainLF[MAX_SENDS];
591 ALboolean WetGainAuto;
592 ALboolean WetGainHFAuto;
593 ALfloat Pitch;
594 ALuint Frequency;
595 ALint NumSends;
596 ALint i, j;
598 DryGainHF = 1.0f;
599 DryGainLF = 1.0f;
600 for(i = 0;i < MAX_SENDS;i++)
602 WetGainHF[i] = 1.0f;
603 WetGainLF[i] = 1.0f;
606 /* Get context/device properties */
607 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
608 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
609 NumSends = Device->NumAuxSends;
610 Frequency = Device->Frequency;
612 /* Get listener properties */
613 ListenerGain = ALContext->Listener->Gain;
614 MetersPerUnit = ALContext->Listener->MetersPerUnit;
616 /* Get source properties */
617 SourceVolume = ALSource->Gain;
618 MinVolume = ALSource->MinGain;
619 MaxVolume = ALSource->MaxGain;
620 Pitch = ALSource->Pitch;
621 Position[0] = ALSource->Position[0];
622 Position[1] = ALSource->Position[1];
623 Position[2] = ALSource->Position[2];
624 Direction[0] = ALSource->Orientation[0];
625 Direction[1] = ALSource->Orientation[1];
626 Direction[2] = ALSource->Orientation[2];
627 Velocity[0] = ALSource->Velocity[0];
628 Velocity[1] = ALSource->Velocity[1];
629 Velocity[2] = ALSource->Velocity[2];
630 MinDist = ALSource->RefDistance;
631 MaxDist = ALSource->MaxDistance;
632 Rolloff = ALSource->RollOffFactor;
633 InnerAngle = ALSource->InnerAngle;
634 OuterAngle = ALSource->OuterAngle;
635 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
636 DryGainHFAuto = ALSource->DryGainHFAuto;
637 WetGainAuto = ALSource->WetGainAuto;
638 WetGainHFAuto = ALSource->WetGainHFAuto;
639 RoomRolloffBase = ALSource->RoomRolloffFactor;
641 src->Direct.OutBuffer = Device->DryBuffer;
642 for(i = 0;i < NumSends;i++)
644 ALeffectslot *Slot = ALSource->Send[i].Slot;
646 if(!Slot && i == 0)
647 Slot = Device->DefaultSlot;
648 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
650 Slot = NULL;
651 RoomRolloff[i] = 0.0f;
652 DecayDistance[i] = 0.0f;
653 RoomAirAbsorption[i] = 1.0f;
655 else if(Slot->AuxSendAuto)
657 RoomRolloff[i] = RoomRolloffBase;
658 if(IsReverbEffect(Slot->EffectType))
660 RoomRolloff[i] += Slot->EffectProps.Reverb.RoomRolloffFactor;
661 DecayDistance[i] = Slot->EffectProps.Reverb.DecayTime *
662 SPEEDOFSOUNDMETRESPERSEC;
663 RoomAirAbsorption[i] = Slot->EffectProps.Reverb.AirAbsorptionGainHF;
665 else
667 DecayDistance[i] = 0.0f;
668 RoomAirAbsorption[i] = 1.0f;
671 else
673 /* If the slot's auxiliary send auto is off, the data sent to the
674 * effect slot is the same as the dry path, sans filter effects */
675 RoomRolloff[i] = Rolloff;
676 DecayDistance[i] = 0.0f;
677 RoomAirAbsorption[i] = AIRABSORBGAINHF;
680 if(!Slot || Slot->EffectType == AL_EFFECT_NULL)
681 src->Send[i].OutBuffer = NULL;
682 else
683 src->Send[i].OutBuffer = Slot->WetBuffer;
686 /* Transform source to listener space (convert to head relative) */
687 if(ALSource->HeadRelative == AL_FALSE)
689 ALfloat (*restrict Matrix)[4] = ALContext->Listener->Params.Matrix;
690 /* Transform source vectors */
691 aluMatrixVector(Position, 1.0f, Matrix);
692 aluMatrixVector(Direction, 0.0f, Matrix);
693 aluMatrixVector(Velocity, 0.0f, Matrix);
695 else
697 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
698 /* Offset the source velocity to be relative of the listener velocity */
699 Velocity[0] += ListenerVel[0];
700 Velocity[1] += ListenerVel[1];
701 Velocity[2] += ListenerVel[2];
704 SourceToListener[0] = -Position[0];
705 SourceToListener[1] = -Position[1];
706 SourceToListener[2] = -Position[2];
707 aluNormalize(SourceToListener);
708 aluNormalize(Direction);
710 /* Calculate distance attenuation */
711 Distance = sqrtf(aluDotproduct(Position, Position));
712 ClampedDist = Distance;
714 Attenuation = 1.0f;
715 for(i = 0;i < NumSends;i++)
716 RoomAttenuation[i] = 1.0f;
717 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
718 ALContext->DistanceModel)
720 case InverseDistanceClamped:
721 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
722 if(MaxDist < MinDist)
723 break;
724 /*fall-through*/
725 case InverseDistance:
726 if(MinDist > 0.0f)
728 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
729 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
730 for(i = 0;i < NumSends;i++)
732 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
733 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
736 break;
738 case LinearDistanceClamped:
739 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
740 if(MaxDist < MinDist)
741 break;
742 /*fall-through*/
743 case LinearDistance:
744 if(MaxDist != MinDist)
746 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
747 Attenuation = maxf(Attenuation, 0.0f);
748 for(i = 0;i < NumSends;i++)
750 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
751 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
754 break;
756 case ExponentDistanceClamped:
757 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
758 if(MaxDist < MinDist)
759 break;
760 /*fall-through*/
761 case ExponentDistance:
762 if(ClampedDist > 0.0f && MinDist > 0.0f)
764 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
765 for(i = 0;i < NumSends;i++)
766 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
768 break;
770 case DisableDistance:
771 ClampedDist = MinDist;
772 break;
775 /* Source Gain + Attenuation */
776 DryGain = SourceVolume * Attenuation;
777 for(i = 0;i < NumSends;i++)
778 WetGain[i] = SourceVolume * RoomAttenuation[i];
780 /* Distance-based air absorption */
781 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
783 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
784 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
785 for(i = 0;i < NumSends;i++)
786 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
789 if(WetGainAuto)
791 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
793 /* Apply a decay-time transformation to the wet path, based on the
794 * attenuation of the dry path.
796 * Using the apparent distance, based on the distance attenuation, the
797 * initial decay of the reverb effect is calculated and applied to the
798 * wet path.
800 for(i = 0;i < NumSends;i++)
802 if(DecayDistance[i] > 0.0f)
803 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
807 /* Calculate directional soundcones */
808 Angle = RAD2DEG(acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale) * 2.0f;
809 if(Angle > InnerAngle && Angle <= OuterAngle)
811 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
812 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
813 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
815 else if(Angle > OuterAngle)
817 ConeVolume = ALSource->OuterGain;
818 ConeHF = ALSource->OuterGainHF;
820 else
822 ConeVolume = 1.0f;
823 ConeHF = 1.0f;
826 DryGain *= ConeVolume;
827 if(WetGainAuto)
829 for(i = 0;i < NumSends;i++)
830 WetGain[i] *= ConeVolume;
832 if(DryGainHFAuto)
833 DryGainHF *= ConeHF;
834 if(WetGainHFAuto)
836 for(i = 0;i < NumSends;i++)
837 WetGainHF[i] *= ConeHF;
840 /* Clamp to Min/Max Gain */
841 DryGain = clampf(DryGain, MinVolume, MaxVolume);
842 for(i = 0;i < NumSends;i++)
843 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
845 /* Apply gain and frequency filters */
846 DryGain *= ALSource->Direct.Gain * ListenerGain;
847 DryGainHF *= ALSource->Direct.GainHF;
848 DryGainLF *= ALSource->Direct.GainLF;
849 for(i = 0;i < NumSends;i++)
851 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
852 WetGainHF[i] *= ALSource->Send[i].GainHF;
853 WetGainLF[i] *= ALSource->Send[i].GainLF;
856 /* Calculate velocity-based doppler effect */
857 if(DopplerFactor > 0.0f)
859 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
860 ALfloat VSS, VLS;
862 if(SpeedOfSound < 1.0f)
864 DopplerFactor *= 1.0f/SpeedOfSound;
865 SpeedOfSound = 1.0f;
868 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
869 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
871 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
872 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
875 BufferListItem = ATOMIC_LOAD(&ALSource->queue);
876 while(BufferListItem != NULL)
878 ALbuffer *ALBuffer;
879 if((ALBuffer=BufferListItem->buffer) != NULL)
881 /* Calculate fixed-point stepping value, based on the pitch, buffer
882 * frequency, and output frequency. */
883 Pitch = Pitch * ALBuffer->Frequency / Frequency;
884 if(Pitch > (ALfloat)MAX_PITCH)
885 src->Step = MAX_PITCH<<FRACTIONBITS;
886 else
888 src->Step = fastf2i(Pitch*FRACTIONONE);
889 if(src->Step == 0)
890 src->Step = 1;
893 break;
895 BufferListItem = BufferListItem->next;
898 if(Device->Hrtf)
900 /* Use a binaural HRTF algorithm for stereo headphone playback */
901 ALfloat delta, ev = 0.0f, az = 0.0f;
902 ALfloat radius = ALSource->Radius;
903 ALfloat dirfact = 1.0f;
905 if(Distance > FLT_EPSILON)
907 ALfloat invlen = 1.0f/Distance;
908 Position[0] *= invlen;
909 Position[1] *= invlen;
910 Position[2] *= invlen;
912 /* Calculate elevation and azimuth only when the source is not at
913 * the listener. This prevents +0 and -0 Z from producing
914 * inconsistent panning. Also, clamp Y in case FP precision errors
915 * cause it to land outside of -1..+1. */
916 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
917 az = atan2f(Position[0], -Position[2]*ZScale);
919 if(radius > Distance)
920 dirfact *= Distance / radius;
922 /* Check to see if the HRIR is already moving. */
923 if(src->Direct.Moving)
925 /* Calculate the normalized HRTF transition factor (delta). */
926 delta = CalcHrtfDelta(src->Direct.Mix.Hrtf.Gain, DryGain,
927 src->Direct.Mix.Hrtf.Dir, Position);
928 /* If the delta is large enough, get the moving HRIR target
929 * coefficients, target delays, steppping values, and counter. */
930 if(delta > 0.001f)
932 ALuint counter = GetMovingHrtfCoeffs(Device->Hrtf,
933 ev, az, dirfact, DryGain, delta, src->Direct.Counter,
934 src->Direct.Mix.Hrtf.Params[0].Coeffs, src->Direct.Mix.Hrtf.Params[0].Delay,
935 src->Direct.Mix.Hrtf.Params[0].CoeffStep, src->Direct.Mix.Hrtf.Params[0].DelayStep
937 src->Direct.Counter = counter;
938 src->Direct.Mix.Hrtf.Gain = DryGain;
939 src->Direct.Mix.Hrtf.Dir[0] = Position[0];
940 src->Direct.Mix.Hrtf.Dir[1] = Position[1];
941 src->Direct.Mix.Hrtf.Dir[2] = Position[2];
944 else
946 /* Get the initial (static) HRIR coefficients and delays. */
947 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, dirfact, DryGain,
948 src->Direct.Mix.Hrtf.Params[0].Coeffs,
949 src->Direct.Mix.Hrtf.Params[0].Delay);
950 src->Direct.Counter = 0;
951 src->Direct.Moving = AL_TRUE;
952 src->Direct.Mix.Hrtf.Gain = DryGain;
953 src->Direct.Mix.Hrtf.Dir[0] = Position[0];
954 src->Direct.Mix.Hrtf.Dir[1] = Position[1];
955 src->Direct.Mix.Hrtf.Dir[2] = Position[2];
957 src->Direct.Mix.Hrtf.IrSize = GetHrtfIrSize(Device->Hrtf);
959 src->IsHrtf = AL_TRUE;
961 else
963 MixGains *gains = src->Direct.Mix.Gains[0];
964 ALfloat DirGain = 0.0f;
965 ALfloat AmbientGain;
967 for(j = 0;j < MaxChannels;j++)
968 gains[j].Target = 0.0f;
970 /* Normalize the length, and compute panned gains. */
971 if(Distance > FLT_EPSILON)
973 ALfloat radius = ALSource->Radius;
974 ALfloat Target[MaxChannels];
975 ALfloat invlen = 1.0f/maxf(Distance, radius);
976 Position[0] *= invlen;
977 Position[1] *= invlen;
978 Position[2] *= invlen;
980 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
981 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
982 DryGain*DirGain, Target);
983 for(j = 0;j < MaxChannels;j++)
984 gains[j].Target = Target[j];
987 /* Adjustment for vertical offsets. Not the greatest, but simple
988 * enough. */
989 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
990 for(i = 0;i < (ALint)Device->NumChan;i++)
992 enum Channel chan = Device->Speaker2Chan[i];
993 gains[chan].Target = maxf(gains[chan].Target, AmbientGain);
996 if(!src->Direct.Moving)
998 for(j = 0;j < MaxChannels;j++)
1000 gains[j].Current = gains[j].Target;
1001 gains[j].Step = 1.0f;
1003 src->Direct.Counter = 0;
1004 src->Direct.Moving = AL_TRUE;
1006 else
1008 for(j = 0;j < MaxChannels;j++)
1010 ALfloat cur = maxf(gains[j].Current, FLT_EPSILON);
1011 ALfloat trg = maxf(gains[j].Target, FLT_EPSILON);
1012 if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
1013 gains[j].Step = powf(trg/cur, 1.0f/64.0f);
1014 else
1015 gains[j].Step = 1.0f;
1016 gains[j].Current = cur;
1018 src->Direct.Counter = 64;
1021 src->IsHrtf = AL_FALSE;
1023 for(i = 0;i < NumSends;i++)
1025 src->Send[i].Gain.Target = WetGain[i];
1026 if(!src->Send[i].Moving)
1028 src->Send[i].Gain.Current = src->Send[i].Gain.Target;
1029 src->Send[i].Gain.Step = 1.0f;
1030 src->Send[i].Counter = 0;
1031 src->Send[i].Moving = AL_TRUE;
1033 else
1035 ALfloat cur = maxf(src->Send[i].Gain.Current, FLT_EPSILON);
1036 ALfloat trg = maxf(src->Send[i].Gain.Target, FLT_EPSILON);
1037 if(fabs(trg - cur) >= GAIN_SILENCE_THRESHOLD)
1038 src->Send[i].Gain.Step = powf(trg/cur, 1.0f/64.0f);
1039 else
1040 src->Send[i].Gain.Step = 1.0f;
1041 src->Send[i].Gain.Current = cur;
1042 src->Send[i].Counter = 64;
1047 ALfloat gainhf = maxf(0.01f, DryGainHF);
1048 ALfloat gainlf = maxf(0.01f, DryGainLF);
1049 ALfloat hfscale = ALSource->Direct.HFReference / Frequency;
1050 ALfloat lfscale = ALSource->Direct.LFReference / Frequency;
1051 src->Direct.Filters[0].ActiveType = AF_None;
1052 if(gainhf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_LowPass;
1053 if(gainlf != 1.0f) src->Direct.Filters[0].ActiveType |= AF_HighPass;
1054 ALfilterState_setParams(
1055 &src->Direct.Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1056 hfscale, 0.0f
1058 ALfilterState_setParams(
1059 &src->Direct.Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1060 lfscale, 0.0f
1063 for(i = 0;i < NumSends;i++)
1065 ALfloat gainhf = maxf(0.01f, WetGainHF[i]);
1066 ALfloat gainlf = maxf(0.01f, WetGainLF[i]);
1067 ALfloat hfscale = ALSource->Send[i].HFReference / Frequency;
1068 ALfloat lfscale = ALSource->Send[i].LFReference / Frequency;
1069 src->Send[i].Filters[0].ActiveType = AF_None;
1070 if(gainhf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_LowPass;
1071 if(gainlf != 1.0f) src->Send[i].Filters[0].ActiveType |= AF_HighPass;
1072 ALfilterState_setParams(
1073 &src->Send[i].Filters[0].LowPass, ALfilterType_HighShelf, gainhf,
1074 hfscale, 0.0f
1076 ALfilterState_setParams(
1077 &src->Send[i].Filters[0].HighPass, ALfilterType_LowShelf, gainlf,
1078 lfscale, 0.0f
1084 static inline ALint aluF2I25(ALfloat val)
1086 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1087 if(fabsf(val) > 1.0f)
1088 val = (ALfloat)((0.0f < val) - (val < 0.0f));
1089 /* Convert to a signed integer, between -16777215 and +16777215. */
1090 return fastf2i(val*16777215.0f);
1093 static inline ALfloat aluF2F(ALfloat val)
1094 { return val; }
1095 static inline ALint aluF2I(ALfloat val)
1096 { return aluF2I25(val)<<7; }
1097 static inline ALuint aluF2UI(ALfloat val)
1098 { return aluF2I(val)+2147483648u; }
1099 static inline ALshort aluF2S(ALfloat val)
1100 { return aluF2I25(val)>>9; }
1101 static inline ALushort aluF2US(ALfloat val)
1102 { return aluF2S(val)+32768; }
1103 static inline ALbyte aluF2B(ALfloat val)
1104 { return aluF2I25(val)>>17; }
1105 static inline ALubyte aluF2UB(ALfloat val)
1106 { return aluF2B(val)+128; }
1108 #define DECL_TEMPLATE(T, func) \
1109 static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
1111 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
1112 const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
1113 const ALuint *offsets = device->ChannelOffsets; \
1114 ALuint i, j; \
1116 for(j = 0;j < MaxChannels;j++) \
1118 T *restrict out; \
1120 if(offsets[j] == INVALID_OFFSET) \
1121 continue; \
1123 out = (T*)(*buffer) + offsets[j]; \
1124 for(i = 0;i < SamplesToDo;i++) \
1125 out[i*numchans] = func(DryBuffer[j][i]); \
1127 *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
1130 DECL_TEMPLATE(ALfloat, aluF2F)
1131 DECL_TEMPLATE(ALuint, aluF2UI)
1132 DECL_TEMPLATE(ALint, aluF2I)
1133 DECL_TEMPLATE(ALushort, aluF2US)
1134 DECL_TEMPLATE(ALshort, aluF2S)
1135 DECL_TEMPLATE(ALubyte, aluF2UB)
1136 DECL_TEMPLATE(ALbyte, aluF2B)
1138 #undef DECL_TEMPLATE
1141 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
1143 ALuint SamplesToDo;
1144 ALeffectslot **slot, **slot_end;
1145 ALactivesource **src, **src_end;
1146 ALCcontext *ctx;
1147 FPUCtl oldMode;
1148 ALuint i, c;
1150 SetMixerFPUMode(&oldMode);
1152 while(size > 0)
1154 IncrementRef(&device->MixCount);
1156 SamplesToDo = minu(size, BUFFERSIZE);
1157 for(c = 0;c < MaxChannels;c++)
1158 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
1160 ALCdevice_Lock(device);
1161 V(device->Synth,process)(SamplesToDo, device->DryBuffer);
1163 ctx = ATOMIC_LOAD(&device->ContextList);
1164 while(ctx)
1166 ALenum DeferUpdates = ctx->DeferUpdates;
1167 ALenum UpdateSources = AL_FALSE;
1169 if(!DeferUpdates)
1170 UpdateSources = ATOMIC_EXCHANGE(ALenum, &ctx->UpdateSources, AL_FALSE);
1172 if(UpdateSources)
1173 CalcListenerParams(ctx->Listener);
1175 /* source processing */
1176 src = ctx->ActiveSources;
1177 src_end = src + ctx->ActiveSourceCount;
1178 while(src != src_end)
1180 ALsource *source = (*src)->Source;
1182 if(source->state != AL_PLAYING && source->state != AL_PAUSED)
1184 ALactivesource *temp = *(--src_end);
1185 *src_end = *src;
1186 *src = temp;
1187 --(ctx->ActiveSourceCount);
1188 continue;
1191 if(!DeferUpdates && (ATOMIC_EXCHANGE(ALenum, &source->NeedsUpdate, AL_FALSE) ||
1192 UpdateSources))
1193 (*src)->Update(*src, ctx);
1195 if(source->state != AL_PAUSED)
1196 MixSource(*src, device, SamplesToDo);
1197 src++;
1200 /* effect slot processing */
1201 slot = VECTOR_ITER_BEGIN(ctx->ActiveAuxSlots);
1202 slot_end = VECTOR_ITER_END(ctx->ActiveAuxSlots);
1203 while(slot != slot_end)
1205 if(!DeferUpdates && ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1206 V((*slot)->EffectState,update)(device, *slot);
1208 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1209 device->DryBuffer);
1211 for(i = 0;i < SamplesToDo;i++)
1212 (*slot)->WetBuffer[0][i] = 0.0f;
1214 slot++;
1217 ctx = ctx->next;
1220 slot = &device->DefaultSlot;
1221 if(*slot != NULL)
1223 if(ATOMIC_EXCHANGE(ALenum, &(*slot)->NeedsUpdate, AL_FALSE))
1224 V((*slot)->EffectState,update)(device, *slot);
1226 V((*slot)->EffectState,process)(SamplesToDo, (*slot)->WetBuffer[0],
1227 device->DryBuffer);
1229 for(i = 0;i < SamplesToDo;i++)
1230 (*slot)->WetBuffer[0][i] = 0.0f;
1233 /* Increment the clock time. Every second's worth of samples is
1234 * converted and added to clock base so that large sample counts don't
1235 * overflow during conversion. This also guarantees an exact, stable
1236 * conversion. */
1237 device->SamplesDone += SamplesToDo;
1238 device->ClockBase += (device->SamplesDone/device->Frequency) * DEVICE_CLOCK_RES;
1239 device->SamplesDone %= device->Frequency;
1240 ALCdevice_Unlock(device);
1242 if(device->Bs2b)
1244 /* Apply binaural/crossfeed filter */
1245 for(i = 0;i < SamplesToDo;i++)
1247 float samples[2];
1248 samples[0] = device->DryBuffer[FrontLeft][i];
1249 samples[1] = device->DryBuffer[FrontRight][i];
1250 bs2b_cross_feed(device->Bs2b, samples);
1251 device->DryBuffer[FrontLeft][i] = samples[0];
1252 device->DryBuffer[FrontRight][i] = samples[1];
1256 if(buffer)
1258 switch(device->FmtType)
1260 case DevFmtByte:
1261 Write_ALbyte(device, &buffer, SamplesToDo);
1262 break;
1263 case DevFmtUByte:
1264 Write_ALubyte(device, &buffer, SamplesToDo);
1265 break;
1266 case DevFmtShort:
1267 Write_ALshort(device, &buffer, SamplesToDo);
1268 break;
1269 case DevFmtUShort:
1270 Write_ALushort(device, &buffer, SamplesToDo);
1271 break;
1272 case DevFmtInt:
1273 Write_ALint(device, &buffer, SamplesToDo);
1274 break;
1275 case DevFmtUInt:
1276 Write_ALuint(device, &buffer, SamplesToDo);
1277 break;
1278 case DevFmtFloat:
1279 Write_ALfloat(device, &buffer, SamplesToDo);
1280 break;
1284 size -= SamplesToDo;
1285 IncrementRef(&device->MixCount);
1288 RestoreFPUMode(&oldMode);
1292 ALvoid aluHandleDisconnect(ALCdevice *device)
1294 ALCcontext *Context;
1296 device->Connected = ALC_FALSE;
1298 Context = ATOMIC_LOAD(&device->ContextList);
1299 while(Context)
1301 ALactivesource **src, **src_end;
1303 src = Context->ActiveSources;
1304 src_end = src + Context->ActiveSourceCount;
1305 while(src != src_end)
1307 ALsource *source = (*src)->Source;
1308 if(source->state == AL_PLAYING)
1310 source->state = AL_STOPPED;
1311 ATOMIC_STORE(&source->current_buffer, NULL);
1312 source->position = 0;
1313 source->position_fraction = 0;
1315 src++;
1317 Context->ActiveSourceCount = 0;
1319 Context = Context->next;