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