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 "backends/base.h"
40 #include "midi/base.h"
43 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
44 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
53 ALfloat ConeScale
= 1.0f
;
55 /* Localized Z scalar for mono sources */
56 ALfloat ZScale
= 1.0f
;
58 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
59 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
60 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
62 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
63 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
64 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
66 extern inline ALuint
minu(ALuint a
, ALuint b
);
67 extern inline ALuint
maxu(ALuint a
, ALuint b
);
68 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
70 extern inline ALint
mini(ALint a
, ALint b
);
71 extern inline ALint
maxi(ALint a
, ALint b
);
72 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
74 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
75 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
76 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
78 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
79 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
80 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
82 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
83 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
86 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
88 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
89 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
90 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
93 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
95 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
96 inVector1
[2]*inVector2
[2];
99 static inline void aluNormalize(ALfloat
*inVector
)
101 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
104 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
105 inVector
[0] *= inv_length
;
106 inVector
[1] *= inv_length
;
107 inVector
[2] *= inv_length
;
111 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
114 vector
[0], vector
[1], vector
[2], w
117 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
118 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
119 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
123 static void UpdateDryStepping(DirectParams
*params
, ALuint num_chans
)
129 for(i
= 0;i
< num_chans
;i
++)
131 MixGains
*gains
= params
->Mix
.Gains
[i
];
132 for(j
= 0;j
< MaxChannels
;j
++)
134 gains
[j
].Current
= gains
[j
].Target
;
135 gains
[j
].Step
= 1.0f
;
138 params
->Moving
= AL_TRUE
;
143 for(i
= 0;i
< num_chans
;i
++)
145 MixGains
*gains
= params
->Mix
.Gains
[i
];
146 for(j
= 0;j
< MaxChannels
;j
++)
148 ALfloat cur
= maxf(gains
[j
].Current
, FLT_EPSILON
);
149 ALfloat trg
= maxf(gains
[j
].Target
, FLT_EPSILON
);
150 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
151 gains
[j
].Step
= powf(trg
/cur
, 1.0f
/64.0f
);
153 gains
[j
].Step
= 1.0f
;
154 gains
[j
].Current
= cur
;
157 params
->Counter
= 64;
160 static void UpdateWetStepping(SendParams
*params
)
166 params
->Gain
.Current
= params
->Gain
.Target
;
167 params
->Gain
.Step
= 1.0f
;
169 params
->Moving
= AL_TRUE
;
174 cur
= maxf(params
->Gain
.Current
, FLT_EPSILON
);
175 trg
= maxf(params
->Gain
.Target
, FLT_EPSILON
);
176 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
177 params
->Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
179 params
->Gain
.Step
= 1.0f
;
180 params
->Gain
.Current
= cur
;
182 params
->Counter
= 64;
186 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
188 ALfloat N
[3], V
[3], U
[3], P
[3];
191 N
[0] = Listener
->Forward
[0];
192 N
[1] = Listener
->Forward
[1];
193 N
[2] = Listener
->Forward
[2];
195 V
[0] = Listener
->Up
[0];
196 V
[1] = Listener
->Up
[1];
197 V
[2] = Listener
->Up
[2];
199 /* Build and normalize right-vector */
200 aluCrossproduct(N
, V
, U
);
203 Listener
->Params
.Matrix
[0][0] = U
[0];
204 Listener
->Params
.Matrix
[0][1] = V
[0];
205 Listener
->Params
.Matrix
[0][2] = -N
[0];
206 Listener
->Params
.Matrix
[0][3] = 0.0f
;
207 Listener
->Params
.Matrix
[1][0] = U
[1];
208 Listener
->Params
.Matrix
[1][1] = V
[1];
209 Listener
->Params
.Matrix
[1][2] = -N
[1];
210 Listener
->Params
.Matrix
[1][3] = 0.0f
;
211 Listener
->Params
.Matrix
[2][0] = U
[2];
212 Listener
->Params
.Matrix
[2][1] = V
[2];
213 Listener
->Params
.Matrix
[2][2] = -N
[2];
214 Listener
->Params
.Matrix
[2][3] = 0.0f
;
215 Listener
->Params
.Matrix
[3][0] = 0.0f
;
216 Listener
->Params
.Matrix
[3][1] = 0.0f
;
217 Listener
->Params
.Matrix
[3][2] = 0.0f
;
218 Listener
->Params
.Matrix
[3][3] = 1.0f
;
220 P
[0] = Listener
->Position
[0];
221 P
[1] = Listener
->Position
[1];
222 P
[2] = Listener
->Position
[2];
223 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
224 Listener
->Params
.Matrix
[3][0] = -P
[0];
225 Listener
->Params
.Matrix
[3][1] = -P
[1];
226 Listener
->Params
.Matrix
[3][2] = -P
[2];
228 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
229 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
230 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
231 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
234 ALvoid
CalcNonAttnSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
236 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
, 0.0f
} };
237 static const struct ChanMap StereoMap
[2] = {
238 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
239 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) }
241 static const struct ChanMap StereoWideMap
[2] = {
242 { FrontLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
243 { FrontRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
245 static const struct ChanMap RearMap
[2] = {
246 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
247 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) }
249 static const struct ChanMap QuadMap
[4] = {
250 { FrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(0.0f
) },
251 { FrontRight
, DEG2RAD( 45.0f
), DEG2RAD(0.0f
) },
252 { BackLeft
, DEG2RAD(-135.0f
), DEG2RAD(0.0f
) },
253 { BackRight
, DEG2RAD( 135.0f
), DEG2RAD(0.0f
) }
255 static const struct ChanMap X51Map
[6] = {
256 { FrontLeft
, DEG2RAD( -30.0f
), DEG2RAD(0.0f
) },
257 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
258 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
260 { BackLeft
, DEG2RAD(-110.0f
), DEG2RAD(0.0f
) },
261 { BackRight
, DEG2RAD( 110.0f
), DEG2RAD(0.0f
) }
263 static const struct ChanMap X61Map
[7] = {
264 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
265 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
266 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
268 { BackCenter
, DEG2RAD(180.0f
), DEG2RAD(0.0f
) },
269 { SideLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
270 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
272 static const struct ChanMap X71Map
[8] = {
273 { FrontLeft
, DEG2RAD( -30.0f
), DEG2RAD(0.0f
) },
274 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
275 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
277 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
278 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) },
279 { SideLeft
, DEG2RAD( -90.0f
), DEG2RAD(0.0f
) },
280 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
283 ALCdevice
*Device
= ALContext
->Device
;
284 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
285 ALbufferlistitem
*BufferListItem
;
286 enum FmtChannels Channels
;
287 ALfloat DryGain
, DryGainHF
, DryGainLF
;
288 ALfloat WetGain
[MAX_SENDS
];
289 ALfloat WetGainHF
[MAX_SENDS
];
290 ALfloat WetGainLF
[MAX_SENDS
];
291 ALuint NumSends
, Frequency
;
293 const struct ChanMap
*chans
= NULL
;
294 ALuint num_channels
= 0;
295 ALboolean DirectChannels
;
296 ALboolean isbformat
= AL_FALSE
;
300 /* Get device properties */
301 NumSends
= Device
->NumAuxSends
;
302 Frequency
= Device
->Frequency
;
304 /* Get listener properties */
305 ListenerGain
= ALContext
->Listener
->Gain
;
307 /* Get source properties */
308 SourceVolume
= ALSource
->Gain
;
309 MinVolume
= ALSource
->MinGain
;
310 MaxVolume
= ALSource
->MaxGain
;
311 Pitch
= ALSource
->Pitch
;
312 Relative
= ALSource
->HeadRelative
;
313 DirectChannels
= ALSource
->DirectChannels
;
315 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
316 for(i
= 0;i
< NumSends
;i
++)
318 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
320 Slot
= Device
->DefaultSlot
;
321 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
322 voice
->Send
[i
].OutBuffer
= NULL
;
324 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
327 /* Calculate the stepping value */
329 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
330 while(BufferListItem
!= NULL
)
333 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
335 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
336 if(Pitch
> (ALfloat
)MAX_PITCH
)
337 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
340 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
345 Channels
= ALBuffer
->FmtChannels
;
348 BufferListItem
= BufferListItem
->next
;
351 /* Calculate gains */
352 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
353 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
354 DryGainHF
= ALSource
->Direct
.GainHF
;
355 DryGainLF
= ALSource
->Direct
.GainLF
;
356 for(i
= 0;i
< NumSends
;i
++)
358 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
359 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
360 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
361 WetGainLF
[i
] = ALSource
->Send
[i
].GainLF
;
372 /* HACK: Place the stereo channels at +/-90 degrees when using non-
373 * HRTF stereo output. This helps reduce the "monoization" caused
374 * by them panning towards the center. */
375 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
376 chans
= StereoWideMap
;
410 DirectChannels
= AL_FALSE
;
416 DirectChannels
= AL_FALSE
;
422 ALfloat N
[3], V
[3], U
[3];
423 ALfloat matrix
[4][4];
426 N
[0] = ALSource
->Orientation
[0][0];
427 N
[1] = ALSource
->Orientation
[0][1];
428 N
[2] = ALSource
->Orientation
[0][2];
430 V
[0] = ALSource
->Orientation
[1][0];
431 V
[1] = ALSource
->Orientation
[1][1];
432 V
[2] = ALSource
->Orientation
[1][2];
436 ALfloat (*restrict lmatrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
437 aluMatrixVector(N
, 0.0f
, lmatrix
);
438 aluMatrixVector(V
, 0.0f
, lmatrix
);
440 /* Build and normalize right-vector */
441 aluCrossproduct(N
, V
, U
);
449 matrix
[1][1] = -N
[2];
450 matrix
[1][2] = -N
[0];
455 matrix
[2][3] = -U
[1];
457 matrix
[3][1] = -V
[2];
458 matrix
[3][2] = -V
[0];
461 for(c
= 0;c
< num_channels
;c
++)
463 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
464 ALfloat Target
[MaxChannels
];
466 ComputeBFormatGains(Device
, matrix
[c
], DryGain
, Target
);
467 for(i
= 0;i
< MaxChannels
;i
++)
468 gains
[i
].Target
= Target
[i
];
470 /* B-Format cannot handle logarithmic gain stepping, since the gain can
471 * switch between positive and negative values. */
472 voice
->Direct
.Moving
= AL_FALSE
;
473 UpdateDryStepping(&voice
->Direct
, num_channels
);
475 voice
->IsHrtf
= AL_FALSE
;
476 for(i
= 0;i
< NumSends
;i
++)
477 WetGain
[i
] *= 1.4142f
;
479 else if(DirectChannels
!= AL_FALSE
)
481 for(c
= 0;c
< num_channels
;c
++)
483 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
486 for(j
= 0;j
< MaxChannels
;j
++)
487 gains
[j
].Target
= 0.0f
;
488 if((idx
=GetChannelIdxByName(Device
, chans
[c
].channel
)) != -1)
489 gains
[idx
].Target
= DryGain
;
491 UpdateDryStepping(&voice
->Direct
, num_channels
);
493 voice
->IsHrtf
= AL_FALSE
;
495 else if(Device
->Hrtf
)
497 for(c
= 0;c
< num_channels
;c
++)
499 if(chans
[c
].channel
== LFE
)
502 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[0] = 0;
503 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[1] = 0;
504 for(i
= 0;i
< HRIR_LENGTH
;i
++)
506 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][0] = 0.0f
;
507 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][1] = 0.0f
;
512 /* Get the static HRIR coefficients and delays for this
514 GetLerpedHrtfCoeffs(Device
->Hrtf
,
515 chans
[c
].elevation
, chans
[c
].angle
, 1.0f
, DryGain
,
516 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
,
517 voice
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
);
520 voice
->Direct
.Counter
= 0;
521 voice
->Direct
.Moving
= AL_TRUE
;
522 voice
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
524 voice
->IsHrtf
= AL_TRUE
;
528 for(c
= 0;c
< num_channels
;c
++)
530 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[c
];
531 ALfloat Target
[MaxChannels
];
533 /* Special-case LFE */
534 if(chans
[c
].channel
== LFE
)
537 for(i
= 0;i
< MaxChannels
;i
++)
538 gains
[i
].Target
= 0.0f
;
539 if((idx
=GetChannelIdxByName(Device
, chans
[c
].channel
)) != -1)
540 gains
[idx
].Target
= DryGain
;
544 ComputeAngleGains(Device
, chans
[c
].angle
, chans
[c
].elevation
, DryGain
, Target
);
545 for(i
= 0;i
< MaxChannels
;i
++)
546 gains
[i
].Target
= Target
[i
];
548 UpdateDryStepping(&voice
->Direct
, num_channels
);
550 voice
->IsHrtf
= AL_FALSE
;
552 for(i
= 0;i
< NumSends
;i
++)
554 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
555 UpdateWetStepping(&voice
->Send
[i
]);
559 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
560 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
561 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
562 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
563 for(c
= 0;c
< num_channels
;c
++)
565 voice
->Direct
.Filters
[c
].ActiveType
= AF_None
;
566 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_LowPass
;
567 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_HighPass
;
568 ALfilterState_setParams(
569 &voice
->Direct
.Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
572 ALfilterState_setParams(
573 &voice
->Direct
.Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
578 for(i
= 0;i
< NumSends
;i
++)
580 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
581 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
582 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
583 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
584 for(c
= 0;c
< num_channels
;c
++)
586 voice
->Send
[i
].Filters
[c
].ActiveType
= AF_None
;
587 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_LowPass
;
588 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_HighPass
;
589 ALfilterState_setParams(
590 &voice
->Send
[i
].Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
593 ALfilterState_setParams(
594 &voice
->Send
[i
].Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
601 ALvoid
CalcSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
603 ALCdevice
*Device
= ALContext
->Device
;
604 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
605 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
606 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
607 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
608 ALfloat DopplerFactor
, SpeedOfSound
;
609 ALfloat AirAbsorptionFactor
;
610 ALfloat RoomAirAbsorption
[MAX_SENDS
];
611 ALbufferlistitem
*BufferListItem
;
613 ALfloat RoomAttenuation
[MAX_SENDS
];
614 ALfloat MetersPerUnit
;
615 ALfloat RoomRolloffBase
;
616 ALfloat RoomRolloff
[MAX_SENDS
];
617 ALfloat DecayDistance
[MAX_SENDS
];
621 ALboolean DryGainHFAuto
;
622 ALfloat WetGain
[MAX_SENDS
];
623 ALfloat WetGainHF
[MAX_SENDS
];
624 ALfloat WetGainLF
[MAX_SENDS
];
625 ALboolean WetGainAuto
;
626 ALboolean WetGainHFAuto
;
634 for(i
= 0;i
< MAX_SENDS
;i
++)
640 /* Get context/device properties */
641 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
642 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
643 NumSends
= Device
->NumAuxSends
;
644 Frequency
= Device
->Frequency
;
646 /* Get listener properties */
647 ListenerGain
= ALContext
->Listener
->Gain
;
648 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
650 /* Get source properties */
651 SourceVolume
= ALSource
->Gain
;
652 MinVolume
= ALSource
->MinGain
;
653 MaxVolume
= ALSource
->MaxGain
;
654 Pitch
= ALSource
->Pitch
;
655 Position
[0] = ALSource
->Position
[0];
656 Position
[1] = ALSource
->Position
[1];
657 Position
[2] = ALSource
->Position
[2];
658 Direction
[0] = ALSource
->Direction
[0];
659 Direction
[1] = ALSource
->Direction
[1];
660 Direction
[2] = ALSource
->Direction
[2];
661 Velocity
[0] = ALSource
->Velocity
[0];
662 Velocity
[1] = ALSource
->Velocity
[1];
663 Velocity
[2] = ALSource
->Velocity
[2];
664 MinDist
= ALSource
->RefDistance
;
665 MaxDist
= ALSource
->MaxDistance
;
666 Rolloff
= ALSource
->RollOffFactor
;
667 InnerAngle
= ALSource
->InnerAngle
;
668 OuterAngle
= ALSource
->OuterAngle
;
669 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
670 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
671 WetGainAuto
= ALSource
->WetGainAuto
;
672 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
673 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
675 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
676 for(i
= 0;i
< NumSends
;i
++)
678 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
681 Slot
= Device
->DefaultSlot
;
682 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
685 RoomRolloff
[i
] = 0.0f
;
686 DecayDistance
[i
] = 0.0f
;
687 RoomAirAbsorption
[i
] = 1.0f
;
689 else if(Slot
->AuxSendAuto
)
691 RoomRolloff
[i
] = RoomRolloffBase
;
692 if(IsReverbEffect(Slot
->EffectType
))
694 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
695 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
696 SPEEDOFSOUNDMETRESPERSEC
;
697 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
701 DecayDistance
[i
] = 0.0f
;
702 RoomAirAbsorption
[i
] = 1.0f
;
707 /* If the slot's auxiliary send auto is off, the data sent to the
708 * effect slot is the same as the dry path, sans filter effects */
709 RoomRolloff
[i
] = Rolloff
;
710 DecayDistance
[i
] = 0.0f
;
711 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
714 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
715 voice
->Send
[i
].OutBuffer
= NULL
;
717 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
720 /* Transform source to listener space (convert to head relative) */
721 if(ALSource
->HeadRelative
== AL_FALSE
)
723 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
724 /* Transform source vectors */
725 aluMatrixVector(Position
, 1.0f
, Matrix
);
726 aluMatrixVector(Direction
, 0.0f
, Matrix
);
727 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
731 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
732 /* Offset the source velocity to be relative of the listener velocity */
733 Velocity
[0] += ListenerVel
[0];
734 Velocity
[1] += ListenerVel
[1];
735 Velocity
[2] += ListenerVel
[2];
738 SourceToListener
[0] = -Position
[0];
739 SourceToListener
[1] = -Position
[1];
740 SourceToListener
[2] = -Position
[2];
741 aluNormalize(SourceToListener
);
742 aluNormalize(Direction
);
744 /* Calculate distance attenuation */
745 Distance
= sqrtf(aluDotproduct(Position
, Position
));
746 ClampedDist
= Distance
;
749 for(i
= 0;i
< NumSends
;i
++)
750 RoomAttenuation
[i
] = 1.0f
;
751 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
752 ALContext
->DistanceModel
)
754 case InverseDistanceClamped
:
755 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
756 if(MaxDist
< MinDist
)
759 case InverseDistance
:
762 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
763 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
764 for(i
= 0;i
< NumSends
;i
++)
766 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
767 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
772 case LinearDistanceClamped
:
773 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
774 if(MaxDist
< MinDist
)
778 if(MaxDist
!= MinDist
)
780 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
781 Attenuation
= maxf(Attenuation
, 0.0f
);
782 for(i
= 0;i
< NumSends
;i
++)
784 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
785 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
790 case ExponentDistanceClamped
:
791 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
792 if(MaxDist
< MinDist
)
795 case ExponentDistance
:
796 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
798 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
799 for(i
= 0;i
< NumSends
;i
++)
800 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
804 case DisableDistance
:
805 ClampedDist
= MinDist
;
809 /* Source Gain + Attenuation */
810 DryGain
= SourceVolume
* Attenuation
;
811 for(i
= 0;i
< NumSends
;i
++)
812 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
814 /* Distance-based air absorption */
815 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
817 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
818 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
819 for(i
= 0;i
< NumSends
;i
++)
820 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
825 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
827 /* Apply a decay-time transformation to the wet path, based on the
828 * attenuation of the dry path.
830 * Using the apparent distance, based on the distance attenuation, the
831 * initial decay of the reverb effect is calculated and applied to the
834 for(i
= 0;i
< NumSends
;i
++)
836 if(DecayDistance
[i
] > 0.0f
)
837 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
841 /* Calculate directional soundcones */
842 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
843 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
845 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
846 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
847 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
849 else if(Angle
> OuterAngle
)
851 ConeVolume
= ALSource
->OuterGain
;
852 ConeHF
= ALSource
->OuterGainHF
;
860 DryGain
*= ConeVolume
;
863 for(i
= 0;i
< NumSends
;i
++)
864 WetGain
[i
] *= ConeVolume
;
870 for(i
= 0;i
< NumSends
;i
++)
871 WetGainHF
[i
] *= ConeHF
;
874 /* Clamp to Min/Max Gain */
875 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
876 for(i
= 0;i
< NumSends
;i
++)
877 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
879 /* Apply gain and frequency filters */
880 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
881 DryGainHF
*= ALSource
->Direct
.GainHF
;
882 DryGainLF
*= ALSource
->Direct
.GainLF
;
883 for(i
= 0;i
< NumSends
;i
++)
885 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
886 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
887 WetGainLF
[i
] *= ALSource
->Send
[i
].GainLF
;
890 /* Calculate velocity-based doppler effect */
891 if(DopplerFactor
> 0.0f
)
893 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
896 if(SpeedOfSound
< 1.0f
)
898 DopplerFactor
*= 1.0f
/SpeedOfSound
;
902 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
903 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
905 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
906 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
909 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
910 while(BufferListItem
!= NULL
)
913 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
915 /* Calculate fixed-point stepping value, based on the pitch, buffer
916 * frequency, and output frequency. */
917 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
918 if(Pitch
> (ALfloat
)MAX_PITCH
)
919 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
922 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
929 BufferListItem
= BufferListItem
->next
;
934 /* Use a binaural HRTF algorithm for stereo headphone playback */
935 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
936 ALfloat radius
= ALSource
->Radius
;
937 ALfloat dirfact
= 1.0f
;
939 if(Distance
> FLT_EPSILON
)
941 ALfloat invlen
= 1.0f
/Distance
;
942 Position
[0] *= invlen
;
943 Position
[1] *= invlen
;
944 Position
[2] *= invlen
;
946 /* Calculate elevation and azimuth only when the source is not at
947 * the listener. This prevents +0 and -0 Z from producing
948 * inconsistent panning. Also, clamp Y in case FP precision errors
949 * cause it to land outside of -1..+1. */
950 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
951 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
953 if(radius
> Distance
)
954 dirfact
*= Distance
/ radius
;
956 /* Check to see if the HRIR is already moving. */
957 if(voice
->Direct
.Moving
)
959 /* Calculate the normalized HRTF transition factor (delta). */
960 delta
= CalcHrtfDelta(voice
->Direct
.Mix
.Hrtf
.Gain
, DryGain
,
961 voice
->Direct
.Mix
.Hrtf
.Dir
, Position
);
962 /* If the delta is large enough, get the moving HRIR target
963 * coefficients, target delays, steppping values, and counter. */
966 ALuint counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
967 ev
, az
, dirfact
, DryGain
, delta
, voice
->Direct
.Counter
,
968 voice
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
, voice
->Direct
.Mix
.Hrtf
.Params
[0].Delay
,
969 voice
->Direct
.Mix
.Hrtf
.Params
[0].CoeffStep
, voice
->Direct
.Mix
.Hrtf
.Params
[0].DelayStep
971 voice
->Direct
.Counter
= counter
;
972 voice
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
973 voice
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
974 voice
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
975 voice
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
980 /* Get the initial (static) HRIR coefficients and delays. */
981 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, dirfact
, DryGain
,
982 voice
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
983 voice
->Direct
.Mix
.Hrtf
.Params
[0].Delay
);
984 voice
->Direct
.Counter
= 0;
985 voice
->Direct
.Moving
= AL_TRUE
;
986 voice
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
987 voice
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
988 voice
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
989 voice
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
991 voice
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
993 voice
->IsHrtf
= AL_TRUE
;
997 MixGains
*gains
= voice
->Direct
.Mix
.Gains
[0];
998 ALfloat radius
= ALSource
->Radius
;
999 ALfloat Target
[MaxChannels
];
1001 /* Normalize the length, and compute panned gains. */
1002 if(!(Distance
> FLT_EPSILON
) && !(radius
> FLT_EPSILON
))
1004 const ALfloat front
[3] = { 0.0f
, 0.0f
, -1.0f
};
1005 ComputeDirectionalGains(Device
, front
, DryGain
, Target
);
1009 ALfloat invlen
= 1.0f
/maxf(Distance
, radius
);
1010 Position
[0] *= invlen
;
1011 Position
[1] *= invlen
;
1012 Position
[2] *= invlen
;
1013 ComputeDirectionalGains(Device
, Position
, DryGain
, Target
);
1016 for(j
= 0;j
< MaxChannels
;j
++)
1017 gains
[j
].Target
= Target
[j
];
1018 UpdateDryStepping(&voice
->Direct
, 1);
1020 voice
->IsHrtf
= AL_FALSE
;
1022 for(i
= 0;i
< NumSends
;i
++)
1024 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
1025 UpdateWetStepping(&voice
->Send
[i
]);
1029 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
1030 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
1031 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
1032 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
1033 voice
->Direct
.Filters
[0].ActiveType
= AF_None
;
1034 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_LowPass
;
1035 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_HighPass
;
1036 ALfilterState_setParams(
1037 &voice
->Direct
.Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1040 ALfilterState_setParams(
1041 &voice
->Direct
.Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1045 for(i
= 0;i
< NumSends
;i
++)
1047 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
1048 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
1049 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
1050 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
1051 voice
->Send
[i
].Filters
[0].ActiveType
= AF_None
;
1052 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_LowPass
;
1053 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_HighPass
;
1054 ALfilterState_setParams(
1055 &voice
->Send
[i
].Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1058 ALfilterState_setParams(
1059 &voice
->Send
[i
].Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1066 static inline ALint
aluF2I25(ALfloat val
)
1068 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1069 if(fabsf(val
) > 1.0f
)
1070 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
1071 /* Convert to a signed integer, between -16777215 and +16777215. */
1072 return fastf2i(val
*16777215.0f
);
1075 static inline ALfloat
aluF2F(ALfloat val
)
1077 static inline ALint
aluF2I(ALfloat val
)
1078 { return aluF2I25(val
)<<7; }
1079 static inline ALuint
aluF2UI(ALfloat val
)
1080 { return aluF2I(val
)+2147483648u; }
1081 static inline ALshort
aluF2S(ALfloat val
)
1082 { return aluF2I25(val
)>>9; }
1083 static inline ALushort
aluF2US(ALfloat val
)
1084 { return aluF2S(val
)+32768; }
1085 static inline ALbyte
aluF2B(ALfloat val
)
1086 { return aluF2I25(val
)>>17; }
1087 static inline ALubyte
aluF2UB(ALfloat val
)
1088 { return aluF2B(val
)+128; }
1090 #define DECL_TEMPLATE(T, func) \
1091 static void Write_##T(const ALfloatBUFFERSIZE *DryBuffer, ALvoid *buffer, \
1092 ALuint SamplesToDo, ALuint numchans) \
1095 for(j = 0;j < numchans;j++) \
1097 const ALfloat *in = DryBuffer[j]; \
1098 T *restrict out = (T*)buffer + j; \
1099 for(i = 0;i < SamplesToDo;i++) \
1100 out[i*numchans] = func(in[i]); \
1104 DECL_TEMPLATE(ALfloat
, aluF2F
)
1105 DECL_TEMPLATE(ALuint
, aluF2UI
)
1106 DECL_TEMPLATE(ALint
, aluF2I
)
1107 DECL_TEMPLATE(ALushort
, aluF2US
)
1108 DECL_TEMPLATE(ALshort
, aluF2S
)
1109 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1110 DECL_TEMPLATE(ALbyte
, aluF2B
)
1112 #undef DECL_TEMPLATE
1115 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1118 ALeffectslot
**slot
, **slot_end
;
1119 ALvoice
*voice
, *voice_end
;
1124 SetMixerFPUMode(&oldMode
);
1128 IncrementRef(&device
->MixCount
);
1130 SamplesToDo
= minu(size
, BUFFERSIZE
);
1131 for(c
= 0;c
< MaxChannels
;c
++)
1132 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1134 V0(device
->Backend
,lock
)();
1135 V(device
->Synth
,process
)(SamplesToDo
, device
->DryBuffer
);
1137 ctx
= ATOMIC_LOAD(&device
->ContextList
);
1140 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1141 ALenum UpdateSources
= AL_FALSE
;
1144 UpdateSources
= ATOMIC_EXCHANGE(ALenum
, &ctx
->UpdateSources
, AL_FALSE
);
1147 CalcListenerParams(ctx
->Listener
);
1149 /* source processing */
1150 voice
= ctx
->Voices
;
1151 voice_end
= voice
+ ctx
->VoiceCount
;
1152 while(voice
!= voice_end
)
1154 ALsource
*source
= voice
->Source
;
1155 if(!source
) goto next
;
1157 if(source
->state
!= AL_PLAYING
&& source
->state
!= AL_PAUSED
)
1159 voice
->Source
= NULL
;
1163 if(!DeferUpdates
&& (ATOMIC_EXCHANGE(ALenum
, &source
->NeedsUpdate
, AL_FALSE
) ||
1165 voice
->Update(voice
, source
, ctx
);
1167 if(source
->state
!= AL_PAUSED
)
1168 MixSource(voice
, source
, device
, SamplesToDo
);
1173 /* effect slot processing */
1174 slot
= VECTOR_ITER_BEGIN(ctx
->ActiveAuxSlots
);
1175 slot_end
= VECTOR_ITER_END(ctx
->ActiveAuxSlots
);
1176 while(slot
!= slot_end
)
1178 if(!DeferUpdates
&& ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1179 V((*slot
)->EffectState
,update
)(device
, *slot
);
1181 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1184 for(i
= 0;i
< SamplesToDo
;i
++)
1185 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1193 slot
= &device
->DefaultSlot
;
1196 if(ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1197 V((*slot
)->EffectState
,update
)(device
, *slot
);
1199 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1202 for(i
= 0;i
< SamplesToDo
;i
++)
1203 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1206 /* Increment the clock time. Every second's worth of samples is
1207 * converted and added to clock base so that large sample counts don't
1208 * overflow during conversion. This also guarantees an exact, stable
1210 device
->SamplesDone
+= SamplesToDo
;
1211 device
->ClockBase
+= (device
->SamplesDone
/device
->Frequency
) * DEVICE_CLOCK_RES
;
1212 device
->SamplesDone
%= device
->Frequency
;
1213 V0(device
->Backend
,unlock
)();
1217 /* Apply binaural/crossfeed filter */
1218 for(i
= 0;i
< SamplesToDo
;i
++)
1221 samples
[0] = device
->DryBuffer
[0][i
];
1222 samples
[1] = device
->DryBuffer
[1][i
];
1223 bs2b_cross_feed(device
->Bs2b
, samples
);
1224 device
->DryBuffer
[0][i
] = samples
[0];
1225 device
->DryBuffer
[1][i
] = samples
[1];
1231 switch(device
->FmtType
)
1234 Write_ALbyte(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1235 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALbyte
);
1238 Write_ALubyte(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1239 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALubyte
);
1242 Write_ALshort(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1243 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALshort
);
1246 Write_ALushort(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1247 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALushort
);
1250 Write_ALint(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1251 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALint
);
1254 Write_ALuint(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1255 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALuint
);
1258 Write_ALfloat(device
->DryBuffer
, buffer
, SamplesToDo
, device
->NumSpeakers
);
1259 buffer
= (char*)buffer
+ SamplesToDo
*device
->NumSpeakers
*sizeof(ALfloat
);
1264 size
-= SamplesToDo
;
1265 IncrementRef(&device
->MixCount
);
1268 RestoreFPUMode(&oldMode
);
1272 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1274 ALCcontext
*Context
;
1276 device
->Connected
= ALC_FALSE
;
1278 Context
= ATOMIC_LOAD(&device
->ContextList
);
1281 ALvoice
*voice
, *voice_end
;
1283 voice
= Context
->Voices
;
1284 voice_end
= voice
+ Context
->VoiceCount
;
1285 while(voice
!= voice_end
)
1287 ALsource
*source
= voice
->Source
;
1288 voice
->Source
= NULL
;
1290 if(source
&& source
->state
== AL_PLAYING
)
1292 source
->state
= AL_STOPPED
;
1293 ATOMIC_STORE(&source
->current_buffer
, NULL
);
1294 source
->position
= 0;
1295 source
->position_fraction
= 0;
1300 Context
->VoiceCount
= 0;
1302 Context
= Context
->next
;