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
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
40 static __inline ALvoid
aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
42 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
43 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
44 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
47 static __inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
49 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
50 inVector1
[2]*inVector2
[2];
53 static __inline ALvoid
aluNormalize(ALfloat
*inVector
)
55 ALfloat length
, inverse_length
;
57 length
= aluSqrt(aluDotproduct(inVector
, inVector
));
60 inverse_length
= 1.0f
/length
;
61 inVector
[0] *= inverse_length
;
62 inVector
[1] *= inverse_length
;
63 inVector
[2] *= inverse_length
;
67 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
70 vector
[0], vector
[1], vector
[2], w
73 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
74 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
75 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
79 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
81 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
82 ALbufferlistitem
*BufferListItem
;
83 enum DevFmtChannels DevChans
;
84 enum FmtChannels Channels
;
85 ALfloat DryGain
, DryGainHF
;
86 ALfloat WetGain
[MAX_SENDS
];
87 ALfloat WetGainHF
[MAX_SENDS
];
88 ALint NumSends
, Frequency
;
94 /* Get device properties */
95 DevChans
= ALContext
->Device
->FmtChans
;
96 DupStereo
= ALContext
->Device
->DuplicateStereo
;
97 NumSends
= ALContext
->Device
->NumAuxSends
;
98 Frequency
= ALContext
->Device
->Frequency
;
100 /* Get listener properties */
101 ListenerGain
= ALContext
->Listener
.Gain
;
103 /* Get source properties */
104 SourceVolume
= ALSource
->flGain
;
105 MinVolume
= ALSource
->flMinGain
;
106 MaxVolume
= ALSource
->flMaxGain
;
107 Pitch
= ALSource
->flPitch
;
109 /* Calculate the stepping value */
111 BufferListItem
= ALSource
->queue
;
112 while(BufferListItem
!= NULL
)
115 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
117 ALint maxstep
= STACK_DATA_SIZE
/ FrameSizeFromFmt(ALBuffer
->FmtChannels
,
119 maxstep
-= ResamplerPadding
[ALSource
->Resampler
] +
120 ResamplerPrePadding
[ALSource
->Resampler
] + 1;
121 maxstep
= min(maxstep
, INT_MAX
>>FRACTIONBITS
);
123 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
124 if(Pitch
> (ALfloat
)maxstep
)
125 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
128 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
129 if(ALSource
->Params
.Step
== 0)
130 ALSource
->Params
.Step
= 1;
133 Channels
= ALBuffer
->FmtChannels
;
136 BufferListItem
= BufferListItem
->next
;
139 /* Calculate gains */
140 DryGain
= SourceVolume
;
141 DryGain
= __min(DryGain
,MaxVolume
);
142 DryGain
= __max(DryGain
,MinVolume
);
145 switch(ALSource
->DirectFilter
.type
)
147 case AL_FILTER_LOWPASS
:
148 DryGain
*= ALSource
->DirectFilter
.Gain
;
149 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
153 if(Channels
== FmtStereo
)
155 for(i
= 0;i
< MAXCHANNELS
;i
++)
156 ALSource
->Params
.DryGains
[i
] = 0.0f
;
158 if(DupStereo
== AL_FALSE
)
160 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
161 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
169 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
170 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
175 DryGain
*= aluSqrt(2.0f
/4.0f
);
176 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
177 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
178 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
179 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
183 DryGain
*= aluSqrt(2.0f
/4.0f
);
184 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
185 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
186 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
187 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
191 DryGain
*= aluSqrt(2.0f
/6.0f
);
192 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
193 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
194 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
195 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
196 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
197 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
204 for(i
= 0;i
< MAXCHANNELS
;i
++)
205 ALSource
->Params
.DryGains
[i
] = DryGain
* ListenerGain
;
208 for(i
= 0;i
< NumSends
;i
++)
210 WetGain
[i
] = SourceVolume
;
211 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
212 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
215 switch(ALSource
->Send
[i
].WetFilter
.type
)
217 case AL_FILTER_LOWPASS
:
218 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
219 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
223 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
226 /* Update filter coefficients. Calculations based on the I3DL2
228 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
230 /* We use two chained one-pole filters, so we need to take the
231 * square root of the squared gain, which is the same as the base
233 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
235 for(i
= 0;i
< NumSends
;i
++)
237 /* We use a one-pole filter, so we need to take the squared gain */
238 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
239 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
243 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
245 const ALCdevice
*Device
= ALContext
->Device
;
246 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,OrigDist
;
247 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
248 ALfloat Velocity
[3],ListenerVel
[3];
249 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
,OuterGainHF
;
250 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
251 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
252 ALfloat AirAbsorptionFactor
;
253 ALbufferlistitem
*BufferListItem
;
254 ALfloat Attenuation
, EffectiveDist
;
255 ALfloat RoomAttenuation
[MAX_SENDS
];
256 ALfloat MetersPerUnit
;
257 ALfloat RoomRolloff
[MAX_SENDS
];
260 ALfloat WetGain
[MAX_SENDS
];
261 ALfloat WetGainHF
[MAX_SENDS
];
262 ALfloat DirGain
, AmbientGain
;
263 const ALfloat
*SpeakerGain
;
272 for(i
= 0;i
< MAX_SENDS
;i
++)
275 //Get context properties
276 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
277 DopplerVelocity
= ALContext
->DopplerVelocity
;
278 SpeedOfSound
= ALContext
->flSpeedOfSound
;
279 NumSends
= Device
->NumAuxSends
;
280 Frequency
= Device
->Frequency
;
282 //Get listener properties
283 ListenerGain
= ALContext
->Listener
.Gain
;
284 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
285 memcpy(ListenerVel
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
287 //Get source properties
288 SourceVolume
= ALSource
->flGain
;
289 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
290 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
291 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
292 MinVolume
= ALSource
->flMinGain
;
293 MaxVolume
= ALSource
->flMaxGain
;
294 MinDist
= ALSource
->flRefDistance
;
295 MaxDist
= ALSource
->flMaxDistance
;
296 Rolloff
= ALSource
->flRollOffFactor
;
297 InnerAngle
= ALSource
->flInnerAngle
;
298 OuterAngle
= ALSource
->flOuterAngle
;
299 OuterGainHF
= ALSource
->OuterGainHF
;
300 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
302 //1. Translate Listener to origin (convert to head relative)
303 if(ALSource
->bHeadRelative
== AL_FALSE
)
305 ALfloat U
[3],V
[3],N
[3];
306 ALfloat Matrix
[4][4];
308 // Build transform matrix
309 memcpy(N
, ALContext
->Listener
.Forward
, sizeof(N
)); // At-vector
310 aluNormalize(N
); // Normalized At-vector
311 memcpy(V
, ALContext
->Listener
.Up
, sizeof(V
)); // Up-vector
312 aluNormalize(V
); // Normalized Up-vector
313 aluCrossproduct(N
, V
, U
); // Right-vector
314 aluNormalize(U
); // Normalized Right-vector
315 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
316 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
317 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
318 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
320 // Translate position
321 Position
[0] -= ALContext
->Listener
.Position
[0];
322 Position
[1] -= ALContext
->Listener
.Position
[1];
323 Position
[2] -= ALContext
->Listener
.Position
[2];
325 // Transform source position and direction into listener space
326 aluMatrixVector(Position
, 1.0f
, Matrix
);
327 aluMatrixVector(Direction
, 0.0f
, Matrix
);
328 // Transform source and listener velocity into listener space
329 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
330 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
333 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
335 SourceToListener
[0] = -Position
[0];
336 SourceToListener
[1] = -Position
[1];
337 SourceToListener
[2] = -Position
[2];
338 aluNormalize(SourceToListener
);
339 aluNormalize(Direction
);
341 //2. Calculate distance attenuation
342 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
346 for(i
= 0;i
< NumSends
;i
++)
348 RoomAttenuation
[i
] = 1.0f
;
350 RoomRolloff
[i
] = ALSource
->RoomRolloffFactor
;
351 if(ALSource
->Send
[i
].Slot
&&
352 (ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_REVERB
||
353 ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_EAXREVERB
))
354 RoomRolloff
[i
] += ALSource
->Send
[i
].Slot
->effect
.Reverb
.RoomRolloffFactor
;
357 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
358 ALContext
->DistanceModel
)
360 case AL_INVERSE_DISTANCE_CLAMPED
:
361 Distance
=__max(Distance
,MinDist
);
362 Distance
=__min(Distance
,MaxDist
);
363 if(MaxDist
< MinDist
)
366 case AL_INVERSE_DISTANCE
:
369 if((MinDist
+ (Rolloff
* (Distance
- MinDist
))) > 0.0f
)
370 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (Distance
- MinDist
)));
371 for(i
= 0;i
< NumSends
;i
++)
373 if((MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
))) > 0.0f
)
374 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
)));
379 case AL_LINEAR_DISTANCE_CLAMPED
:
380 Distance
=__max(Distance
,MinDist
);
381 Distance
=__min(Distance
,MaxDist
);
382 if(MaxDist
< MinDist
)
385 case AL_LINEAR_DISTANCE
:
386 if(MaxDist
!= MinDist
)
388 Attenuation
= 1.0f
- (Rolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
389 Attenuation
= __max(Attenuation
, 0.0f
);
390 for(i
= 0;i
< NumSends
;i
++)
392 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(Distance
-MinDist
)/(MaxDist
- MinDist
));
393 RoomAttenuation
[i
] = __max(RoomAttenuation
[i
], 0.0f
);
398 case AL_EXPONENT_DISTANCE_CLAMPED
:
399 Distance
=__max(Distance
,MinDist
);
400 Distance
=__min(Distance
,MaxDist
);
401 if(MaxDist
< MinDist
)
404 case AL_EXPONENT_DISTANCE
:
405 if(Distance
> 0.0f
&& MinDist
> 0.0f
)
407 Attenuation
= aluPow(Distance
/MinDist
, -Rolloff
);
408 for(i
= 0;i
< NumSends
;i
++)
409 RoomAttenuation
[i
] = aluPow(Distance
/MinDist
, -RoomRolloff
[i
]);
417 // Source Gain + Attenuation
418 DryGain
= SourceVolume
* Attenuation
;
419 for(i
= 0;i
< NumSends
;i
++)
420 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
422 EffectiveDist
= 0.0f
;
423 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
424 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
426 // Distance-based air absorption
427 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
431 // Absorption calculation is done in dB
432 absorb
= (AirAbsorptionFactor
*AIRABSORBGAINDBHF
) *
434 // Convert dB to linear gain before applying
435 absorb
= aluPow(10.0f
, absorb
/20.0f
);
440 //3. Apply directional soundcones
441 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * 180.0f
/M_PI
;
442 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
444 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
445 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
)*scale
);
446 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
448 else if(Angle
> OuterAngle
)
450 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
));
451 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
));
459 // Apply some high-frequency attenuation for sources behind the listener
460 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
461 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
462 // the same as SourceToListener[2]
463 Angle
= aluAcos(SourceToListener
[2]) * 180.0f
/M_PI
;
464 // Sources within the minimum distance attenuate less
465 if(OrigDist
< MinDist
)
466 Angle
*= OrigDist
/MinDist
;
469 ALfloat scale
= (Angle
-90.0f
) / (180.1f
-90.0f
); // .1 to account for fp errors
470 ConeHF
*= 1.0f
- (Device
->HeadDampen
*scale
);
473 DryGain
*= ConeVolume
;
474 if(ALSource
->DryGainHFAuto
)
477 // Clamp to Min/Max Gain
478 DryGain
= __min(DryGain
,MaxVolume
);
479 DryGain
= __max(DryGain
,MinVolume
);
481 for(i
= 0;i
< NumSends
;i
++)
483 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
485 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
487 ALSource
->Params
.Send
[i
].WetGain
= 0.0f
;
492 if(Slot
->AuxSendAuto
)
494 if(ALSource
->WetGainAuto
)
495 WetGain
[i
] *= ConeVolume
;
496 if(ALSource
->WetGainHFAuto
)
497 WetGainHF
[i
] *= ConeHF
;
499 // Clamp to Min/Max Gain
500 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
501 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
503 if(Slot
->effect
.type
== AL_EFFECT_REVERB
||
504 Slot
->effect
.type
== AL_EFFECT_EAXREVERB
)
506 /* Apply a decay-time transformation to the wet path, based on
507 * the attenuation of the dry path.
509 * Using the approximate (effective) source to listener
510 * distance, the initial decay of the reverb effect is
511 * calculated and applied to the wet path.
513 WetGain
[i
] *= aluPow(10.0f
, EffectiveDist
/
514 (SPEEDOFSOUNDMETRESPERSEC
*
515 Slot
->effect
.Reverb
.DecayTime
) *
518 WetGainHF
[i
] *= aluPow(Slot
->effect
.Reverb
.AirAbsorptionGainHF
,
519 AirAbsorptionFactor
* EffectiveDist
);
524 /* If the slot's auxiliary send auto is off, the data sent to the
525 * effect slot is the same as the dry path, sans filter effects */
526 WetGain
[i
] = DryGain
;
527 WetGainHF
[i
] = DryGainHF
;
530 switch(ALSource
->Send
[i
].WetFilter
.type
)
532 case AL_FILTER_LOWPASS
:
533 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
534 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
537 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
540 // Apply filter gains and filters
541 switch(ALSource
->DirectFilter
.type
)
543 case AL_FILTER_LOWPASS
:
544 DryGain
*= ALSource
->DirectFilter
.Gain
;
545 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
548 DryGain
*= ListenerGain
;
550 // Calculate Velocity
551 Pitch
= ALSource
->flPitch
;
552 if(DopplerFactor
!= 0.0f
)
555 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
558 VSS
= aluDotproduct(Velocity
, SourceToListener
);
559 if(VSS
>= MaxVelocity
)
560 VSS
= (MaxVelocity
- 1.0f
);
561 else if(VSS
<= -MaxVelocity
)
562 VSS
= -MaxVelocity
+ 1.0f
;
564 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
565 if(VLS
>= MaxVelocity
)
566 VLS
= (MaxVelocity
- 1.0f
);
567 else if(VLS
<= -MaxVelocity
)
568 VLS
= -MaxVelocity
+ 1.0f
;
570 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
571 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
574 BufferListItem
= ALSource
->queue
;
575 while(BufferListItem
!= NULL
)
578 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
580 ALint maxstep
= STACK_DATA_SIZE
/ FrameSizeFromFmt(ALBuffer
->FmtChannels
,
582 maxstep
-= ResamplerPadding
[ALSource
->Resampler
] +
583 ResamplerPrePadding
[ALSource
->Resampler
] + 1;
584 maxstep
= min(maxstep
, INT_MAX
>>FRACTIONBITS
);
586 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
587 if(Pitch
> (ALfloat
)maxstep
)
588 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
591 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
592 if(ALSource
->Params
.Step
== 0)
593 ALSource
->Params
.Step
= 1;
597 BufferListItem
= BufferListItem
->next
;
600 // Use energy-preserving panning algorithm for multi-speaker playback
601 length
= __max(OrigDist
, MinDist
);
604 ALfloat invlen
= 1.0f
/length
;
605 Position
[0] *= invlen
;
606 Position
[1] *= invlen
;
607 Position
[2] *= invlen
;
610 pos
= aluCart2LUTpos(-Position
[2], Position
[0]);
611 SpeakerGain
= &Device
->PanningLUT
[MAXCHANNELS
* pos
];
613 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
614 // elevation adjustment for directional gain. this sucks, but
615 // has low complexity
616 AmbientGain
= aluSqrt(1.0/Device
->NumChan
);
617 for(s
= 0;s
< MAXCHANNELS
;s
++)
618 ALSource
->Params
.DryGains
[s
] = 0.0f
;
619 for(s
= 0;s
< (ALsizei
)Device
->NumChan
;s
++)
621 Channel chan
= Device
->Speaker2Chan
[s
];
622 ALfloat gain
= AmbientGain
+ (SpeakerGain
[chan
]-AmbientGain
)*DirGain
;
623 ALSource
->Params
.DryGains
[chan
] = DryGain
* gain
;
626 /* Update filter coefficients. */
627 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
629 /* Spatialized sources use four chained one-pole filters, so we need to
630 * take the fourth root of the squared gain, which is the same as the
631 * square root of the base gain. */
632 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(aluSqrt(DryGainHF
), cw
);
634 for(i
= 0;i
< NumSends
;i
++)
636 /* The wet path uses two chained one-pole filters, so take the
637 * base gain (square root of the squared gain) */
638 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= lpCoeffCalc(WetGainHF
[i
], cw
);
643 static __inline ALfloat
aluF2F(ALfloat val
)
647 static __inline ALushort
aluF2US(ALfloat val
)
649 if(val
> 1.0f
) return 65535;
650 if(val
< -1.0f
) return 0;
651 return (ALint
)(val
*32767.0f
) + 32768;
653 static __inline ALshort
aluF2S(ALfloat val
)
655 if(val
> 1.0f
) return 32767;
656 if(val
< -1.0f
) return -32768;
657 return (ALint
)(val
*32767.0f
);
659 static __inline ALubyte
aluF2UB(ALfloat val
)
661 ALushort i
= aluF2US(val
);
664 static __inline ALbyte
aluF2B(ALfloat val
)
666 ALshort i
= aluF2S(val
);
670 static const Channel MonoChans
[] = { FRONT_CENTER
};
671 static const Channel StereoChans
[] = { FRONT_LEFT
, FRONT_RIGHT
};
672 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
673 BACK_LEFT
, BACK_RIGHT
};
674 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
676 BACK_LEFT
, BACK_RIGHT
};
677 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_LEFT
,
678 FRONT_CENTER
, LFE
, BACK_CENTER
,
679 SIDE_LEFT
, SIDE_RIGHT
};
680 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
682 BACK_LEFT
, BACK_RIGHT
,
683 SIDE_LEFT
, SIDE_RIGHT
};
685 #define DECL_TEMPLATE(T, chans,N, func) \
686 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
688 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
689 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
690 const ALuint *ChanMap = device->DevChannels; \
693 for(i = 0;i < SamplesToDo;i++) \
695 for(j = 0;j < N;j++) \
697 ALfloat samp = 0.0f; \
698 for(c = 0;c < MAXCHANNELS;c++) \
699 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
700 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
702 buffer = ((T*)buffer) + N; \
706 DECL_TEMPLATE(ALfloat
, MonoChans
,1, aluF2F
)
707 DECL_TEMPLATE(ALfloat
, QuadChans
,4, aluF2F
)
708 DECL_TEMPLATE(ALfloat
, X51Chans
,6, aluF2F
)
709 DECL_TEMPLATE(ALfloat
, X61Chans
,7, aluF2F
)
710 DECL_TEMPLATE(ALfloat
, X71Chans
,8, aluF2F
)
712 DECL_TEMPLATE(ALushort
, MonoChans
,1, aluF2US
)
713 DECL_TEMPLATE(ALushort
, QuadChans
,4, aluF2US
)
714 DECL_TEMPLATE(ALushort
, X51Chans
,6, aluF2US
)
715 DECL_TEMPLATE(ALushort
, X61Chans
,7, aluF2US
)
716 DECL_TEMPLATE(ALushort
, X71Chans
,8, aluF2US
)
718 DECL_TEMPLATE(ALshort
, MonoChans
,1, aluF2S
)
719 DECL_TEMPLATE(ALshort
, QuadChans
,4, aluF2S
)
720 DECL_TEMPLATE(ALshort
, X51Chans
,6, aluF2S
)
721 DECL_TEMPLATE(ALshort
, X61Chans
,7, aluF2S
)
722 DECL_TEMPLATE(ALshort
, X71Chans
,8, aluF2S
)
724 DECL_TEMPLATE(ALubyte
, MonoChans
,1, aluF2UB
)
725 DECL_TEMPLATE(ALubyte
, QuadChans
,4, aluF2UB
)
726 DECL_TEMPLATE(ALubyte
, X51Chans
,6, aluF2UB
)
727 DECL_TEMPLATE(ALubyte
, X61Chans
,7, aluF2UB
)
728 DECL_TEMPLATE(ALubyte
, X71Chans
,8, aluF2UB
)
730 DECL_TEMPLATE(ALbyte
, MonoChans
,1, aluF2B
)
731 DECL_TEMPLATE(ALbyte
, QuadChans
,4, aluF2B
)
732 DECL_TEMPLATE(ALbyte
, X51Chans
,6, aluF2B
)
733 DECL_TEMPLATE(ALbyte
, X61Chans
,7, aluF2B
)
734 DECL_TEMPLATE(ALbyte
, X71Chans
,8, aluF2B
)
738 #define DECL_TEMPLATE(T, chans,N, func) \
739 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
741 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
742 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
743 const ALuint *ChanMap = device->DevChannels; \
748 for(i = 0;i < SamplesToDo;i++) \
750 float samples[2] = { 0.0f, 0.0f }; \
751 for(c = 0;c < MAXCHANNELS;c++) \
753 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
754 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
756 bs2b_cross_feed(device->Bs2b, samples); \
757 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
758 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
759 buffer = ((T*)buffer) + 2; \
764 for(i = 0;i < SamplesToDo;i++) \
766 for(j = 0;j < N;j++) \
768 ALfloat samp = 0.0f; \
769 for(c = 0;c < MAXCHANNELS;c++) \
770 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
771 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
773 buffer = ((T*)buffer) + N; \
778 DECL_TEMPLATE(ALfloat
, StereoChans
,2, aluF2F
)
779 DECL_TEMPLATE(ALushort
, StereoChans
,2, aluF2US
)
780 DECL_TEMPLATE(ALshort
, StereoChans
,2, aluF2S
)
781 DECL_TEMPLATE(ALubyte
, StereoChans
,2, aluF2UB
)
782 DECL_TEMPLATE(ALbyte
, StereoChans
,2, aluF2B
)
786 #define DECL_TEMPLATE(T, func) \
787 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
789 switch(device->FmtChans) \
792 Write_##T##_MonoChans(device, buffer, SamplesToDo); \
795 Write_##T##_StereoChans(device, buffer, SamplesToDo); \
798 Write_##T##_QuadChans(device, buffer, SamplesToDo); \
801 Write_##T##_X51Chans(device, buffer, SamplesToDo); \
804 Write_##T##_X61Chans(device, buffer, SamplesToDo); \
807 Write_##T##_X71Chans(device, buffer, SamplesToDo); \
812 DECL_TEMPLATE(ALfloat
, aluF2F
)
813 DECL_TEMPLATE(ALushort
, aluF2US
)
814 DECL_TEMPLATE(ALshort
, aluF2S
)
815 DECL_TEMPLATE(ALubyte
, aluF2UB
)
816 DECL_TEMPLATE(ALbyte
, aluF2B
)
820 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
823 ALeffectslot
*ALEffectSlot
;
824 ALCcontext
**ctx
, **ctx_end
;
825 ALsource
**src
, **src_end
;
830 #if defined(HAVE_FESETROUND)
831 fpuState
= fegetround();
832 fesetround(FE_TOWARDZERO
);
833 #elif defined(HAVE__CONTROLFP)
834 fpuState
= _controlfp(_RC_CHOP
, _MCW_RC
);
841 /* Setup variables */
842 SamplesToDo
= min(size
, BUFFERSIZE
);
844 /* Clear mixing buffer */
845 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
847 SuspendContext(NULL
);
848 ctx
= device
->Contexts
;
849 ctx_end
= ctx
+ device
->NumContexts
;
850 while(ctx
!= ctx_end
)
852 SuspendContext(*ctx
);
854 src
= (*ctx
)->ActiveSources
;
855 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
856 while(src
!= src_end
)
858 if((*src
)->state
!= AL_PLAYING
)
860 --((*ctx
)->ActiveSourceCount
);
865 if((*src
)->NeedsUpdate
)
867 ALsource_Update(*src
, *ctx
);
868 (*src
)->NeedsUpdate
= AL_FALSE
;
871 MixSource(*src
, device
, SamplesToDo
);
875 /* effect slot processing */
876 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
878 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
880 for(i
= 0;i
< SamplesToDo
;i
++)
882 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
883 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
887 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
888 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
891 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
892 SamplesToDo
, ALEffectSlot
->WetBuffer
,
895 for(i
= 0;i
< SamplesToDo
;i
++)
896 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
899 ProcessContext(*ctx
);
902 ProcessContext(NULL
);
904 //Post processing loop
905 for(i
= 0;i
< SamplesToDo
;i
++)
907 for(c
= 0;c
< MAXCHANNELS
;c
++)
909 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
910 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
913 for(i
= 0;i
< MAXCHANNELS
;i
++)
915 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
916 device
->PendingClicks
[i
] = 0.0f
;
919 switch(device
->FmtType
)
922 Write_ALbyte(device
, buffer
, SamplesToDo
);
925 Write_ALubyte(device
, buffer
, SamplesToDo
);
928 Write_ALshort(device
, buffer
, SamplesToDo
);
931 Write_ALushort(device
, buffer
, SamplesToDo
);
934 Write_ALfloat(device
, buffer
, SamplesToDo
);
941 #if defined(HAVE_FESETROUND)
942 fesetround(fpuState
);
943 #elif defined(HAVE__CONTROLFP)
944 _controlfp(fpuState
, _MCW_RC
);
949 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
953 SuspendContext(NULL
);
954 for(i
= 0;i
< device
->NumContexts
;i
++)
956 ALCcontext
*Context
= device
->Contexts
[i
];
960 SuspendContext(Context
);
962 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
964 source
= Context
->SourceMap
.array
[pos
].value
;
965 if(source
->state
== AL_PLAYING
)
967 source
->state
= AL_STOPPED
;
968 source
->BuffersPlayed
= source
->BuffersInQueue
;
969 source
->position
= 0;
970 source
->position_fraction
= 0;
973 ProcessContext(Context
);
976 device
->Connected
= ALC_FALSE
;
977 ProcessContext(NULL
);