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"
46 ALfloat ConeScale
= 1.0f
;
48 /* Localized Z scalar for mono sources */
49 ALfloat ZScale
= 1.0f
;
52 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
54 if(increment
== FRACTIONONE
)
55 return Resample_copy32_C
;
59 return Resample_point32_C
;
61 return Resample_lerp32_C
;
63 return Resample_cubic32_C
;
65 /* Shouldn't happen */
69 return Resample_point32_C
;
73 static DryMixerFunc
SelectHrtfMixer(void)
76 if((CPUCapFlags
&CPU_CAP_SSE
))
77 return MixDirect_Hrtf_SSE
;
80 if((CPUCapFlags
&CPU_CAP_NEON
))
81 return MixDirect_Hrtf_Neon
;
84 return MixDirect_Hrtf_C
;
87 static DryMixerFunc
SelectDirectMixer(void)
90 if((CPUCapFlags
&CPU_CAP_SSE
))
97 static WetMixerFunc
SelectSendMixer(void)
100 if((CPUCapFlags
&CPU_CAP_SSE
))
108 static __inline
void aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
110 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
111 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
112 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
115 static __inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
117 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
118 inVector1
[2]*inVector2
[2];
121 static __inline
void aluNormalize(ALfloat
*inVector
)
123 ALfloat lengthsqr
= aluDotproduct(inVector
, inVector
);
126 ALfloat inv_length
= 1.0f
/sqrtf(lengthsqr
);
127 inVector
[0] *= inv_length
;
128 inVector
[1] *= inv_length
;
129 inVector
[2] *= inv_length
;
133 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*RESTRICT matrix
)[4])
136 vector
[0], vector
[1], vector
[2], w
139 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
140 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
141 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
145 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
147 ALfloat N
[3], V
[3], U
[3], P
[3];
150 N
[0] = Listener
->Forward
[0];
151 N
[1] = Listener
->Forward
[1];
152 N
[2] = Listener
->Forward
[2];
154 V
[0] = Listener
->Up
[0];
155 V
[1] = Listener
->Up
[1];
156 V
[2] = Listener
->Up
[2];
158 /* Build and normalize right-vector */
159 aluCrossproduct(N
, V
, U
);
162 Listener
->Params
.Matrix
[0][0] = U
[0];
163 Listener
->Params
.Matrix
[0][1] = V
[0];
164 Listener
->Params
.Matrix
[0][2] = -N
[0];
165 Listener
->Params
.Matrix
[0][3] = 0.0f
;
166 Listener
->Params
.Matrix
[1][0] = U
[1];
167 Listener
->Params
.Matrix
[1][1] = V
[1];
168 Listener
->Params
.Matrix
[1][2] = -N
[1];
169 Listener
->Params
.Matrix
[1][3] = 0.0f
;
170 Listener
->Params
.Matrix
[2][0] = U
[2];
171 Listener
->Params
.Matrix
[2][1] = V
[2];
172 Listener
->Params
.Matrix
[2][2] = -N
[2];
173 Listener
->Params
.Matrix
[2][3] = 0.0f
;
174 Listener
->Params
.Matrix
[3][0] = 0.0f
;
175 Listener
->Params
.Matrix
[3][1] = 0.0f
;
176 Listener
->Params
.Matrix
[3][2] = 0.0f
;
177 Listener
->Params
.Matrix
[3][3] = 1.0f
;
179 P
[0] = Listener
->Position
[0];
180 P
[1] = Listener
->Position
[1];
181 P
[2] = Listener
->Position
[2];
182 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
183 Listener
->Params
.Matrix
[3][0] = -P
[0];
184 Listener
->Params
.Matrix
[3][1] = -P
[1];
185 Listener
->Params
.Matrix
[3][2] = -P
[2];
187 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
188 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
189 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
190 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
193 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
195 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
196 static const struct ChanMap StereoMap
[2] = {
197 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
198 { FrontRight
, 30.0f
* F_PI
/180.0f
}
200 static const struct ChanMap StereoWideMap
[2] = {
201 { FrontLeft
, -90.0f
* F_PI
/180.0f
},
202 { FrontRight
, 90.0f
* F_PI
/180.0f
}
204 static const struct ChanMap RearMap
[2] = {
205 { BackLeft
, -150.0f
* F_PI
/180.0f
},
206 { BackRight
, 150.0f
* F_PI
/180.0f
}
208 static const struct ChanMap QuadMap
[4] = {
209 { FrontLeft
, -45.0f
* F_PI
/180.0f
},
210 { FrontRight
, 45.0f
* F_PI
/180.0f
},
211 { BackLeft
, -135.0f
* F_PI
/180.0f
},
212 { BackRight
, 135.0f
* F_PI
/180.0f
}
214 static const struct ChanMap X51Map
[6] = {
215 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
216 { FrontRight
, 30.0f
* F_PI
/180.0f
},
217 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
219 { BackLeft
, -110.0f
* F_PI
/180.0f
},
220 { BackRight
, 110.0f
* F_PI
/180.0f
}
222 static const struct ChanMap X61Map
[7] = {
223 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
224 { FrontRight
, 30.0f
* F_PI
/180.0f
},
225 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
227 { BackCenter
, 180.0f
* F_PI
/180.0f
},
228 { SideLeft
, -90.0f
* F_PI
/180.0f
},
229 { SideRight
, 90.0f
* F_PI
/180.0f
}
231 static const struct ChanMap X71Map
[8] = {
232 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
233 { FrontRight
, 30.0f
* F_PI
/180.0f
},
234 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
236 { BackLeft
, -150.0f
* F_PI
/180.0f
},
237 { BackRight
, 150.0f
* F_PI
/180.0f
},
238 { SideLeft
, -90.0f
* F_PI
/180.0f
},
239 { SideRight
, 90.0f
* F_PI
/180.0f
}
242 ALCdevice
*Device
= ALContext
->Device
;
243 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
244 ALbufferlistitem
*BufferListItem
;
245 enum FmtChannels Channels
;
246 ALfloat (*SrcMatrix
)[MaxChannels
];
247 ALfloat DryGain
, DryGainHF
;
248 ALfloat WetGain
[MAX_SENDS
];
249 ALfloat WetGainHF
[MAX_SENDS
];
250 ALint NumSends
, Frequency
;
251 const struct ChanMap
*chans
= NULL
;
252 enum Resampler Resampler
;
253 ALint num_channels
= 0;
254 ALboolean DirectChannels
;
255 ALfloat hwidth
= 0.0f
;
260 /* Get device properties */
261 NumSends
= Device
->NumAuxSends
;
262 Frequency
= Device
->Frequency
;
264 /* Get listener properties */
265 ListenerGain
= ALContext
->Listener
->Gain
;
267 /* Get source properties */
268 SourceVolume
= ALSource
->Gain
;
269 MinVolume
= ALSource
->MinGain
;
270 MaxVolume
= ALSource
->MaxGain
;
271 Pitch
= ALSource
->Pitch
;
272 Resampler
= ALSource
->Resampler
;
273 DirectChannels
= ALSource
->DirectChannels
;
275 /* Calculate the stepping value */
277 BufferListItem
= ALSource
->queue
;
278 while(BufferListItem
!= NULL
)
281 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
283 ALsizei maxstep
= BUFFERSIZE
;
284 maxstep
-= ResamplerPadding
[Resampler
] +
285 ResamplerPrePadding
[Resampler
] + 1;
286 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
288 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
289 if(Pitch
> (ALfloat
)maxstep
)
290 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
293 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
294 if(ALSource
->Params
.Step
== 0)
295 ALSource
->Params
.Step
= 1;
297 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
299 Channels
= ALBuffer
->FmtChannels
;
302 BufferListItem
= BufferListItem
->next
;
304 if(!DirectChannels
&& Device
->Hrtf
)
305 ALSource
->Params
.DryMix
= SelectHrtfMixer();
307 ALSource
->Params
.DryMix
= SelectDirectMixer();
308 ALSource
->Params
.WetMix
= SelectSendMixer();
310 /* Calculate gains */
311 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
312 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
313 DryGainHF
= ALSource
->DirectGainHF
;
314 for(i
= 0;i
< NumSends
;i
++)
316 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
317 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
318 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
321 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
322 for(i
= 0;i
< MaxChannels
;i
++)
324 for(c
= 0;c
< MaxChannels
;c
++)
325 SrcMatrix
[i
][c
] = 0.0f
;
335 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
337 /* HACK: Place the stereo channels at +/-90 degrees when using non-
338 * HRTF stereo output. This helps reduce the "monoization" caused
339 * by them panning towards the center. */
340 if(Device
->FmtChans
== DevFmtStereo
&& !Device
->Hrtf
)
341 chans
= StereoWideMap
;
347 chans
= StereoWideMap
;
348 hwidth
= 60.0f
* F_PI
/180.0f
;
379 if(DirectChannels
!= AL_FALSE
)
381 for(c
= 0;c
< num_channels
;c
++)
383 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
385 enum Channel chan
= Device
->Speaker2Chan
[i
];
386 if(chan
== chans
[c
].channel
)
388 SrcMatrix
[c
][chan
] = DryGain
;
394 else if(Device
->Hrtf
)
396 for(c
= 0;c
< num_channels
;c
++)
398 if(chans
[c
].channel
== LFE
)
401 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
][0] = 0;
402 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
][1] = 0;
403 for(i
= 0;i
< HRIR_LENGTH
;i
++)
405 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
][i
][0] = 0.0f
;
406 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
][i
][1] = 0.0f
;
411 /* Get the static HRIR coefficients and delays for this
413 GetLerpedHrtfCoeffs(Device
->Hrtf
,
414 0.0f
, chans
[c
].angle
, DryGain
,
415 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[c
],
416 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[c
]);
419 ALSource
->Hrtf
.Counter
= 0;
420 ALSource
->Params
.Direct
.Hrtf
.Params
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
422 ALSource
->Params
.Direct
.Hrtf
.State
= &ALSource
->Hrtf
;
426 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf((float)Device
->NumChan
), hwidth
/F_PI
);
427 for(c
= 0;c
< num_channels
;c
++)
429 /* Special-case LFE */
430 if(chans
[c
].channel
== LFE
)
432 SrcMatrix
[c
][chans
[c
].channel
] = DryGain
;
435 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
440 ALSource
->Params
.Direct
.OutBuffer
= Device
->DryBuffer
;
441 ALSource
->Params
.Direct
.ClickRemoval
= Device
->ClickRemoval
;
442 ALSource
->Params
.Direct
.PendingClicks
= Device
->PendingClicks
;
443 for(i
= 0;i
< NumSends
;i
++)
445 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
448 Slot
= Device
->DefaultSlot
;
449 if(Slot
&& Slot
->effect
.type
== AL_EFFECT_NULL
)
451 ALSource
->Params
.Send
[i
].Slot
= Slot
;
452 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
455 /* Update filter coefficients. Calculations based on the I3DL2
457 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
459 /* We use two chained one-pole filters, so we need to take the
460 * square root of the squared gain, which is the same as the base
462 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
463 for(i
= 0;i
< NumSends
;i
++)
465 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
466 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
470 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
472 ALCdevice
*Device
= ALContext
->Device
;
473 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
474 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
475 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
476 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
477 ALfloat DopplerFactor
, SpeedOfSound
;
478 ALfloat AirAbsorptionFactor
;
479 ALfloat RoomAirAbsorption
[MAX_SENDS
];
480 ALbufferlistitem
*BufferListItem
;
482 ALfloat RoomAttenuation
[MAX_SENDS
];
483 ALfloat MetersPerUnit
;
484 ALfloat RoomRolloffBase
;
485 ALfloat RoomRolloff
[MAX_SENDS
];
486 ALfloat DecayDistance
[MAX_SENDS
];
489 ALboolean DryGainHFAuto
;
490 ALfloat WetGain
[MAX_SENDS
];
491 ALfloat WetGainHF
[MAX_SENDS
];
492 ALboolean WetGainAuto
;
493 ALboolean WetGainHFAuto
;
494 enum Resampler Resampler
;
502 for(i
= 0;i
< MAX_SENDS
;i
++)
505 /* Get context/device properties */
506 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
507 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
508 NumSends
= Device
->NumAuxSends
;
509 Frequency
= Device
->Frequency
;
511 /* Get listener properties */
512 ListenerGain
= ALContext
->Listener
->Gain
;
513 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
515 /* Get source properties */
516 SourceVolume
= ALSource
->Gain
;
517 MinVolume
= ALSource
->MinGain
;
518 MaxVolume
= ALSource
->MaxGain
;
519 Pitch
= ALSource
->Pitch
;
520 Resampler
= ALSource
->Resampler
;
521 Position
[0] = ALSource
->Position
[0];
522 Position
[1] = ALSource
->Position
[1];
523 Position
[2] = ALSource
->Position
[2];
524 Direction
[0] = ALSource
->Orientation
[0];
525 Direction
[1] = ALSource
->Orientation
[1];
526 Direction
[2] = ALSource
->Orientation
[2];
527 Velocity
[0] = ALSource
->Velocity
[0];
528 Velocity
[1] = ALSource
->Velocity
[1];
529 Velocity
[2] = ALSource
->Velocity
[2];
530 MinDist
= ALSource
->RefDistance
;
531 MaxDist
= ALSource
->MaxDistance
;
532 Rolloff
= ALSource
->RollOffFactor
;
533 InnerAngle
= ALSource
->InnerAngle
;
534 OuterAngle
= ALSource
->OuterAngle
;
535 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
536 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
537 WetGainAuto
= ALSource
->WetGainAuto
;
538 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
539 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
541 ALSource
->Params
.Direct
.OutBuffer
= Device
->DryBuffer
;
542 ALSource
->Params
.Direct
.ClickRemoval
= Device
->ClickRemoval
;
543 ALSource
->Params
.Direct
.PendingClicks
= Device
->PendingClicks
;
544 for(i
= 0;i
< NumSends
;i
++)
546 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
549 Slot
= Device
->DefaultSlot
;
550 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
553 RoomRolloff
[i
] = 0.0f
;
554 DecayDistance
[i
] = 0.0f
;
555 RoomAirAbsorption
[i
] = 1.0f
;
557 else if(Slot
->AuxSendAuto
)
559 RoomRolloff
[i
] = RoomRolloffBase
;
560 if(IsReverbEffect(Slot
->effect
.type
))
562 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
563 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
564 SPEEDOFSOUNDMETRESPERSEC
;
565 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
569 DecayDistance
[i
] = 0.0f
;
570 RoomAirAbsorption
[i
] = 1.0f
;
575 /* If the slot's auxiliary send auto is off, the data sent to the
576 * effect slot is the same as the dry path, sans filter effects */
577 RoomRolloff
[i
] = Rolloff
;
578 DecayDistance
[i
] = 0.0f
;
579 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
582 ALSource
->Params
.Send
[i
].Slot
= Slot
;
585 /* Transform source to listener space (convert to head relative) */
586 if(ALSource
->HeadRelative
== AL_FALSE
)
588 ALfloat (*RESTRICT Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
589 /* Transform source vectors */
590 aluMatrixVector(Position
, 1.0f
, Matrix
);
591 aluMatrixVector(Direction
, 0.0f
, Matrix
);
592 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
596 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
597 /* Offset the source velocity to be relative of the listener velocity */
598 Velocity
[0] += ListenerVel
[0];
599 Velocity
[1] += ListenerVel
[1];
600 Velocity
[2] += ListenerVel
[2];
603 SourceToListener
[0] = -Position
[0];
604 SourceToListener
[1] = -Position
[1];
605 SourceToListener
[2] = -Position
[2];
606 aluNormalize(SourceToListener
);
607 aluNormalize(Direction
);
609 /* Calculate distance attenuation */
610 Distance
= sqrtf(aluDotproduct(Position
, Position
));
611 ClampedDist
= Distance
;
614 for(i
= 0;i
< NumSends
;i
++)
615 RoomAttenuation
[i
] = 1.0f
;
616 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
617 ALContext
->DistanceModel
)
619 case InverseDistanceClamped
:
620 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
621 if(MaxDist
< MinDist
)
624 case InverseDistance
:
627 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
628 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
629 for(i
= 0;i
< NumSends
;i
++)
631 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
632 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
637 case LinearDistanceClamped
:
638 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
639 if(MaxDist
< MinDist
)
643 if(MaxDist
!= MinDist
)
645 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
646 Attenuation
= maxf(Attenuation
, 0.0f
);
647 for(i
= 0;i
< NumSends
;i
++)
649 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
650 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
655 case ExponentDistanceClamped
:
656 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
657 if(MaxDist
< MinDist
)
660 case ExponentDistance
:
661 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
663 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
664 for(i
= 0;i
< NumSends
;i
++)
665 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
669 case DisableDistance
:
670 ClampedDist
= MinDist
;
674 /* Source Gain + Attenuation */
675 DryGain
= SourceVolume
* Attenuation
;
676 for(i
= 0;i
< NumSends
;i
++)
677 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
679 /* Distance-based air absorption */
680 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
682 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
683 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
684 for(i
= 0;i
< NumSends
;i
++)
685 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
690 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
692 /* Apply a decay-time transformation to the wet path, based on the
693 * attenuation of the dry path.
695 * Using the apparent distance, based on the distance attenuation, the
696 * initial decay of the reverb effect is calculated and applied to the
699 for(i
= 0;i
< NumSends
;i
++)
701 if(DecayDistance
[i
] > 0.0f
)
702 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
706 /* Calculate directional soundcones */
707 Angle
= acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
* (360.0f
/F_PI
);
708 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
710 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
711 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
712 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
714 else if(Angle
> OuterAngle
)
716 ConeVolume
= ALSource
->OuterGain
;
717 ConeHF
= ALSource
->OuterGainHF
;
725 DryGain
*= ConeVolume
;
728 for(i
= 0;i
< NumSends
;i
++)
729 WetGain
[i
] *= ConeVolume
;
735 for(i
= 0;i
< NumSends
;i
++)
736 WetGainHF
[i
] *= ConeHF
;
739 /* Clamp to Min/Max Gain */
740 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
741 for(i
= 0;i
< NumSends
;i
++)
742 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
744 /* Apply gain and frequency filters */
745 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
746 DryGainHF
*= ALSource
->DirectGainHF
;
747 for(i
= 0;i
< NumSends
;i
++)
749 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
750 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
753 /* Calculate velocity-based doppler effect */
754 if(DopplerFactor
> 0.0f
)
756 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
759 if(SpeedOfSound
< 1.0f
)
761 DopplerFactor
*= 1.0f
/SpeedOfSound
;
765 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
766 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
768 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
769 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
772 BufferListItem
= ALSource
->queue
;
773 while(BufferListItem
!= NULL
)
776 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
778 /* Calculate fixed-point stepping value, based on the pitch, buffer
779 * frequency, and output frequency. */
780 ALsizei maxstep
= BUFFERSIZE
;
781 maxstep
-= ResamplerPadding
[Resampler
] +
782 ResamplerPrePadding
[Resampler
] + 1;
783 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
785 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
786 if(Pitch
> (ALfloat
)maxstep
)
787 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
790 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
791 if(ALSource
->Params
.Step
== 0)
792 ALSource
->Params
.Step
= 1;
794 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
798 BufferListItem
= BufferListItem
->next
;
801 ALSource
->Params
.DryMix
= SelectHrtfMixer();
803 ALSource
->Params
.DryMix
= SelectDirectMixer();
804 ALSource
->Params
.WetMix
= SelectSendMixer();
808 /* Use a binaural HRTF algorithm for stereo headphone playback */
809 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
811 if(Distance
> FLT_EPSILON
)
813 ALfloat invlen
= 1.0f
/Distance
;
814 Position
[0] *= invlen
;
815 Position
[1] *= invlen
;
816 Position
[2] *= invlen
;
818 /* Calculate elevation and azimuth only when the source is not at
819 * the listener. This prevents +0 and -0 Z from producing
820 * inconsistent panning. Also, clamp Y in case FP precision errors
821 * cause it to land outside of -1..+1. */
822 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
823 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
826 /* Check to see if the HRIR is already moving. */
827 if(ALSource
->Hrtf
.Moving
)
829 /* Calculate the normalized HRTF transition factor (delta). */
830 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
, DryGain
,
831 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
, Position
);
832 /* If the delta is large enough, get the moving HRIR target
833 * coefficients, target delays, steppping values, and counter. */
836 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
837 ev
, az
, DryGain
, delta
,
838 ALSource
->Hrtf
.Counter
,
839 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[0],
840 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[0],
841 ALSource
->Params
.Direct
.Hrtf
.Params
.CoeffStep
,
842 ALSource
->Params
.Direct
.Hrtf
.Params
.DelayStep
);
843 ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
= DryGain
;
844 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[0] = Position
[0];
845 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[1] = Position
[1];
846 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[2] = Position
[2];
851 /* Get the initial (static) HRIR coefficients and delays. */
852 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
853 ALSource
->Params
.Direct
.Hrtf
.Params
.Coeffs
[0],
854 ALSource
->Params
.Direct
.Hrtf
.Params
.Delay
[0]);
855 ALSource
->Hrtf
.Counter
= 0;
856 ALSource
->Hrtf
.Moving
= AL_TRUE
;
857 ALSource
->Params
.Direct
.Hrtf
.Params
.Gain
= DryGain
;
858 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[0] = Position
[0];
859 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[1] = Position
[1];
860 ALSource
->Params
.Direct
.Hrtf
.Params
.Dir
[2] = Position
[2];
862 ALSource
->Params
.Direct
.Hrtf
.Params
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
864 ALSource
->Params
.Direct
.Hrtf
.State
= &ALSource
->Hrtf
;
868 ALfloat (*Matrix
)[MaxChannels
] = ALSource
->Params
.Direct
.Gains
;
869 ALfloat DirGain
= 0.0f
;
872 for(i
= 0;i
< MaxChannels
;i
++)
874 for(j
= 0;j
< MaxChannels
;j
++)
878 /* Normalize the length, and compute panned gains. */
879 if(Distance
> FLT_EPSILON
)
881 ALfloat invlen
= 1.0f
/Distance
;
882 Position
[0] *= invlen
;
883 Position
[1] *= invlen
;
884 Position
[2] *= invlen
;
886 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
887 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
888 DryGain
*DirGain
, Matrix
[0]);
891 /* Adjustment for vertical offsets. Not the greatest, but simple
893 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
894 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
896 enum Channel chan
= Device
->Speaker2Chan
[i
];
897 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
900 for(i
= 0;i
< NumSends
;i
++)
901 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
903 /* Update filter coefficients. */
904 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
906 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
907 for(i
= 0;i
< NumSends
;i
++)
909 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
910 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
915 static __inline ALfloat
aluF2F(ALfloat val
)
917 static __inline ALint
aluF2I(ALfloat val
)
919 /* Clamp the value between -1 and +1. This handles that without branching. */
920 val
= val
+1.0f
- fabsf(val
-1.0f
);
921 val
= (val
-2.0f
+ fabsf(val
+2.0f
)) * 0.25f
;
922 /* Convert to a signed integer, between -2147483647 and +2147483647. */
923 return fastf2i((ALfloat
)(val
*2147483647.0));
925 static __inline ALuint
aluF2UI(ALfloat val
)
926 { return aluF2I(val
)+2147483648u; }
927 static __inline ALshort
aluF2S(ALfloat val
)
928 { return aluF2I(val
)>>16; }
929 static __inline ALushort
aluF2US(ALfloat val
)
930 { return aluF2S(val
)+32768; }
931 static __inline ALbyte
aluF2B(ALfloat val
)
932 { return aluF2I(val
)>>24; }
933 static __inline ALubyte
aluF2UB(ALfloat val
)
934 { return aluF2B(val
)+128; }
936 #define DECL_TEMPLATE(T, func) \
937 static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \
938 ALuint SamplesToDo) \
940 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
941 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
942 const ALuint *offsets = device->ChannelOffsets; \
945 for(j = 0;j < MaxChannels;j++) \
949 if(offsets[j] == INVALID_OFFSET) \
952 out = buffer + offsets[j]; \
953 for(i = 0;i < SamplesToDo;i++) \
954 out[i*numchans] = func(DryBuffer[j][i]); \
956 return SamplesToDo*numchans*sizeof(T); \
959 DECL_TEMPLATE(ALfloat
, aluF2F
)
960 DECL_TEMPLATE(ALuint
, aluF2UI
)
961 DECL_TEMPLATE(ALint
, aluF2I
)
962 DECL_TEMPLATE(ALushort
, aluF2US
)
963 DECL_TEMPLATE(ALshort
, aluF2S
)
964 DECL_TEMPLATE(ALubyte
, aluF2UB
)
965 DECL_TEMPLATE(ALbyte
, aluF2B
)
970 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
973 ALeffectslot
**slot
, **slot_end
;
974 ALsource
**src
, **src_end
;
979 SetMixerFPUMode(&oldMode
);
983 SamplesToDo
= minu(size
, BUFFERSIZE
);
984 for(c
= 0;c
< MaxChannels
;c
++)
985 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
987 ALCdevice_Lock(device
);
988 ctx
= device
->ContextList
;
991 ALenum DeferUpdates
= ctx
->DeferUpdates
;
992 ALenum UpdateSources
= AL_FALSE
;
995 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
998 CalcListenerParams(ctx
->Listener
);
1000 /* source processing */
1001 src
= ctx
->ActiveSources
;
1002 src_end
= src
+ ctx
->ActiveSourceCount
;
1003 while(src
!= src_end
)
1005 if((*src
)->state
!= AL_PLAYING
)
1007 --(ctx
->ActiveSourceCount
);
1008 *src
= *(--src_end
);
1012 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
1014 ALsource_Update(*src
, ctx
);
1016 MixSource(*src
, device
, SamplesToDo
);
1020 /* effect slot processing */
1021 slot
= ctx
->ActiveEffectSlots
;
1022 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
1023 while(slot
!= slot_end
)
1025 ALfloat offset
= (*slot
)->ClickRemoval
[0];
1026 if(offset
< (1.0f
/32768.0f
))
1028 else for(i
= 0;i
< SamplesToDo
;i
++)
1030 (*slot
)->WetBuffer
[0][i
] += offset
;
1031 offset
-= offset
* (1.0f
/256.0f
);
1033 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
1034 (*slot
)->PendingClicks
[0] = 0.0f
;
1036 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1037 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
1039 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1040 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
1042 for(i
= 0;i
< SamplesToDo
;i
++)
1043 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1051 slot
= &device
->DefaultSlot
;
1054 ALfloat offset
= (*slot
)->ClickRemoval
[0];
1055 if(offset
< (1.0f
/32768.0f
))
1057 else for(i
= 0;i
< SamplesToDo
;i
++)
1059 (*slot
)->WetBuffer
[0][i
] += offset
;
1060 offset
-= offset
* (1.0f
/256.0f
);
1062 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
1063 (*slot
)->PendingClicks
[0] = 0.0f
;
1065 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1066 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
1068 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1069 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
1071 for(i
= 0;i
< SamplesToDo
;i
++)
1072 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1074 ALCdevice_Unlock(device
);
1076 /* Click-removal. Could do better; this only really handles immediate
1077 * changes between updates where a predictive sample could be
1078 * generated. Delays caused by effects and HRTF aren't caught. */
1079 if(device
->FmtChans
== DevFmtMono
)
1081 ALfloat offset
= device
->ClickRemoval
[FrontCenter
];
1082 if(offset
< (1.0f
/32768.0f
))
1084 else for(i
= 0;i
< SamplesToDo
;i
++)
1086 device
->DryBuffer
[FrontCenter
][i
] += offset
;
1087 offset
-= offset
* (1.0f
/256.0f
);
1089 device
->ClickRemoval
[FrontCenter
] = offset
+ device
->PendingClicks
[FrontCenter
];
1090 device
->PendingClicks
[FrontCenter
] = 0.0f
;
1092 else if(device
->FmtChans
== DevFmtStereo
)
1094 /* Assumes the first two channels are FrontLeft and FrontRight */
1095 for(c
= 0;c
< 2;c
++)
1097 ALfloat offset
= device
->ClickRemoval
[c
];
1098 if(offset
< (1.0f
/32768.0f
))
1100 else for(i
= 0;i
< SamplesToDo
;i
++)
1102 device
->DryBuffer
[c
][i
] += offset
;
1103 offset
-= offset
* (1.0f
/256.0f
);
1105 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1106 device
->PendingClicks
[c
] = 0.0f
;
1111 for(i
= 0;i
< SamplesToDo
;i
++)
1113 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1114 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1115 bs2b_cross_feed(device
->Bs2b
, samples
);
1116 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1117 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1123 for(c
= 0;c
< MaxChannels
;c
++)
1125 ALfloat offset
= device
->ClickRemoval
[c
];
1126 if(offset
< (1.0f
/32768.0f
))
1128 else for(i
= 0;i
< SamplesToDo
;i
++)
1130 device
->DryBuffer
[c
][i
] += offset
;
1131 offset
-= offset
* (1.0f
/256.0f
);
1133 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1134 device
->PendingClicks
[c
] = 0.0f
;
1141 switch(device
->FmtType
)
1144 bytes
= Write_ALbyte(device
, buffer
, SamplesToDo
);
1147 bytes
= Write_ALubyte(device
, buffer
, SamplesToDo
);
1150 bytes
= Write_ALshort(device
, buffer
, SamplesToDo
);
1153 bytes
= Write_ALushort(device
, buffer
, SamplesToDo
);
1156 bytes
= Write_ALint(device
, buffer
, SamplesToDo
);
1159 bytes
= Write_ALuint(device
, buffer
, SamplesToDo
);
1162 bytes
= Write_ALfloat(device
, buffer
, SamplesToDo
);
1166 buffer
= (ALubyte
*)buffer
+ bytes
;
1169 size
-= SamplesToDo
;
1172 RestoreFPUMode(&oldMode
);
1176 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1178 ALCcontext
*Context
;
1180 device
->Connected
= ALC_FALSE
;
1182 Context
= device
->ContextList
;
1185 ALsource
**src
, **src_end
;
1187 src
= Context
->ActiveSources
;
1188 src_end
= src
+ Context
->ActiveSourceCount
;
1189 while(src
!= src_end
)
1191 if((*src
)->state
== AL_PLAYING
)
1193 (*src
)->state
= AL_STOPPED
;
1194 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1195 (*src
)->position
= 0;
1196 (*src
)->position_fraction
= 0;
1200 Context
->ActiveSourceCount
= 0;
1202 Context
= Context
->next
;