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"
38 #include "mixer_defs.h"
40 #include "midi/base.h"
49 ALfloat ConeScale
= 1.0f
;
51 /* Localized Z scalar for mono sources */
52 ALfloat ZScale
= 1.0f
;
54 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
55 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
56 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
58 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
59 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
60 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
62 extern inline ALuint
minu(ALuint a
, ALuint b
);
63 extern inline ALuint
maxu(ALuint a
, ALuint b
);
64 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
66 extern inline ALint
mini(ALint a
, ALint b
);
67 extern inline ALint
maxi(ALint a
, ALint b
);
68 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
70 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
71 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
72 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
74 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
75 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
76 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
78 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
79 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
81 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
83 if(increment
== FRACTIONONE
)
84 return Resample_copy32_C
;
88 return Resample_point32_C
;
90 return Resample_lerp32_C
;
92 return Resample_cubic32_C
;
94 /* Shouldn't happen */
98 return Resample_point32_C
;
102 static DryMixerFunc
SelectHrtfMixer(void)
105 if((CPUCapFlags
&CPU_CAP_SSE
))
106 return MixDirect_Hrtf_SSE
;
109 if((CPUCapFlags
&CPU_CAP_NEON
))
110 return MixDirect_Hrtf_Neon
;
113 return MixDirect_Hrtf_C
;
116 static DryMixerFunc
SelectDirectMixer(void)
119 if((CPUCapFlags
&CPU_CAP_SSE
))
120 return MixDirect_SSE
;
123 if((CPUCapFlags
&CPU_CAP_NEON
))
124 return MixDirect_Neon
;
130 static WetMixerFunc
SelectSendMixer(void)
133 if((CPUCapFlags
&CPU_CAP_SSE
))
137 if((CPUCapFlags
&CPU_CAP_NEON
))
145 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
147 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
148 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
149 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
152 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
154 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
155 inVector1
[2]*inVector2
[2];
158 static inline void aluNormalize(ALfloat
*inVector
)
160 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
163 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
164 inVector
[0] *= inv_length
;
165 inVector
[1] *= inv_length
;
166 inVector
[2] *= inv_length
;
170 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
173 vector
[0], vector
[1], vector
[2], w
176 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
177 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
178 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
182 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
184 ALfloat N
[3], V
[3], U
[3], P
[3];
187 N
[0] = Listener
->Forward
[0];
188 N
[1] = Listener
->Forward
[1];
189 N
[2] = Listener
->Forward
[2];
191 V
[0] = Listener
->Up
[0];
192 V
[1] = Listener
->Up
[1];
193 V
[2] = Listener
->Up
[2];
195 /* Build and normalize right-vector */
196 aluCrossproduct(N
, V
, U
);
199 Listener
->Params
.Matrix
[0][0] = U
[0];
200 Listener
->Params
.Matrix
[0][1] = V
[0];
201 Listener
->Params
.Matrix
[0][2] = -N
[0];
202 Listener
->Params
.Matrix
[0][3] = 0.0f
;
203 Listener
->Params
.Matrix
[1][0] = U
[1];
204 Listener
->Params
.Matrix
[1][1] = V
[1];
205 Listener
->Params
.Matrix
[1][2] = -N
[1];
206 Listener
->Params
.Matrix
[1][3] = 0.0f
;
207 Listener
->Params
.Matrix
[2][0] = U
[2];
208 Listener
->Params
.Matrix
[2][1] = V
[2];
209 Listener
->Params
.Matrix
[2][2] = -N
[2];
210 Listener
->Params
.Matrix
[2][3] = 0.0f
;
211 Listener
->Params
.Matrix
[3][0] = 0.0f
;
212 Listener
->Params
.Matrix
[3][1] = 0.0f
;
213 Listener
->Params
.Matrix
[3][2] = 0.0f
;
214 Listener
->Params
.Matrix
[3][3] = 1.0f
;
216 P
[0] = Listener
->Position
[0];
217 P
[1] = Listener
->Position
[1];
218 P
[2] = Listener
->Position
[2];
219 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
220 Listener
->Params
.Matrix
[3][0] = -P
[0];
221 Listener
->Params
.Matrix
[3][1] = -P
[1];
222 Listener
->Params
.Matrix
[3][2] = -P
[2];
224 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
225 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
226 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
227 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
230 ALvoid
CalcNonAttnSourceParams(ALactivesource
*src
, const ALCcontext
*ALContext
)
232 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
233 static const struct ChanMap StereoMap
[2] = {
234 { FrontLeft
, DEG2RAD(-30.0f
) },
235 { FrontRight
, DEG2RAD( 30.0f
) }
237 static const struct ChanMap StereoWideMap
[2] = {
238 { FrontLeft
, DEG2RAD(-90.0f
) },
239 { FrontRight
, DEG2RAD( 90.0f
) }
241 static const struct ChanMap RearMap
[2] = {
242 { BackLeft
, DEG2RAD(-150.0f
) },
243 { BackRight
, DEG2RAD( 150.0f
) }
245 static const struct ChanMap QuadMap
[4] = {
246 { FrontLeft
, DEG2RAD( -45.0f
) },
247 { FrontRight
, DEG2RAD( 45.0f
) },
248 { BackLeft
, DEG2RAD(-135.0f
) },
249 { BackRight
, DEG2RAD( 135.0f
) }
251 static const struct ChanMap X51Map
[6] = {
252 { FrontLeft
, DEG2RAD( -30.0f
) },
253 { FrontRight
, DEG2RAD( 30.0f
) },
254 { FrontCenter
, DEG2RAD( 0.0f
) },
256 { BackLeft
, DEG2RAD(-110.0f
) },
257 { BackRight
, DEG2RAD( 110.0f
) }
259 static const struct ChanMap X61Map
[7] = {
260 { FrontLeft
, DEG2RAD(-30.0f
) },
261 { FrontRight
, DEG2RAD( 30.0f
) },
262 { FrontCenter
, DEG2RAD( 0.0f
) },
264 { BackCenter
, DEG2RAD(180.0f
) },
265 { SideLeft
, DEG2RAD(-90.0f
) },
266 { SideRight
, DEG2RAD( 90.0f
) }
268 static const struct ChanMap X71Map
[8] = {
269 { FrontLeft
, DEG2RAD( -30.0f
) },
270 { FrontRight
, DEG2RAD( 30.0f
) },
271 { FrontCenter
, DEG2RAD( 0.0f
) },
273 { BackLeft
, DEG2RAD(-150.0f
) },
274 { BackRight
, DEG2RAD( 150.0f
) },
275 { SideLeft
, DEG2RAD( -90.0f
) },
276 { SideRight
, DEG2RAD( 90.0f
) }
279 ALCdevice
*Device
= ALContext
->Device
;
280 const ALsource
*ALSource
= src
->Source
;
281 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
282 ALbufferlistitem
*BufferListItem
;
283 enum FmtChannels Channels
;
284 ALfloat DryGain
, DryGainHF
;
285 ALfloat WetGain
[MAX_SENDS
];
286 ALfloat WetGainHF
[MAX_SENDS
];
287 ALint NumSends
, Frequency
;
288 const struct ChanMap
*chans
= NULL
;
289 enum Resampler Resampler
;
290 ALint num_channels
= 0;
291 ALboolean DirectChannels
;
292 ALfloat hwidth
= 0.0f
;
296 /* Get device properties */
297 NumSends
= Device
->NumAuxSends
;
298 Frequency
= Device
->Frequency
;
300 /* Get listener properties */
301 ListenerGain
= ALContext
->Listener
->Gain
;
303 /* Get source properties */
304 SourceVolume
= ALSource
->Gain
;
305 MinVolume
= ALSource
->MinGain
;
306 MaxVolume
= ALSource
->MaxGain
;
307 Pitch
= ALSource
->Pitch
;
308 Resampler
= ALSource
->Resampler
;
309 DirectChannels
= ALSource
->DirectChannels
;
311 src
->Direct
.OutBuffer
= Device
->DryBuffer
;
312 for(i
= 0;i
< NumSends
;i
++)
314 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
316 Slot
= Device
->DefaultSlot
;
317 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
318 src
->Send
[i
].OutBuffer
= NULL
;
320 src
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
323 /* Calculate the stepping value */
325 BufferListItem
= ALSource
->queue
;
326 while(BufferListItem
!= NULL
)
329 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
331 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
333 src
->Step
= 10<<FRACTIONBITS
;
336 src
->Step
= fastf2i(Pitch
*FRACTIONONE
);
340 src
->Resample
= SelectResampler(Resampler
, src
->Step
);
342 Channels
= ALBuffer
->FmtChannels
;
345 BufferListItem
= BufferListItem
->next
;
348 /* Calculate gains */
349 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
350 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
351 DryGainHF
= ALSource
->Direct
.GainHF
;
352 for(i
= 0;i
< NumSends
;i
++)
354 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
355 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
356 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
367 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
369 /* HACK: Place the stereo channels at +/-90 degrees when using non-
370 * HRTF stereo output. This helps reduce the "monoization" caused
371 * by them panning towards the center. */
372 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
373 chans
= StereoWideMap
;
379 chans
= StereoWideMap
;
380 hwidth
= DEG2RAD(60.0f
);
411 if(DirectChannels
!= AL_FALSE
)
413 ALfloat (*Matrix
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Target
;
414 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
416 for(c
= 0;c
< MaxChannels
;c
++)
419 for(c
= 0;c
< num_channels
;c
++)
421 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
423 enum Channel chan
= Device
->Speaker2Chan
[i
];
424 if(chan
== chans
[c
].channel
)
426 Matrix
[c
][chan
] = DryGain
;
432 if(src
->Direct
.Moving
)
434 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
435 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
436 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
438 for(j
= 0;j
< MaxChannels
;j
++)
440 ALfloat cur
= maxf(Current
[i
][j
], FLT_EPSILON
);
441 ALfloat trg
= maxf(Matrix
[i
][j
], FLT_EPSILON
);
442 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
443 Step
[i
][j
] = powf(trg
/cur
, 1.0f
/64.0f
);
449 src
->Direct
.Counter
= 64;
453 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
454 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
455 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
457 for(j
= 0;j
< MaxChannels
;j
++)
459 Current
[i
][j
] = Matrix
[i
][j
];
463 src
->Direct
.Counter
= 0;
464 src
->Direct
.Moving
= AL_TRUE
;
467 src
->DryMix
= SelectDirectMixer();
469 else if(Device
->Hrtf
)
471 for(c
= 0;c
< num_channels
;c
++)
473 if(chans
[c
].channel
== LFE
)
476 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[0] = 0;
477 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[1] = 0;
478 for(i
= 0;i
< HRIR_LENGTH
;i
++)
480 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][0] = 0.0f
;
481 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][1] = 0.0f
;
486 /* Get the static HRIR coefficients and delays for this
488 GetLerpedHrtfCoeffs(Device
->Hrtf
,
489 0.0f
, chans
[c
].angle
, DryGain
,
490 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
,
491 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
);
494 src
->Direct
.Counter
= 0;
495 src
->Direct
.Moving
= AL_TRUE
;
496 src
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
498 src
->DryMix
= SelectHrtfMixer();
502 ALfloat (*Matrix
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Target
;
503 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
505 for(c
= 0;c
< MaxChannels
;c
++)
509 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf((float)Device
->NumChan
), hwidth
/F_PI
);
510 for(c
= 0;c
< num_channels
;c
++)
512 /* Special-case LFE */
513 if(chans
[c
].channel
== LFE
)
515 Matrix
[c
][chans
[c
].channel
] = DryGain
;
518 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
522 if(src
->Direct
.Moving
)
524 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
525 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
526 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
528 for(j
= 0;j
< MaxChannels
;j
++)
530 ALfloat trg
= maxf(Matrix
[i
][j
], FLT_EPSILON
);
531 ALfloat cur
= maxf(Current
[i
][j
], FLT_EPSILON
);
532 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
533 Step
[i
][j
] = powf(trg
/cur
, 1.0f
/64.0f
);
539 src
->Direct
.Counter
= 64;
543 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
544 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
545 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
547 for(j
= 0;j
< MaxChannels
;j
++)
549 Current
[i
][j
] = Matrix
[i
][j
];
553 src
->Direct
.Counter
= 0;
554 src
->Direct
.Moving
= AL_TRUE
;
557 src
->DryMix
= SelectDirectMixer();
559 for(i
= 0;i
< NumSends
;i
++)
561 src
->Send
[i
].Gain
.Target
= WetGain
[i
];
562 if(src
->Send
[i
].Moving
)
564 ALfloat cur
= maxf(src
->Send
[i
].Gain
.Current
, FLT_EPSILON
);
565 ALfloat trg
= maxf(src
->Send
[i
].Gain
.Target
, FLT_EPSILON
);
566 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
567 src
->Send
[i
].Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
569 src
->Send
[i
].Gain
.Step
= 1.0f
;
570 src
->Send
[i
].Gain
.Current
= cur
;
571 src
->Send
[i
].Counter
= 64;
575 src
->Send
[i
].Gain
.Current
= src
->Send
[i
].Gain
.Target
;
576 src
->Send
[i
].Gain
.Step
= 1.0f
;
577 src
->Send
[i
].Counter
= 0;
578 src
->Send
[i
].Moving
= AL_TRUE
;
581 src
->WetMix
= SelectSendMixer();
584 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
585 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
586 for(c
= 0;c
< num_channels
;c
++)
588 src
->Direct
.Filters
[c
] = (gainhf
!= 1.0f
) ? AF_LowPass
: AF_None
;
589 ALfilterState_setParams(
590 &src
->Direct
.LpFilter
[c
], ALfilterType_HighShelf
, gainhf
,
595 for(i
= 0;i
< NumSends
;i
++)
597 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
598 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
599 for(c
= 0;c
< num_channels
;c
++)
601 src
->Send
[i
].Filters
[c
] = (gainhf
!= 1.0f
) ? AF_LowPass
: AF_None
;
602 ALfilterState_setParams(
603 &src
->Send
[i
].LpFilter
[c
], ALfilterType_HighShelf
, gainhf
,
610 ALvoid
CalcSourceParams(ALactivesource
*src
, const ALCcontext
*ALContext
)
612 ALCdevice
*Device
= ALContext
->Device
;
613 const ALsource
*ALSource
= src
->Source
;
614 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
615 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
616 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
617 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
618 ALfloat DopplerFactor
, SpeedOfSound
;
619 ALfloat AirAbsorptionFactor
;
620 ALfloat RoomAirAbsorption
[MAX_SENDS
];
621 ALbufferlistitem
*BufferListItem
;
623 ALfloat RoomAttenuation
[MAX_SENDS
];
624 ALfloat MetersPerUnit
;
625 ALfloat RoomRolloffBase
;
626 ALfloat RoomRolloff
[MAX_SENDS
];
627 ALfloat DecayDistance
[MAX_SENDS
];
630 ALboolean DryGainHFAuto
;
631 ALfloat WetGain
[MAX_SENDS
];
632 ALfloat WetGainHF
[MAX_SENDS
];
633 ALboolean WetGainAuto
;
634 ALboolean WetGainHFAuto
;
635 enum Resampler Resampler
;
642 for(i
= 0;i
< MAX_SENDS
;i
++)
645 /* Get context/device properties */
646 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
647 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
648 NumSends
= Device
->NumAuxSends
;
649 Frequency
= Device
->Frequency
;
651 /* Get listener properties */
652 ListenerGain
= ALContext
->Listener
->Gain
;
653 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
655 /* Get source properties */
656 SourceVolume
= ALSource
->Gain
;
657 MinVolume
= ALSource
->MinGain
;
658 MaxVolume
= ALSource
->MaxGain
;
659 Pitch
= ALSource
->Pitch
;
660 Resampler
= ALSource
->Resampler
;
661 Position
[0] = ALSource
->Position
[0];
662 Position
[1] = ALSource
->Position
[1];
663 Position
[2] = ALSource
->Position
[2];
664 Direction
[0] = ALSource
->Orientation
[0];
665 Direction
[1] = ALSource
->Orientation
[1];
666 Direction
[2] = ALSource
->Orientation
[2];
667 Velocity
[0] = ALSource
->Velocity
[0];
668 Velocity
[1] = ALSource
->Velocity
[1];
669 Velocity
[2] = ALSource
->Velocity
[2];
670 MinDist
= ALSource
->RefDistance
;
671 MaxDist
= ALSource
->MaxDistance
;
672 Rolloff
= ALSource
->RollOffFactor
;
673 InnerAngle
= ALSource
->InnerAngle
;
674 OuterAngle
= ALSource
->OuterAngle
;
675 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
676 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
677 WetGainAuto
= ALSource
->WetGainAuto
;
678 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
679 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
681 src
->Direct
.OutBuffer
= Device
->DryBuffer
;
682 for(i
= 0;i
< NumSends
;i
++)
684 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
687 Slot
= Device
->DefaultSlot
;
688 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
691 RoomRolloff
[i
] = 0.0f
;
692 DecayDistance
[i
] = 0.0f
;
693 RoomAirAbsorption
[i
] = 1.0f
;
695 else if(Slot
->AuxSendAuto
)
697 RoomRolloff
[i
] = RoomRolloffBase
;
698 if(IsReverbEffect(Slot
->EffectType
))
700 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
701 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
702 SPEEDOFSOUNDMETRESPERSEC
;
703 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
707 DecayDistance
[i
] = 0.0f
;
708 RoomAirAbsorption
[i
] = 1.0f
;
713 /* If the slot's auxiliary send auto is off, the data sent to the
714 * effect slot is the same as the dry path, sans filter effects */
715 RoomRolloff
[i
] = Rolloff
;
716 DecayDistance
[i
] = 0.0f
;
717 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
720 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
721 src
->Send
[i
].OutBuffer
= NULL
;
723 src
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
726 /* Transform source to listener space (convert to head relative) */
727 if(ALSource
->HeadRelative
== AL_FALSE
)
729 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
730 /* Transform source vectors */
731 aluMatrixVector(Position
, 1.0f
, Matrix
);
732 aluMatrixVector(Direction
, 0.0f
, Matrix
);
733 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
737 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
738 /* Offset the source velocity to be relative of the listener velocity */
739 Velocity
[0] += ListenerVel
[0];
740 Velocity
[1] += ListenerVel
[1];
741 Velocity
[2] += ListenerVel
[2];
744 SourceToListener
[0] = -Position
[0];
745 SourceToListener
[1] = -Position
[1];
746 SourceToListener
[2] = -Position
[2];
747 aluNormalize(SourceToListener
);
748 aluNormalize(Direction
);
750 /* Calculate distance attenuation */
751 Distance
= sqrtf(aluDotproduct(Position
, Position
));
752 ClampedDist
= Distance
;
755 for(i
= 0;i
< NumSends
;i
++)
756 RoomAttenuation
[i
] = 1.0f
;
757 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
758 ALContext
->DistanceModel
)
760 case InverseDistanceClamped
:
761 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
762 if(MaxDist
< MinDist
)
765 case InverseDistance
:
768 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
769 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
770 for(i
= 0;i
< NumSends
;i
++)
772 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
773 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
778 case LinearDistanceClamped
:
779 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
780 if(MaxDist
< MinDist
)
784 if(MaxDist
!= MinDist
)
786 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
787 Attenuation
= maxf(Attenuation
, 0.0f
);
788 for(i
= 0;i
< NumSends
;i
++)
790 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
791 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
796 case ExponentDistanceClamped
:
797 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
798 if(MaxDist
< MinDist
)
801 case ExponentDistance
:
802 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
804 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
805 for(i
= 0;i
< NumSends
;i
++)
806 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
810 case DisableDistance
:
811 ClampedDist
= MinDist
;
815 /* Source Gain + Attenuation */
816 DryGain
= SourceVolume
* Attenuation
;
817 for(i
= 0;i
< NumSends
;i
++)
818 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
820 /* Distance-based air absorption */
821 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
823 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
824 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
825 for(i
= 0;i
< NumSends
;i
++)
826 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
831 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
833 /* Apply a decay-time transformation to the wet path, based on the
834 * attenuation of the dry path.
836 * Using the apparent distance, based on the distance attenuation, the
837 * initial decay of the reverb effect is calculated and applied to the
840 for(i
= 0;i
< NumSends
;i
++)
842 if(DecayDistance
[i
] > 0.0f
)
843 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
847 /* Calculate directional soundcones */
848 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
849 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
851 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
852 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
853 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
855 else if(Angle
> OuterAngle
)
857 ConeVolume
= ALSource
->OuterGain
;
858 ConeHF
= ALSource
->OuterGainHF
;
866 DryGain
*= ConeVolume
;
869 for(i
= 0;i
< NumSends
;i
++)
870 WetGain
[i
] *= ConeVolume
;
876 for(i
= 0;i
< NumSends
;i
++)
877 WetGainHF
[i
] *= ConeHF
;
880 /* Clamp to Min/Max Gain */
881 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
882 for(i
= 0;i
< NumSends
;i
++)
883 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
885 /* Apply gain and frequency filters */
886 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
887 DryGainHF
*= ALSource
->Direct
.GainHF
;
888 for(i
= 0;i
< NumSends
;i
++)
890 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
891 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
894 /* Calculate velocity-based doppler effect */
895 if(DopplerFactor
> 0.0f
)
897 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
900 if(SpeedOfSound
< 1.0f
)
902 DopplerFactor
*= 1.0f
/SpeedOfSound
;
906 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
907 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
909 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
910 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
913 BufferListItem
= ALSource
->queue
;
914 while(BufferListItem
!= NULL
)
917 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
919 /* Calculate fixed-point stepping value, based on the pitch, buffer
920 * frequency, and output frequency. */
921 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
923 src
->Step
= 10<<FRACTIONBITS
;
926 src
->Step
= fastf2i(Pitch
*FRACTIONONE
);
930 src
->Resample
= SelectResampler(Resampler
, src
->Step
);
934 BufferListItem
= BufferListItem
->next
;
939 /* Use a binaural HRTF algorithm for stereo headphone playback */
940 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
942 if(Distance
> FLT_EPSILON
)
944 ALfloat invlen
= 1.0f
/Distance
;
945 Position
[0] *= invlen
;
946 Position
[1] *= invlen
;
947 Position
[2] *= invlen
;
949 /* Calculate elevation and azimuth only when the source is not at
950 * the listener. This prevents +0 and -0 Z from producing
951 * inconsistent panning. Also, clamp Y in case FP precision errors
952 * cause it to land outside of -1..+1. */
953 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
954 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
957 /* Check to see if the HRIR is already moving. */
958 if(src
->Direct
.Moving
)
960 /* Calculate the normalized HRTF transition factor (delta). */
961 delta
= CalcHrtfDelta(src
->Direct
.Mix
.Hrtf
.Gain
, DryGain
,
962 src
->Direct
.Mix
.Hrtf
.Dir
, Position
);
963 /* If the delta is large enough, get the moving HRIR target
964 * coefficients, target delays, steppping values, and counter. */
967 ALuint counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
968 ev
, az
, DryGain
, delta
,
970 src
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
971 src
->Direct
.Mix
.Hrtf
.Params
[0].Delay
,
972 src
->Direct
.Mix
.Hrtf
.Params
[0].CoeffStep
,
973 src
->Direct
.Mix
.Hrtf
.Params
[0].DelayStep
);
974 src
->Direct
.Counter
= counter
;
975 src
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
976 src
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
977 src
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
978 src
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
983 /* Get the initial (static) HRIR coefficients and delays. */
984 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
985 src
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
986 src
->Direct
.Mix
.Hrtf
.Params
[0].Delay
);
987 src
->Direct
.Counter
= 0;
988 src
->Direct
.Moving
= AL_TRUE
;
989 src
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
990 src
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
991 src
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
992 src
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
994 src
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
996 src
->DryMix
= SelectHrtfMixer();
1000 ALfloat (*Matrix
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Target
;
1001 ALfloat DirGain
= 0.0f
;
1002 ALfloat AmbientGain
;
1004 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
1006 for(j
= 0;j
< MaxChannels
;j
++)
1007 Matrix
[i
][j
] = 0.0f
;
1010 /* Normalize the length, and compute panned gains. */
1011 if(Distance
> FLT_EPSILON
)
1013 ALfloat invlen
= 1.0f
/Distance
;
1014 Position
[0] *= invlen
;
1015 Position
[1] *= invlen
;
1016 Position
[2] *= invlen
;
1018 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
1019 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
1020 DryGain
*DirGain
, Matrix
[0]);
1023 /* Adjustment for vertical offsets. Not the greatest, but simple
1025 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
1026 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
1028 enum Channel chan
= Device
->Speaker2Chan
[i
];
1029 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
1032 if(src
->Direct
.Moving
)
1034 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
1035 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
1036 for(j
= 0;j
< MaxChannels
;j
++)
1038 ALfloat cur
= maxf(Current
[0][j
], FLT_EPSILON
);
1039 ALfloat trg
= maxf(Matrix
[0][j
], FLT_EPSILON
);
1040 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
1041 Step
[0][j
] = powf(trg
/cur
, 1.0f
/64.0f
);
1044 Current
[0][j
] = cur
;
1046 src
->Direct
.Counter
= 64;
1050 ALfloat (*restrict Current
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Current
;
1051 ALfloat (*restrict Step
)[MaxChannels
] = src
->Direct
.Mix
.Gains
.Step
;
1052 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
1054 for(j
= 0;j
< MaxChannels
;j
++)
1056 Current
[i
][j
] = Matrix
[i
][j
];
1060 src
->Direct
.Counter
= 0;
1061 src
->Direct
.Moving
= AL_TRUE
;
1064 src
->DryMix
= SelectDirectMixer();
1066 for(i
= 0;i
< NumSends
;i
++)
1068 src
->Send
[i
].Gain
.Target
= WetGain
[i
];
1069 if(src
->Send
[i
].Moving
)
1071 ALfloat cur
= maxf(src
->Send
[i
].Gain
.Current
, FLT_EPSILON
);
1072 ALfloat trg
= maxf(src
->Send
[i
].Gain
.Target
, FLT_EPSILON
);
1073 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
1074 src
->Send
[i
].Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
1076 src
->Send
[i
].Gain
.Step
= 1.0f
;
1077 src
->Send
[i
].Gain
.Current
= cur
;
1078 src
->Send
[i
].Counter
= 64;
1082 src
->Send
[i
].Gain
.Current
= src
->Send
[i
].Gain
.Target
;
1083 src
->Send
[i
].Gain
.Step
= 1.0f
;
1084 src
->Send
[i
].Counter
= 0;
1085 src
->Send
[i
].Moving
= AL_TRUE
;
1088 src
->WetMix
= SelectSendMixer();
1091 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
1092 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
1093 src
->Direct
.Filters
[0] = (gainhf
!= 1.0f
) ? AF_LowPass
: AF_None
;
1094 ALfilterState_setParams(
1095 &src
->Direct
.LpFilter
[0], ALfilterType_HighShelf
, gainhf
,
1099 for(i
= 0;i
< NumSends
;i
++)
1101 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
1102 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
1103 src
->Direct
.Filters
[0] = (gainhf
!= 1.0f
) ? AF_LowPass
: AF_None
;
1104 ALfilterState_setParams(
1105 &src
->Send
[i
].LpFilter
[0], ALfilterType_HighShelf
, gainhf
,
1112 static inline ALint
aluF2I25(ALfloat val
)
1114 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1115 if(fabsf(val
) > 1.0f
)
1116 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
1117 /* Convert to a signed integer, between -16777215 and +16777215. */
1118 return fastf2i(val
*16777215.0f
);
1121 static inline ALfloat
aluF2F(ALfloat val
)
1123 static inline ALint
aluF2I(ALfloat val
)
1124 { return aluF2I25(val
)<<7; }
1125 static inline ALuint
aluF2UI(ALfloat val
)
1126 { return aluF2I(val
)+2147483648u; }
1127 static inline ALshort
aluF2S(ALfloat val
)
1128 { return aluF2I25(val
)>>9; }
1129 static inline ALushort
aluF2US(ALfloat val
)
1130 { return aluF2S(val
)+32768; }
1131 static inline ALbyte
aluF2B(ALfloat val
)
1132 { return aluF2I25(val
)>>17; }
1133 static inline ALubyte
aluF2UB(ALfloat val
)
1134 { return aluF2B(val
)+128; }
1136 #define DECL_TEMPLATE(T, func) \
1137 static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
1139 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
1140 const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
1141 const ALuint *offsets = device->ChannelOffsets; \
1144 for(j = 0;j < MaxChannels;j++) \
1148 if(offsets[j] == INVALID_OFFSET) \
1151 out = (T*)(*buffer) + offsets[j]; \
1152 for(i = 0;i < SamplesToDo;i++) \
1153 out[i*numchans] = func(DryBuffer[j][i]); \
1155 *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
1158 DECL_TEMPLATE(ALfloat
, aluF2F
)
1159 DECL_TEMPLATE(ALuint
, aluF2UI
)
1160 DECL_TEMPLATE(ALint
, aluF2I
)
1161 DECL_TEMPLATE(ALushort
, aluF2US
)
1162 DECL_TEMPLATE(ALshort
, aluF2S
)
1163 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1164 DECL_TEMPLATE(ALbyte
, aluF2B
)
1166 #undef DECL_TEMPLATE
1169 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1172 ALeffectslot
**slot
, **slot_end
;
1173 ALactivesource
**src
, **src_end
;
1178 SetMixerFPUMode(&oldMode
);
1182 IncrementRef(&device
->MixCount
);
1184 SamplesToDo
= minu(size
, BUFFERSIZE
);
1185 for(c
= 0;c
< MaxChannels
;c
++)
1186 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1188 ALCdevice_Lock(device
);
1189 V(device
->Synth
,process
)(SamplesToDo
, device
->DryBuffer
);
1191 ctx
= device
->ContextList
;
1194 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1195 ALenum UpdateSources
= AL_FALSE
;
1198 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
1201 CalcListenerParams(ctx
->Listener
);
1203 /* source processing */
1204 src
= ctx
->ActiveSources
;
1205 src_end
= src
+ ctx
->ActiveSourceCount
;
1206 while(src
!= src_end
)
1208 ALsource
*source
= (*src
)->Source
;
1210 if(source
->state
!= AL_PLAYING
&& source
->state
!= AL_PAUSED
)
1212 ALactivesource
*temp
= *(--src_end
);
1215 --(ctx
->ActiveSourceCount
);
1219 if(!DeferUpdates
&& (ExchangeInt(&source
->NeedsUpdate
, AL_FALSE
) ||
1221 (*src
)->Update(*src
, ctx
);
1223 if(source
->state
!= AL_PAUSED
)
1224 MixSource(*src
, device
, SamplesToDo
);
1228 /* effect slot processing */
1229 slot
= VECTOR_ITER_BEGIN(ctx
->ActiveAuxSlots
);
1230 slot_end
= VECTOR_ITER_END(ctx
->ActiveAuxSlots
);
1231 while(slot
!= slot_end
)
1233 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1234 V((*slot
)->EffectState
,update
)(device
, *slot
);
1236 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1239 for(i
= 0;i
< SamplesToDo
;i
++)
1240 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1248 slot
= &device
->DefaultSlot
;
1251 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1252 V((*slot
)->EffectState
,update
)(device
, *slot
);
1254 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1257 for(i
= 0;i
< SamplesToDo
;i
++)
1258 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1261 /* Increment the clock time. Every second's worth of samples is
1262 * converted and added to clock base so that large sample counts don't
1263 * overflow during conversion. This also guarantees an exact, stable
1265 device
->SamplesDone
+= SamplesToDo
;
1266 device
->ClockBase
+= (device
->SamplesDone
/device
->Frequency
) * DEVICE_CLOCK_RES
;
1267 device
->SamplesDone
%= device
->Frequency
;
1268 ALCdevice_Unlock(device
);
1272 /* Apply binaural/crossfeed filter */
1273 for(i
= 0;i
< SamplesToDo
;i
++)
1276 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1277 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1278 bs2b_cross_feed(device
->Bs2b
, samples
);
1279 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1280 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1286 switch(device
->FmtType
)
1289 Write_ALbyte(device
, &buffer
, SamplesToDo
);
1292 Write_ALubyte(device
, &buffer
, SamplesToDo
);
1295 Write_ALshort(device
, &buffer
, SamplesToDo
);
1298 Write_ALushort(device
, &buffer
, SamplesToDo
);
1301 Write_ALint(device
, &buffer
, SamplesToDo
);
1304 Write_ALuint(device
, &buffer
, SamplesToDo
);
1307 Write_ALfloat(device
, &buffer
, SamplesToDo
);
1312 size
-= SamplesToDo
;
1313 IncrementRef(&device
->MixCount
);
1316 RestoreFPUMode(&oldMode
);
1320 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1322 ALCcontext
*Context
;
1324 device
->Connected
= ALC_FALSE
;
1326 Context
= device
->ContextList
;
1329 ALactivesource
**src
, **src_end
;
1331 src
= Context
->ActiveSources
;
1332 src_end
= src
+ Context
->ActiveSourceCount
;
1333 while(src
!= src_end
)
1335 ALsource
*source
= (*src
)->Source
;
1336 if(source
->state
== AL_PLAYING
)
1338 source
->state
= AL_STOPPED
;
1339 source
->current_buffer
= NULL
;
1340 source
->position
= 0;
1341 source
->position_fraction
= 0;
1345 Context
->ActiveSourceCount
= 0;
1347 Context
= Context
->next
;