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
32 #include "alListener.h"
33 #include "alAuxEffectSlot.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!");
52 ALfloat ConeScale
= 1.0f
;
54 /* Localized Z scalar for mono sources */
55 ALfloat ZScale
= 1.0f
;
57 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
58 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
59 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
61 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
62 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
63 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
65 extern inline ALuint
minu(ALuint a
, ALuint b
);
66 extern inline ALuint
maxu(ALuint a
, ALuint b
);
67 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
69 extern inline ALint
mini(ALint a
, ALint b
);
70 extern inline ALint
maxi(ALint a
, ALint b
);
71 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
73 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
74 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
75 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
77 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
78 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
79 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
81 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
82 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
85 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
87 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
88 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
89 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
92 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
94 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
95 inVector1
[2]*inVector2
[2];
98 static inline void aluNormalize(ALfloat
*inVector
)
100 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
103 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
104 inVector
[0] *= inv_length
;
105 inVector
[1] *= inv_length
;
106 inVector
[2] *= inv_length
;
110 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
113 vector
[0], vector
[1], vector
[2], w
116 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
117 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
118 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
122 static void UpdateDryStepping(DirectParams
*params
, ALuint num_chans
)
128 for(i
= 0;i
< num_chans
;i
++)
130 MixGains
*gains
= params
->Mix
.Gains
[i
];
131 for(j
= 0;j
< MaxChannels
;j
++)
133 gains
[j
].Current
= gains
[j
].Target
;
134 gains
[j
].Step
= 1.0f
;
137 params
->Moving
= AL_TRUE
;
142 for(i
= 0;i
< num_chans
;i
++)
144 MixGains
*gains
= params
->Mix
.Gains
[i
];
145 for(j
= 0;j
< MaxChannels
;j
++)
147 ALfloat cur
= maxf(gains
[j
].Current
, FLT_EPSILON
);
148 ALfloat trg
= maxf(gains
[j
].Target
, FLT_EPSILON
);
149 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
150 gains
[j
].Step
= powf(trg
/cur
, 1.0f
/64.0f
);
152 gains
[j
].Step
= 1.0f
;
153 gains
[j
].Current
= cur
;
156 params
->Counter
= 64;
159 static void UpdateWetStepping(SendParams
*params
)
165 params
->Gain
.Current
= params
->Gain
.Target
;
166 params
->Gain
.Step
= 1.0f
;
168 params
->Moving
= AL_TRUE
;
173 cur
= maxf(params
->Gain
.Current
, FLT_EPSILON
);
174 trg
= maxf(params
->Gain
.Target
, FLT_EPSILON
);
175 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
176 params
->Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
178 params
->Gain
.Step
= 1.0f
;
179 params
->Gain
.Current
= cur
;
181 params
->Counter
= 64;
185 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
187 ALfloat N
[3], V
[3], U
[3], P
[3];
190 N
[0] = Listener
->Forward
[0];
191 N
[1] = Listener
->Forward
[1];
192 N
[2] = Listener
->Forward
[2];
194 V
[0] = Listener
->Up
[0];
195 V
[1] = Listener
->Up
[1];
196 V
[2] = Listener
->Up
[2];
198 /* Build and normalize right-vector */
199 aluCrossproduct(N
, V
, U
);
202 Listener
->Params
.Matrix
[0][0] = U
[0];
203 Listener
->Params
.Matrix
[0][1] = V
[0];
204 Listener
->Params
.Matrix
[0][2] = -N
[0];
205 Listener
->Params
.Matrix
[0][3] = 0.0f
;
206 Listener
->Params
.Matrix
[1][0] = U
[1];
207 Listener
->Params
.Matrix
[1][1] = V
[1];
208 Listener
->Params
.Matrix
[1][2] = -N
[1];
209 Listener
->Params
.Matrix
[1][3] = 0.0f
;
210 Listener
->Params
.Matrix
[2][0] = U
[2];
211 Listener
->Params
.Matrix
[2][1] = V
[2];
212 Listener
->Params
.Matrix
[2][2] = -N
[2];
213 Listener
->Params
.Matrix
[2][3] = 0.0f
;
214 Listener
->Params
.Matrix
[3][0] = 0.0f
;
215 Listener
->Params
.Matrix
[3][1] = 0.0f
;
216 Listener
->Params
.Matrix
[3][2] = 0.0f
;
217 Listener
->Params
.Matrix
[3][3] = 1.0f
;
219 P
[0] = Listener
->Position
[0];
220 P
[1] = Listener
->Position
[1];
221 P
[2] = Listener
->Position
[2];
222 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
223 Listener
->Params
.Matrix
[3][0] = -P
[0];
224 Listener
->Params
.Matrix
[3][1] = -P
[1];
225 Listener
->Params
.Matrix
[3][2] = -P
[2];
227 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
228 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
229 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
230 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
233 ALvoid
CalcNonAttnSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
235 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
, 0.0f
} };
236 static const struct ChanMap StereoMap
[2] = {
237 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
238 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) }
240 static const struct ChanMap StereoWideMap
[2] = {
241 { FrontLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
242 { FrontRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
244 static const struct ChanMap RearMap
[2] = {
245 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
246 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) }
248 static const struct ChanMap QuadMap
[4] = {
249 { FrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(0.0f
) },
250 { FrontRight
, DEG2RAD( 45.0f
), DEG2RAD(0.0f
) },
251 { BackLeft
, DEG2RAD(-135.0f
), DEG2RAD(0.0f
) },
252 { BackRight
, DEG2RAD( 135.0f
), DEG2RAD(0.0f
) }
254 static const struct ChanMap X51Map
[6] = {
255 { FrontLeft
, DEG2RAD( -30.0f
), DEG2RAD(0.0f
) },
256 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
257 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
259 { BackLeft
, DEG2RAD(-110.0f
), DEG2RAD(0.0f
) },
260 { BackRight
, DEG2RAD( 110.0f
), DEG2RAD(0.0f
) }
262 static const struct ChanMap X61Map
[7] = {
263 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
264 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
265 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
267 { BackCenter
, DEG2RAD(180.0f
), DEG2RAD(0.0f
) },
268 { SideLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
269 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
271 static const struct ChanMap X71Map
[8] = {
272 { FrontLeft
, DEG2RAD( -30.0f
), DEG2RAD(0.0f
) },
273 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
274 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
276 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
277 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) },
278 { SideLeft
, DEG2RAD( -90.0f
), DEG2RAD(0.0f
) },
279 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
282 ALCdevice
*Device
= ALContext
->Device
;
283 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
284 ALbufferlistitem
*BufferListItem
;
285 enum FmtChannels Channels
;
286 ALfloat DryGain
, DryGainHF
, DryGainLF
;
287 ALfloat WetGain
[MAX_SENDS
];
288 ALfloat WetGainHF
[MAX_SENDS
];
289 ALfloat WetGainLF
[MAX_SENDS
];
290 ALuint NumSends
, Frequency
;
291 const struct ChanMap
*chans
= NULL
;
292 ALuint num_channels
= 0;
293 ALboolean DirectChannels
;
294 ALboolean isbformat
= AL_FALSE
;
298 /* Get device properties */
299 NumSends
= Device
->NumAuxSends
;
300 Frequency
= Device
->Frequency
;
302 /* Get listener properties */
303 ListenerGain
= ALContext
->Listener
->Gain
;
305 /* Get source properties */
306 SourceVolume
= ALSource
->Gain
;
307 MinVolume
= ALSource
->MinGain
;
308 MaxVolume
= ALSource
->MaxGain
;
309 Pitch
= ALSource
->Pitch
;
310 DirectChannels
= ALSource
->DirectChannels
;
312 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
313 for(i
= 0;i
< NumSends
;i
++)
315 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
317 Slot
= Device
->DefaultSlot
;
318 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
319 voice
->Send
[i
].OutBuffer
= NULL
;
321 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
324 /* Calculate the stepping value */
326 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
327 while(BufferListItem
!= NULL
)
330 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
332 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
333 if(Pitch
> (ALfloat
)MAX_PITCH
)
334 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
337 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
342 Channels
= ALBuffer
->FmtChannels
;
345 BufferListItem
= BufferListItem
->next
;
348 /* Calculate gains */
349 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
350 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
351 DryGainHF
= ALSource
->Direct
.GainHF
;
352 DryGainLF
= ALSource
->Direct
.GainLF
;
353 for(i
= 0;i
< NumSends
;i
++)
355 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
356 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
357 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
358 WetGainLF
[i
] = ALSource
->Send
[i
].GainLF
;
369 /* HACK: Place the stereo channels at +/-90 degrees when using non-
370 * HRTF stereo output. This helps reduce the "monoization" caused
371 * by them panning towards the center. */
372 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
373 chans
= StereoWideMap
;
407 DirectChannels
= AL_FALSE
;
412 DirectChannels
= AL_FALSE
;
417 for(c
= 0;c
< num_channels
;c
++)
419 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
420 ALfloat Target
[MaxChannels
];
422 ComputeBFormatGains(Device
, c
, DryGain
, Target
);
423 for(i
= 0;i
< MaxChannels
;i
++)
424 gains
[i
].Target
= Target
[i
];
426 /* B-Format cannot handle logarithmic gain stepping, since the gain can
427 * switch between positive and negative values. */
428 voice
->Direct
.Moving
= AL_FALSE
;
429 UpdateDryStepping(&voice
->Direct
, num_channels
);
431 voice
->IsHrtf
= AL_FALSE
;
432 for(i
= 0;i
< NumSends
;i
++)
433 WetGain
[i
] *= 1.4142f
;
435 else if(DirectChannels
!= AL_FALSE
)
437 for(c
= 0;c
< num_channels
;c
++)
439 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
441 for(j
= 0;j
< MaxChannels
;j
++)
442 gains
[j
].Target
= 0.0f
;
443 if(GetChannelIdxByName(Device
, chans
[c
].channel
) != -1)
444 gains
[chans
[c
].channel
].Target
= DryGain
;
446 UpdateDryStepping(&voice
->Direct
, num_channels
);
448 voice
->IsHrtf
= AL_FALSE
;
450 else if(Device
->Hrtf
)
452 for(c
= 0;c
< num_channels
;c
++)
454 if(chans
[c
].channel
== LFE
)
457 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[0] = 0;
458 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[1] = 0;
459 for(i
= 0;i
< HRIR_LENGTH
;i
++)
461 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][0] = 0.0f
;
462 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][1] = 0.0f
;
467 /* Get the static HRIR coefficients and delays for this
469 GetLerpedHrtfCoeffs(Device
->Hrtf
,
470 chans
[c
].elevation
, chans
[c
].angle
, 1.0f
, DryGain
,
471 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
,
472 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
);
475 voice
->Direct
.Counter
= 0;
476 voice
->Direct
.Moving
= AL_TRUE
;
477 voice
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
479 voice
->IsHrtf
= AL_TRUE
;
483 for(c
= 0;c
< num_channels
;c
++)
485 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
486 ALfloat Target
[MaxChannels
];
488 /* Special-case LFE */
489 if(chans
[c
].channel
== LFE
)
491 for(i
= 0;i
< MaxChannels
;i
++)
492 gains
[i
].Target
= 0.0f
;
493 if(GetChannelIdxByName(Device
, chans
[c
].channel
) != -1)
494 gains
[chans
[c
].channel
].Target
= DryGain
;
498 ComputeAngleGains(Device
, chans
[c
].angle
, chans
[c
].elevation
, DryGain
, Target
);
499 for(i
= 0;i
< MaxChannels
;i
++)
500 gains
[i
].Target
= Target
[i
];
502 UpdateDryStepping(&voice
->Direct
, num_channels
);
504 voice
->IsHrtf
= AL_FALSE
;
506 for(i
= 0;i
< NumSends
;i
++)
508 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
509 UpdateWetStepping(&voice
->Send
[i
]);
513 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
514 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
515 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
516 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
517 for(c
= 0;c
< num_channels
;c
++)
519 voice
->Direct
.Filters
[c
].ActiveType
= AF_None
;
520 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_LowPass
;
521 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_HighPass
;
522 ALfilterState_setParams(
523 &voice
->Direct
.Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
526 ALfilterState_setParams(
527 &voice
->Direct
.Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
532 for(i
= 0;i
< NumSends
;i
++)
534 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
535 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
536 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
537 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
538 for(c
= 0;c
< num_channels
;c
++)
540 voice
->Send
[i
].Filters
[c
].ActiveType
= AF_None
;
541 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_LowPass
;
542 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_HighPass
;
543 ALfilterState_setParams(
544 &voice
->Send
[i
].Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
547 ALfilterState_setParams(
548 &voice
->Send
[i
].Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
555 ALvoid
CalcSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
557 ALCdevice
*Device
= ALContext
->Device
;
558 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
559 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
560 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
561 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
562 ALfloat DopplerFactor
, SpeedOfSound
;
563 ALfloat AirAbsorptionFactor
;
564 ALfloat RoomAirAbsorption
[MAX_SENDS
];
565 ALbufferlistitem
*BufferListItem
;
567 ALfloat RoomAttenuation
[MAX_SENDS
];
568 ALfloat MetersPerUnit
;
569 ALfloat RoomRolloffBase
;
570 ALfloat RoomRolloff
[MAX_SENDS
];
571 ALfloat DecayDistance
[MAX_SENDS
];
575 ALboolean DryGainHFAuto
;
576 ALfloat WetGain
[MAX_SENDS
];
577 ALfloat WetGainHF
[MAX_SENDS
];
578 ALfloat WetGainLF
[MAX_SENDS
];
579 ALboolean WetGainAuto
;
580 ALboolean WetGainHFAuto
;
588 for(i
= 0;i
< MAX_SENDS
;i
++)
594 /* Get context/device properties */
595 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
596 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
597 NumSends
= Device
->NumAuxSends
;
598 Frequency
= Device
->Frequency
;
600 /* Get listener properties */
601 ListenerGain
= ALContext
->Listener
->Gain
;
602 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
604 /* Get source properties */
605 SourceVolume
= ALSource
->Gain
;
606 MinVolume
= ALSource
->MinGain
;
607 MaxVolume
= ALSource
->MaxGain
;
608 Pitch
= ALSource
->Pitch
;
609 Position
[0] = ALSource
->Position
[0];
610 Position
[1] = ALSource
->Position
[1];
611 Position
[2] = ALSource
->Position
[2];
612 Direction
[0] = ALSource
->Direction
[0];
613 Direction
[1] = ALSource
->Direction
[1];
614 Direction
[2] = ALSource
->Direction
[2];
615 Velocity
[0] = ALSource
->Velocity
[0];
616 Velocity
[1] = ALSource
->Velocity
[1];
617 Velocity
[2] = ALSource
->Velocity
[2];
618 MinDist
= ALSource
->RefDistance
;
619 MaxDist
= ALSource
->MaxDistance
;
620 Rolloff
= ALSource
->RollOffFactor
;
621 InnerAngle
= ALSource
->InnerAngle
;
622 OuterAngle
= ALSource
->OuterAngle
;
623 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
624 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
625 WetGainAuto
= ALSource
->WetGainAuto
;
626 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
627 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
629 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
630 for(i
= 0;i
< NumSends
;i
++)
632 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
635 Slot
= Device
->DefaultSlot
;
636 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
639 RoomRolloff
[i
] = 0.0f
;
640 DecayDistance
[i
] = 0.0f
;
641 RoomAirAbsorption
[i
] = 1.0f
;
643 else if(Slot
->AuxSendAuto
)
645 RoomRolloff
[i
] = RoomRolloffBase
;
646 if(IsReverbEffect(Slot
->EffectType
))
648 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
649 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
650 SPEEDOFSOUNDMETRESPERSEC
;
651 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
655 DecayDistance
[i
] = 0.0f
;
656 RoomAirAbsorption
[i
] = 1.0f
;
661 /* If the slot's auxiliary send auto is off, the data sent to the
662 * effect slot is the same as the dry path, sans filter effects */
663 RoomRolloff
[i
] = Rolloff
;
664 DecayDistance
[i
] = 0.0f
;
665 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
668 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
669 voice
->Send
[i
].OutBuffer
= NULL
;
671 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
674 /* Transform source to listener space (convert to head relative) */
675 if(ALSource
->HeadRelative
== AL_FALSE
)
677 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
678 /* Transform source vectors */
679 aluMatrixVector(Position
, 1.0f
, Matrix
);
680 aluMatrixVector(Direction
, 0.0f
, Matrix
);
681 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
685 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
686 /* Offset the source velocity to be relative of the listener velocity */
687 Velocity
[0] += ListenerVel
[0];
688 Velocity
[1] += ListenerVel
[1];
689 Velocity
[2] += ListenerVel
[2];
692 SourceToListener
[0] = -Position
[0];
693 SourceToListener
[1] = -Position
[1];
694 SourceToListener
[2] = -Position
[2];
695 aluNormalize(SourceToListener
);
696 aluNormalize(Direction
);
698 /* Calculate distance attenuation */
699 Distance
= sqrtf(aluDotproduct(Position
, Position
));
700 ClampedDist
= Distance
;
703 for(i
= 0;i
< NumSends
;i
++)
704 RoomAttenuation
[i
] = 1.0f
;
705 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
706 ALContext
->DistanceModel
)
708 case InverseDistanceClamped
:
709 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
710 if(MaxDist
< MinDist
)
713 case InverseDistance
:
716 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
717 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
718 for(i
= 0;i
< NumSends
;i
++)
720 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
721 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
726 case LinearDistanceClamped
:
727 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
728 if(MaxDist
< MinDist
)
732 if(MaxDist
!= MinDist
)
734 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
735 Attenuation
= maxf(Attenuation
, 0.0f
);
736 for(i
= 0;i
< NumSends
;i
++)
738 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
739 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
744 case ExponentDistanceClamped
:
745 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
746 if(MaxDist
< MinDist
)
749 case ExponentDistance
:
750 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
752 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
753 for(i
= 0;i
< NumSends
;i
++)
754 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
758 case DisableDistance
:
759 ClampedDist
= MinDist
;
763 /* Source Gain + Attenuation */
764 DryGain
= SourceVolume
* Attenuation
;
765 for(i
= 0;i
< NumSends
;i
++)
766 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
768 /* Distance-based air absorption */
769 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
771 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
772 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
773 for(i
= 0;i
< NumSends
;i
++)
774 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
779 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
781 /* Apply a decay-time transformation to the wet path, based on the
782 * attenuation of the dry path.
784 * Using the apparent distance, based on the distance attenuation, the
785 * initial decay of the reverb effect is calculated and applied to the
788 for(i
= 0;i
< NumSends
;i
++)
790 if(DecayDistance
[i
] > 0.0f
)
791 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
795 /* Calculate directional soundcones */
796 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
797 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
799 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
800 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
801 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
803 else if(Angle
> OuterAngle
)
805 ConeVolume
= ALSource
->OuterGain
;
806 ConeHF
= ALSource
->OuterGainHF
;
814 DryGain
*= ConeVolume
;
817 for(i
= 0;i
< NumSends
;i
++)
818 WetGain
[i
] *= ConeVolume
;
824 for(i
= 0;i
< NumSends
;i
++)
825 WetGainHF
[i
] *= ConeHF
;
828 /* Clamp to Min/Max Gain */
829 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
830 for(i
= 0;i
< NumSends
;i
++)
831 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
833 /* Apply gain and frequency filters */
834 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
835 DryGainHF
*= ALSource
->Direct
.GainHF
;
836 DryGainLF
*= ALSource
->Direct
.GainLF
;
837 for(i
= 0;i
< NumSends
;i
++)
839 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
840 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
841 WetGainLF
[i
] *= ALSource
->Send
[i
].GainLF
;
844 /* Calculate velocity-based doppler effect */
845 if(DopplerFactor
> 0.0f
)
847 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
850 if(SpeedOfSound
< 1.0f
)
852 DopplerFactor
*= 1.0f
/SpeedOfSound
;
856 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
857 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
859 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
860 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
863 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
864 while(BufferListItem
!= NULL
)
867 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
869 /* Calculate fixed-point stepping value, based on the pitch, buffer
870 * frequency, and output frequency. */
871 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
872 if(Pitch
> (ALfloat
)MAX_PITCH
)
873 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
876 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
883 BufferListItem
= BufferListItem
->next
;
888 /* Use a binaural HRTF algorithm for stereo headphone playback */
889 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
890 ALfloat radius
= ALSource
->Radius
;
891 ALfloat dirfact
= 1.0f
;
893 if(Distance
> FLT_EPSILON
)
895 ALfloat invlen
= 1.0f
/Distance
;
896 Position
[0] *= invlen
;
897 Position
[1] *= invlen
;
898 Position
[2] *= invlen
;
900 /* Calculate elevation and azimuth only when the source is not at
901 * the listener. This prevents +0 and -0 Z from producing
902 * inconsistent panning. Also, clamp Y in case FP precision errors
903 * cause it to land outside of -1..+1. */
904 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
905 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
907 if(radius
> Distance
)
908 dirfact
*= Distance
/ radius
;
910 /* Check to see if the HRIR is already moving. */
911 if(voice
->Direct
.Moving
)
913 /* Calculate the normalized HRTF transition factor (delta). */
914 delta
= CalcHrtfDelta(voice
->Direct
.Mix
.Hrtf
.Gain
, DryGain
,
915 voice
->Direct
.Mix
.Hrtf
.Dir
, Position
);
916 /* If the delta is large enough, get the moving HRIR target
917 * coefficients, target delays, steppping values, and counter. */
920 ALuint counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
921 ev
, az
, dirfact
, DryGain
, delta
, voice
->Direct
.Counter
,
922 voice
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
, voice
->Direct
.Mix
.Hrtf
.Params
[0].Delay
,
923 voice
->Direct
.Mix
.Hrtf
.Params
[0].CoeffStep
, voice
->Direct
.Mix
.Hrtf
.Params
[0].DelayStep
925 voice
->Direct
.Counter
= counter
;
926 voice
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
927 voice
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
928 voice
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
929 voice
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
934 /* Get the initial (static) HRIR coefficients and delays. */
935 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, dirfact
, DryGain
,
936 voice
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
937 voice
->Direct
.Mix
.Hrtf
.Params
[0].Delay
);
938 voice
->Direct
.Counter
= 0;
939 voice
->Direct
.Moving
= AL_TRUE
;
940 voice
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
941 voice
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
942 voice
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
943 voice
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
945 voice
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
947 voice
->IsHrtf
= AL_TRUE
;
951 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[0];
952 ALfloat Target
[MaxChannels
];
954 /* Normalize the length, and compute panned gains. */
955 if(!(Distance
> FLT_EPSILON
))
956 Position
[0] = Position
[1] = Position
[2] = 0.0f
;
959 ALfloat radius
= ALSource
->Radius
;
960 ALfloat invlen
= 1.0f
/maxf(Distance
, radius
);
961 Position
[0] *= invlen
;
962 Position
[1] *= invlen
;
963 Position
[2] *= invlen
;
965 ComputeDirectionalGains(Device
, Position
, DryGain
, Target
);
967 for(j
= 0;j
< MaxChannels
;j
++)
968 gains
[j
].Target
= Target
[j
];
969 UpdateDryStepping(&voice
->Direct
, 1);
971 voice
->IsHrtf
= AL_FALSE
;
973 for(i
= 0;i
< NumSends
;i
++)
975 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
976 UpdateWetStepping(&voice
->Send
[i
]);
980 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
981 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
982 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
983 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
984 voice
->Direct
.Filters
[0].ActiveType
= AF_None
;
985 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_LowPass
;
986 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_HighPass
;
987 ALfilterState_setParams(
988 &voice
->Direct
.Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
991 ALfilterState_setParams(
992 &voice
->Direct
.Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
996 for(i
= 0;i
< NumSends
;i
++)
998 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
999 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
1000 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
1001 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
1002 voice
->Send
[i
].Filters
[0].ActiveType
= AF_None
;
1003 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_LowPass
;
1004 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_HighPass
;
1005 ALfilterState_setParams(
1006 &voice
->Send
[i
].Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1009 ALfilterState_setParams(
1010 &voice
->Send
[i
].Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1017 static inline ALint
aluF2I25(ALfloat val
)
1019 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1020 if(fabsf(val
) > 1.0f
)
1021 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
1022 /* Convert to a signed integer, between -16777215 and +16777215. */
1023 return fastf2i(val
*16777215.0f
);
1026 static inline ALfloat
aluF2F(ALfloat val
)
1028 static inline ALint
aluF2I(ALfloat val
)
1029 { return aluF2I25(val
)<<7; }
1030 static inline ALuint
aluF2UI(ALfloat val
)
1031 { return aluF2I(val
)+2147483648u; }
1032 static inline ALshort
aluF2S(ALfloat val
)
1033 { return aluF2I25(val
)>>9; }
1034 static inline ALushort
aluF2US(ALfloat val
)
1035 { return aluF2S(val
)+32768; }
1036 static inline ALbyte
aluF2B(ALfloat val
)
1037 { return aluF2I25(val
)>>17; }
1038 static inline ALubyte
aluF2UB(ALfloat val
)
1039 { return aluF2B(val
)+128; }
1041 #define DECL_TEMPLATE(T, func) \
1042 static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
1044 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
1045 const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
1046 const enum Channel *chans = device->ChannelName; \
1049 for(j = 0;j < MaxChannels;j++) \
1051 const enum Channel c = chans[j]; \
1052 const ALfloat *in; \
1055 if(c == InvalidChannel) \
1058 in = DryBuffer[c]; \
1059 out = (T*)(*buffer) + j; \
1060 for(i = 0;i < SamplesToDo;i++) \
1061 out[i*numchans] = func(in[i]); \
1063 *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
1066 DECL_TEMPLATE(ALfloat
, aluF2F
)
1067 DECL_TEMPLATE(ALuint
, aluF2UI
)
1068 DECL_TEMPLATE(ALint
, aluF2I
)
1069 DECL_TEMPLATE(ALushort
, aluF2US
)
1070 DECL_TEMPLATE(ALshort
, aluF2S
)
1071 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1072 DECL_TEMPLATE(ALbyte
, aluF2B
)
1074 #undef DECL_TEMPLATE
1077 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1080 ALeffectslot
**slot
, **slot_end
;
1081 ALvoice
*voice
, *voice_end
;
1086 SetMixerFPUMode(&oldMode
);
1090 IncrementRef(&device
->MixCount
);
1092 SamplesToDo
= minu(size
, BUFFERSIZE
);
1093 for(c
= 0;c
< MaxChannels
;c
++)
1094 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1096 ALCdevice_Lock(device
);
1097 V(device
->Synth
,process
)(SamplesToDo
, device
->DryBuffer
);
1099 ctx
= ATOMIC_LOAD(&device
->ContextList
);
1102 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1103 ALenum UpdateSources
= AL_FALSE
;
1106 UpdateSources
= ATOMIC_EXCHANGE(ALenum
, &ctx
->UpdateSources
, AL_FALSE
);
1109 CalcListenerParams(ctx
->Listener
);
1111 /* source processing */
1112 voice
= ctx
->Voices
;
1113 voice_end
= voice
+ ctx
->VoiceCount
;
1114 while(voice
!= voice_end
)
1116 ALsource
*source
= voice
->Source
;
1117 if(!source
) goto next
;
1119 if(source
->state
!= AL_PLAYING
&& source
->state
!= AL_PAUSED
)
1121 voice
->Source
= NULL
;
1125 if(!DeferUpdates
&& (ATOMIC_EXCHANGE(ALenum
, &source
->NeedsUpdate
, AL_FALSE
) ||
1127 voice
->Update(voice
, source
, ctx
);
1129 if(source
->state
!= AL_PAUSED
)
1130 MixSource(voice
, source
, device
, SamplesToDo
);
1135 /* effect slot processing */
1136 slot
= VECTOR_ITER_BEGIN(ctx
->ActiveAuxSlots
);
1137 slot_end
= VECTOR_ITER_END(ctx
->ActiveAuxSlots
);
1138 while(slot
!= slot_end
)
1140 if(!DeferUpdates
&& ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1141 V((*slot
)->EffectState
,update
)(device
, *slot
);
1143 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1146 for(i
= 0;i
< SamplesToDo
;i
++)
1147 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1155 slot
= &device
->DefaultSlot
;
1158 if(ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1159 V((*slot
)->EffectState
,update
)(device
, *slot
);
1161 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1164 for(i
= 0;i
< SamplesToDo
;i
++)
1165 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1168 /* Increment the clock time. Every second's worth of samples is
1169 * converted and added to clock base so that large sample counts don't
1170 * overflow during conversion. This also guarantees an exact, stable
1172 device
->SamplesDone
+= SamplesToDo
;
1173 device
->ClockBase
+= (device
->SamplesDone
/device
->Frequency
) * DEVICE_CLOCK_RES
;
1174 device
->SamplesDone
%= device
->Frequency
;
1175 ALCdevice_Unlock(device
);
1179 /* Apply binaural/crossfeed filter */
1180 for(i
= 0;i
< SamplesToDo
;i
++)
1183 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1184 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1185 bs2b_cross_feed(device
->Bs2b
, samples
);
1186 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1187 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1193 switch(device
->FmtType
)
1196 Write_ALbyte(device
, &buffer
, SamplesToDo
);
1199 Write_ALubyte(device
, &buffer
, SamplesToDo
);
1202 Write_ALshort(device
, &buffer
, SamplesToDo
);
1205 Write_ALushort(device
, &buffer
, SamplesToDo
);
1208 Write_ALint(device
, &buffer
, SamplesToDo
);
1211 Write_ALuint(device
, &buffer
, SamplesToDo
);
1214 Write_ALfloat(device
, &buffer
, SamplesToDo
);
1219 size
-= SamplesToDo
;
1220 IncrementRef(&device
->MixCount
);
1223 RestoreFPUMode(&oldMode
);
1227 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1229 ALCcontext
*Context
;
1231 device
->Connected
= ALC_FALSE
;
1233 Context
= ATOMIC_LOAD(&device
->ContextList
);
1236 ALvoice
*voice
, *voice_end
;
1238 voice
= Context
->Voices
;
1239 voice_end
= voice
+ Context
->VoiceCount
;
1240 while(voice
!= voice_end
)
1242 ALsource
*source
= voice
->Source
;
1243 voice
->Source
= NULL
;
1245 if(source
&& source
->state
== AL_PLAYING
)
1247 source
->state
= AL_STOPPED
;
1248 ATOMIC_STORE(&source
->current_buffer
, NULL
);
1249 source
->position
= 0;
1250 source
->position_fraction
= 0;
1255 Context
->VoiceCount
= 0;
1257 Context
= Context
->next
;