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 ALuint
aluBytesFromFormat(ALenum format
)
45 case AL_FORMAT_STEREO8
:
46 case AL_FORMAT_QUAD8_LOKI
:
49 case AL_FORMAT_51CHN8
:
50 case AL_FORMAT_61CHN8
:
51 case AL_FORMAT_71CHN8
:
54 case AL_FORMAT_MONO16
:
55 case AL_FORMAT_STEREO16
:
56 case AL_FORMAT_QUAD16_LOKI
:
57 case AL_FORMAT_QUAD16
:
58 case AL_FORMAT_REAR16
:
59 case AL_FORMAT_51CHN16
:
60 case AL_FORMAT_61CHN16
:
61 case AL_FORMAT_71CHN16
:
64 case AL_FORMAT_MONO_FLOAT32
:
65 case AL_FORMAT_STEREO_FLOAT32
:
66 case AL_FORMAT_QUAD32
:
67 case AL_FORMAT_REAR32
:
68 case AL_FORMAT_51CHN32
:
69 case AL_FORMAT_61CHN32
:
70 case AL_FORMAT_71CHN32
:
73 case AL_FORMAT_MONO_DOUBLE_EXT
:
74 case AL_FORMAT_STEREO_DOUBLE_EXT
:
77 case AL_FORMAT_MONO_MULAW
:
78 case AL_FORMAT_STEREO_MULAW
:
79 case AL_FORMAT_QUAD_MULAW
:
80 case AL_FORMAT_REAR_MULAW
:
81 case AL_FORMAT_51CHN_MULAW
:
82 case AL_FORMAT_61CHN_MULAW
:
83 case AL_FORMAT_71CHN_MULAW
:
90 ALuint
aluChannelsFromFormat(ALenum format
)
95 case AL_FORMAT_MONO16
:
96 case AL_FORMAT_MONO_FLOAT32
:
97 case AL_FORMAT_MONO_DOUBLE_EXT
:
98 case AL_FORMAT_MONO_MULAW
:
101 case AL_FORMAT_STEREO8
:
102 case AL_FORMAT_STEREO16
:
103 case AL_FORMAT_STEREO_FLOAT32
:
104 case AL_FORMAT_STEREO_DOUBLE_EXT
:
105 case AL_FORMAT_STEREO_MULAW
:
108 case AL_FORMAT_QUAD8_LOKI
:
109 case AL_FORMAT_QUAD16_LOKI
:
110 case AL_FORMAT_QUAD8
:
111 case AL_FORMAT_QUAD16
:
112 case AL_FORMAT_QUAD32
:
113 case AL_FORMAT_QUAD_MULAW
:
116 case AL_FORMAT_REAR8
:
117 case AL_FORMAT_REAR16
:
118 case AL_FORMAT_REAR32
:
119 case AL_FORMAT_REAR_MULAW
:
122 case AL_FORMAT_51CHN8
:
123 case AL_FORMAT_51CHN16
:
124 case AL_FORMAT_51CHN32
:
125 case AL_FORMAT_51CHN_MULAW
:
128 case AL_FORMAT_61CHN8
:
129 case AL_FORMAT_61CHN16
:
130 case AL_FORMAT_61CHN32
:
131 case AL_FORMAT_61CHN_MULAW
:
134 case AL_FORMAT_71CHN8
:
135 case AL_FORMAT_71CHN16
:
136 case AL_FORMAT_71CHN32
:
137 case AL_FORMAT_71CHN_MULAW
:
146 static __inline ALvoid
aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
148 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
149 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
150 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
153 static __inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
155 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
156 inVector1
[2]*inVector2
[2];
159 static __inline ALvoid
aluNormalize(ALfloat
*inVector
)
161 ALfloat length
, inverse_length
;
163 length
= aluSqrt(aluDotproduct(inVector
, inVector
));
166 inverse_length
= 1.0f
/length
;
167 inVector
[0] *= inverse_length
;
168 inVector
[1] *= inverse_length
;
169 inVector
[2] *= inverse_length
;
173 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
176 vector
[0], vector
[1], vector
[2], w
179 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
180 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
181 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
185 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
187 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
188 ALbufferlistitem
*BufferListItem
;
189 enum FmtChannels Channels
;
190 ALfloat DryGain
, DryGainHF
;
191 ALfloat WetGain
[MAX_SENDS
];
192 ALfloat WetGainHF
[MAX_SENDS
];
193 ALint NumSends
, Frequency
;
200 /* Get device properties */
201 Format
= ALContext
->Device
->Format
;
202 DupStereo
= ALContext
->Device
->DuplicateStereo
;
203 NumSends
= ALContext
->Device
->NumAuxSends
;
204 Frequency
= ALContext
->Device
->Frequency
;
206 /* Get listener properties */
207 ListenerGain
= ALContext
->Listener
.Gain
;
209 /* Get source properties */
210 SourceVolume
= ALSource
->flGain
;
211 MinVolume
= ALSource
->flMinGain
;
212 MaxVolume
= ALSource
->flMaxGain
;
213 Pitch
= ALSource
->flPitch
;
215 /* Calculate the stepping value */
217 BufferListItem
= ALSource
->queue
;
218 while(BufferListItem
!= NULL
)
221 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
223 ALint maxstep
= STACK_DATA_SIZE
/ FrameSizeFromFmt(ALBuffer
->FmtChannels
,
225 maxstep
-= ResamplerPadding
[ALSource
->Resampler
] +
226 ResamplerPrePadding
[ALSource
->Resampler
] + 1;
227 maxstep
= min(maxstep
, INT_MAX
>>FRACTIONBITS
);
229 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
230 if(Pitch
> (ALfloat
)maxstep
)
231 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
234 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
235 if(ALSource
->Params
.Step
== 0)
236 ALSource
->Params
.Step
= 1;
239 Channels
= ALBuffer
->FmtChannels
;
242 BufferListItem
= BufferListItem
->next
;
245 /* Calculate gains */
246 DryGain
= SourceVolume
;
247 DryGain
= __min(DryGain
,MaxVolume
);
248 DryGain
= __max(DryGain
,MinVolume
);
251 switch(ALSource
->DirectFilter
.type
)
253 case AL_FILTER_LOWPASS
:
254 DryGain
*= ALSource
->DirectFilter
.Gain
;
255 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
259 if(Channels
== FmtStereo
)
261 for(i
= 0;i
< MAXCHANNELS
;i
++)
262 ALSource
->Params
.DryGains
[i
] = 0.0f
;
264 if(DupStereo
== AL_FALSE
)
266 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
267 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
273 case AL_FORMAT_MONO8
:
274 case AL_FORMAT_MONO16
:
275 case AL_FORMAT_MONO_FLOAT32
:
276 case AL_FORMAT_STEREO8
:
277 case AL_FORMAT_STEREO16
:
278 case AL_FORMAT_STEREO_FLOAT32
:
279 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
280 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
283 case AL_FORMAT_QUAD8
:
284 case AL_FORMAT_QUAD16
:
285 case AL_FORMAT_QUAD32
:
286 case AL_FORMAT_51CHN8
:
287 case AL_FORMAT_51CHN16
:
288 case AL_FORMAT_51CHN32
:
289 DryGain
*= aluSqrt(2.0f
/4.0f
);
290 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
291 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
292 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
293 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
296 case AL_FORMAT_61CHN8
:
297 case AL_FORMAT_61CHN16
:
298 case AL_FORMAT_61CHN32
:
299 DryGain
*= aluSqrt(2.0f
/4.0f
);
300 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
301 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
302 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
303 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
306 case AL_FORMAT_71CHN8
:
307 case AL_FORMAT_71CHN16
:
308 case AL_FORMAT_71CHN32
:
309 DryGain
*= aluSqrt(2.0f
/6.0f
);
310 ALSource
->Params
.DryGains
[FRONT_LEFT
] = DryGain
* ListenerGain
;
311 ALSource
->Params
.DryGains
[FRONT_RIGHT
] = DryGain
* ListenerGain
;
312 ALSource
->Params
.DryGains
[BACK_LEFT
] = DryGain
* ListenerGain
;
313 ALSource
->Params
.DryGains
[BACK_RIGHT
] = DryGain
* ListenerGain
;
314 ALSource
->Params
.DryGains
[SIDE_LEFT
] = DryGain
* ListenerGain
;
315 ALSource
->Params
.DryGains
[SIDE_RIGHT
] = DryGain
* ListenerGain
;
325 for(i
= 0;i
< MAXCHANNELS
;i
++)
326 ALSource
->Params
.DryGains
[i
] = DryGain
* ListenerGain
;
329 for(i
= 0;i
< NumSends
;i
++)
331 WetGain
[i
] = SourceVolume
;
332 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
333 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
336 switch(ALSource
->Send
[i
].WetFilter
.type
)
338 case AL_FILTER_LOWPASS
:
339 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
340 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
344 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
347 /* Update filter coefficients. Calculations based on the I3DL2
349 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
351 /* We use two chained one-pole filters, so we need to take the
352 * square root of the squared gain, which is the same as the base
354 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
356 for(i
= 0;i
< NumSends
;i
++)
358 /* We use a one-pole filter, so we need to take the squared gain */
359 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
360 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
364 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
366 const ALCdevice
*Device
= ALContext
->Device
;
367 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,OrigDist
;
368 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
369 ALfloat Velocity
[3],ListenerVel
[3];
370 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
,OuterGainHF
;
371 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
372 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
373 ALfloat AirAbsorptionFactor
;
374 ALbufferlistitem
*BufferListItem
;
375 ALfloat Attenuation
, EffectiveDist
;
376 ALfloat RoomAttenuation
[MAX_SENDS
];
377 ALfloat MetersPerUnit
;
378 ALfloat RoomRolloff
[MAX_SENDS
];
381 ALfloat WetGain
[MAX_SENDS
];
382 ALfloat WetGainHF
[MAX_SENDS
];
383 ALfloat DirGain
, AmbientGain
;
384 const ALfloat
*SpeakerGain
;
393 for(i
= 0;i
< MAX_SENDS
;i
++)
396 //Get context properties
397 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
398 DopplerVelocity
= ALContext
->DopplerVelocity
;
399 SpeedOfSound
= ALContext
->flSpeedOfSound
;
400 NumSends
= Device
->NumAuxSends
;
401 Frequency
= Device
->Frequency
;
403 //Get listener properties
404 ListenerGain
= ALContext
->Listener
.Gain
;
405 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
406 memcpy(ListenerVel
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
408 //Get source properties
409 SourceVolume
= ALSource
->flGain
;
410 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
411 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
412 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
413 MinVolume
= ALSource
->flMinGain
;
414 MaxVolume
= ALSource
->flMaxGain
;
415 MinDist
= ALSource
->flRefDistance
;
416 MaxDist
= ALSource
->flMaxDistance
;
417 Rolloff
= ALSource
->flRollOffFactor
;
418 InnerAngle
= ALSource
->flInnerAngle
;
419 OuterAngle
= ALSource
->flOuterAngle
;
420 OuterGainHF
= ALSource
->OuterGainHF
;
421 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
423 //1. Translate Listener to origin (convert to head relative)
424 if(ALSource
->bHeadRelative
== AL_FALSE
)
426 ALfloat U
[3],V
[3],N
[3];
427 ALfloat Matrix
[4][4];
429 // Build transform matrix
430 memcpy(N
, ALContext
->Listener
.Forward
, sizeof(N
)); // At-vector
431 aluNormalize(N
); // Normalized At-vector
432 memcpy(V
, ALContext
->Listener
.Up
, sizeof(V
)); // Up-vector
433 aluNormalize(V
); // Normalized Up-vector
434 aluCrossproduct(N
, V
, U
); // Right-vector
435 aluNormalize(U
); // Normalized Right-vector
436 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
437 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
438 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
439 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
441 // Translate position
442 Position
[0] -= ALContext
->Listener
.Position
[0];
443 Position
[1] -= ALContext
->Listener
.Position
[1];
444 Position
[2] -= ALContext
->Listener
.Position
[2];
446 // Transform source position and direction into listener space
447 aluMatrixVector(Position
, 1.0f
, Matrix
);
448 aluMatrixVector(Direction
, 0.0f
, Matrix
);
449 // Transform source and listener velocity into listener space
450 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
451 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
454 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
456 SourceToListener
[0] = -Position
[0];
457 SourceToListener
[1] = -Position
[1];
458 SourceToListener
[2] = -Position
[2];
459 aluNormalize(SourceToListener
);
460 aluNormalize(Direction
);
462 //2. Calculate distance attenuation
463 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
467 for(i
= 0;i
< NumSends
;i
++)
469 RoomAttenuation
[i
] = 1.0f
;
471 RoomRolloff
[i
] = ALSource
->RoomRolloffFactor
;
472 if(ALSource
->Send
[i
].Slot
&&
473 (ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_REVERB
||
474 ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_EAXREVERB
))
475 RoomRolloff
[i
] += ALSource
->Send
[i
].Slot
->effect
.Reverb
.RoomRolloffFactor
;
478 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
479 ALContext
->DistanceModel
)
481 case AL_INVERSE_DISTANCE_CLAMPED
:
482 Distance
=__max(Distance
,MinDist
);
483 Distance
=__min(Distance
,MaxDist
);
484 if(MaxDist
< MinDist
)
487 case AL_INVERSE_DISTANCE
:
490 if((MinDist
+ (Rolloff
* (Distance
- MinDist
))) > 0.0f
)
491 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (Distance
- MinDist
)));
492 for(i
= 0;i
< NumSends
;i
++)
494 if((MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
))) > 0.0f
)
495 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
)));
500 case AL_LINEAR_DISTANCE_CLAMPED
:
501 Distance
=__max(Distance
,MinDist
);
502 Distance
=__min(Distance
,MaxDist
);
503 if(MaxDist
< MinDist
)
506 case AL_LINEAR_DISTANCE
:
507 if(MaxDist
!= MinDist
)
509 Attenuation
= 1.0f
- (Rolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
510 Attenuation
= __max(Attenuation
, 0.0f
);
511 for(i
= 0;i
< NumSends
;i
++)
513 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(Distance
-MinDist
)/(MaxDist
- MinDist
));
514 RoomAttenuation
[i
] = __max(RoomAttenuation
[i
], 0.0f
);
519 case AL_EXPONENT_DISTANCE_CLAMPED
:
520 Distance
=__max(Distance
,MinDist
);
521 Distance
=__min(Distance
,MaxDist
);
522 if(MaxDist
< MinDist
)
525 case AL_EXPONENT_DISTANCE
:
526 if(Distance
> 0.0f
&& MinDist
> 0.0f
)
528 Attenuation
= aluPow(Distance
/MinDist
, -Rolloff
);
529 for(i
= 0;i
< NumSends
;i
++)
530 RoomAttenuation
[i
] = aluPow(Distance
/MinDist
, -RoomRolloff
[i
]);
538 // Source Gain + Attenuation
539 DryGain
= SourceVolume
* Attenuation
;
540 for(i
= 0;i
< NumSends
;i
++)
541 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
543 EffectiveDist
= 0.0f
;
544 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
545 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
547 // Distance-based air absorption
548 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
552 // Absorption calculation is done in dB
553 absorb
= (AirAbsorptionFactor
*AIRABSORBGAINDBHF
) *
555 // Convert dB to linear gain before applying
556 absorb
= aluPow(10.0f
, absorb
/20.0f
);
561 //3. Apply directional soundcones
562 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * 180.0f
/M_PI
;
563 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
565 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
566 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
)*scale
);
567 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
569 else if(Angle
> OuterAngle
)
571 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
));
572 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
));
580 // Apply some high-frequency attenuation for sources behind the listener
581 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
582 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
583 // the same as SourceToListener[2]
584 Angle
= aluAcos(SourceToListener
[2]) * 180.0f
/M_PI
;
585 // Sources within the minimum distance attenuate less
586 if(OrigDist
< MinDist
)
587 Angle
*= OrigDist
/MinDist
;
590 ALfloat scale
= (Angle
-90.0f
) / (180.1f
-90.0f
); // .1 to account for fp errors
591 ConeHF
*= 1.0f
- (Device
->HeadDampen
*scale
);
594 DryGain
*= ConeVolume
;
595 if(ALSource
->DryGainHFAuto
)
598 // Clamp to Min/Max Gain
599 DryGain
= __min(DryGain
,MaxVolume
);
600 DryGain
= __max(DryGain
,MinVolume
);
602 for(i
= 0;i
< NumSends
;i
++)
604 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
606 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
608 ALSource
->Params
.Send
[i
].WetGain
= 0.0f
;
613 if(Slot
->AuxSendAuto
)
615 if(ALSource
->WetGainAuto
)
616 WetGain
[i
] *= ConeVolume
;
617 if(ALSource
->WetGainHFAuto
)
618 WetGainHF
[i
] *= ConeHF
;
620 // Clamp to Min/Max Gain
621 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
622 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
624 if(Slot
->effect
.type
== AL_EFFECT_REVERB
||
625 Slot
->effect
.type
== AL_EFFECT_EAXREVERB
)
627 /* Apply a decay-time transformation to the wet path, based on
628 * the attenuation of the dry path.
630 * Using the approximate (effective) source to listener
631 * distance, the initial decay of the reverb effect is
632 * calculated and applied to the wet path.
634 WetGain
[i
] *= aluPow(10.0f
, EffectiveDist
/
635 (SPEEDOFSOUNDMETRESPERSEC
*
636 Slot
->effect
.Reverb
.DecayTime
) *
639 WetGainHF
[i
] *= aluPow(Slot
->effect
.Reverb
.AirAbsorptionGainHF
,
640 AirAbsorptionFactor
* EffectiveDist
);
645 /* If the slot's auxiliary send auto is off, the data sent to the
646 * effect slot is the same as the dry path, sans filter effects */
647 WetGain
[i
] = DryGain
;
648 WetGainHF
[i
] = DryGainHF
;
651 switch(ALSource
->Send
[i
].WetFilter
.type
)
653 case AL_FILTER_LOWPASS
:
654 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
655 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
658 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
661 // Apply filter gains and filters
662 switch(ALSource
->DirectFilter
.type
)
664 case AL_FILTER_LOWPASS
:
665 DryGain
*= ALSource
->DirectFilter
.Gain
;
666 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
669 DryGain
*= ListenerGain
;
671 // Calculate Velocity
672 Pitch
= ALSource
->flPitch
;
673 if(DopplerFactor
!= 0.0f
)
676 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
679 VSS
= aluDotproduct(Velocity
, SourceToListener
);
680 if(VSS
>= MaxVelocity
)
681 VSS
= (MaxVelocity
- 1.0f
);
682 else if(VSS
<= -MaxVelocity
)
683 VSS
= -MaxVelocity
+ 1.0f
;
685 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
686 if(VLS
>= MaxVelocity
)
687 VLS
= (MaxVelocity
- 1.0f
);
688 else if(VLS
<= -MaxVelocity
)
689 VLS
= -MaxVelocity
+ 1.0f
;
691 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
692 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
695 BufferListItem
= ALSource
->queue
;
696 while(BufferListItem
!= NULL
)
699 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
701 ALint maxstep
= STACK_DATA_SIZE
/ FrameSizeFromFmt(ALBuffer
->FmtChannels
,
703 maxstep
-= ResamplerPadding
[ALSource
->Resampler
] +
704 ResamplerPrePadding
[ALSource
->Resampler
] + 1;
705 maxstep
= min(maxstep
, INT_MAX
>>FRACTIONBITS
);
707 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
708 if(Pitch
> (ALfloat
)maxstep
)
709 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
712 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
713 if(ALSource
->Params
.Step
== 0)
714 ALSource
->Params
.Step
= 1;
718 BufferListItem
= BufferListItem
->next
;
721 // Use energy-preserving panning algorithm for multi-speaker playback
722 length
= __max(OrigDist
, MinDist
);
725 ALfloat invlen
= 1.0f
/length
;
726 Position
[0] *= invlen
;
727 Position
[1] *= invlen
;
728 Position
[2] *= invlen
;
731 pos
= aluCart2LUTpos(-Position
[2], Position
[0]);
732 SpeakerGain
= &Device
->PanningLUT
[MAXCHANNELS
* pos
];
734 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
735 // elevation adjustment for directional gain. this sucks, but
736 // has low complexity
737 AmbientGain
= aluSqrt(1.0/Device
->NumChan
);
738 for(s
= 0;s
< MAXCHANNELS
;s
++)
739 ALSource
->Params
.DryGains
[s
] = 0.0f
;
740 for(s
= 0;s
< (ALsizei
)Device
->NumChan
;s
++)
742 Channel chan
= Device
->Speaker2Chan
[s
];
743 ALfloat gain
= AmbientGain
+ (SpeakerGain
[chan
]-AmbientGain
)*DirGain
;
744 ALSource
->Params
.DryGains
[chan
] = DryGain
* gain
;
747 /* Update filter coefficients. */
748 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
750 /* Spatialized sources use four chained one-pole filters, so we need to
751 * take the fourth root of the squared gain, which is the same as the
752 * square root of the base gain. */
753 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(aluSqrt(DryGainHF
), cw
);
755 for(i
= 0;i
< NumSends
;i
++)
757 /* The wet path uses two chained one-pole filters, so take the
758 * base gain (square root of the squared gain) */
759 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= lpCoeffCalc(WetGainHF
[i
], cw
);
764 static __inline ALfloat
aluF2F(ALfloat Value
)
768 static __inline ALshort
aluF2S(ALfloat Value
)
772 if(Value
<= -1.0f
) i
= -32768;
773 else if(Value
>= 1.0f
) i
= 32767;
774 else i
= (ALint
)(Value
*32767.0f
);
778 static __inline ALubyte
aluF2UB(ALfloat Value
)
780 ALshort i
= aluF2S(Value
);
784 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
787 ALeffectslot
*ALEffectSlot
;
788 ALCcontext
**ctx
, **ctx_end
;
789 ALsource
**src
, **src_end
;
794 #if defined(HAVE_FESETROUND)
795 fpuState
= fegetround();
796 fesetround(FE_TOWARDZERO
);
797 #elif defined(HAVE__CONTROLFP)
798 fpuState
= _controlfp(_RC_CHOP
, _MCW_RC
);
805 /* Setup variables */
806 SamplesToDo
= min(size
, BUFFERSIZE
);
808 /* Clear mixing buffer */
809 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
811 SuspendContext(NULL
);
812 ctx
= device
->Contexts
;
813 ctx_end
= ctx
+ device
->NumContexts
;
814 while(ctx
!= ctx_end
)
816 SuspendContext(*ctx
);
818 src
= (*ctx
)->ActiveSources
;
819 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
820 while(src
!= src_end
)
822 if((*src
)->state
!= AL_PLAYING
)
824 --((*ctx
)->ActiveSourceCount
);
829 if((*src
)->NeedsUpdate
)
831 ALsource_Update(*src
, *ctx
);
832 (*src
)->NeedsUpdate
= AL_FALSE
;
835 MixSource(*src
, device
, SamplesToDo
);
839 /* effect slot processing */
840 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
842 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
844 for(i
= 0;i
< SamplesToDo
;i
++)
846 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
847 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
851 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
852 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
855 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
856 SamplesToDo
, ALEffectSlot
->WetBuffer
,
859 for(i
= 0;i
< SamplesToDo
;i
++)
860 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
863 ProcessContext(*ctx
);
866 ProcessContext(NULL
);
868 //Post processing loop
869 for(i
= 0;i
< SamplesToDo
;i
++)
871 for(c
= 0;c
< MAXCHANNELS
;c
++)
873 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
874 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
877 for(i
= 0;i
< MAXCHANNELS
;i
++)
879 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
880 device
->PendingClicks
[i
] = 0.0f
;
883 switch(device
->Format
)
885 #define DO_WRITE(T, func, N, ...) do { \
886 const Channel chans[] = { \
889 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
890 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
891 const ALuint *ChanMap = device->DevChannels; \
893 for(i = 0;i < SamplesToDo;i++) \
895 for(j = 0;j < N;j++) \
897 ALfloat samp = 0.0f; \
898 for(c = 0;c < MAXCHANNELS;c++) \
899 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
900 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
902 buffer = ((T*)buffer) + N; \
906 #define CHECK_WRITE_FORMAT(bits, T, func) \
907 case AL_FORMAT_MONO##bits: \
908 DO_WRITE(T, func, 1, FRONT_CENTER); \
910 case AL_FORMAT_STEREO##bits: \
913 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
914 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
915 const ALuint *ChanMap = device->DevChannels; \
917 for(i = 0;i < SamplesToDo;i++) \
919 float samples[2] = { 0.0f, 0.0f }; \
920 for(c = 0;c < MAXCHANNELS;c++) \
922 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
923 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
925 bs2b_cross_feed(device->Bs2b, samples); \
926 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
927 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
928 buffer = ((T*)buffer) + 2; \
932 DO_WRITE(T, func, 2, FRONT_LEFT, FRONT_RIGHT); \
934 case AL_FORMAT_QUAD##bits: \
935 DO_WRITE(T, func, 4, FRONT_LEFT, FRONT_RIGHT, \
936 BACK_LEFT, BACK_RIGHT); \
938 case AL_FORMAT_51CHN##bits: \
939 DO_WRITE(T, func, 6, FRONT_LEFT, FRONT_RIGHT, \
941 BACK_LEFT, BACK_RIGHT); \
943 case AL_FORMAT_61CHN##bits: \
944 DO_WRITE(T, func, 7, FRONT_LEFT, FRONT_RIGHT, \
945 FRONT_CENTER, LFE, BACK_CENTER, \
946 SIDE_LEFT, SIDE_RIGHT); \
948 case AL_FORMAT_71CHN##bits: \
949 DO_WRITE(T, func, 8, FRONT_LEFT, FRONT_RIGHT, \
951 BACK_LEFT, BACK_RIGHT, \
952 SIDE_LEFT, SIDE_RIGHT); \
955 #define AL_FORMAT_MONO32 AL_FORMAT_MONO_FLOAT32
956 #define AL_FORMAT_STEREO32 AL_FORMAT_STEREO_FLOAT32
957 CHECK_WRITE_FORMAT(8, ALubyte
, aluF2UB
)
958 CHECK_WRITE_FORMAT(16, ALshort
, aluF2S
)
959 CHECK_WRITE_FORMAT(32, ALfloat
, aluF2F
)
960 #undef AL_FORMAT_STEREO32
961 #undef AL_FORMAT_MONO32
962 #undef CHECK_WRITE_FORMAT
972 #if defined(HAVE_FESETROUND)
973 fesetround(fpuState
);
974 #elif defined(HAVE__CONTROLFP)
975 _controlfp(fpuState
, _MCW_RC
);
980 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
984 SuspendContext(NULL
);
985 for(i
= 0;i
< device
->NumContexts
;i
++)
987 ALCcontext
*Context
= device
->Contexts
[i
];
991 SuspendContext(Context
);
993 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
995 source
= Context
->SourceMap
.array
[pos
].value
;
996 if(source
->state
== AL_PLAYING
)
998 source
->state
= AL_STOPPED
;
999 source
->BuffersPlayed
= source
->BuffersInQueue
;
1000 source
->position
= 0;
1001 source
->position_fraction
= 0;
1004 ProcessContext(Context
);
1007 device
->Connected
= ALC_FALSE
;
1008 ProcessContext(NULL
);