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 "mixer_defs.h"
39 #include "midi/base.h"
48 ALfloat ConeScale
= 1.0f
;
50 /* Localized Z scalar for mono sources */
51 ALfloat ZScale
= 1.0f
;
53 extern inline ALfloat
minf(ALfloat a
, ALfloat b
);
54 extern inline ALfloat
maxf(ALfloat a
, ALfloat b
);
55 extern inline ALfloat
clampf(ALfloat val
, ALfloat min
, ALfloat max
);
57 extern inline ALdouble
mind(ALdouble a
, ALdouble b
);
58 extern inline ALdouble
maxd(ALdouble a
, ALdouble b
);
59 extern inline ALdouble
clampd(ALdouble val
, ALdouble min
, ALdouble max
);
61 extern inline ALuint
minu(ALuint a
, ALuint b
);
62 extern inline ALuint
maxu(ALuint a
, ALuint b
);
63 extern inline ALuint
clampu(ALuint val
, ALuint min
, ALuint max
);
65 extern inline ALint
mini(ALint a
, ALint b
);
66 extern inline ALint
maxi(ALint a
, ALint b
);
67 extern inline ALint
clampi(ALint val
, ALint min
, ALint max
);
69 extern inline ALint64
mini64(ALint64 a
, ALint64 b
);
70 extern inline ALint64
maxi64(ALint64 a
, ALint64 b
);
71 extern inline ALint64
clampi64(ALint64 val
, ALint64 min
, ALint64 max
);
73 extern inline ALuint64
minu64(ALuint64 a
, ALuint64 b
);
74 extern inline ALuint64
maxu64(ALuint64 a
, ALuint64 b
);
75 extern inline ALuint64
clampu64(ALuint64 val
, ALuint64 min
, ALuint64 max
);
77 extern inline ALfloat
lerp(ALfloat val1
, ALfloat val2
, ALfloat mu
);
78 extern inline ALfloat
cubic(ALfloat val0
, ALfloat val1
, ALfloat val2
, ALfloat val3
, ALfloat mu
);
80 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
82 if(increment
== FRACTIONONE
)
83 return Resample_copy32_C
;
87 return Resample_point32_C
;
89 return Resample_lerp32_C
;
91 return Resample_cubic32_C
;
93 /* Shouldn't happen */
97 return Resample_point32_C
;
101 static DryMixerFunc
SelectHrtfMixer(void)
104 if((CPUCapFlags
&CPU_CAP_SSE
))
105 return MixDirect_Hrtf_SSE
;
108 if((CPUCapFlags
&CPU_CAP_NEON
))
109 return MixDirect_Hrtf_Neon
;
112 return MixDirect_Hrtf_C
;
115 static DryMixerFunc
SelectDirectMixer(void)
118 if((CPUCapFlags
&CPU_CAP_SSE
))
119 return MixDirect_SSE
;
125 static WetMixerFunc
SelectSendMixer(void)
128 if((CPUCapFlags
&CPU_CAP_SSE
))
136 static inline void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
138 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
139 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
140 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
143 static inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
145 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
146 inVector1
[2]*inVector2
[2];
149 static inline void aluNormalize(ALfloat
*inVector
)
151 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
154 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
155 inVector
[0] *= inv_length
;
156 inVector
[1] *= inv_length
;
157 inVector
[2] *= inv_length
;
161 static inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*restrict matrix
)[4])
164 vector
[0], vector
[1], vector
[2], w
167 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
168 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
169 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
173 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
175 ALfloat N
[3], V
[3], U
[3], P
[3];
178 N
[0] = Listener
->Forward
[0];
179 N
[1] = Listener
->Forward
[1];
180 N
[2] = Listener
->Forward
[2];
182 V
[0] = Listener
->Up
[0];
183 V
[1] = Listener
->Up
[1];
184 V
[2] = Listener
->Up
[2];
186 /* Build and normalize right-vector */
187 aluCrossproduct(N
, V
, U
);
190 Listener
->Params
.Matrix
[0][0] = U
[0];
191 Listener
->Params
.Matrix
[0][1] = V
[0];
192 Listener
->Params
.Matrix
[0][2] = -N
[0];
193 Listener
->Params
.Matrix
[0][3] = 0.0f
;
194 Listener
->Params
.Matrix
[1][0] = U
[1];
195 Listener
->Params
.Matrix
[1][1] = V
[1];
196 Listener
->Params
.Matrix
[1][2] = -N
[1];
197 Listener
->Params
.Matrix
[1][3] = 0.0f
;
198 Listener
->Params
.Matrix
[2][0] = U
[2];
199 Listener
->Params
.Matrix
[2][1] = V
[2];
200 Listener
->Params
.Matrix
[2][2] = -N
[2];
201 Listener
->Params
.Matrix
[2][3] = 0.0f
;
202 Listener
->Params
.Matrix
[3][0] = 0.0f
;
203 Listener
->Params
.Matrix
[3][1] = 0.0f
;
204 Listener
->Params
.Matrix
[3][2] = 0.0f
;
205 Listener
->Params
.Matrix
[3][3] = 1.0f
;
207 P
[0] = Listener
->Position
[0];
208 P
[1] = Listener
->Position
[1];
209 P
[2] = Listener
->Position
[2];
210 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
211 Listener
->Params
.Matrix
[3][0] = -P
[0];
212 Listener
->Params
.Matrix
[3][1] = -P
[1];
213 Listener
->Params
.Matrix
[3][2] = -P
[2];
215 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
216 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
217 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
218 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
221 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
223 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
224 static const struct ChanMap StereoMap
[2] = {
225 { FrontLeft
, DEG2RAD(-30.0f
) },
226 { FrontRight
, DEG2RAD( 30.0f
) }
228 static const struct ChanMap StereoWideMap
[2] = {
229 { FrontLeft
, DEG2RAD(-90.0f
) },
230 { FrontRight
, DEG2RAD( 90.0f
) }
232 static const struct ChanMap RearMap
[2] = {
233 { BackLeft
, DEG2RAD(-150.0f
) },
234 { BackRight
, DEG2RAD( 150.0f
) }
236 static const struct ChanMap QuadMap
[4] = {
237 { FrontLeft
, DEG2RAD( -45.0f
) },
238 { FrontRight
, DEG2RAD( 45.0f
) },
239 { BackLeft
, DEG2RAD(-135.0f
) },
240 { BackRight
, DEG2RAD( 135.0f
) }
242 static const struct ChanMap X51Map
[6] = {
243 { FrontLeft
, DEG2RAD( -30.0f
) },
244 { FrontRight
, DEG2RAD( 30.0f
) },
245 { FrontCenter
, DEG2RAD( 0.0f
) },
247 { BackLeft
, DEG2RAD(-110.0f
) },
248 { BackRight
, DEG2RAD( 110.0f
) }
250 static const struct ChanMap X61Map
[7] = {
251 { FrontLeft
, DEG2RAD(-30.0f
) },
252 { FrontRight
, DEG2RAD( 30.0f
) },
253 { FrontCenter
, DEG2RAD( 0.0f
) },
255 { BackCenter
, DEG2RAD(180.0f
) },
256 { SideLeft
, DEG2RAD(-90.0f
) },
257 { SideRight
, DEG2RAD( 90.0f
) }
259 static const struct ChanMap X71Map
[8] = {
260 { FrontLeft
, DEG2RAD( -30.0f
) },
261 { FrontRight
, DEG2RAD( 30.0f
) },
262 { FrontCenter
, DEG2RAD( 0.0f
) },
264 { BackLeft
, DEG2RAD(-150.0f
) },
265 { BackRight
, DEG2RAD( 150.0f
) },
266 { SideLeft
, DEG2RAD( -90.0f
) },
267 { SideRight
, DEG2RAD( 90.0f
) }
270 ALCdevice
*Device
= ALContext
->Device
;
271 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
272 ALbufferlistitem
*BufferListItem
;
273 enum FmtChannels Channels
;
274 ALfloat (*SrcMatrix
)[MaxChannels
];
275 ALfloat DryGain
, DryGainHF
;
276 ALfloat WetGain
[MAX_SENDS
];
277 ALfloat WetGainHF
[MAX_SENDS
];
278 ALint NumSends
, Frequency
;
279 const struct ChanMap
*chans
= NULL
;
280 enum Resampler Resampler
;
281 ALint num_channels
= 0;
282 ALboolean DirectChannels
;
283 ALfloat hwidth
= 0.0f
;
287 /* Get device properties */
288 NumSends
= Device
->NumAuxSends
;
289 Frequency
= Device
->Frequency
;
291 /* Get listener properties */
292 ListenerGain
= ALContext
->Listener
->Gain
;
294 /* Get source properties */
295 SourceVolume
= ALSource
->Gain
;
296 MinVolume
= ALSource
->MinGain
;
297 MaxVolume
= ALSource
->MaxGain
;
298 Pitch
= ALSource
->Pitch
;
299 Resampler
= ALSource
->Resampler
;
300 DirectChannels
= ALSource
->DirectChannels
;
302 /* Calculate the stepping value */
304 BufferListItem
= ALSource
->queue
;
305 while(BufferListItem
!= NULL
)
308 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
310 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
312 ALSource
->Params
.Step
= 10<<FRACTIONBITS
;
315 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
316 if(ALSource
->Params
.Step
== 0)
317 ALSource
->Params
.Step
= 1;
319 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
321 Channels
= ALBuffer
->FmtChannels
;
324 BufferListItem
= BufferListItem
->next
;
326 if(!DirectChannels
&& Device
->Hrtf
)
327 ALSource
->Params
.DryMix
= SelectHrtfMixer();
329 ALSource
->Params
.DryMix
= SelectDirectMixer();
330 ALSource
->Params
.WetMix
= SelectSendMixer();
332 /* Calculate gains */
333 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
334 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
335 DryGainHF
= ALSource
->DirectGainHF
;
336 for(i
= 0;i
< NumSends
;i
++)
338 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
339 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
340 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
343 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
344 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
346 for(c
= 0;c
< MaxChannels
;c
++)
347 SrcMatrix
[i
][c
] = 0.0f
;
357 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
359 /* HACK: Place the stereo channels at +/-90 degrees when using non-
360 * HRTF stereo output. This helps reduce the "monoization" caused
361 * by them panning towards the center. */
362 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
363 chans
= StereoWideMap
;
369 chans
= StereoWideMap
;
370 hwidth
= DEG2RAD(60.0f
);
401 if(DirectChannels
!= AL_FALSE
)
403 for(c
= 0;c
< num_channels
;c
++)
405 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
407 enum Channel chan
= Device
->Speaker2Chan
[i
];
408 if(chan
== chans
[c
].channel
)
410 SrcMatrix
[c
][chan
] = DryGain
;
416 else if(Device
->Hrtf
)
418 for(c
= 0;c
< num_channels
;c
++)
420 if(chans
[c
].channel
== LFE
)
423 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
][0] = 0;
424 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
][1] = 0;
425 for(i
= 0;i
< HRIR_LENGTH
;i
++)
427 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
][i
][0] = 0.0f
;
428 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
][i
][1] = 0.0f
;
433 /* Get the static HRIR coefficients and delays for this
435 GetLerpedHrtfCoeffs(Device
->Hrtf
,
436 0.0f
, chans
[c
].angle
, DryGain
,
437 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
],
438 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
]);
441 ALSource
->Hrtf
.Counter
= 0;
442 ALSource
->Params
.Direct
.Hrtf
.Params
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
444 ALSource
->Params
.Direct
.Hrtf
.State
= &ALSource
->Hrtf
;
448 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf((float)Device
->NumChan
), hwidth
/F_PI
);
449 for(c
= 0;c
< num_channels
;c
++)
451 /* Special-case LFE */
452 if(chans
[c
].channel
== LFE
)
454 SrcMatrix
[c
][chans
[c
].channel
] = DryGain
;
457 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
462 ALSource
->Params
.Direct
.OutBuffer
= Device
->DryBuffer
;
463 ALSource
->Params
.Direct
.ClickRemoval
= Device
->ClickRemoval
;
464 ALSource
->Params
.Direct
.PendingClicks
= Device
->PendingClicks
;
465 for(i
= 0;i
< NumSends
;i
++)
467 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
469 Slot
= Device
->DefaultSlot
;
470 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
472 ALSource
->Params
.Send
[i
].OutBuffer
= NULL
;
473 ALSource
->Params
.Send
[i
].ClickRemoval
= NULL
;
474 ALSource
->Params
.Send
[i
].PendingClicks
= NULL
;
478 ALSource
->Params
.Send
[i
].OutBuffer
= Slot
->WetBuffer
;
479 ALSource
->Params
.Send
[i
].ClickRemoval
= Slot
->ClickRemoval
;
480 ALSource
->Params
.Send
[i
].PendingClicks
= Slot
->PendingClicks
;
482 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
486 ALfloat gain
= maxf(0.01f
, DryGainHF
);
487 for(c
= 0;c
< num_channels
;c
++)
488 ALfilterState_setParams(&ALSource
->Params
.Direct
.LpFilter
[c
],
489 ALfilterType_HighShelf
, gain
,
490 (ALfloat
)LOWPASSFREQREF
/Frequency
, 0.0f
);
492 for(i
= 0;i
< NumSends
;i
++)
494 ALfloat gain
= maxf(0.01f
, WetGainHF
[i
]);
495 for(c
= 0;c
< num_channels
;c
++)
496 ALfilterState_setParams(&ALSource
->Params
.Send
[i
].LpFilter
[c
],
497 ALfilterType_HighShelf
, gain
,
498 (ALfloat
)LOWPASSFREQREF
/Frequency
, 0.0f
);
502 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
504 ALCdevice
*Device
= ALContext
->Device
;
505 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
506 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
507 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
508 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
509 ALfloat DopplerFactor
, SpeedOfSound
;
510 ALfloat AirAbsorptionFactor
;
511 ALfloat RoomAirAbsorption
[MAX_SENDS
];
512 ALbufferlistitem
*BufferListItem
;
514 ALfloat RoomAttenuation
[MAX_SENDS
];
515 ALfloat MetersPerUnit
;
516 ALfloat RoomRolloffBase
;
517 ALfloat RoomRolloff
[MAX_SENDS
];
518 ALfloat DecayDistance
[MAX_SENDS
];
521 ALboolean DryGainHFAuto
;
522 ALfloat WetGain
[MAX_SENDS
];
523 ALfloat WetGainHF
[MAX_SENDS
];
524 ALboolean WetGainAuto
;
525 ALboolean WetGainHFAuto
;
526 enum Resampler Resampler
;
533 for(i
= 0;i
< MAX_SENDS
;i
++)
536 /* Get context/device properties */
537 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
538 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
539 NumSends
= Device
->NumAuxSends
;
540 Frequency
= Device
->Frequency
;
542 /* Get listener properties */
543 ListenerGain
= ALContext
->Listener
->Gain
;
544 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
546 /* Get source properties */
547 SourceVolume
= ALSource
->Gain
;
548 MinVolume
= ALSource
->MinGain
;
549 MaxVolume
= ALSource
->MaxGain
;
550 Pitch
= ALSource
->Pitch
;
551 Resampler
= ALSource
->Resampler
;
552 Position
[0] = ALSource
->Position
[0];
553 Position
[1] = ALSource
->Position
[1];
554 Position
[2] = ALSource
->Position
[2];
555 Direction
[0] = ALSource
->Orientation
[0];
556 Direction
[1] = ALSource
->Orientation
[1];
557 Direction
[2] = ALSource
->Orientation
[2];
558 Velocity
[0] = ALSource
->Velocity
[0];
559 Velocity
[1] = ALSource
->Velocity
[1];
560 Velocity
[2] = ALSource
->Velocity
[2];
561 MinDist
= ALSource
->RefDistance
;
562 MaxDist
= ALSource
->MaxDistance
;
563 Rolloff
= ALSource
->RollOffFactor
;
564 InnerAngle
= ALSource
->InnerAngle
;
565 OuterAngle
= ALSource
->OuterAngle
;
566 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
567 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
568 WetGainAuto
= ALSource
->WetGainAuto
;
569 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
570 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
572 ALSource
->Params
.Direct
.OutBuffer
= Device
->DryBuffer
;
573 ALSource
->Params
.Direct
.ClickRemoval
= Device
->ClickRemoval
;
574 ALSource
->Params
.Direct
.PendingClicks
= Device
->PendingClicks
;
575 for(i
= 0;i
< NumSends
;i
++)
577 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
580 Slot
= Device
->DefaultSlot
;
581 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
584 RoomRolloff
[i
] = 0.0f
;
585 DecayDistance
[i
] = 0.0f
;
586 RoomAirAbsorption
[i
] = 1.0f
;
588 else if(Slot
->AuxSendAuto
)
590 RoomRolloff
[i
] = RoomRolloffBase
;
591 if(IsReverbEffect(Slot
->EffectType
))
593 RoomRolloff
[i
] += Slot
->EffectProps
.Reverb
.RoomRolloffFactor
;
594 DecayDistance
[i
] = Slot
->EffectProps
.Reverb
.DecayTime
*
595 SPEEDOFSOUNDMETRESPERSEC
;
596 RoomAirAbsorption
[i
] = Slot
->EffectProps
.Reverb
.AirAbsorptionGainHF
;
600 DecayDistance
[i
] = 0.0f
;
601 RoomAirAbsorption
[i
] = 1.0f
;
606 /* If the slot's auxiliary send auto is off, the data sent to the
607 * effect slot is the same as the dry path, sans filter effects */
608 RoomRolloff
[i
] = Rolloff
;
609 DecayDistance
[i
] = 0.0f
;
610 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
613 if(!Slot
|| Slot
->EffectType
== AL_EFFECT_NULL
)
615 ALSource
->Params
.Send
[i
].OutBuffer
= NULL
;
616 ALSource
->Params
.Send
[i
].ClickRemoval
= NULL
;
617 ALSource
->Params
.Send
[i
].PendingClicks
= NULL
;
621 ALSource
->Params
.Send
[i
].OutBuffer
= Slot
->WetBuffer
;
622 ALSource
->Params
.Send
[i
].ClickRemoval
= Slot
->ClickRemoval
;
623 ALSource
->Params
.Send
[i
].PendingClicks
= Slot
->PendingClicks
;
627 /* Transform source to listener space (convert to head relative) */
628 if(ALSource
->HeadRelative
== AL_FALSE
)
630 ALfloat (*restrict Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
631 /* Transform source vectors */
632 aluMatrixVector(Position
, 1.0f
, Matrix
);
633 aluMatrixVector(Direction
, 0.0f
, Matrix
);
634 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
638 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
639 /* Offset the source velocity to be relative of the listener velocity */
640 Velocity
[0] += ListenerVel
[0];
641 Velocity
[1] += ListenerVel
[1];
642 Velocity
[2] += ListenerVel
[2];
645 SourceToListener
[0] = -Position
[0];
646 SourceToListener
[1] = -Position
[1];
647 SourceToListener
[2] = -Position
[2];
648 aluNormalize(SourceToListener
);
649 aluNormalize(Direction
);
651 /* Calculate distance attenuation */
652 Distance
= sqrtf(aluDotproduct(Position
, Position
));
653 ClampedDist
= Distance
;
656 for(i
= 0;i
< NumSends
;i
++)
657 RoomAttenuation
[i
] = 1.0f
;
658 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
659 ALContext
->DistanceModel
)
661 case InverseDistanceClamped
:
662 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
663 if(MaxDist
< MinDist
)
666 case InverseDistance
:
669 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
670 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
671 for(i
= 0;i
< NumSends
;i
++)
673 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
674 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
679 case LinearDistanceClamped
:
680 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
681 if(MaxDist
< MinDist
)
685 if(MaxDist
!= MinDist
)
687 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
688 Attenuation
= maxf(Attenuation
, 0.0f
);
689 for(i
= 0;i
< NumSends
;i
++)
691 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
692 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
697 case ExponentDistanceClamped
:
698 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
699 if(MaxDist
< MinDist
)
702 case ExponentDistance
:
703 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
705 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
706 for(i
= 0;i
< NumSends
;i
++)
707 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
711 case DisableDistance
:
712 ClampedDist
= MinDist
;
716 /* Source Gain + Attenuation */
717 DryGain
= SourceVolume
* Attenuation
;
718 for(i
= 0;i
< NumSends
;i
++)
719 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
721 /* Distance-based air absorption */
722 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
724 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
725 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
726 for(i
= 0;i
< NumSends
;i
++)
727 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
732 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
734 /* Apply a decay-time transformation to the wet path, based on the
735 * attenuation of the dry path.
737 * Using the apparent distance, based on the distance attenuation, the
738 * initial decay of the reverb effect is calculated and applied to the
741 for(i
= 0;i
< NumSends
;i
++)
743 if(DecayDistance
[i
] > 0.0f
)
744 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
748 /* Calculate directional soundcones */
749 Angle
= RAD2DEG(acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
) * 2.0f
;
750 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
752 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
753 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
754 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
756 else if(Angle
> OuterAngle
)
758 ConeVolume
= ALSource
->OuterGain
;
759 ConeHF
= ALSource
->OuterGainHF
;
767 DryGain
*= ConeVolume
;
770 for(i
= 0;i
< NumSends
;i
++)
771 WetGain
[i
] *= ConeVolume
;
777 for(i
= 0;i
< NumSends
;i
++)
778 WetGainHF
[i
] *= ConeHF
;
781 /* Clamp to Min/Max Gain */
782 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
783 for(i
= 0;i
< NumSends
;i
++)
784 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
786 /* Apply gain and frequency filters */
787 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
788 DryGainHF
*= ALSource
->DirectGainHF
;
789 for(i
= 0;i
< NumSends
;i
++)
791 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
792 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
795 /* Calculate velocity-based doppler effect */
796 if(DopplerFactor
> 0.0f
)
798 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
801 if(SpeedOfSound
< 1.0f
)
803 DopplerFactor
*= 1.0f
/SpeedOfSound
;
807 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
808 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
810 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
811 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
814 BufferListItem
= ALSource
->queue
;
815 while(BufferListItem
!= NULL
)
818 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
820 /* Calculate fixed-point stepping value, based on the pitch, buffer
821 * frequency, and output frequency. */
822 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
824 ALSource
->Params
.Step
= 10<<FRACTIONBITS
;
827 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
828 if(ALSource
->Params
.Step
== 0)
829 ALSource
->Params
.Step
= 1;
831 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
835 BufferListItem
= BufferListItem
->next
;
838 ALSource
->Params
.DryMix
= SelectHrtfMixer();
840 ALSource
->Params
.DryMix
= SelectDirectMixer();
841 ALSource
->Params
.WetMix
= SelectSendMixer();
845 /* Use a binaural HRTF algorithm for stereo headphone playback */
846 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
848 if(Distance
> FLT_EPSILON
)
850 ALfloat invlen
= 1.0f
/Distance
;
851 Position
[0] *= invlen
;
852 Position
[1] *= invlen
;
853 Position
[2] *= invlen
;
855 /* Calculate elevation and azimuth only when the source is not at
856 * the listener. This prevents +0 and -0 Z from producing
857 * inconsistent panning. Also, clamp Y in case FP precision errors
858 * cause it to land outside of -1..+1. */
859 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
860 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
863 /* Check to see if the HRIR is already moving. */
864 if(ALSource
->Hrtf
.Moving
)
866 /* Calculate the normalized HRTF transition factor (delta). */
867 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
, DryGain
,
868 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
, Position
);
869 /* If the delta is large enough, get the moving HRIR target
870 * coefficients, target delays, steppping values, and counter. */
873 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
874 ev
, az
, DryGain
, delta
,
875 ALSource
->Hrtf
.Counter
,
876 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[0],
877 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[0],
878 ALSource
->Params
.Direct
.Hrtf
.Params
.CoeffStep
,
879 ALSource
->Params
.Direct
.Hrtf
.Params
.DelayStep
);
880 ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
= DryGain
;
881 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[0] = Position
[0];
882 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[1] = Position
[1];
883 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[2] = Position
[2];
888 /* Get the initial (static) HRIR coefficients and delays. */
889 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
890 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[0],
891 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[0]);
892 ALSource
->Hrtf
.Counter
= 0;
893 ALSource
->Hrtf
.Moving
= AL_TRUE
;
894 ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
= DryGain
;
895 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[0] = Position
[0];
896 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[1] = Position
[1];
897 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[2] = Position
[2];
899 ALSource
->Params
.Direct
.Hrtf
.Params
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
901 ALSource
->Params
.Direct
.Hrtf
.State
= &ALSource
->Hrtf
;
905 ALfloat (*Matrix
)[MaxChannels
] = ALSource
->Params
.Direct
.Gains
;
906 ALfloat DirGain
= 0.0f
;
909 for(i
= 0;i
< MAX_INPUT_CHANNELS
;i
++)
911 for(j
= 0;j
< MaxChannels
;j
++)
915 /* Normalize the length, and compute panned gains. */
916 if(Distance
> FLT_EPSILON
)
918 ALfloat invlen
= 1.0f
/Distance
;
919 Position
[0] *= invlen
;
920 Position
[1] *= invlen
;
921 Position
[2] *= invlen
;
923 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
924 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
925 DryGain
*DirGain
, Matrix
[0]);
928 /* Adjustment for vertical offsets. Not the greatest, but simple
930 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
931 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
933 enum Channel chan
= Device
->Speaker2Chan
[i
];
934 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
937 for(i
= 0;i
< NumSends
;i
++)
938 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
942 ALfloat gain
= maxf(0.01f
, DryGainHF
);
943 ALfilterState_setParams(&ALSource
->Params
.Direct
.LpFilter
[0],
944 ALfilterType_HighShelf
, gain
,
945 (ALfloat
)LOWPASSFREQREF
/Frequency
, 0.0f
);
947 for(i
= 0;i
< NumSends
;i
++)
949 ALfloat gain
= maxf(0.01f
, WetGainHF
[i
]);
950 ALfilterState_setParams(&ALSource
->Params
.Send
[i
].LpFilter
[0],
951 ALfilterType_HighShelf
, gain
,
952 (ALfloat
)LOWPASSFREQREF
/Frequency
, 0.0f
);
957 static inline ALint
aluF2I25(ALfloat val
)
959 /* Clamp the value between -1 and +1. This handles that with only a single branch. */
960 if(fabsf(val
) > 1.0f
)
961 val
= (ALfloat
)((0.0f
< val
) - (val
< 0.0f
));
962 /* Convert to a signed integer, between -16777215 and +16777215. */
963 return fastf2i(val
*16777215.0f
);
966 static inline ALfloat
aluF2F(ALfloat val
)
968 static inline ALint
aluF2I(ALfloat val
)
969 { return aluF2I25(val
)<<7; }
970 static inline ALuint
aluF2UI(ALfloat val
)
971 { return aluF2I(val
)+2147483648u; }
972 static inline ALshort
aluF2S(ALfloat val
)
973 { return aluF2I25(val
)>>9; }
974 static inline ALushort
aluF2US(ALfloat val
)
975 { return aluF2S(val
)+32768; }
976 static inline ALbyte
aluF2B(ALfloat val
)
977 { return aluF2I25(val
)>>17; }
978 static inline ALubyte
aluF2UB(ALfloat val
)
979 { return aluF2B(val
)+128; }
981 #define DECL_TEMPLATE(T, func) \
982 static int Write_##T(ALCdevice *device, T *restrict buffer, \
983 ALuint SamplesToDo) \
985 ALfloat (*restrict DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
986 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
987 const ALuint *offsets = device->ChannelOffsets; \
990 for(j = 0;j < MaxChannels;j++) \
994 if(offsets[j] == INVALID_OFFSET) \
997 out = buffer + offsets[j]; \
998 for(i = 0;i < SamplesToDo;i++) \
999 out[i*numchans] = func(DryBuffer[j][i]); \
1001 return SamplesToDo*numchans*sizeof(T); \
1004 DECL_TEMPLATE(ALfloat
, aluF2F
)
1005 DECL_TEMPLATE(ALuint
, aluF2UI
)
1006 DECL_TEMPLATE(ALint
, aluF2I
)
1007 DECL_TEMPLATE(ALushort
, aluF2US
)
1008 DECL_TEMPLATE(ALshort
, aluF2S
)
1009 DECL_TEMPLATE(ALubyte
, aluF2UB
)
1010 DECL_TEMPLATE(ALbyte
, aluF2B
)
1012 #undef DECL_TEMPLATE
1015 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
1018 ALeffectslot
**slot
, **slot_end
;
1019 ALsource
**src
, **src_end
;
1024 SetMixerFPUMode(&oldMode
);
1028 SamplesToDo
= minu(size
, BUFFERSIZE
);
1029 for(c
= 0;c
< MaxChannels
;c
++)
1030 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
1032 ALCdevice_Lock(device
);
1033 V(device
->Synth
,process
)(SamplesToDo
, device
->DryBuffer
);
1035 ctx
= device
->ContextList
;
1038 ALenum DeferUpdates
= ctx
->DeferUpdates
;
1039 ALenum UpdateSources
= AL_FALSE
;
1042 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
1045 CalcListenerParams(ctx
->Listener
);
1047 /* source processing */
1048 src
= ctx
->ActiveSources
;
1049 src_end
= src
+ ctx
->ActiveSourceCount
;
1050 while(src
!= src_end
)
1052 if((*src
)->state
!= AL_PLAYING
)
1054 --(ctx
->ActiveSourceCount
);
1055 *src
= *(--src_end
);
1059 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
1061 ALsource_Update(*src
, ctx
);
1063 MixSource(*src
, device
, SamplesToDo
);
1067 /* effect slot processing */
1068 slot
= ctx
->ActiveEffectSlots
;
1069 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
1070 while(slot
!= slot_end
)
1072 ALfloat offset
= (*slot
)->ClickRemoval
[0];
1073 if(offset
< (1.0f
/32768.0f
))
1075 else for(i
= 0;i
< SamplesToDo
;i
++)
1077 (*slot
)->WetBuffer
[0][i
] += offset
;
1078 offset
-= offset
* (1.0f
/256.0f
);
1080 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
1081 (*slot
)->PendingClicks
[0] = 0.0f
;
1083 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1084 V((*slot
)->EffectState
,update
)(device
, *slot
);
1086 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1089 for(i
= 0;i
< SamplesToDo
;i
++)
1090 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1098 slot
= &device
->DefaultSlot
;
1101 ALfloat offset
= (*slot
)->ClickRemoval
[0];
1102 if(offset
< (1.0f
/32768.0f
))
1104 else for(i
= 0;i
< SamplesToDo
;i
++)
1106 (*slot
)->WetBuffer
[0][i
] += offset
;
1107 offset
-= offset
* (1.0f
/256.0f
);
1109 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
1110 (*slot
)->PendingClicks
[0] = 0.0f
;
1112 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1113 V((*slot
)->EffectState
,update
)(device
, *slot
);
1115 V((*slot
)->EffectState
,process
)(SamplesToDo
, (*slot
)->WetBuffer
[0],
1118 for(i
= 0;i
< SamplesToDo
;i
++)
1119 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1121 ALCdevice_Unlock(device
);
1123 /* Click-removal. Could do better; this only really handles immediate
1124 * changes between updates where a predictive sample could be
1125 * generated. Delays caused by effects and HRTF aren't caught. */
1126 if(device
->FmtChans
== DevFmtMono
)
1128 ALfloat offset
= device
->ClickRemoval
[FrontCenter
];
1129 if(offset
< (1.0f
/32768.0f
))
1131 else for(i
= 0;i
< SamplesToDo
;i
++)
1133 device
->DryBuffer
[FrontCenter
][i
] += offset
;
1134 offset
-= offset
* (1.0f
/256.0f
);
1136 device
->ClickRemoval
[FrontCenter
] = offset
+ device
->PendingClicks
[FrontCenter
];
1137 device
->PendingClicks
[FrontCenter
] = 0.0f
;
1139 else if(device
->FmtChans
== DevFmtStereo
)
1141 /* Assumes the first two channels are FrontLeft and FrontRight */
1142 for(c
= 0;c
< 2;c
++)
1144 ALfloat offset
= device
->ClickRemoval
[c
];
1145 if(offset
< (1.0f
/32768.0f
))
1147 else for(i
= 0;i
< SamplesToDo
;i
++)
1149 device
->DryBuffer
[c
][i
] += offset
;
1150 offset
-= offset
* (1.0f
/256.0f
);
1152 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1153 device
->PendingClicks
[c
] = 0.0f
;
1158 for(i
= 0;i
< SamplesToDo
;i
++)
1160 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1161 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1162 bs2b_cross_feed(device
->Bs2b
, samples
);
1163 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1164 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1170 for(c
= 0;c
< MaxChannels
;c
++)
1172 ALfloat offset
= device
->ClickRemoval
[c
];
1173 if(offset
< (1.0f
/32768.0f
))
1175 else for(i
= 0;i
< SamplesToDo
;i
++)
1177 device
->DryBuffer
[c
][i
] += offset
;
1178 offset
-= offset
* (1.0f
/256.0f
);
1180 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1181 device
->PendingClicks
[c
] = 0.0f
;
1188 switch(device
->FmtType
)
1191 bytes
= Write_ALbyte(device
, buffer
, SamplesToDo
);
1194 bytes
= Write_ALubyte(device
, buffer
, SamplesToDo
);
1197 bytes
= Write_ALshort(device
, buffer
, SamplesToDo
);
1200 bytes
= Write_ALushort(device
, buffer
, SamplesToDo
);
1203 bytes
= Write_ALint(device
, buffer
, SamplesToDo
);
1206 bytes
= Write_ALuint(device
, buffer
, SamplesToDo
);
1209 bytes
= Write_ALfloat(device
, buffer
, SamplesToDo
);
1213 buffer
= (ALubyte
*)buffer
+ bytes
;
1216 size
-= SamplesToDo
;
1219 RestoreFPUMode(&oldMode
);
1223 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1225 ALCcontext
*Context
;
1227 device
->Connected
= ALC_FALSE
;
1229 Context
= device
->ContextList
;
1232 ALsource
**src
, **src_end
;
1234 src
= Context
->ActiveSources
;
1235 src_end
= src
+ Context
->ActiveSourceCount
;
1236 while(src
!= src_end
)
1238 if((*src
)->state
== AL_PLAYING
)
1240 (*src
)->state
= AL_STOPPED
;
1241 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1242 (*src
)->position
= 0;
1243 (*src
)->position_fraction
= 0;
1247 Context
->ActiveSourceCount
= 0;
1249 Context
= Context
->next
;