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 "mixer_defs.h"
41 #include "backends/base.h"
42 #include "midi/base.h"
45 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
46 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
55 ALfloat ConeScale
= 1.0f
;
57 /* Localized Z scalar for mono sources */
58 ALfloat ZScale
= 1.0f
;
60 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
61 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
62 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
64 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
65 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
66 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
68 extern inline ALuint
minu(ALuint a
, ALuint b
);
69 extern inline ALuint
maxu(ALuint a
, ALuint b
);
70 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
72 extern inline ALint
mini(ALint a
, ALint b
);
73 extern inline ALint
maxi(ALint a
, ALint b
);
74 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
76 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
77 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
78 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
80 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
81 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
82 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
84 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
85 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
88 static inline HrtfMixerFunc
SelectHrtfMixer(void)
91 if((CPUCapFlags
&CPU_CAP_SSE
))
95 if((CPUCapFlags
&CPU_CAP_NEON
))
103 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
105 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
106 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
107 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
110 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
112 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
113 inVector1
[2]*inVector2
[2];
116 static inline void aluNormalize(ALfloat
*inVector
)
118 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
121 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
122 inVector
[0] *= inv_length
;
123 inVector
[1] *= inv_length
;
124 inVector
[2] *= inv_length
;
128 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
131 vector
[0], vector
[1], vector
[2], w
134 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
135 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
136 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
140 static void UpdateDryStepping(DirectParams
*params
, ALuint num_chans
)
146 for(i
= 0;i
< num_chans
;i
++)
148 MixGains
*gains
= params
->Gains
[i
];
149 for(j
= 0;j
< params
->OutChannels
;j
++)
151 gains
[j
].Current
= gains
[j
].Target
;
152 gains
[j
].Step
= 1.0f
;
155 params
->Moving
= AL_TRUE
;
160 for(i
= 0;i
< num_chans
;i
++)
162 MixGains
*gains
= params
->Gains
[i
];
163 for(j
= 0;j
< params
->OutChannels
;j
++)
165 ALfloat cur
= maxf(gains
[j
].Current
, FLT_EPSILON
);
166 ALfloat trg
= maxf(gains
[j
].Target
, FLT_EPSILON
);
167 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
168 gains
[j
].Step
= powf(trg
/cur
, 1.0f
/64.0f
);
170 gains
[j
].Step
= 1.0f
;
171 gains
[j
].Current
= cur
;
174 params
->Counter
= 64;
177 static void UpdateWetStepping(SendParams
*params
)
183 params
->Gain
.Current
= params
->Gain
.Target
;
184 params
->Gain
.Step
= 1.0f
;
186 params
->Moving
= AL_TRUE
;
191 cur
= maxf(params
->Gain
.Current
, FLT_EPSILON
);
192 trg
= maxf(params
->Gain
.Target
, FLT_EPSILON
);
193 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
194 params
->Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
196 params
->Gain
.Step
= 1.0f
;
197 params
->Gain
.Current
= cur
;
199 params
->Counter
= 64;
203 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
205 ALfloat N
[3], V
[3], U
[3], P
[3];
208 N
[0] = Listener
->Forward
[0];
209 N
[1] = Listener
->Forward
[1];
210 N
[2] = Listener
->Forward
[2];
212 V
[0] = Listener
->Up
[0];
213 V
[1] = Listener
->Up
[1];
214 V
[2] = Listener
->Up
[2];
216 /* Build and normalize right-vector */
217 aluCrossproduct(N
, V
, U
);
220 Listener
->Params
.Matrix
[0][0] = U
[0];
221 Listener
->Params
.Matrix
[0][1] = V
[0];
222 Listener
->Params
.Matrix
[0][2] = -N
[0];
223 Listener
->Params
.Matrix
[0][3] = 0.0f
;
224 Listener
->Params
.Matrix
[1][0] = U
[1];
225 Listener
->Params
.Matrix
[1][1] = V
[1];
226 Listener
->Params
.Matrix
[1][2] = -N
[1];
227 Listener
->Params
.Matrix
[1][3] = 0.0f
;
228 Listener
->Params
.Matrix
[2][0] = U
[2];
229 Listener
->Params
.Matrix
[2][1] = V
[2];
230 Listener
->Params
.Matrix
[2][2] = -N
[2];
231 Listener
->Params
.Matrix
[2][3] = 0.0f
;
232 Listener
->Params
.Matrix
[3][0] = 0.0f
;
233 Listener
->Params
.Matrix
[3][1] = 0.0f
;
234 Listener
->Params
.Matrix
[3][2] = 0.0f
;
235 Listener
->Params
.Matrix
[3][3] = 1.0f
;
237 P
[0] = Listener
->Position
[0];
238 P
[1] = Listener
->Position
[1];
239 P
[2] = Listener
->Position
[2];
240 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
241 Listener
->Params
.Matrix
[3][0] = -P
[0];
242 Listener
->Params
.Matrix
[3][1] = -P
[1];
243 Listener
->Params
.Matrix
[3][2] = -P
[2];
245 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
246 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
247 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
248 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
251 ALvoid
CalcNonAttnSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
253 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
, 0.0f
} };
254 static const struct ChanMap StereoMap
[2] = {
255 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
256 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) }
258 static const struct ChanMap StereoWideMap
[2] = {
259 { FrontLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
260 { FrontRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
262 static const struct ChanMap RearMap
[2] = {
263 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
264 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) }
266 static const struct ChanMap QuadMap
[4] = {
267 { FrontLeft
, DEG2RAD( -45.0f
), DEG2RAD(0.0f
) },
268 { FrontRight
, DEG2RAD( 45.0f
), DEG2RAD(0.0f
) },
269 { BackLeft
, DEG2RAD(-135.0f
), DEG2RAD(0.0f
) },
270 { BackRight
, DEG2RAD( 135.0f
), DEG2RAD(0.0f
) }
272 static const struct ChanMap X51Map
[6] = {
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 { SideLeft
, DEG2RAD(-110.0f
), DEG2RAD(0.0f
) },
278 { SideRight
, DEG2RAD( 110.0f
), DEG2RAD(0.0f
) }
280 static const struct ChanMap X61Map
[7] = {
281 { FrontLeft
, DEG2RAD(-30.0f
), DEG2RAD(0.0f
) },
282 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
283 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
285 { BackCenter
, DEG2RAD(180.0f
), DEG2RAD(0.0f
) },
286 { SideLeft
, DEG2RAD(-90.0f
), DEG2RAD(0.0f
) },
287 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
289 static const struct ChanMap X71Map
[8] = {
290 { FrontLeft
, DEG2RAD( -30.0f
), DEG2RAD(0.0f
) },
291 { FrontRight
, DEG2RAD( 30.0f
), DEG2RAD(0.0f
) },
292 { FrontCenter
, DEG2RAD( 0.0f
), DEG2RAD(0.0f
) },
294 { BackLeft
, DEG2RAD(-150.0f
), DEG2RAD(0.0f
) },
295 { BackRight
, DEG2RAD( 150.0f
), DEG2RAD(0.0f
) },
296 { SideLeft
, DEG2RAD( -90.0f
), DEG2RAD(0.0f
) },
297 { SideRight
, DEG2RAD( 90.0f
), DEG2RAD(0.0f
) }
300 ALCdevice
*Device
= ALContext
->Device
;
301 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
302 ALbufferlistitem
*BufferListItem
;
303 enum FmtChannels Channels
;
304 ALfloat DryGain
, DryGainHF
, DryGainLF
;
305 ALfloat WetGain
[MAX_SENDS
];
306 ALfloat WetGainHF
[MAX_SENDS
];
307 ALfloat WetGainLF
[MAX_SENDS
];
308 ALuint NumSends
, Frequency
;
310 const struct ChanMap
*chans
= NULL
;
311 ALuint num_channels
= 0;
312 ALboolean DirectChannels
;
313 ALboolean isbformat
= AL_FALSE
;
317 /* Get device properties */
318 NumSends
= Device
->NumAuxSends
;
319 Frequency
= Device
->Frequency
;
321 /* Get listener properties */
322 ListenerGain
= ALContext
->Listener
->Gain
;
324 /* Get source properties */
325 SourceVolume
= ALSource
->Gain
;
326 MinVolume
= ALSource
->MinGain
;
327 MaxVolume
= ALSource
->MaxGain
;
328 Pitch
= ALSource
->Pitch
;
329 Relative
= ALSource
->HeadRelative
;
330 DirectChannels
= ALSource
->DirectChannels
;
332 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
333 voice
->Direct
.OutChannels
= Device
->NumChannels
;
334 for(i
= 0;i
< NumSends
;i
++)
336 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
338 Slot
= Device
->DefaultSlot
;
339 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
340 voice
->Send
[i
].OutBuffer
= NULL
;
342 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
345 /* Calculate the stepping value */
347 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
348 while(BufferListItem
!= NULL
)
351 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
353 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
354 if(Pitch
> (ALfloat
)MAX_PITCH
)
355 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
358 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
363 Channels
= ALBuffer
->FmtChannels
;
366 BufferListItem
= BufferListItem
->next
;
369 /* Calculate gains */
370 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
371 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
372 DryGainHF
= ALSource
->Direct
.GainHF
;
373 DryGainLF
= ALSource
->Direct
.GainLF
;
374 for(i
= 0;i
< NumSends
;i
++)
376 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
377 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
378 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
379 WetGainLF
[i
] = ALSource
->Send
[i
].GainLF
;
390 /* HACK: Place the stereo channels at +/-90 degrees when using non-
391 * HRTF stereo output. This helps reduce the "monoization" caused
392 * by them panning towards the center. */
393 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
394 chans
= StereoWideMap
;
428 DirectChannels
= AL_FALSE
;
434 DirectChannels
= AL_FALSE
;
440 ALfloat N
[3], V
[3], U
[3];
441 ALfloat matrix
[4][4];
444 N
[0] = ALSource
->Orientation
[0][0];
445 N
[1] = ALSource
->Orientation
[0][1];
446 N
[2] = ALSource
->Orientation
[0][2];
448 V
[0] = ALSource
->Orientation
[1][0];
449 V
[1] = ALSource
->Orientation
[1][1];
450 V
[2] = ALSource
->Orientation
[1][2];
454 ALfloat (*restrict lmatrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
455 aluMatrixVector(N
, 0.0f
, lmatrix
);
456 aluMatrixVector(V
, 0.0f
, lmatrix
);
458 /* Build and normalize right-vector */
459 aluCrossproduct(N
, V
, U
);
467 matrix
[1][1] = -N
[2];
468 matrix
[1][2] = -N
[0];
473 matrix
[2][3] = -U
[1];
475 matrix
[3][1] = -V
[2];
476 matrix
[3][2] = -V
[0];
479 for(c
= 0;c
< num_channels
;c
++)
481 MixGains
*gains
= voice
->Direct
.Gains
[c
];
482 ALfloat Target
[MAX_OUTPUT_CHANNELS
];
484 ComputeBFormatGains(Device
, matrix
[c
], DryGain
, Target
);
485 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
486 gains
[i
].Target
= Target
[i
];
488 /* B-Format cannot handle logarithmic gain stepping, since the gain can
489 * switch between positive and negative values. */
490 voice
->Direct
.Moving
= AL_FALSE
;
491 UpdateDryStepping(&voice
->Direct
, num_channels
);
493 voice
->IsHrtf
= AL_FALSE
;
494 for(i
= 0;i
< NumSends
;i
++)
495 WetGain
[i
] *= 1.4142f
;
497 else if(DirectChannels
!= AL_FALSE
)
501 voice
->Direct
.OutBuffer
= &voice
->Direct
.OutBuffer
[voice
->Direct
.OutChannels
];
502 voice
->Direct
.OutChannels
= 2;
503 for(c
= 0;c
< num_channels
;c
++)
505 MixGains
*gains
= voice
->Direct
.Gains
[c
];
507 for(j
= 0;j
< MAX_OUTPUT_CHANNELS
;j
++)
508 gains
[j
].Target
= 0.0f
;
510 if(chans
[c
].channel
== FrontLeft
)
511 gains
[0].Target
= DryGain
;
512 else if(chans
[c
].channel
== FrontRight
)
513 gains
[1].Target
= DryGain
;
516 else for(c
= 0;c
< num_channels
;c
++)
518 MixGains
*gains
= voice
->Direct
.Gains
[c
];
521 for(j
= 0;j
< MAX_OUTPUT_CHANNELS
;j
++)
522 gains
[j
].Target
= 0.0f
;
523 if((idx
=GetChannelIdxByName(Device
, chans
[c
].channel
)) != -1)
524 gains
[idx
].Target
= DryGain
;
526 UpdateDryStepping(&voice
->Direct
, num_channels
);
528 voice
->IsHrtf
= AL_FALSE
;
530 else if(Device
->Hrtf
)
532 voice
->Direct
.OutBuffer
= &voice
->Direct
.OutBuffer
[voice
->Direct
.OutChannels
];
533 voice
->Direct
.OutChannels
= 2;
534 for(c
= 0;c
< num_channels
;c
++)
536 if(chans
[c
].channel
== LFE
)
539 voice
->Direct
.Hrtf
.Params
[c
].Delay
[0] = 0;
540 voice
->Direct
.Hrtf
.Params
[c
].Delay
[1] = 0;
541 for(i
= 0;i
< HRIR_LENGTH
;i
++)
543 voice
->Direct
.Hrtf
.Params
[c
].Coeffs
[i
][0] = 0.0f
;
544 voice
->Direct
.Hrtf
.Params
[c
].Coeffs
[i
][1] = 0.0f
;
549 /* Get the static HRIR coefficients and delays for this
551 GetLerpedHrtfCoeffs(Device
->Hrtf
,
552 chans
[c
].elevation
, chans
[c
].angle
, 1.0f
, DryGain
,
553 voice
->Direct
.Hrtf
.Params
[c
].Coeffs
,
554 voice
->Direct
.Hrtf
.Params
[c
].Delay
);
557 voice
->Direct
.Counter
= 0;
558 voice
->Direct
.Moving
= AL_TRUE
;
559 voice
->Direct
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
561 voice
->IsHrtf
= AL_TRUE
;
565 for(c
= 0;c
< num_channels
;c
++)
567 MixGains
*gains
= voice
->Direct
.Gains
[c
];
568 ALfloat Target
[MAX_OUTPUT_CHANNELS
];
570 /* Special-case LFE */
571 if(chans
[c
].channel
== LFE
)
574 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
575 gains
[i
].Target
= 0.0f
;
576 if((idx
=GetChannelIdxByName(Device
, chans
[c
].channel
)) != -1)
577 gains
[idx
].Target
= DryGain
;
581 ComputeAngleGains(Device
, chans
[c
].angle
, chans
[c
].elevation
, DryGain
, Target
);
582 for(i
= 0;i
< MAX_OUTPUT_CHANNELS
;i
++)
583 gains
[i
].Target
= Target
[i
];
585 UpdateDryStepping(&voice
->Direct
, num_channels
);
587 voice
->IsHrtf
= AL_FALSE
;
589 for(i
= 0;i
< NumSends
;i
++)
591 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
592 UpdateWetStepping(&voice
->Send
[i
]);
596 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
597 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
598 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
599 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
600 for(c
= 0;c
< num_channels
;c
++)
602 voice
->Direct
.Filters
[c
].ActiveType
= AF_None
;
603 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_LowPass
;
604 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[c
].ActiveType
|= AF_HighPass
;
605 ALfilterState_setParams(
606 &voice
->Direct
.Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
609 ALfilterState_setParams(
610 &voice
->Direct
.Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
615 for(i
= 0;i
< NumSends
;i
++)
617 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
618 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
619 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
620 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
621 for(c
= 0;c
< num_channels
;c
++)
623 voice
->Send
[i
].Filters
[c
].ActiveType
= AF_None
;
624 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_LowPass
;
625 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[c
].ActiveType
|= AF_HighPass
;
626 ALfilterState_setParams(
627 &voice
->Send
[i
].Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
630 ALfilterState_setParams(
631 &voice
->Send
[i
].Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
638 ALvoid
CalcSourceParams(ALvoice
*voice
, const ALsource
*ALSource
, const ALCcontext
*ALContext
)
640 ALCdevice
*Device
= ALContext
->Device
;
641 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
642 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
643 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
644 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
645 ALfloat DopplerFactor
, SpeedOfSound
;
646 ALfloat AirAbsorptionFactor
;
647 ALfloat RoomAirAbsorption
[MAX_SENDS
];
648 ALbufferlistitem
*BufferListItem
;
650 ALfloat RoomAttenuation
[MAX_SENDS
];
651 ALfloat MetersPerUnit
;
652 ALfloat RoomRolloffBase
;
653 ALfloat RoomRolloff
[MAX_SENDS
];
654 ALfloat DecayDistance
[MAX_SENDS
];
658 ALboolean DryGainHFAuto
;
659 ALfloat WetGain
[MAX_SENDS
];
660 ALfloat WetGainHF
[MAX_SENDS
];
661 ALfloat WetGainLF
[MAX_SENDS
];
662 ALboolean WetGainAuto
;
663 ALboolean WetGainHFAuto
;
671 for(i
= 0;i
< MAX_SENDS
;i
++)
677 /* Get context/device properties */
678 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
679 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
680 NumSends
= Device
->NumAuxSends
;
681 Frequency
= Device
->Frequency
;
683 /* Get listener properties */
684 ListenerGain
= ALContext
->Listener
->Gain
;
685 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
687 /* Get source properties */
688 SourceVolume
= ALSource
->Gain
;
689 MinVolume
= ALSource
->MinGain
;
690 MaxVolume
= ALSource
->MaxGain
;
691 Pitch
= ALSource
->Pitch
;
692 Position
[0] = ALSource
->Position
[0];
693 Position
[1] = ALSource
->Position
[1];
694 Position
[2] = ALSource
->Position
[2];
695 Direction
[0] = ALSource
->Direction
[0];
696 Direction
[1] = ALSource
->Direction
[1];
697 Direction
[2] = ALSource
->Direction
[2];
698 Velocity
[0] = ALSource
->Velocity
[0];
699 Velocity
[1] = ALSource
->Velocity
[1];
700 Velocity
[2] = ALSource
->Velocity
[2];
701 MinDist
= ALSource
->RefDistance
;
702 MaxDist
= ALSource
->MaxDistance
;
703 Rolloff
= ALSource
->RollOffFactor
;
704 InnerAngle
= ALSource
->InnerAngle
;
705 OuterAngle
= ALSource
->OuterAngle
;
706 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
707 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
708 WetGainAuto
= ALSource
->WetGainAuto
;
709 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
710 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
712 voice
->Direct
.OutBuffer
= Device
->DryBuffer
;
713 voice
->Direct
.OutChannels
= Device
->NumChannels
;
714 for(i
= 0;i
< NumSends
;i
++)
716 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
719 Slot
= Device
->DefaultSlot
;
720 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
723 RoomRolloff
[i
] = 0.0f
;
724 DecayDistance
[i
] = 0.0f
;
725 RoomAirAbsorption
[i
] = 1.0f
;
727 else if(Slot
->AuxSendAuto
)
729 RoomRolloff
[i
] = RoomRolloffBase
;
730 if(IsReverbEffect(Slot
->EffectType
))
732 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
733 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
734 SPEEDOFSOUNDMETRESPERSEC
;
735 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
739 DecayDistance
[i
] = 0.0f
;
740 RoomAirAbsorption
[i
] = 1.0f
;
745 /* If the slot's auxiliary send auto is off, the data sent to the
746 * effect slot is the same as the dry path, sans filter effects */
747 RoomRolloff
[i
] = Rolloff
;
748 DecayDistance
[i
] = 0.0f
;
749 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
752 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
753 voice
->Send
[i
].OutBuffer
= NULL
;
755 voice
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
758 /* Transform source to listener space (convert to head relative) */
759 if(ALSource
->HeadRelative
== AL_FALSE
)
761 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
762 /* Transform source vectors */
763 aluMatrixVector(Position
, 1.0f
, Matrix
);
764 aluMatrixVector(Direction
, 0.0f
, Matrix
);
765 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
769 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
770 /* Offset the source velocity to be relative of the listener velocity */
771 Velocity
[0] += ListenerVel
[0];
772 Velocity
[1] += ListenerVel
[1];
773 Velocity
[2] += ListenerVel
[2];
776 SourceToListener
[0] = -Position
[0];
777 SourceToListener
[1] = -Position
[1];
778 SourceToListener
[2] = -Position
[2];
779 aluNormalize(SourceToListener
);
780 aluNormalize(Direction
);
782 /* Calculate distance attenuation */
783 Distance
= sqrtf(aluDotproduct(Position
, Position
));
784 ClampedDist
= Distance
;
787 for(i
= 0;i
< NumSends
;i
++)
788 RoomAttenuation
[i
] = 1.0f
;
789 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
790 ALContext
->DistanceModel
)
792 case InverseDistanceClamped
:
793 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
794 if(MaxDist
< MinDist
)
797 case InverseDistance
:
800 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
801 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
802 for(i
= 0;i
< NumSends
;i
++)
804 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
805 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
810 case LinearDistanceClamped
:
811 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
812 if(MaxDist
< MinDist
)
816 if(MaxDist
!= MinDist
)
818 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
819 Attenuation
= maxf(Attenuation
, 0.0f
);
820 for(i
= 0;i
< NumSends
;i
++)
822 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
823 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
828 case ExponentDistanceClamped
:
829 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
830 if(MaxDist
< MinDist
)
833 case ExponentDistance
:
834 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
836 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
837 for(i
= 0;i
< NumSends
;i
++)
838 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
842 case DisableDistance
:
843 ClampedDist
= MinDist
;
847 /* Source Gain + Attenuation */
848 DryGain
= SourceVolume
* Attenuation
;
849 for(i
= 0;i
< NumSends
;i
++)
850 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
852 /* Distance-based air absorption */
853 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
855 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
856 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
857 for(i
= 0;i
< NumSends
;i
++)
858 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
863 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
865 /* Apply a decay-time transformation to the wet path, based on the
866 * attenuation of the dry path.
868 * Using the apparent distance, based on the distance attenuation, the
869 * initial decay of the reverb effect is calculated and applied to the
872 for(i
= 0;i
< NumSends
;i
++)
874 if(DecayDistance
[i
] > 0.0f
)
875 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
879 /* Calculate directional soundcones */
880 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
881 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
883 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
884 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
885 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
887 else if(Angle
> OuterAngle
)
889 ConeVolume
= ALSource
->OuterGain
;
890 ConeHF
= ALSource
->OuterGainHF
;
898 DryGain
*= ConeVolume
;
901 for(i
= 0;i
< NumSends
;i
++)
902 WetGain
[i
] *= ConeVolume
;
908 for(i
= 0;i
< NumSends
;i
++)
909 WetGainHF
[i
] *= ConeHF
;
912 /* Clamp to Min/Max Gain */
913 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
914 for(i
= 0;i
< NumSends
;i
++)
915 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
917 /* Apply gain and frequency filters */
918 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
919 DryGainHF
*= ALSource
->Direct
.GainHF
;
920 DryGainLF
*= ALSource
->Direct
.GainLF
;
921 for(i
= 0;i
< NumSends
;i
++)
923 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
924 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
925 WetGainLF
[i
] *= ALSource
->Send
[i
].GainLF
;
928 /* Calculate velocity-based doppler effect */
929 if(DopplerFactor
> 0.0f
)
931 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
934 if(SpeedOfSound
< 1.0f
)
936 DopplerFactor
*= 1.0f
/SpeedOfSound
;
940 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
941 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
943 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
944 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
947 BufferListItem
= ATOMIC_LOAD(&ALSource
->queue
);
948 while(BufferListItem
!= NULL
)
951 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
953 /* Calculate fixed-point stepping value, based on the pitch, buffer
954 * frequency, and output frequency. */
955 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
956 if(Pitch
> (ALfloat
)MAX_PITCH
)
957 voice
->Step
= MAX_PITCH
<<FRACTIONBITS
;
960 voice
->Step
= fastf2i(Pitch
*FRACTIONONE
);
967 BufferListItem
= BufferListItem
->next
;
972 /* Use a binaural HRTF algorithm for stereo headphone playback */
973 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
974 ALfloat radius
= ALSource
->Radius
;
975 ALfloat dirfact
= 1.0f
;
977 voice
->Direct
.OutBuffer
= &voice
->Direct
.OutBuffer
[voice
->Direct
.OutChannels
];
978 voice
->Direct
.OutChannels
= 2;
980 if(Distance
> FLT_EPSILON
)
982 ALfloat invlen
= 1.0f
/Distance
;
983 Position
[0] *= invlen
;
984 Position
[1] *= invlen
;
985 Position
[2] *= invlen
;
987 /* Calculate elevation and azimuth only when the source is not at
988 * the listener. This prevents +0 and -0 Z from producing
989 * inconsistent panning. Also, clamp Y in case FP precision errors
990 * cause it to land outside of -1..+1. */
991 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
992 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
994 if(radius
> Distance
)
995 dirfact
*= Distance
/ radius
;
997 /* Check to see if the HRIR is already moving. */
998 if(voice
->Direct
.Moving
)
1000 /* Calculate the normalized HRTF transition factor (delta). */
1001 delta
= CalcHrtfDelta(voice
->Direct
.LastGain
, DryGain
,
1002 voice
->Direct
.LastDir
, Position
);
1003 /* If the delta is large enough, get the moving HRIR target
1004 * coefficients, target delays, steppping values, and counter. */
1007 ALuint counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
1008 ev
, az
, dirfact
, DryGain
, delta
, voice
->Direct
.Counter
,
1009 voice
->Direct
.Hrtf
.Params
[0].Coeffs
, voice
->Direct
.Hrtf
.Params
[0].Delay
,
1010 voice
->Direct
.Hrtf
.Params
[0].CoeffStep
, voice
->Direct
.Hrtf
.Params
[0].DelayStep
1012 voice
->Direct
.Counter
= counter
;
1013 voice
->Direct
.LastGain
= DryGain
;
1014 voice
->Direct
.LastDir
[0] = Position
[0];
1015 voice
->Direct
.LastDir
[1] = Position
[1];
1016 voice
->Direct
.LastDir
[2] = Position
[2];
1021 /* Get the initial (static) HRIR coefficients and delays. */
1022 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, dirfact
, DryGain
,
1023 voice
->Direct
.Hrtf
.Params
[0].Coeffs
,
1024 voice
->Direct
.Hrtf
.Params
[0].Delay
);
1025 voice
->Direct
.Counter
= 0;
1026 voice
->Direct
.Moving
= AL_TRUE
;
1027 voice
->Direct
.LastGain
= DryGain
;
1028 voice
->Direct
.LastDir
[0] = Position
[0];
1029 voice
->Direct
.LastDir
[1] = Position
[1];
1030 voice
->Direct
.LastDir
[2] = Position
[2];
1032 voice
->Direct
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
1034 voice
->IsHrtf
= AL_TRUE
;
1038 MixGains
*gains
= voice
->Direct
.Gains
[0];
1039 ALfloat radius
= ALSource
->Radius
;
1040 ALfloat Target
[MAX_OUTPUT_CHANNELS
];
1042 /* Normalize the length, and compute panned gains. */
1043 if(!(Distance
> FLT_EPSILON
) && !(radius
> FLT_EPSILON
))
1045 const ALfloat front
[3] = { 0.0f
, 0.0f
, -1.0f
};
1046 ComputeDirectionalGains(Device
, front
, DryGain
, Target
);
1050 ALfloat invlen
= 1.0f
/maxf(Distance
, radius
);
1051 Position
[0] *= invlen
;
1052 Position
[1] *= invlen
;
1053 Position
[2] *= invlen
;
1054 ComputeDirectionalGains(Device
, Position
, DryGain
, Target
);
1057 for(j
= 0;j
< MAX_OUTPUT_CHANNELS
;j
++)
1058 gains
[j
].Target
= Target
[j
];
1059 UpdateDryStepping(&voice
->Direct
, 1);
1061 voice
->IsHrtf
= AL_FALSE
;
1063 for(i
= 0;i
< NumSends
;i
++)
1065 voice
->Send
[i
].Gain
.Target
= WetGain
[i
];
1066 UpdateWetStepping(&voice
->Send
[i
]);
1070 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
1071 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
1072 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
1073 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
1074 voice
->Direct
.Filters
[0].ActiveType
= AF_None
;
1075 if(gainhf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_LowPass
;
1076 if(gainlf
!= 1.0f
) voice
->Direct
.Filters
[0].ActiveType
|= AF_HighPass
;
1077 ALfilterState_setParams(
1078 &voice
->Direct
.Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1081 ALfilterState_setParams(
1082 &voice
->Direct
.Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1086 for(i
= 0;i
< NumSends
;i
++)
1088 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
1089 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
1090 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
1091 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
1092 voice
->Send
[i
].Filters
[0].ActiveType
= AF_None
;
1093 if(gainhf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_LowPass
;
1094 if(gainlf
!= 1.0f
) voice
->Send
[i
].Filters
[0].ActiveType
|= AF_HighPass
;
1095 ALfilterState_setParams(
1096 &voice
->Send
[i
].Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1099 ALfilterState_setParams(
1100 &voice
->Send
[i
].Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1107 static inline ALint
aluF2I25(ALfloat val
)
1109 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1110 if(fabsf(val
) > 1.0f
)
1111 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
1112 /* Convert to a signed integer, between -16777215 and +16777215. */
1113 return fastf2i(val
*16777215.0f
);
1116 static inline ALfloat
aluF2F(ALfloat val
)
1118 static inline ALint
aluF2I(ALfloat val
)
1119 { return aluF2I25(val
)<<7; }
1120 static inline ALuint
aluF2UI(ALfloat val
)
1121 { return aluF2I(val
)+2147483648u; }
1122 static inline ALshort
aluF2S(ALfloat val
)
1123 { return aluF2I25(val
)>>9; }
1124 static inline ALushort
aluF2US(ALfloat val
)
1125 { return aluF2S(val
)+32768; }
1126 static inline ALbyte
aluF2B(ALfloat val
)
1127 { return aluF2I25(val
)>>17; }
1128 static inline ALubyte
aluF2UB(ALfloat val
)
1129 { return aluF2B(val
)+128; }
1131 #define DECL_TEMPLATE(T, func) \
1132 static void Write_##T(const ALfloatBUFFERSIZE *InBuffer, ALvoid *OutBuffer, \
1133 ALuint SamplesToDo, ALuint numchans) \
1136 for(j = 0;j < numchans;j++) \
1138 const ALfloat *in = InBuffer[j]; \
1139 T *restrict out = (T*)OutBuffer + j; \
1140 for(i = 0;i < SamplesToDo;i++) \
1141 out[i*numchans] = func(in[i]); \
1145 DECL_TEMPLATE(ALfloat
, aluF2F
)
1146 DECL_TEMPLATE(ALuint
, aluF2UI
)
1147 DECL_TEMPLATE(ALint
, aluF2I
)
1148 DECL_TEMPLATE(ALushort
, aluF2US
)
1149 DECL_TEMPLATE(ALshort
, aluF2S
)
1150 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1151 DECL_TEMPLATE(ALbyte
, aluF2B
)
1153 #undef DECL_TEMPLATE
1156 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1159 ALeffectslot
**slot
, **slot_end
;
1160 ALvoice
*voice
, *voice_end
;
1165 SetMixerFPUMode(&oldMode
);
1169 ALuint outchanoffset
= 0;
1170 ALuint outchancount
= device
->NumChannels
;
1172 IncrementRef(&device
->MixCount
);
1174 SamplesToDo
= minu(size
, BUFFERSIZE
);
1175 for(c
= 0;c
< device
->NumChannels
;c
++)
1176 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1179 outchanoffset
= device
->NumChannels
;
1181 for(c
= 0;c
< outchancount
;c
++)
1182 memset(device
->DryBuffer
[outchanoffset
+c
], 0, SamplesToDo
*sizeof(ALfloat
));
1185 V0(device
->Backend
,lock
)();
1186 V(device
->Synth
,process
)(SamplesToDo
, &device
->DryBuffer
[outchanoffset
]);
1188 ctx
= ATOMIC_LOAD(&device
->ContextList
);
1191 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1192 ALenum UpdateSources
= AL_FALSE
;
1195 UpdateSources
= ATOMIC_EXCHANGE(ALenum
, &ctx
->UpdateSources
, AL_FALSE
);
1198 CalcListenerParams(ctx
->Listener
);
1200 /* source processing */
1201 voice
= ctx
->Voices
;
1202 voice_end
= voice
+ ctx
->VoiceCount
;
1203 while(voice
!= voice_end
)
1205 ALsource
*source
= voice
->Source
;
1206 if(!source
) goto next
;
1208 if(source
->state
!= AL_PLAYING
&& source
->state
!= AL_PAUSED
)
1210 voice
->Source
= NULL
;
1214 if(!DeferUpdates
&& (ATOMIC_EXCHANGE(ALenum
, &source
->NeedsUpdate
, AL_FALSE
) ||
1216 voice
->Update(voice
, source
, ctx
);
1218 if(source
->state
!= AL_PAUSED
)
1219 MixSource(voice
, source
, device
, SamplesToDo
);
1224 /* effect slot processing */
1225 slot
= VECTOR_ITER_BEGIN(ctx
->ActiveAuxSlots
);
1226 slot_end
= VECTOR_ITER_END(ctx
->ActiveAuxSlots
);
1227 while(slot
!= slot_end
)
1229 if(!DeferUpdates
&& ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1230 V((*slot
)->EffectState
,update
)(device
, *slot
);
1232 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1233 device
->DryBuffer
, device
->NumChannels
);
1235 for(i
= 0;i
< SamplesToDo
;i
++)
1236 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1244 slot
= &device
->DefaultSlot
;
1247 if(ATOMIC_EXCHANGE(ALenum
, &(*slot
)->NeedsUpdate
, AL_FALSE
))
1248 V((*slot
)->EffectState
,update
)(device
, *slot
);
1250 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1251 device
->DryBuffer
, device
->NumChannels
);
1253 for(i
= 0;i
< SamplesToDo
;i
++)
1254 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1257 /* Increment the clock time. Every second's worth of samples is
1258 * converted and added to clock base so that large sample counts don't
1259 * overflow during conversion. This also guarantees an exact, stable
1261 device
->SamplesDone
+= SamplesToDo
;
1262 device
->ClockBase
+= (device
->SamplesDone
/device
->Frequency
) * DEVICE_CLOCK_RES
;
1263 device
->SamplesDone
%= device
->Frequency
;
1264 V0(device
->Backend
,unlock
)();
1268 HrtfMixerFunc HrtfMix
= SelectHrtfMixer();
1269 ALuint irsize
= GetHrtfIrSize(device
->Hrtf
);
1270 for(c
= 0;c
< device
->NumChannels
;c
++)
1271 HrtfMix(&device
->DryBuffer
[outchanoffset
], device
->DryBuffer
[c
], 0.0f
,
1272 device
->Hrtf_Offset
, 0.0f
, irsize
, &device
->Hrtf_Params
[c
],
1273 &device
->Hrtf_State
[c
], SamplesToDo
1275 device
->Hrtf_Offset
+= SamplesToDo
;
1277 else if(device
->Bs2b
)
1279 /* Apply binaural/crossfeed filter */
1280 for(i
= 0;i
< SamplesToDo
;i
++)
1283 samples
[0] = device
->DryBuffer
[0][i
];
1284 samples
[1] = device
->DryBuffer
[1][i
];
1285 bs2b_cross_feed(device
->Bs2b
, samples
);
1286 device
->DryBuffer
[0][i
] = samples
[0];
1287 device
->DryBuffer
[1][i
] = samples
[1];
1293 #define WRITE(T, a, b, c, d) do { \
1294 Write_##T((a), (b), (c), (d)); \
1295 buffer = (char*)buffer + (c)*(d)*sizeof(T); \
1297 switch(device
->FmtType
)
1300 WRITE(ALbyte
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1303 WRITE(ALubyte
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1306 WRITE(ALshort
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1309 WRITE(ALushort
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1312 WRITE(ALint
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1315 WRITE(ALuint
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1318 WRITE(ALfloat
, device
->DryBuffer
+outchanoffset
, buffer
, SamplesToDo
, outchancount
);
1324 size
-= SamplesToDo
;
1325 IncrementRef(&device
->MixCount
);
1328 RestoreFPUMode(&oldMode
);
1332 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1334 ALCcontext
*Context
;
1336 device
->Connected
= ALC_FALSE
;
1338 Context
= ATOMIC_LOAD(&device
->ContextList
);
1341 ALvoice
*voice
, *voice_end
;
1343 voice
= Context
->Voices
;
1344 voice_end
= voice
+ Context
->VoiceCount
;
1345 while(voice
!= voice_end
)
1347 ALsource
*source
= voice
->Source
;
1348 voice
->Source
= NULL
;
1350 if(source
&& source
->state
== AL_PLAYING
)
1352 source
->state
= AL_STOPPED
;
1353 ATOMIC_STORE(&source
->current_buffer
, NULL
);
1354 source
->position
= 0;
1355 source
->position_fraction
= 0;
1360 Context
->VoiceCount
= 0;
1362 Context
= Context
->next
;