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 ALfloat DryGain
, DryGainHF
;
84 ALfloat WetGain
[MAX_SENDS
];
85 ALfloat WetGainHF
[MAX_SENDS
];
86 ALint NumSends
, Frequency
;
94 //Get context properties
95 Format
= ALContext
->Device
->Format
;
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
;
108 //1. Multi-channel buffers always play "normal"
110 Pitch
= ALSource
->flPitch
;
111 BufferListItem
= ALSource
->queue
;
112 while(BufferListItem
!= NULL
)
115 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
117 Channels
= aluChannelsFromFormat(ALBuffer
->format
);
118 Pitch
= Pitch
* ALBuffer
->frequency
/ Frequency
;
121 BufferListItem
= BufferListItem
->next
;
124 if(Pitch
> (float)MAX_PITCH
)
125 ALSource
->Params
.Step
= MAX_PITCH
<<FRACTIONBITS
;
126 else if(!(Pitch
> 0.0f
))
127 ALSource
->Params
.Step
= 1<<FRACTIONBITS
;
130 ALSource
->Params
.Step
= Pitch
*(1<<FRACTIONBITS
);
131 if(ALSource
->Params
.Step
== 0)
132 ALSource
->Params
.Step
= 1;
135 DryGain
= SourceVolume
;
136 DryGain
= __min(DryGain
,MaxVolume
);
137 DryGain
= __max(DryGain
,MinVolume
);
140 switch(ALSource
->DirectFilter
.type
)
142 case AL_FILTER_LOWPASS
:
143 DryGain
*= ALSource
->DirectFilter
.Gain
;
144 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
150 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
151 ALSource
->Params
.DryGains
[i
] = 0.0f
;
153 if(DupStereo
== AL_FALSE
)
155 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
156 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
162 case AL_FORMAT_MONO8
:
163 case AL_FORMAT_MONO16
:
164 case AL_FORMAT_MONO_FLOAT32
:
165 case AL_FORMAT_STEREO8
:
166 case AL_FORMAT_STEREO16
:
167 case AL_FORMAT_STEREO_FLOAT32
:
168 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
169 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
172 case AL_FORMAT_QUAD8
:
173 case AL_FORMAT_QUAD16
:
174 case AL_FORMAT_QUAD32
:
175 case AL_FORMAT_51CHN8
:
176 case AL_FORMAT_51CHN16
:
177 case AL_FORMAT_51CHN32
:
178 DryGain
*= aluSqrt(2.0f
/4.0f
);
179 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
180 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
181 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
182 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
185 case AL_FORMAT_61CHN8
:
186 case AL_FORMAT_61CHN16
:
187 case AL_FORMAT_61CHN32
:
188 DryGain
*= aluSqrt(2.0f
/4.0f
);
189 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
190 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
191 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
192 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
195 case AL_FORMAT_71CHN8
:
196 case AL_FORMAT_71CHN16
:
197 case AL_FORMAT_71CHN32
:
198 DryGain
*= aluSqrt(2.0f
/6.0f
);
199 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
200 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
201 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
202 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
203 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
204 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
214 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
215 ALSource
->Params
.DryGains
[i
] = DryGain
* ListenerGain
;
218 for(i
= 0;i
< NumSends
;i
++)
220 WetGain
[i
] = SourceVolume
;
221 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
222 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
225 switch(ALSource
->Send
[i
].WetFilter
.type
)
227 case AL_FILTER_LOWPASS
:
228 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
229 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
233 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
236 /* Update filter coefficients. Calculations based on the I3DL2
238 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
240 /* We use two chained one-pole filters, so we need to take the
241 * square root of the squared gain, which is the same as the base
243 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
245 for(i
= 0;i
< NumSends
;i
++)
247 /* We use a one-pole filter, so we need to take the squared gain */
248 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
249 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
253 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
255 const ALCdevice
*Device
= ALContext
->Device
;
256 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,OrigDist
;
257 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
258 ALfloat Velocity
[3],ListenerVel
[3];
259 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
,OuterGainHF
;
260 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
261 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
262 ALfloat AirAbsorptionFactor
;
263 ALbufferlistitem
*BufferListItem
;
264 ALfloat Attenuation
, EffectiveDist
;
265 ALfloat RoomAttenuation
[MAX_SENDS
];
266 ALfloat MetersPerUnit
;
267 ALfloat RoomRolloff
[MAX_SENDS
];
270 ALfloat WetGain
[MAX_SENDS
];
271 ALfloat WetGainHF
[MAX_SENDS
];
272 ALfloat DirGain
, AmbientGain
;
273 const ALfloat
*SpeakerGain
;
282 for(i
= 0;i
< MAX_SENDS
;i
++)
285 //Get context properties
286 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
287 DopplerVelocity
= ALContext
->DopplerVelocity
;
288 SpeedOfSound
= ALContext
->flSpeedOfSound
;
289 NumSends
= Device
->NumAuxSends
;
290 Frequency
= Device
->Frequency
;
292 //Get listener properties
293 ListenerGain
= ALContext
->Listener
.Gain
;
294 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
295 memcpy(ListenerVel
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
297 //Get source properties
298 SourceVolume
= ALSource
->flGain
;
299 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
300 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
301 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
302 MinVolume
= ALSource
->flMinGain
;
303 MaxVolume
= ALSource
->flMaxGain
;
304 MinDist
= ALSource
->flRefDistance
;
305 MaxDist
= ALSource
->flMaxDistance
;
306 Rolloff
= ALSource
->flRollOffFactor
;
307 InnerAngle
= ALSource
->flInnerAngle
;
308 OuterAngle
= ALSource
->flOuterAngle
;
309 OuterGainHF
= ALSource
->OuterGainHF
;
310 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
312 //1. Translate Listener to origin (convert to head relative)
313 if(ALSource
->bHeadRelative
== AL_FALSE
)
315 ALfloat U
[3],V
[3],N
[3];
316 ALfloat Matrix
[4][4];
318 // Build transform matrix
319 memcpy(N
, ALContext
->Listener
.Forward
, sizeof(N
)); // At-vector
320 aluNormalize(N
); // Normalized At-vector
321 memcpy(V
, ALContext
->Listener
.Up
, sizeof(V
)); // Up-vector
322 aluNormalize(V
); // Normalized Up-vector
323 aluCrossproduct(N
, V
, U
); // Right-vector
324 aluNormalize(U
); // Normalized Right-vector
325 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
326 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
327 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
328 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
330 // Translate position
331 Position
[0] -= ALContext
->Listener
.Position
[0];
332 Position
[1] -= ALContext
->Listener
.Position
[1];
333 Position
[2] -= ALContext
->Listener
.Position
[2];
335 // Transform source position and direction into listener space
336 aluMatrixVector(Position
, 1.0f
, Matrix
);
337 aluMatrixVector(Direction
, 0.0f
, Matrix
);
338 // Transform source and listener velocity into listener space
339 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
340 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
343 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
345 SourceToListener
[0] = -Position
[0];
346 SourceToListener
[1] = -Position
[1];
347 SourceToListener
[2] = -Position
[2];
348 aluNormalize(SourceToListener
);
349 aluNormalize(Direction
);
351 //2. Calculate distance attenuation
352 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
356 for(i
= 0;i
< NumSends
;i
++)
358 RoomAttenuation
[i
] = 1.0f
;
360 RoomRolloff
[i
] = ALSource
->RoomRolloffFactor
;
361 if(ALSource
->Send
[i
].Slot
&&
362 (ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_REVERB
||
363 ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_EAXREVERB
))
364 RoomRolloff
[i
] += ALSource
->Send
[i
].Slot
->effect
.Reverb
.RoomRolloffFactor
;
367 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
368 ALContext
->DistanceModel
)
370 case AL_INVERSE_DISTANCE_CLAMPED
:
371 Distance
=__max(Distance
,MinDist
);
372 Distance
=__min(Distance
,MaxDist
);
373 if(MaxDist
< MinDist
)
376 case AL_INVERSE_DISTANCE
:
379 if((MinDist
+ (Rolloff
* (Distance
- MinDist
))) > 0.0f
)
380 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (Distance
- MinDist
)));
381 for(i
= 0;i
< NumSends
;i
++)
383 if((MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
))) > 0.0f
)
384 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
)));
389 case AL_LINEAR_DISTANCE_CLAMPED
:
390 Distance
=__max(Distance
,MinDist
);
391 Distance
=__min(Distance
,MaxDist
);
392 if(MaxDist
< MinDist
)
395 case AL_LINEAR_DISTANCE
:
396 if(MaxDist
!= MinDist
)
398 Attenuation
= 1.0f
- (Rolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
399 Attenuation
= __max(Attenuation
, 0.0f
);
400 for(i
= 0;i
< NumSends
;i
++)
402 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(Distance
-MinDist
)/(MaxDist
- MinDist
));
403 RoomAttenuation
[i
] = __max(RoomAttenuation
[i
], 0.0f
);
408 case AL_EXPONENT_DISTANCE_CLAMPED
:
409 Distance
=__max(Distance
,MinDist
);
410 Distance
=__min(Distance
,MaxDist
);
411 if(MaxDist
< MinDist
)
414 case AL_EXPONENT_DISTANCE
:
415 if(Distance
> 0.0f
&& MinDist
> 0.0f
)
417 Attenuation
= aluPow(Distance
/MinDist
, -Rolloff
);
418 for(i
= 0;i
< NumSends
;i
++)
419 RoomAttenuation
[i
] = aluPow(Distance
/MinDist
, -RoomRolloff
[i
]);
427 // Source Gain + Attenuation
428 DryGain
= SourceVolume
* Attenuation
;
429 for(i
= 0;i
< NumSends
;i
++)
430 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
432 EffectiveDist
= 0.0f
;
433 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
434 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
436 // Distance-based air absorption
437 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
441 // Absorption calculation is done in dB
442 absorb
= (AirAbsorptionFactor
*AIRABSORBGAINDBHF
) *
444 // Convert dB to linear gain before applying
445 absorb
= aluPow(10.0f
, absorb
/20.0f
);
450 //3. Apply directional soundcones
451 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * 180.0f
/M_PI
;
452 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
454 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
455 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
)*scale
);
456 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
458 else if(Angle
> OuterAngle
)
460 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
));
461 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
));
469 // Apply some high-frequency attenuation for sources behind the listener
470 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
471 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
472 // the same as SourceToListener[2]
473 Angle
= aluAcos(SourceToListener
[2]) * 180.0f
/M_PI
;
474 // Sources within the minimum distance attenuate less
475 if(OrigDist
< MinDist
)
476 Angle
*= OrigDist
/MinDist
;
479 ALfloat scale
= (Angle
-90.0f
) / (180.1f
-90.0f
); // .1 to account for fp errors
480 ConeHF
*= 1.0f
- (Device
->HeadDampen
*scale
);
483 DryGain
*= ConeVolume
;
484 if(ALSource
->DryGainHFAuto
)
487 // Clamp to Min/Max Gain
488 DryGain
= __min(DryGain
,MaxVolume
);
489 DryGain
= __max(DryGain
,MinVolume
);
491 for(i
= 0;i
< NumSends
;i
++)
493 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
495 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
497 ALSource
->Params
.Send
[i
].WetGain
= 0.0f
;
502 if(Slot
->AuxSendAuto
)
504 if(ALSource
->WetGainAuto
)
505 WetGain
[i
] *= ConeVolume
;
506 if(ALSource
->WetGainHFAuto
)
507 WetGainHF
[i
] *= ConeHF
;
509 // Clamp to Min/Max Gain
510 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
511 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
513 if(Slot
->effect
.type
== AL_EFFECT_REVERB
||
514 Slot
->effect
.type
== AL_EFFECT_EAXREVERB
)
516 /* Apply a decay-time transformation to the wet path, based on
517 * the attenuation of the dry path.
519 * Using the approximate (effective) source to listener
520 * distance, the initial decay of the reverb effect is
521 * calculated and applied to the wet path.
523 WetGain
[i
] *= aluPow(10.0f
, EffectiveDist
/
524 (SPEEDOFSOUNDMETRESPERSEC
*
525 Slot
->effect
.Reverb
.DecayTime
) *
528 WetGainHF
[i
] *= aluPow(Slot
->effect
.Reverb
.AirAbsorptionGainHF
,
529 AirAbsorptionFactor
* EffectiveDist
);
534 /* If the slot's auxiliary send auto is off, the data sent to the
535 * effect slot is the same as the dry path, sans filter effects */
536 WetGain
[i
] = DryGain
;
537 WetGainHF
[i
] = DryGainHF
;
540 switch(ALSource
->Send
[i
].WetFilter
.type
)
542 case AL_FILTER_LOWPASS
:
543 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
544 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
547 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
550 // Apply filter gains and filters
551 switch(ALSource
->DirectFilter
.type
)
553 case AL_FILTER_LOWPASS
:
554 DryGain
*= ALSource
->DirectFilter
.Gain
;
555 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
558 DryGain
*= ListenerGain
;
560 // Calculate Velocity
561 Pitch
= ALSource
->flPitch
;
562 if(DopplerFactor
!= 0.0f
)
565 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
568 VSS
= aluDotproduct(Velocity
, SourceToListener
);
569 if(VSS
>= MaxVelocity
)
570 VSS
= (MaxVelocity
- 1.0f
);
571 else if(VSS
<= -MaxVelocity
)
572 VSS
= -MaxVelocity
+ 1.0f
;
574 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
575 if(VLS
>= MaxVelocity
)
576 VLS
= (MaxVelocity
- 1.0f
);
577 else if(VLS
<= -MaxVelocity
)
578 VLS
= -MaxVelocity
+ 1.0f
;
580 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
581 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
584 BufferListItem
= ALSource
->queue
;
585 while(BufferListItem
!= NULL
)
588 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
590 Pitch
= Pitch
* ALBuffer
->frequency
/ Frequency
;
593 BufferListItem
= BufferListItem
->next
;
596 if(Pitch
> (float)MAX_PITCH
)
597 ALSource
->Params
.Step
= MAX_PITCH
<<FRACTIONBITS
;
598 else if(!(Pitch
> 0.0f
))
599 ALSource
->Params
.Step
= 1<<FRACTIONBITS
;
602 ALSource
->Params
.Step
= Pitch
*(1<<FRACTIONBITS
);
603 if(ALSource
->Params
.Step
== 0)
604 ALSource
->Params
.Step
= 1;
607 // Use energy-preserving panning algorithm for multi-speaker playback
608 length
= __max(OrigDist
, MinDist
);
611 ALfloat invlen
= 1.0f
/length
;
612 Position
[0] *= invlen
;
613 Position
[1] *= invlen
;
614 Position
[2] *= invlen
;
617 pos
= aluCart2LUTpos(-Position
[2], Position
[0]);
618 SpeakerGain
= &Device
->PanningLUT
[OUTPUTCHANNELS
* pos
];
620 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
621 // elevation adjustment for directional gain. this sucks, but
622 // has low complexity
623 AmbientGain
= aluSqrt(1.0/Device
->NumChan
);
624 for(s
= 0;s
< OUTPUTCHANNELS
;s
++)
625 ALSource
->Params
.DryGains
[s
] = 0.0f
;
626 for(s
= 0;s
< (ALsizei
)Device
->NumChan
;s
++)
628 Channel chan
= Device
->Speaker2Chan
[s
];
629 ALfloat gain
= AmbientGain
+ (SpeakerGain
[chan
]-AmbientGain
)*DirGain
;
630 ALSource
->Params
.DryGains
[chan
] = DryGain
* gain
;
633 /* Update filter coefficients. */
634 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
636 /* Spatialized sources use four chained one-pole filters, so we need to
637 * take the fourth root of the squared gain, which is the same as the
638 * square root of the base gain. */
639 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(aluSqrt(DryGainHF
), cw
);
641 for(i
= 0;i
< NumSends
;i
++)
643 /* The wet path uses two chained one-pole filters, so take the
644 * base gain (square root of the squared gain) */
645 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= lpCoeffCalc(WetGainHF
[i
], cw
);
650 static __inline ALfloat
aluF2F(ALfloat Value
)
654 static __inline ALshort
aluF2S(ALfloat Value
)
658 if(Value
<= -1.0f
) i
= -32768;
659 else if(Value
>= 1.0f
) i
= 32767;
660 else i
= (ALint
)(Value
*32767.0f
);
664 static __inline ALubyte
aluF2UB(ALfloat Value
)
666 ALshort i
= aluF2S(Value
);
670 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
673 ALeffectslot
*ALEffectSlot
;
674 ALCcontext
**ctx
, **ctx_end
;
675 ALsource
**src
, **src_end
;
680 #if defined(HAVE_FESETROUND)
681 fpuState
= fegetround();
682 fesetround(FE_TOWARDZERO
);
683 #elif defined(HAVE__CONTROLFP)
684 fpuState
= _controlfp(_RC_CHOP
, _MCW_RC
);
691 /* Setup variables */
692 SamplesToDo
= min(size
, BUFFERSIZE
);
694 /* Clear mixing buffer */
695 memset(device
->DryBuffer
, 0, SamplesToDo
*OUTPUTCHANNELS
*sizeof(ALfloat
));
697 SuspendContext(NULL
);
698 ctx
= device
->Contexts
;
699 ctx_end
= ctx
+ device
->NumContexts
;
700 while(ctx
!= ctx_end
)
702 SuspendContext(*ctx
);
704 src
= (*ctx
)->ActiveSources
;
705 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
706 while(src
!= src_end
)
708 if((*src
)->state
!= AL_PLAYING
)
710 --((*ctx
)->ActiveSourceCount
);
715 if((*src
)->NeedsUpdate
)
717 ALsource_Update(*src
, *ctx
);
718 (*src
)->NeedsUpdate
= AL_FALSE
;
721 MixSource(*src
, device
, SamplesToDo
);
725 /* effect slot processing */
726 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
728 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
730 for(i
= 0;i
< SamplesToDo
;i
++)
732 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
733 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
737 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
738 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
741 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
742 SamplesToDo
, ALEffectSlot
->WetBuffer
,
745 for(i
= 0;i
< SamplesToDo
;i
++)
746 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
749 ProcessContext(*ctx
);
752 ProcessContext(NULL
);
754 //Post processing loop
755 for(i
= 0;i
< SamplesToDo
;i
++)
757 for(c
= 0;c
< OUTPUTCHANNELS
;c
++)
759 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
760 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
763 for(i
= 0;i
< OUTPUTCHANNELS
;i
++)
765 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
766 device
->PendingClicks
[i
] = 0.0f
;
769 switch(device
->Format
)
771 #define DO_WRITE(T, func, N, ...) do { \
772 const Channel chans[] = { \
775 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
776 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
777 const ALuint *ChanMap = device->DevChannels; \
779 for(i = 0;i < SamplesToDo;i++) \
781 for(j = 0;j < N;j++) \
783 ALfloat samp = 0.0f; \
784 for(c = 0;c < OUTPUTCHANNELS;c++) \
785 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
786 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
788 buffer = ((T*)buffer) + N; \
792 #define CHECK_WRITE_FORMAT(bits, T, func) \
793 case AL_FORMAT_MONO##bits: \
794 DO_WRITE(T, func, 1, FRONT_CENTER); \
796 case AL_FORMAT_STEREO##bits: \
799 ALfloat (*DryBuffer)[OUTPUTCHANNELS] = device->DryBuffer; \
800 ALfloat (*Matrix)[OUTPUTCHANNELS] = device->ChannelMatrix; \
801 const ALuint *ChanMap = device->DevChannels; \
803 for(i = 0;i < SamplesToDo;i++) \
805 float samples[2] = { 0.0f, 0.0f }; \
806 for(c = 0;c < OUTPUTCHANNELS;c++) \
808 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
809 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
811 bs2b_cross_feed(device->Bs2b, samples); \
812 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
813 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
814 buffer = ((T*)buffer) + 2; \
818 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
820 case AL_FORMAT_QUAD##bits: \
821 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
822 BACK_LEFT, BACK_RIGHT); \
824 case AL_FORMAT_51CHN##bits: \
825 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
827 BACK_LEFT, BACK_RIGHT); \
829 case AL_FORMAT_61CHN##bits: \
830 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
831 FRONT_CENTER, LFE, BACK_CENTER, \
832 SIDE_LEFT, SIDE_RIGHT); \
834 case AL_FORMAT_71CHN##bits: \
835 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
837 BACK_LEFT, BACK_RIGHT, \
838 SIDE_LEFT, SIDE_RIGHT); \
841 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
842 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
843 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
844 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
845 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
846 #undef AL_FORMAT_STEREO32
847 #undef AL_FORMAT_MONO32
848 #undef CHECK_WRITE_FORMAT
858 #if defined(HAVE_FESETROUND)
859 fesetround(fpuState
);
860 #elif defined(HAVE__CONTROLFP)
861 _controlfp(fpuState
, _MCW_RC
);
866 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
870 SuspendContext(NULL
);
871 for(i
= 0;i
< device
->NumContexts
;i
++)
873 ALCcontext
*Context
= device
->Contexts
[i
];
877 SuspendContext(Context
);
879 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
881 source
= Context
->SourceMap
.array
[pos
].value
;
882 if(source
->state
== AL_PLAYING
)
884 source
->state
= AL_STOPPED
;
885 source
->BuffersPlayed
= source
->BuffersInQueue
;
886 source
->position
= 0;
887 source
->position_fraction
= 0;
890 ProcessContext(Context
);
893 device
->Connected
= ALC_FALSE
;
894 ProcessContext(NULL
);