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 "mixer_defs.h"
41 #include "midi/base.h"
44 static_assert((INT_MAX
>>FRACTIONBITS
)/MAX_PITCH
> BUFFERSIZE
,
45 "MAX_PITCH and/or BUFFERSIZE are too large for FRACTIONBITS!");
53 ALfloat ConeScale
= 1.0f
;
55 /* Localized Z scalar for mono sources */
56 ALfloat ZScale
= 1.0f
;
58 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
59 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
60 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
62 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
63 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
64 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
66 extern inline ALuint
minu(ALuint a
, ALuint b
);
67 extern inline ALuint
maxu(ALuint a
, ALuint b
);
68 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
70 extern inline ALint
mini(ALint a
, ALint b
);
71 extern inline ALint
maxi(ALint a
, ALint b
);
72 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
74 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
75 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
76 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
78 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
79 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
80 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
82 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
83 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
85 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
87 if(increment
== FRACTIONONE
)
88 return Resample_copy32_C
;
92 return Resample_point32_C
;
95 if((CPUCapFlags
&CPU_CAP_SSE4_1
))
96 return Resample_lerp32_SSE41
;
99 if((CPUCapFlags
&CPU_CAP_SSE2
))
100 return Resample_lerp32_SSE2
;
102 return Resample_lerp32_C
;
104 return Resample_cubic32_C
;
106 /* Shouldn't happen */
110 return Resample_point32_C
;
114 static HrtfMixerFunc
SelectHrtfMixer(void)
117 if((CPUCapFlags
&CPU_CAP_SSE
))
118 return MixDirect_Hrtf_SSE
;
121 if((CPUCapFlags
&CPU_CAP_NEON
))
122 return MixDirect_Hrtf_Neon
;
125 return MixDirect_Hrtf_C
;
128 static DryMixerFunc
SelectDirectMixer(void)
131 if((CPUCapFlags
&CPU_CAP_SSE
))
132 return MixDirect_SSE
;
135 if((CPUCapFlags
&CPU_CAP_NEON
))
136 return MixDirect_Neon
;
142 static WetMixerFunc
SelectSendMixer(void)
145 if((CPUCapFlags
&CPU_CAP_SSE
))
149 if((CPUCapFlags
&CPU_CAP_NEON
))
157 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
159 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
160 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
161 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
164 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
166 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
167 inVector1
[2]*inVector2
[2];
170 static inline void aluNormalize(ALfloat
*inVector
)
172 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
175 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
176 inVector
[0] *= inv_length
;
177 inVector
[1] *= inv_length
;
178 inVector
[2] *= inv_length
;
182 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
185 vector
[0], vector
[1], vector
[2], w
188 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
189 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
190 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
194 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
196 ALfloat N
[3], V
[3], U
[3], P
[3];
199 N
[0] = Listener
->Forward
[0];
200 N
[1] = Listener
->Forward
[1];
201 N
[2] = Listener
->Forward
[2];
203 V
[0] = Listener
->Up
[0];
204 V
[1] = Listener
->Up
[1];
205 V
[2] = Listener
->Up
[2];
207 /* Build and normalize right-vector */
208 aluCrossproduct(N
, V
, U
);
211 Listener
->Params
.Matrix
[0][0] = U
[0];
212 Listener
->Params
.Matrix
[0][1] = V
[0];
213 Listener
->Params
.Matrix
[0][2] = -N
[0];
214 Listener
->Params
.Matrix
[0][3] = 0.0f
;
215 Listener
->Params
.Matrix
[1][0] = U
[1];
216 Listener
->Params
.Matrix
[1][1] = V
[1];
217 Listener
->Params
.Matrix
[1][2] = -N
[1];
218 Listener
->Params
.Matrix
[1][3] = 0.0f
;
219 Listener
->Params
.Matrix
[2][0] = U
[2];
220 Listener
->Params
.Matrix
[2][1] = V
[2];
221 Listener
->Params
.Matrix
[2][2] = -N
[2];
222 Listener
->Params
.Matrix
[2][3] = 0.0f
;
223 Listener
->Params
.Matrix
[3][0] = 0.0f
;
224 Listener
->Params
.Matrix
[3][1] = 0.0f
;
225 Listener
->Params
.Matrix
[3][2] = 0.0f
;
226 Listener
->Params
.Matrix
[3][3] = 1.0f
;
228 P
[0] = Listener
->Position
[0];
229 P
[1] = Listener
->Position
[1];
230 P
[2] = Listener
->Position
[2];
231 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
232 Listener
->Params
.Matrix
[3][0] = -P
[0];
233 Listener
->Params
.Matrix
[3][1] = -P
[1];
234 Listener
->Params
.Matrix
[3][2] = -P
[2];
236 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
237 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
238 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
239 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
242 ALvoid
CalcNonAttnSourceParams(ALactivesource
*src
, const ALCcontext
*ALContext
)
244 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
245 static const struct ChanMap StereoMap
[2] = {
246 { FrontLeft
, DEG2RAD(-30.0f
) },
247 { FrontRight
, DEG2RAD( 30.0f
) }
249 static const struct ChanMap StereoWideMap
[2] = {
250 { FrontLeft
, DEG2RAD(-90.0f
) },
251 { FrontRight
, DEG2RAD( 90.0f
) }
253 static const struct ChanMap RearMap
[2] = {
254 { BackLeft
, DEG2RAD(-150.0f
) },
255 { BackRight
, DEG2RAD( 150.0f
) }
257 static const struct ChanMap QuadMap
[4] = {
258 { FrontLeft
, DEG2RAD( -45.0f
) },
259 { FrontRight
, DEG2RAD( 45.0f
) },
260 { BackLeft
, DEG2RAD(-135.0f
) },
261 { BackRight
, DEG2RAD( 135.0f
) }
263 static const struct ChanMap X51Map
[6] = {
264 { FrontLeft
, DEG2RAD( -30.0f
) },
265 { FrontRight
, DEG2RAD( 30.0f
) },
266 { FrontCenter
, DEG2RAD( 0.0f
) },
268 { BackLeft
, DEG2RAD(-110.0f
) },
269 { BackRight
, DEG2RAD( 110.0f
) }
271 static const struct ChanMap X61Map
[7] = {
272 { FrontLeft
, DEG2RAD(-30.0f
) },
273 { FrontRight
, DEG2RAD( 30.0f
) },
274 { FrontCenter
, DEG2RAD( 0.0f
) },
276 { BackCenter
, DEG2RAD(180.0f
) },
277 { SideLeft
, DEG2RAD(-90.0f
) },
278 { SideRight
, DEG2RAD( 90.0f
) }
280 static const struct ChanMap X71Map
[8] = {
281 { FrontLeft
, DEG2RAD( -30.0f
) },
282 { FrontRight
, DEG2RAD( 30.0f
) },
283 { FrontCenter
, DEG2RAD( 0.0f
) },
285 { BackLeft
, DEG2RAD(-150.0f
) },
286 { BackRight
, DEG2RAD( 150.0f
) },
287 { SideLeft
, DEG2RAD( -90.0f
) },
288 { SideRight
, DEG2RAD( 90.0f
) }
291 ALCdevice
*Device
= ALContext
->Device
;
292 const ALsource
*ALSource
= src
->Source
;
293 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
294 ALbufferlistitem
*BufferListItem
;
295 enum FmtChannels Channels
;
296 ALfloat DryGain
, DryGainHF
, DryGainLF
;
297 ALfloat WetGain
[MAX_SENDS
];
298 ALfloat WetGainHF
[MAX_SENDS
];
299 ALfloat WetGainLF
[MAX_SENDS
];
300 ALint NumSends
, Frequency
;
301 const struct ChanMap
*chans
= NULL
;
302 enum Resampler Resampler
;
303 ALint num_channels
= 0;
304 ALboolean DirectChannels
;
305 ALfloat hwidth
= 0.0f
;
309 /* Get device properties */
310 NumSends
= Device
->NumAuxSends
;
311 Frequency
= Device
->Frequency
;
313 /* Get listener properties */
314 ListenerGain
= ALContext
->Listener
->Gain
;
316 /* Get source properties */
317 SourceVolume
= ALSource
->Gain
;
318 MinVolume
= ALSource
->MinGain
;
319 MaxVolume
= ALSource
->MaxGain
;
320 Pitch
= ALSource
->Pitch
;
321 Resampler
= ALSource
->Resampler
;
322 DirectChannels
= ALSource
->DirectChannels
;
324 src
->Direct
.OutBuffer
= Device
->DryBuffer
;
325 for(i
= 0;i
< NumSends
;i
++)
327 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
329 Slot
= Device
->DefaultSlot
;
330 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
331 src
->Send
[i
].OutBuffer
= NULL
;
333 src
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
336 /* Calculate the stepping value */
338 BufferListItem
= ALSource
->queue
;
339 while(BufferListItem
!= NULL
)
342 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
344 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
345 if(Pitch
> (ALfloat
)MAX_PITCH
)
346 src
->Step
= MAX_PITCH
<<FRACTIONBITS
;
349 src
->Step
= fastf2i(Pitch
*FRACTIONONE
);
353 src
->Resample
= SelectResampler(Resampler
, src
->Step
);
355 Channels
= ALBuffer
->FmtChannels
;
358 BufferListItem
= BufferListItem
->next
;
361 /* Calculate gains */
362 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
363 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
364 DryGainHF
= ALSource
->Direct
.GainHF
;
365 DryGainLF
= ALSource
->Direct
.GainLF
;
366 for(i
= 0;i
< NumSends
;i
++)
368 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
369 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
370 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
371 WetGainLF
[i
] = ALSource
->Send
[i
].GainLF
;
382 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
384 /* HACK: Place the stereo channels at +/-90 degrees when using non-
385 * HRTF stereo output. This helps reduce the "monoization" caused
386 * by them panning towards the center. */
387 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
388 chans
= StereoWideMap
;
394 chans
= StereoWideMap
;
395 hwidth
= DEG2RAD(60.0f
);
426 if(DirectChannels
!= AL_FALSE
)
428 for(c
= 0;c
< num_channels
;c
++)
430 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[c
].Target
;
431 for(j
= 0;j
< MaxChannels
;j
++)
435 for(c
= 0;c
< num_channels
;c
++)
437 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[c
].Target
;
438 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
440 enum Channel chan
= Device
->Speaker2Chan
[i
];
441 if(chan
== chans
[c
].channel
)
443 Target
[chan
] = DryGain
;
449 if(!src
->Direct
.Moving
)
451 for(i
= 0;i
< num_channels
;i
++)
453 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[i
].Current
;
454 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[i
].Step
;
455 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[i
].Target
;
456 for(j
= 0;j
< MaxChannels
;j
++)
458 Current
[j
] = Target
[j
];
462 src
->Direct
.Counter
= 0;
463 src
->Direct
.Moving
= AL_TRUE
;
467 for(i
= 0;i
< num_channels
;i
++)
469 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[i
].Current
;
470 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[i
].Step
;
471 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[i
].Target
;
472 for(j
= 0;j
< MaxChannels
;j
++)
474 ALfloat cur
= maxf(Current
[j
], FLT_EPSILON
);
475 ALfloat trg
= maxf(Target
[j
], FLT_EPSILON
);
476 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
477 Step
[j
] = powf(trg
/cur
, 1.0f
/64.0f
);
483 src
->Direct
.Counter
= 64;
486 src
->IsHrtf
= AL_FALSE
;
487 src
->Dry
.Mix
= SelectDirectMixer();
489 else if(Device
->Hrtf
)
491 for(c
= 0;c
< num_channels
;c
++)
493 if(chans
[c
].channel
== LFE
)
496 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[0] = 0;
497 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
[1] = 0;
498 for(i
= 0;i
< HRIR_LENGTH
;i
++)
500 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][0] = 0.0f
;
501 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
[i
][1] = 0.0f
;
506 /* Get the static HRIR coefficients and delays for this
508 GetLerpedHrtfCoeffs(Device
->Hrtf
,
509 0.0f
, chans
[c
].angle
, DryGain
,
510 src
->Direct
.Mix
.Hrtf
.Params
[c
].Coeffs
,
511 src
->Direct
.Mix
.Hrtf
.Params
[c
].Delay
);
514 src
->Direct
.Counter
= 0;
515 src
->Direct
.Moving
= AL_TRUE
;
516 src
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
518 src
->IsHrtf
= AL_TRUE
;
519 src
->Dry
.HrtfMix
= SelectHrtfMixer();
523 for(i
= 0;i
< num_channels
;i
++)
525 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[i
].Target
;
526 for(j
= 0;j
< MaxChannels
;j
++)
530 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf((float)Device
->NumChan
), hwidth
/F_PI
);
531 for(c
= 0;c
< num_channels
;c
++)
533 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[c
].Target
;
534 /* Special-case LFE */
535 if(chans
[c
].channel
== LFE
)
537 Target
[chans
[c
].channel
] = DryGain
;
540 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
, Target
);
543 if(!src
->Direct
.Moving
)
545 for(i
= 0;i
< num_channels
;i
++)
547 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[i
].Current
;
548 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[i
].Step
;
549 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[i
].Target
;
550 for(j
= 0;j
< MaxChannels
;j
++)
552 Current
[j
] = Target
[j
];
556 src
->Direct
.Counter
= 0;
557 src
->Direct
.Moving
= AL_TRUE
;
561 for(i
= 0;i
< num_channels
;i
++)
563 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[i
].Current
;
564 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[i
].Step
;
565 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[i
].Target
;
566 for(j
= 0;j
< MaxChannels
;j
++)
568 ALfloat trg
= maxf(Target
[j
], FLT_EPSILON
);
569 ALfloat cur
= maxf(Current
[j
], FLT_EPSILON
);
570 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
571 Step
[j
] = powf(trg
/cur
, 1.0f
/64.0f
);
577 src
->Direct
.Counter
= 64;
580 src
->IsHrtf
= AL_FALSE
;
581 src
->Dry
.Mix
= SelectDirectMixer();
583 for(i
= 0;i
< NumSends
;i
++)
585 src
->Send
[i
].Gain
.Target
= WetGain
[i
];
586 if(!src
->Send
[i
].Moving
)
588 src
->Send
[i
].Gain
.Current
= src
->Send
[i
].Gain
.Target
;
589 src
->Send
[i
].Gain
.Step
= 1.0f
;
590 src
->Send
[i
].Counter
= 0;
591 src
->Send
[i
].Moving
= AL_TRUE
;
595 ALfloat cur
= maxf(src
->Send
[i
].Gain
.Current
, FLT_EPSILON
);
596 ALfloat trg
= maxf(src
->Send
[i
].Gain
.Target
, FLT_EPSILON
);
597 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
598 src
->Send
[i
].Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
600 src
->Send
[i
].Gain
.Step
= 1.0f
;
601 src
->Send
[i
].Gain
.Current
= cur
;
602 src
->Send
[i
].Counter
= 64;
605 src
->WetMix
= SelectSendMixer();
608 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
609 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
610 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
611 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
612 for(c
= 0;c
< num_channels
;c
++)
614 src
->Direct
.Filters
[c
].ActiveType
= AF_None
;
615 if(gainhf
!= 1.0f
) src
->Direct
.Filters
[c
].ActiveType
|= AF_LowPass
;
616 if(gainlf
!= 1.0f
) src
->Direct
.Filters
[c
].ActiveType
|= AF_HighPass
;
617 ALfilterState_setParams(
618 &src
->Direct
.Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
621 ALfilterState_setParams(
622 &src
->Direct
.Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
627 for(i
= 0;i
< NumSends
;i
++)
629 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
630 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
631 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
632 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
633 for(c
= 0;c
< num_channels
;c
++)
635 src
->Send
[i
].Filters
[c
].ActiveType
= AF_None
;
636 if(gainhf
!= 1.0f
) src
->Send
[i
].Filters
[c
].ActiveType
|= AF_LowPass
;
637 if(gainlf
!= 1.0f
) src
->Send
[i
].Filters
[c
].ActiveType
|= AF_HighPass
;
638 ALfilterState_setParams(
639 &src
->Send
[i
].Filters
[c
].LowPass
, ALfilterType_HighShelf
, gainhf
,
642 ALfilterState_setParams(
643 &src
->Send
[i
].Filters
[c
].HighPass
, ALfilterType_LowShelf
, gainlf
,
650 ALvoid
CalcSourceParams(ALactivesource
*src
, const ALCcontext
*ALContext
)
652 ALCdevice
*Device
= ALContext
->Device
;
653 const ALsource
*ALSource
= src
->Source
;
654 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
655 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
656 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
657 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
658 ALfloat DopplerFactor
, SpeedOfSound
;
659 ALfloat AirAbsorptionFactor
;
660 ALfloat RoomAirAbsorption
[MAX_SENDS
];
661 ALbufferlistitem
*BufferListItem
;
663 ALfloat RoomAttenuation
[MAX_SENDS
];
664 ALfloat MetersPerUnit
;
665 ALfloat RoomRolloffBase
;
666 ALfloat RoomRolloff
[MAX_SENDS
];
667 ALfloat DecayDistance
[MAX_SENDS
];
671 ALboolean DryGainHFAuto
;
672 ALfloat WetGain
[MAX_SENDS
];
673 ALfloat WetGainHF
[MAX_SENDS
];
674 ALfloat WetGainLF
[MAX_SENDS
];
675 ALboolean WetGainAuto
;
676 ALboolean WetGainHFAuto
;
677 enum Resampler Resampler
;
685 for(i
= 0;i
< MAX_SENDS
;i
++)
691 /* Get context/device properties */
692 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
693 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
694 NumSends
= Device
->NumAuxSends
;
695 Frequency
= Device
->Frequency
;
697 /* Get listener properties */
698 ListenerGain
= ALContext
->Listener
->Gain
;
699 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
701 /* Get source properties */
702 SourceVolume
= ALSource
->Gain
;
703 MinVolume
= ALSource
->MinGain
;
704 MaxVolume
= ALSource
->MaxGain
;
705 Pitch
= ALSource
->Pitch
;
706 Resampler
= ALSource
->Resampler
;
707 Position
[0] = ALSource
->Position
[0];
708 Position
[1] = ALSource
->Position
[1];
709 Position
[2] = ALSource
->Position
[2];
710 Direction
[0] = ALSource
->Orientation
[0];
711 Direction
[1] = ALSource
->Orientation
[1];
712 Direction
[2] = ALSource
->Orientation
[2];
713 Velocity
[0] = ALSource
->Velocity
[0];
714 Velocity
[1] = ALSource
->Velocity
[1];
715 Velocity
[2] = ALSource
->Velocity
[2];
716 MinDist
= ALSource
->RefDistance
;
717 MaxDist
= ALSource
->MaxDistance
;
718 Rolloff
= ALSource
->RollOffFactor
;
719 InnerAngle
= ALSource
->InnerAngle
;
720 OuterAngle
= ALSource
->OuterAngle
;
721 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
722 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
723 WetGainAuto
= ALSource
->WetGainAuto
;
724 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
725 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
727 src
->Direct
.OutBuffer
= Device
->DryBuffer
;
728 for(i
= 0;i
< NumSends
;i
++)
730 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
733 Slot
= Device
->DefaultSlot
;
734 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
737 RoomRolloff
[i
] = 0.0f
;
738 DecayDistance
[i
] = 0.0f
;
739 RoomAirAbsorption
[i
] = 1.0f
;
741 else if(Slot
->AuxSendAuto
)
743 RoomRolloff
[i
] = RoomRolloffBase
;
744 if(IsReverbEffect(Slot
->EffectType
))
746 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
747 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
748 SPEEDOFSOUNDMETRESPERSEC
;
749 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
753 DecayDistance
[i
] = 0.0f
;
754 RoomAirAbsorption
[i
] = 1.0f
;
759 /* If the slot's auxiliary send auto is off, the data sent to the
760 * effect slot is the same as the dry path, sans filter effects */
761 RoomRolloff
[i
] = Rolloff
;
762 DecayDistance
[i
] = 0.0f
;
763 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
766 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
767 src
->Send
[i
].OutBuffer
= NULL
;
769 src
->Send
[i
].OutBuffer
= Slot
->WetBuffer
;
772 /* Transform source to listener space (convert to head relative) */
773 if(ALSource
->HeadRelative
== AL_FALSE
)
775 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
776 /* Transform source vectors */
777 aluMatrixVector(Position
, 1.0f
, Matrix
);
778 aluMatrixVector(Direction
, 0.0f
, Matrix
);
779 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
783 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
784 /* Offset the source velocity to be relative of the listener velocity */
785 Velocity
[0] += ListenerVel
[0];
786 Velocity
[1] += ListenerVel
[1];
787 Velocity
[2] += ListenerVel
[2];
790 SourceToListener
[0] = -Position
[0];
791 SourceToListener
[1] = -Position
[1];
792 SourceToListener
[2] = -Position
[2];
793 aluNormalize(SourceToListener
);
794 aluNormalize(Direction
);
796 /* Calculate distance attenuation */
797 Distance
= sqrtf(aluDotproduct(Position
, Position
));
798 ClampedDist
= Distance
;
801 for(i
= 0;i
< NumSends
;i
++)
802 RoomAttenuation
[i
] = 1.0f
;
803 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
804 ALContext
->DistanceModel
)
806 case InverseDistanceClamped
:
807 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
808 if(MaxDist
< MinDist
)
811 case InverseDistance
:
814 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
815 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
816 for(i
= 0;i
< NumSends
;i
++)
818 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
819 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
824 case LinearDistanceClamped
:
825 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
826 if(MaxDist
< MinDist
)
830 if(MaxDist
!= MinDist
)
832 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
833 Attenuation
= maxf(Attenuation
, 0.0f
);
834 for(i
= 0;i
< NumSends
;i
++)
836 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
837 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
842 case ExponentDistanceClamped
:
843 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
844 if(MaxDist
< MinDist
)
847 case ExponentDistance
:
848 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
850 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
851 for(i
= 0;i
< NumSends
;i
++)
852 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
856 case DisableDistance
:
857 ClampedDist
= MinDist
;
861 /* Source Gain + Attenuation */
862 DryGain
= SourceVolume
* Attenuation
;
863 for(i
= 0;i
< NumSends
;i
++)
864 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
866 /* Distance-based air absorption */
867 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
869 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
870 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
871 for(i
= 0;i
< NumSends
;i
++)
872 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
877 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
879 /* Apply a decay-time transformation to the wet path, based on the
880 * attenuation of the dry path.
882 * Using the apparent distance, based on the distance attenuation, the
883 * initial decay of the reverb effect is calculated and applied to the
886 for(i
= 0;i
< NumSends
;i
++)
888 if(DecayDistance
[i
] > 0.0f
)
889 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
893 /* Calculate directional soundcones */
894 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
895 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
897 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
898 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
899 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
901 else if(Angle
> OuterAngle
)
903 ConeVolume
= ALSource
->OuterGain
;
904 ConeHF
= ALSource
->OuterGainHF
;
912 DryGain
*= ConeVolume
;
915 for(i
= 0;i
< NumSends
;i
++)
916 WetGain
[i
] *= ConeVolume
;
922 for(i
= 0;i
< NumSends
;i
++)
923 WetGainHF
[i
] *= ConeHF
;
926 /* Clamp to Min/Max Gain */
927 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
928 for(i
= 0;i
< NumSends
;i
++)
929 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
931 /* Apply gain and frequency filters */
932 DryGain
*= ALSource
->Direct
.Gain
* ListenerGain
;
933 DryGainHF
*= ALSource
->Direct
.GainHF
;
934 DryGainLF
*= ALSource
->Direct
.GainLF
;
935 for(i
= 0;i
< NumSends
;i
++)
937 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
938 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
939 WetGainLF
[i
] *= ALSource
->Send
[i
].GainLF
;
942 /* Calculate velocity-based doppler effect */
943 if(DopplerFactor
> 0.0f
)
945 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
948 if(SpeedOfSound
< 1.0f
)
950 DopplerFactor
*= 1.0f
/SpeedOfSound
;
954 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
955 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
957 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
958 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
961 BufferListItem
= ALSource
->queue
;
962 while(BufferListItem
!= NULL
)
965 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
967 /* Calculate fixed-point stepping value, based on the pitch, buffer
968 * frequency, and output frequency. */
969 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
970 if(Pitch
> (ALfloat
)MAX_PITCH
)
971 src
->Step
= MAX_PITCH
<<FRACTIONBITS
;
974 src
->Step
= fastf2i(Pitch
*FRACTIONONE
);
978 src
->Resample
= SelectResampler(Resampler
, src
->Step
);
982 BufferListItem
= BufferListItem
->next
;
987 /* Use a binaural HRTF algorithm for stereo headphone playback */
988 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
990 if(Distance
> FLT_EPSILON
)
992 ALfloat invlen
= 1.0f
/Distance
;
993 Position
[0] *= invlen
;
994 Position
[1] *= invlen
;
995 Position
[2] *= invlen
;
997 /* Calculate elevation and azimuth only when the source is not at
998 * the listener. This prevents +0 and -0 Z from producing
999 * inconsistent panning. Also, clamp Y in case FP precision errors
1000 * cause it to land outside of -1..+1. */
1001 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
1002 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
1005 /* Check to see if the HRIR is already moving. */
1006 if(src
->Direct
.Moving
)
1008 /* Calculate the normalized HRTF transition factor (delta). */
1009 delta
= CalcHrtfDelta(src
->Direct
.Mix
.Hrtf
.Gain
, DryGain
,
1010 src
->Direct
.Mix
.Hrtf
.Dir
, Position
);
1011 /* If the delta is large enough, get the moving HRIR target
1012 * coefficients, target delays, steppping values, and counter. */
1015 ALuint counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
1016 ev
, az
, DryGain
, delta
,
1017 src
->Direct
.Counter
,
1018 src
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
1019 src
->Direct
.Mix
.Hrtf
.Params
[0].Delay
,
1020 src
->Direct
.Mix
.Hrtf
.Params
[0].CoeffStep
,
1021 src
->Direct
.Mix
.Hrtf
.Params
[0].DelayStep
);
1022 src
->Direct
.Counter
= counter
;
1023 src
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
1024 src
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
1025 src
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
1026 src
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
1031 /* Get the initial (static) HRIR coefficients and delays. */
1032 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
1033 src
->Direct
.Mix
.Hrtf
.Params
[0].Coeffs
,
1034 src
->Direct
.Mix
.Hrtf
.Params
[0].Delay
);
1035 src
->Direct
.Counter
= 0;
1036 src
->Direct
.Moving
= AL_TRUE
;
1037 src
->Direct
.Mix
.Hrtf
.Gain
= DryGain
;
1038 src
->Direct
.Mix
.Hrtf
.Dir
[0] = Position
[0];
1039 src
->Direct
.Mix
.Hrtf
.Dir
[1] = Position
[1];
1040 src
->Direct
.Mix
.Hrtf
.Dir
[2] = Position
[2];
1042 src
->Direct
.Mix
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
1044 src
->IsHrtf
= AL_TRUE
;
1045 src
->Dry
.HrtfMix
= SelectHrtfMixer();
1049 ALfloat
*restrict Target
= src
->Direct
.Mix
.Gains
[0].Target
;
1050 ALfloat DirGain
= 0.0f
;
1051 ALfloat AmbientGain
;
1053 for(j
= 0;j
< MaxChannels
;j
++)
1056 /* Normalize the length, and compute panned gains. */
1057 if(Distance
> FLT_EPSILON
)
1059 ALfloat invlen
= 1.0f
/Distance
;
1060 Position
[0] *= invlen
;
1061 Position
[1] *= invlen
;
1062 Position
[2] *= invlen
;
1064 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
1065 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
1066 DryGain
*DirGain
, Target
);
1069 /* Adjustment for vertical offsets. Not the greatest, but simple
1071 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
1072 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
1074 enum Channel chan
= Device
->Speaker2Chan
[i
];
1075 Target
[chan
] = maxf(Target
[chan
], AmbientGain
);
1078 if(!src
->Direct
.Moving
)
1080 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[0].Current
;
1081 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[0].Step
;
1082 for(j
= 0;j
< MaxChannels
;j
++)
1084 Current
[j
] = Target
[j
];
1087 src
->Direct
.Counter
= 0;
1088 src
->Direct
.Moving
= AL_TRUE
;
1092 ALfloat
*restrict Current
= src
->Direct
.Mix
.Gains
[0].Current
;
1093 ALfloat
*restrict Step
= src
->Direct
.Mix
.Gains
[0].Step
;
1094 for(j
= 0;j
< MaxChannels
;j
++)
1096 ALfloat cur
= maxf(Current
[j
], FLT_EPSILON
);
1097 ALfloat trg
= maxf(Target
[j
], FLT_EPSILON
);
1098 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
1099 Step
[j
] = powf(trg
/cur
, 1.0f
/64.0f
);
1104 src
->Direct
.Counter
= 64;
1107 src
->IsHrtf
= AL_FALSE
;
1108 src
->Dry
.Mix
= SelectDirectMixer();
1110 for(i
= 0;i
< NumSends
;i
++)
1112 src
->Send
[i
].Gain
.Target
= WetGain
[i
];
1113 if(!src
->Send
[i
].Moving
)
1115 src
->Send
[i
].Gain
.Current
= src
->Send
[i
].Gain
.Target
;
1116 src
->Send
[i
].Gain
.Step
= 1.0f
;
1117 src
->Send
[i
].Counter
= 0;
1118 src
->Send
[i
].Moving
= AL_TRUE
;
1122 ALfloat cur
= maxf(src
->Send
[i
].Gain
.Current
, FLT_EPSILON
);
1123 ALfloat trg
= maxf(src
->Send
[i
].Gain
.Target
, FLT_EPSILON
);
1124 if(fabs(trg
- cur
) >= GAIN_SILENCE_THRESHOLD
)
1125 src
->Send
[i
].Gain
.Step
= powf(trg
/cur
, 1.0f
/64.0f
);
1127 src
->Send
[i
].Gain
.Step
= 1.0f
;
1128 src
->Send
[i
].Gain
.Current
= cur
;
1129 src
->Send
[i
].Counter
= 64;
1132 src
->WetMix
= SelectSendMixer();
1135 ALfloat gainhf
= maxf(0.01f
, DryGainHF
);
1136 ALfloat gainlf
= maxf(0.01f
, DryGainLF
);
1137 ALfloat hfscale
= ALSource
->Direct
.HFReference
/ Frequency
;
1138 ALfloat lfscale
= ALSource
->Direct
.LFReference
/ Frequency
;
1139 src
->Direct
.Filters
[0].ActiveType
= AF_None
;
1140 if(gainhf
!= 1.0f
) src
->Direct
.Filters
[0].ActiveType
|= AF_LowPass
;
1141 if(gainlf
!= 1.0f
) src
->Direct
.Filters
[0].ActiveType
|= AF_HighPass
;
1142 ALfilterState_setParams(
1143 &src
->Direct
.Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1146 ALfilterState_setParams(
1147 &src
->Direct
.Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1151 for(i
= 0;i
< NumSends
;i
++)
1153 ALfloat gainhf
= maxf(0.01f
, WetGainHF
[i
]);
1154 ALfloat gainlf
= maxf(0.01f
, WetGainLF
[i
]);
1155 ALfloat hfscale
= ALSource
->Send
[i
].HFReference
/ Frequency
;
1156 ALfloat lfscale
= ALSource
->Send
[i
].LFReference
/ Frequency
;
1157 src
->Send
[i
].Filters
[0].ActiveType
= AF_None
;
1158 if(gainhf
!= 1.0f
) src
->Send
[i
].Filters
[0].ActiveType
|= AF_LowPass
;
1159 if(gainlf
!= 1.0f
) src
->Send
[i
].Filters
[0].ActiveType
|= AF_HighPass
;
1160 ALfilterState_setParams(
1161 &src
->Send
[i
].Filters
[0].LowPass
, ALfilterType_HighShelf
, gainhf
,
1164 ALfilterState_setParams(
1165 &src
->Send
[i
].Filters
[0].HighPass
, ALfilterType_LowShelf
, gainlf
,
1172 static inline ALint
aluF2I25(ALfloat val
)
1174 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
1175 if(fabsf(val
) > 1.0f
)
1176 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
1177 /* Convert to a signed integer, between -16777215 and +16777215. */
1178 return fastf2i(val
*16777215.0f
);
1181 static inline ALfloat
aluF2F(ALfloat val
)
1183 static inline ALint
aluF2I(ALfloat val
)
1184 { return aluF2I25(val
)<<7; }
1185 static inline ALuint
aluF2UI(ALfloat val
)
1186 { return aluF2I(val
)+2147483648u; }
1187 static inline ALshort
aluF2S(ALfloat val
)
1188 { return aluF2I25(val
)>>9; }
1189 static inline ALushort
aluF2US(ALfloat val
)
1190 { return aluF2S(val
)+32768; }
1191 static inline ALbyte
aluF2B(ALfloat val
)
1192 { return aluF2I25(val
)>>17; }
1193 static inline ALubyte
aluF2UB(ALfloat val
)
1194 { return aluF2B(val
)+128; }
1196 #define DECL_TEMPLATE(T, func) \
1197 static void Write_##T(ALCdevice *device, ALvoid **buffer, ALuint SamplesToDo) \
1199 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
1200 const ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
1201 const ALuint *offsets = device->ChannelOffsets; \
1204 for(j = 0;j < MaxChannels;j++) \
1208 if(offsets[j] == INVALID_OFFSET) \
1211 out = (T*)(*buffer) + offsets[j]; \
1212 for(i = 0;i < SamplesToDo;i++) \
1213 out[i*numchans] = func(DryBuffer[j][i]); \
1215 *buffer = (char*)(*buffer) + SamplesToDo*numchans*sizeof(T); \
1218 DECL_TEMPLATE(ALfloat
, aluF2F
)
1219 DECL_TEMPLATE(ALuint
, aluF2UI
)
1220 DECL_TEMPLATE(ALint
, aluF2I
)
1221 DECL_TEMPLATE(ALushort
, aluF2US
)
1222 DECL_TEMPLATE(ALshort
, aluF2S
)
1223 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1224 DECL_TEMPLATE(ALbyte
, aluF2B
)
1226 #undef DECL_TEMPLATE
1229 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1232 ALeffectslot
**slot
, **slot_end
;
1233 ALactivesource
**src
, **src_end
;
1238 SetMixerFPUMode(&oldMode
);
1242 IncrementRef(&device
->MixCount
);
1244 SamplesToDo
= minu(size
, BUFFERSIZE
);
1245 for(c
= 0;c
< MaxChannels
;c
++)
1246 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1248 ALCdevice_Lock(device
);
1249 V(device
->Synth
,process
)(SamplesToDo
, device
->DryBuffer
);
1251 ctx
= device
->ContextList
;
1254 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1255 ALenum UpdateSources
= AL_FALSE
;
1258 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
1261 CalcListenerParams(ctx
->Listener
);
1263 /* source processing */
1264 src
= ctx
->ActiveSources
;
1265 src_end
= src
+ ctx
->ActiveSourceCount
;
1266 while(src
!= src_end
)
1268 ALsource
*source
= (*src
)->Source
;
1270 if(source
->state
!= AL_PLAYING
&& source
->state
!= AL_PAUSED
)
1272 ALactivesource
*temp
= *(--src_end
);
1275 --(ctx
->ActiveSourceCount
);
1279 if(!DeferUpdates
&& (ExchangeInt(&source
->NeedsUpdate
, AL_FALSE
) ||
1281 (*src
)->Update(*src
, ctx
);
1283 if(source
->state
!= AL_PAUSED
)
1284 MixSource(*src
, device
, SamplesToDo
);
1288 /* effect slot processing */
1289 slot
= VECTOR_ITER_BEGIN(ctx
->ActiveAuxSlots
);
1290 slot_end
= VECTOR_ITER_END(ctx
->ActiveAuxSlots
);
1291 while(slot
!= slot_end
)
1293 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1294 V((*slot
)->EffectState
,update
)(device
, *slot
);
1296 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1299 for(i
= 0;i
< SamplesToDo
;i
++)
1300 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1308 slot
= &device
->DefaultSlot
;
1311 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1312 V((*slot
)->EffectState
,update
)(device
, *slot
);
1314 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1317 for(i
= 0;i
< SamplesToDo
;i
++)
1318 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1321 /* Increment the clock time. Every second's worth of samples is
1322 * converted and added to clock base so that large sample counts don't
1323 * overflow during conversion. This also guarantees an exact, stable
1325 device
->SamplesDone
+= SamplesToDo
;
1326 device
->ClockBase
+= (device
->SamplesDone
/device
->Frequency
) * DEVICE_CLOCK_RES
;
1327 device
->SamplesDone
%= device
->Frequency
;
1328 ALCdevice_Unlock(device
);
1332 /* Apply binaural/crossfeed filter */
1333 for(i
= 0;i
< SamplesToDo
;i
++)
1336 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1337 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1338 bs2b_cross_feed(device
->Bs2b
, samples
);
1339 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1340 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1346 switch(device
->FmtType
)
1349 Write_ALbyte(device
, &buffer
, SamplesToDo
);
1352 Write_ALubyte(device
, &buffer
, SamplesToDo
);
1355 Write_ALshort(device
, &buffer
, SamplesToDo
);
1358 Write_ALushort(device
, &buffer
, SamplesToDo
);
1361 Write_ALint(device
, &buffer
, SamplesToDo
);
1364 Write_ALuint(device
, &buffer
, SamplesToDo
);
1367 Write_ALfloat(device
, &buffer
, SamplesToDo
);
1372 size
-= SamplesToDo
;
1373 IncrementRef(&device
->MixCount
);
1376 RestoreFPUMode(&oldMode
);
1380 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1382 ALCcontext
*Context
;
1384 device
->Connected
= ALC_FALSE
;
1386 Context
= device
->ContextList
;
1389 ALactivesource
**src
, **src_end
;
1391 src
= Context
->ActiveSources
;
1392 src_end
= src
+ Context
->ActiveSourceCount
;
1393 while(src
!= src_end
)
1395 ALsource
*source
= (*src
)->Source
;
1396 if(source
->state
== AL_PLAYING
)
1398 source
->state
= AL_STOPPED
;
1399 source
->current_buffer
= NULL
;
1400 source
->position
= 0;
1401 source
->position_fraction
= 0;
1405 Context
->ActiveSourceCount
= 0;
1407 Context
= Context
->next
;