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 for(i
= 0;i
< MAXCHANNELS
;i
++)
156 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
157 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
163 ALSource
->Params
.DryGains
[0][FRONT_CENTER
] = DryGain
* ListenerGain
;
166 if(DupStereo
== AL_FALSE
)
168 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
169 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
177 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
178 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
183 DryGain
*= aluSqrt(2.0f
/4.0f
);
184 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
185 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
186 ALSource
->Params
.DryGains
[0][BACK_LEFT
] = DryGain
* ListenerGain
;
187 ALSource
->Params
.DryGains
[1][BACK_RIGHT
] = DryGain
* ListenerGain
;
191 DryGain
*= aluSqrt(2.0f
/4.0f
);
192 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
193 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
194 ALSource
->Params
.DryGains
[0][SIDE_LEFT
] = DryGain
* ListenerGain
;
195 ALSource
->Params
.DryGains
[1][SIDE_RIGHT
] = DryGain
* ListenerGain
;
199 DryGain
*= aluSqrt(2.0f
/6.0f
);
200 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
201 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
202 ALSource
->Params
.DryGains
[0][BACK_LEFT
] = DryGain
* ListenerGain
;
203 ALSource
->Params
.DryGains
[1][BACK_RIGHT
] = DryGain
* ListenerGain
;
204 ALSource
->Params
.DryGains
[0][SIDE_LEFT
] = DryGain
* ListenerGain
;
205 ALSource
->Params
.DryGains
[1][SIDE_RIGHT
] = DryGain
* ListenerGain
;
212 ALSource
->Params
.DryGains
[0][BACK_LEFT
] = DryGain
* ListenerGain
;
213 ALSource
->Params
.DryGains
[1][BACK_RIGHT
] = DryGain
* ListenerGain
;
217 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
218 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
219 ALSource
->Params
.DryGains
[2][BACK_LEFT
] = DryGain
* ListenerGain
;
220 ALSource
->Params
.DryGains
[3][BACK_RIGHT
] = DryGain
* ListenerGain
;
224 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
225 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
226 ALSource
->Params
.DryGains
[2][FRONT_CENTER
] = DryGain
* ListenerGain
;
227 ALSource
->Params
.DryGains
[3][LFE
] = DryGain
* ListenerGain
;
228 ALSource
->Params
.DryGains
[4][BACK_LEFT
] = DryGain
* ListenerGain
;
229 ALSource
->Params
.DryGains
[5][BACK_RIGHT
] = DryGain
* ListenerGain
;
233 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
234 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
235 ALSource
->Params
.DryGains
[2][FRONT_CENTER
] = DryGain
* ListenerGain
;
236 ALSource
->Params
.DryGains
[3][LFE
] = DryGain
* ListenerGain
;
237 ALSource
->Params
.DryGains
[4][BACK_CENTER
] = DryGain
* ListenerGain
;
238 ALSource
->Params
.DryGains
[5][SIDE_LEFT
] = DryGain
* ListenerGain
;
239 ALSource
->Params
.DryGains
[6][SIDE_RIGHT
] = DryGain
* ListenerGain
;
243 ALSource
->Params
.DryGains
[0][FRONT_LEFT
] = DryGain
* ListenerGain
;
244 ALSource
->Params
.DryGains
[1][FRONT_RIGHT
] = DryGain
* ListenerGain
;
245 ALSource
->Params
.DryGains
[2][FRONT_CENTER
] = DryGain
* ListenerGain
;
246 ALSource
->Params
.DryGains
[3][LFE
] = DryGain
* ListenerGain
;
247 ALSource
->Params
.DryGains
[4][BACK_LEFT
] = DryGain
* ListenerGain
;
248 ALSource
->Params
.DryGains
[5][BACK_RIGHT
] = DryGain
* ListenerGain
;
249 ALSource
->Params
.DryGains
[6][SIDE_LEFT
] = DryGain
* ListenerGain
;
250 ALSource
->Params
.DryGains
[7][SIDE_RIGHT
] = DryGain
* ListenerGain
;
254 for(i
= 0;i
< NumSends
;i
++)
256 WetGain
[i
] = SourceVolume
;
257 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
258 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
261 switch(ALSource
->Send
[i
].WetFilter
.type
)
263 case AL_FILTER_LOWPASS
:
264 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
265 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
269 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
272 /* Update filter coefficients. Calculations based on the I3DL2
274 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
276 /* We use two chained one-pole filters, so we need to take the
277 * square root of the squared gain, which is the same as the base
279 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
281 for(i
= 0;i
< NumSends
;i
++)
283 /* We use a one-pole filter, so we need to take the squared gain */
284 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
285 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
289 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
291 const ALCdevice
*Device
= ALContext
->Device
;
292 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,OrigDist
;
293 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
294 ALfloat Velocity
[3],ListenerVel
[3];
295 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
,OuterGainHF
;
296 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
297 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
298 ALfloat AirAbsorptionFactor
;
299 ALbufferlistitem
*BufferListItem
;
300 ALfloat Attenuation
, EffectiveDist
;
301 ALfloat RoomAttenuation
[MAX_SENDS
];
302 ALfloat MetersPerUnit
;
303 ALfloat RoomRolloff
[MAX_SENDS
];
306 ALfloat WetGain
[MAX_SENDS
];
307 ALfloat WetGainHF
[MAX_SENDS
];
308 ALfloat DirGain
, AmbientGain
;
309 const ALfloat
*SpeakerGain
;
318 for(i
= 0;i
< MAX_SENDS
;i
++)
321 //Get context properties
322 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
323 DopplerVelocity
= ALContext
->DopplerVelocity
;
324 SpeedOfSound
= ALContext
->flSpeedOfSound
;
325 NumSends
= Device
->NumAuxSends
;
326 Frequency
= Device
->Frequency
;
328 //Get listener properties
329 ListenerGain
= ALContext
->Listener
.Gain
;
330 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
331 memcpy(ListenerVel
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
333 //Get source properties
334 SourceVolume
= ALSource
->flGain
;
335 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
336 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
337 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
338 MinVolume
= ALSource
->flMinGain
;
339 MaxVolume
= ALSource
->flMaxGain
;
340 MinDist
= ALSource
->flRefDistance
;
341 MaxDist
= ALSource
->flMaxDistance
;
342 Rolloff
= ALSource
->flRollOffFactor
;
343 InnerAngle
= ALSource
->flInnerAngle
;
344 OuterAngle
= ALSource
->flOuterAngle
;
345 OuterGainHF
= ALSource
->OuterGainHF
;
346 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
348 //1. Translate Listener to origin (convert to head relative)
349 if(ALSource
->bHeadRelative
== AL_FALSE
)
351 ALfloat U
[3],V
[3],N
[3];
352 ALfloat Matrix
[4][4];
354 // Build transform matrix
355 memcpy(N
, ALContext
->Listener
.Forward
, sizeof(N
)); // At-vector
356 aluNormalize(N
); // Normalized At-vector
357 memcpy(V
, ALContext
->Listener
.Up
, sizeof(V
)); // Up-vector
358 aluNormalize(V
); // Normalized Up-vector
359 aluCrossproduct(N
, V
, U
); // Right-vector
360 aluNormalize(U
); // Normalized Right-vector
361 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
362 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
363 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
364 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
366 // Translate position
367 Position
[0] -= ALContext
->Listener
.Position
[0];
368 Position
[1] -= ALContext
->Listener
.Position
[1];
369 Position
[2] -= ALContext
->Listener
.Position
[2];
371 // Transform source position and direction into listener space
372 aluMatrixVector(Position
, 1.0f
, Matrix
);
373 aluMatrixVector(Direction
, 0.0f
, Matrix
);
374 // Transform source and listener velocity into listener space
375 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
376 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
379 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
381 SourceToListener
[0] = -Position
[0];
382 SourceToListener
[1] = -Position
[1];
383 SourceToListener
[2] = -Position
[2];
384 aluNormalize(SourceToListener
);
385 aluNormalize(Direction
);
387 //2. Calculate distance attenuation
388 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
392 for(i
= 0;i
< NumSends
;i
++)
394 RoomAttenuation
[i
] = 1.0f
;
396 RoomRolloff
[i
] = ALSource
->RoomRolloffFactor
;
397 if(ALSource
->Send
[i
].Slot
&&
398 (ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_REVERB
||
399 ALSource
->Send
[i
].Slot
->effect
.type
== AL_EFFECT_EAXREVERB
))
400 RoomRolloff
[i
] += ALSource
->Send
[i
].Slot
->effect
.Reverb
.RoomRolloffFactor
;
403 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
404 ALContext
->DistanceModel
)
406 case AL_INVERSE_DISTANCE_CLAMPED
:
407 Distance
=__max(Distance
,MinDist
);
408 Distance
=__min(Distance
,MaxDist
);
409 if(MaxDist
< MinDist
)
412 case AL_INVERSE_DISTANCE
:
415 if((MinDist
+ (Rolloff
* (Distance
- MinDist
))) > 0.0f
)
416 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (Distance
- MinDist
)));
417 for(i
= 0;i
< NumSends
;i
++)
419 if((MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
))) > 0.0f
)
420 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (Distance
- MinDist
)));
425 case AL_LINEAR_DISTANCE_CLAMPED
:
426 Distance
=__max(Distance
,MinDist
);
427 Distance
=__min(Distance
,MaxDist
);
428 if(MaxDist
< MinDist
)
431 case AL_LINEAR_DISTANCE
:
432 if(MaxDist
!= MinDist
)
434 Attenuation
= 1.0f
- (Rolloff
*(Distance
-MinDist
)/(MaxDist
- MinDist
));
435 Attenuation
= __max(Attenuation
, 0.0f
);
436 for(i
= 0;i
< NumSends
;i
++)
438 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(Distance
-MinDist
)/(MaxDist
- MinDist
));
439 RoomAttenuation
[i
] = __max(RoomAttenuation
[i
], 0.0f
);
444 case AL_EXPONENT_DISTANCE_CLAMPED
:
445 Distance
=__max(Distance
,MinDist
);
446 Distance
=__min(Distance
,MaxDist
);
447 if(MaxDist
< MinDist
)
450 case AL_EXPONENT_DISTANCE
:
451 if(Distance
> 0.0f
&& MinDist
> 0.0f
)
453 Attenuation
= aluPow(Distance
/MinDist
, -Rolloff
);
454 for(i
= 0;i
< NumSends
;i
++)
455 RoomAttenuation
[i
] = aluPow(Distance
/MinDist
, -RoomRolloff
[i
]);
463 // Source Gain + Attenuation
464 DryGain
= SourceVolume
* Attenuation
;
465 for(i
= 0;i
< NumSends
;i
++)
466 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
468 EffectiveDist
= 0.0f
;
469 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
470 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
472 // Distance-based air absorption
473 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
477 // Absorption calculation is done in dB
478 absorb
= (AirAbsorptionFactor
*AIRABSORBGAINDBHF
) *
480 // Convert dB to linear gain before applying
481 absorb
= aluPow(10.0f
, absorb
/20.0f
);
486 //3. Apply directional soundcones
487 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * 180.0f
/M_PI
;
488 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
490 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
491 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
)*scale
);
492 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
)*scale
);
494 else if(Angle
> OuterAngle
)
496 ConeVolume
= (1.0f
+(ALSource
->flOuterGain
-1.0f
));
497 ConeHF
= (1.0f
+(OuterGainHF
-1.0f
));
505 // Apply some high-frequency attenuation for sources behind the listener
506 // NOTE: This should be aluDotproduct({0,0,-1}, ListenerToSource), however
507 // that is equivalent to aluDotproduct({0,0,1}, SourceToListener), which is
508 // the same as SourceToListener[2]
509 Angle
= aluAcos(SourceToListener
[2]) * 180.0f
/M_PI
;
510 // Sources within the minimum distance attenuate less
511 if(OrigDist
< MinDist
)
512 Angle
*= OrigDist
/MinDist
;
515 ALfloat scale
= (Angle
-90.0f
) / (180.1f
-90.0f
); // .1 to account for fp errors
516 ConeHF
*= 1.0f
- (Device
->HeadDampen
*scale
);
519 DryGain
*= ConeVolume
;
520 if(ALSource
->DryGainHFAuto
)
523 // Clamp to Min/Max Gain
524 DryGain
= __min(DryGain
,MaxVolume
);
525 DryGain
= __max(DryGain
,MinVolume
);
527 for(i
= 0;i
< NumSends
;i
++)
529 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
531 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
533 ALSource
->Params
.Send
[i
].WetGain
= 0.0f
;
538 if(Slot
->AuxSendAuto
)
540 if(ALSource
->WetGainAuto
)
541 WetGain
[i
] *= ConeVolume
;
542 if(ALSource
->WetGainHFAuto
)
543 WetGainHF
[i
] *= ConeHF
;
545 // Clamp to Min/Max Gain
546 WetGain
[i
] = __min(WetGain
[i
],MaxVolume
);
547 WetGain
[i
] = __max(WetGain
[i
],MinVolume
);
549 if(Slot
->effect
.type
== AL_EFFECT_REVERB
||
550 Slot
->effect
.type
== AL_EFFECT_EAXREVERB
)
552 /* Apply a decay-time transformation to the wet path, based on
553 * the attenuation of the dry path.
555 * Using the approximate (effective) source to listener
556 * distance, the initial decay of the reverb effect is
557 * calculated and applied to the wet path.
559 WetGain
[i
] *= aluPow(10.0f
, EffectiveDist
/
560 (SPEEDOFSOUNDMETRESPERSEC
*
561 Slot
->effect
.Reverb
.DecayTime
) *
564 WetGainHF
[i
] *= aluPow(Slot
->effect
.Reverb
.AirAbsorptionGainHF
,
565 AirAbsorptionFactor
* EffectiveDist
);
570 /* If the slot's auxiliary send auto is off, the data sent to the
571 * effect slot is the same as the dry path, sans filter effects */
572 WetGain
[i
] = DryGain
;
573 WetGainHF
[i
] = DryGainHF
;
576 switch(ALSource
->Send
[i
].WetFilter
.type
)
578 case AL_FILTER_LOWPASS
:
579 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
580 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
583 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
586 // Apply filter gains and filters
587 switch(ALSource
->DirectFilter
.type
)
589 case AL_FILTER_LOWPASS
:
590 DryGain
*= ALSource
->DirectFilter
.Gain
;
591 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
594 DryGain
*= ListenerGain
;
596 // Calculate Velocity
597 Pitch
= ALSource
->flPitch
;
598 if(DopplerFactor
!= 0.0f
)
601 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
604 VSS
= aluDotproduct(Velocity
, SourceToListener
);
605 if(VSS
>= MaxVelocity
)
606 VSS
= (MaxVelocity
- 1.0f
);
607 else if(VSS
<= -MaxVelocity
)
608 VSS
= -MaxVelocity
+ 1.0f
;
610 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
611 if(VLS
>= MaxVelocity
)
612 VLS
= (MaxVelocity
- 1.0f
);
613 else if(VLS
<= -MaxVelocity
)
614 VLS
= -MaxVelocity
+ 1.0f
;
616 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
617 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
620 BufferListItem
= ALSource
->queue
;
621 while(BufferListItem
!= NULL
)
624 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
626 ALint maxstep
= STACK_DATA_SIZE
/ FrameSizeFromFmt(ALBuffer
->FmtChannels
,
628 maxstep
-= ResamplerPadding
[ALSource
->Resampler
] +
629 ResamplerPrePadding
[ALSource
->Resampler
] + 1;
630 maxstep
= min(maxstep
, INT_MAX
>>FRACTIONBITS
);
632 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
633 if(Pitch
> (ALfloat
)maxstep
)
634 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
637 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
638 if(ALSource
->Params
.Step
== 0)
639 ALSource
->Params
.Step
= 1;
643 BufferListItem
= BufferListItem
->next
;
646 // Use energy-preserving panning algorithm for multi-speaker playback
647 length
= __max(OrigDist
, MinDist
);
650 ALfloat invlen
= 1.0f
/length
;
651 Position
[0] *= invlen
;
652 Position
[1] *= invlen
;
653 Position
[2] *= invlen
;
656 pos
= aluCart2LUTpos(-Position
[2], Position
[0]);
657 SpeakerGain
= &Device
->PanningLUT
[MAXCHANNELS
* pos
];
659 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
660 // elevation adjustment for directional gain. this sucks, but
661 // has low complexity
662 AmbientGain
= aluSqrt(1.0/Device
->NumChan
);
663 for(s
= 0;s
< MAXCHANNELS
;s
++)
666 for(s2
= 0;s2
< MAXCHANNELS
;s2
++)
667 ALSource
->Params
.DryGains
[s
][s2
] = 0.0f
;
669 for(s
= 0;s
< (ALsizei
)Device
->NumChan
;s
++)
671 Channel chan
= Device
->Speaker2Chan
[s
];
672 ALfloat gain
= AmbientGain
+ (SpeakerGain
[chan
]-AmbientGain
)*DirGain
;
673 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
676 /* Update filter coefficients. */
677 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
679 /* Spatialized sources use four chained one-pole filters, so we need to
680 * take the fourth root of the squared gain, which is the same as the
681 * square root of the base gain. */
682 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(aluSqrt(DryGainHF
), cw
);
684 for(i
= 0;i
< NumSends
;i
++)
686 /* The wet path uses two chained one-pole filters, so take the
687 * base gain (square root of the squared gain) */
688 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= lpCoeffCalc(WetGainHF
[i
], cw
);
693 static __inline ALfloat
aluF2F(ALfloat val
)
697 static __inline ALushort
aluF2US(ALfloat val
)
699 if(val
> 1.0f
) return 65535;
700 if(val
< -1.0f
) return 0;
701 return (ALint
)(val
*32767.0f
) + 32768;
703 static __inline ALshort
aluF2S(ALfloat val
)
705 if(val
> 1.0f
) return 32767;
706 if(val
< -1.0f
) return -32768;
707 return (ALint
)(val
*32767.0f
);
709 static __inline ALubyte
aluF2UB(ALfloat val
)
711 ALushort i
= aluF2US(val
);
714 static __inline ALbyte
aluF2B(ALfloat val
)
716 ALshort i
= aluF2S(val
);
720 static const Channel MonoChans
[] = { FRONT_CENTER
};
721 static const Channel StereoChans
[] = { FRONT_LEFT
, FRONT_RIGHT
};
722 static const Channel QuadChans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
723 BACK_LEFT
, BACK_RIGHT
};
724 static const Channel X51Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
726 BACK_LEFT
, BACK_RIGHT
};
727 static const Channel X61Chans
[] = { FRONT_LEFT
, FRONT_LEFT
,
728 FRONT_CENTER
, LFE
, BACK_CENTER
,
729 SIDE_LEFT
, SIDE_RIGHT
};
730 static const Channel X71Chans
[] = { FRONT_LEFT
, FRONT_RIGHT
,
732 BACK_LEFT
, BACK_RIGHT
,
733 SIDE_LEFT
, SIDE_RIGHT
};
735 #define DECL_TEMPLATE(T, chans,N, func) \
736 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
738 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
739 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
740 const ALuint *ChanMap = device->DevChannels; \
743 for(i = 0;i < SamplesToDo;i++) \
745 for(j = 0;j < N;j++) \
747 ALfloat samp = 0.0f; \
748 for(c = 0;c < MAXCHANNELS;c++) \
749 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
750 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
752 buffer = ((T*)buffer) + N; \
756 DECL_TEMPLATE(ALfloat
, MonoChans
,1, aluF2F
)
757 DECL_TEMPLATE(ALfloat
, QuadChans
,4, aluF2F
)
758 DECL_TEMPLATE(ALfloat
, X51Chans
,6, aluF2F
)
759 DECL_TEMPLATE(ALfloat
, X61Chans
,7, aluF2F
)
760 DECL_TEMPLATE(ALfloat
, X71Chans
,8, aluF2F
)
762 DECL_TEMPLATE(ALushort
, MonoChans
,1, aluF2US
)
763 DECL_TEMPLATE(ALushort
, QuadChans
,4, aluF2US
)
764 DECL_TEMPLATE(ALushort
, X51Chans
,6, aluF2US
)
765 DECL_TEMPLATE(ALushort
, X61Chans
,7, aluF2US
)
766 DECL_TEMPLATE(ALushort
, X71Chans
,8, aluF2US
)
768 DECL_TEMPLATE(ALshort
, MonoChans
,1, aluF2S
)
769 DECL_TEMPLATE(ALshort
, QuadChans
,4, aluF2S
)
770 DECL_TEMPLATE(ALshort
, X51Chans
,6, aluF2S
)
771 DECL_TEMPLATE(ALshort
, X61Chans
,7, aluF2S
)
772 DECL_TEMPLATE(ALshort
, X71Chans
,8, aluF2S
)
774 DECL_TEMPLATE(ALubyte
, MonoChans
,1, aluF2UB
)
775 DECL_TEMPLATE(ALubyte
, QuadChans
,4, aluF2UB
)
776 DECL_TEMPLATE(ALubyte
, X51Chans
,6, aluF2UB
)
777 DECL_TEMPLATE(ALubyte
, X61Chans
,7, aluF2UB
)
778 DECL_TEMPLATE(ALubyte
, X71Chans
,8, aluF2UB
)
780 DECL_TEMPLATE(ALbyte
, MonoChans
,1, aluF2B
)
781 DECL_TEMPLATE(ALbyte
, QuadChans
,4, aluF2B
)
782 DECL_TEMPLATE(ALbyte
, X51Chans
,6, aluF2B
)
783 DECL_TEMPLATE(ALbyte
, X61Chans
,7, aluF2B
)
784 DECL_TEMPLATE(ALbyte
, X71Chans
,8, aluF2B
)
788 #define DECL_TEMPLATE(T, chans,N, func) \
789 static void Write_##T##_##chans(ALCdevice *device, T *buffer, ALuint SamplesToDo)\
791 ALfloat (*DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
792 ALfloat (*Matrix)[MAXCHANNELS] = device->ChannelMatrix; \
793 const ALuint *ChanMap = device->DevChannels; \
798 for(i = 0;i < SamplesToDo;i++) \
800 float samples[2] = { 0.0f, 0.0f }; \
801 for(c = 0;c < MAXCHANNELS;c++) \
803 samples[0] += DryBuffer[i][c]*Matrix[c][FRONT_LEFT]; \
804 samples[1] += DryBuffer[i][c]*Matrix[c][FRONT_RIGHT]; \
806 bs2b_cross_feed(device->Bs2b, samples); \
807 ((T*)buffer)[ChanMap[FRONT_LEFT]] = func(samples[0]); \
808 ((T*)buffer)[ChanMap[FRONT_RIGHT]] = func(samples[1]); \
809 buffer = ((T*)buffer) + 2; \
814 for(i = 0;i < SamplesToDo;i++) \
816 for(j = 0;j < N;j++) \
818 ALfloat samp = 0.0f; \
819 for(c = 0;c < MAXCHANNELS;c++) \
820 samp += DryBuffer[i][c] * Matrix[c][chans[j]]; \
821 ((T*)buffer)[ChanMap[chans[j]]] = func(samp); \
823 buffer = ((T*)buffer) + N; \
828 DECL_TEMPLATE(ALfloat
, StereoChans
,2, aluF2F
)
829 DECL_TEMPLATE(ALushort
, StereoChans
,2, aluF2US
)
830 DECL_TEMPLATE(ALshort
, StereoChans
,2, aluF2S
)
831 DECL_TEMPLATE(ALubyte
, StereoChans
,2, aluF2UB
)
832 DECL_TEMPLATE(ALbyte
, StereoChans
,2, aluF2B
)
836 #define DECL_TEMPLATE(T, func) \
837 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
839 switch(device->FmtChans) \
842 Write_##T##_MonoChans(device, buffer, SamplesToDo); \
845 Write_##T##_StereoChans(device, buffer, SamplesToDo); \
848 Write_##T##_QuadChans(device, buffer, SamplesToDo); \
851 Write_##T##_X51Chans(device, buffer, SamplesToDo); \
854 Write_##T##_X61Chans(device, buffer, SamplesToDo); \
857 Write_##T##_X71Chans(device, buffer, SamplesToDo); \
862 DECL_TEMPLATE(ALfloat
, aluF2F
)
863 DECL_TEMPLATE(ALushort
, aluF2US
)
864 DECL_TEMPLATE(ALshort
, aluF2S
)
865 DECL_TEMPLATE(ALubyte
, aluF2UB
)
866 DECL_TEMPLATE(ALbyte
, aluF2B
)
870 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
873 ALeffectslot
*ALEffectSlot
;
874 ALCcontext
**ctx
, **ctx_end
;
875 ALsource
**src
, **src_end
;
880 #if defined(HAVE_FESETROUND)
881 fpuState
= fegetround();
882 fesetround(FE_TOWARDZERO
);
883 #elif defined(HAVE__CONTROLFP)
884 fpuState
= _controlfp(_RC_CHOP
, _MCW_RC
);
891 /* Setup variables */
892 SamplesToDo
= min(size
, BUFFERSIZE
);
894 /* Clear mixing buffer */
895 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
897 SuspendContext(NULL
);
898 ctx
= device
->Contexts
;
899 ctx_end
= ctx
+ device
->NumContexts
;
900 while(ctx
!= ctx_end
)
902 SuspendContext(*ctx
);
904 src
= (*ctx
)->ActiveSources
;
905 src_end
= src
+ (*ctx
)->ActiveSourceCount
;
906 while(src
!= src_end
)
908 if((*src
)->state
!= AL_PLAYING
)
910 --((*ctx
)->ActiveSourceCount
);
915 if((*src
)->NeedsUpdate
)
917 ALsource_Update(*src
, *ctx
);
918 (*src
)->NeedsUpdate
= AL_FALSE
;
921 MixSource(*src
, device
, SamplesToDo
);
925 /* effect slot processing */
926 for(e
= 0;e
< (*ctx
)->EffectSlotMap
.size
;e
++)
928 ALEffectSlot
= (*ctx
)->EffectSlotMap
.array
[e
].value
;
930 for(i
= 0;i
< SamplesToDo
;i
++)
932 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
933 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
937 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
938 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
941 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
942 SamplesToDo
, ALEffectSlot
->WetBuffer
,
945 for(i
= 0;i
< SamplesToDo
;i
++)
946 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
949 ProcessContext(*ctx
);
952 ProcessContext(NULL
);
954 //Post processing loop
955 for(i
= 0;i
< SamplesToDo
;i
++)
957 for(c
= 0;c
< MAXCHANNELS
;c
++)
959 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
960 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
963 for(i
= 0;i
< MAXCHANNELS
;i
++)
965 device
->ClickRemoval
[i
] += device
->PendingClicks
[i
];
966 device
->PendingClicks
[i
] = 0.0f
;
969 switch(device
->FmtType
)
972 Write_ALbyte(device
, buffer
, SamplesToDo
);
975 Write_ALubyte(device
, buffer
, SamplesToDo
);
978 Write_ALshort(device
, buffer
, SamplesToDo
);
981 Write_ALushort(device
, buffer
, SamplesToDo
);
984 Write_ALfloat(device
, buffer
, SamplesToDo
);
991 #if defined(HAVE_FESETROUND)
992 fesetround(fpuState
);
993 #elif defined(HAVE__CONTROLFP)
994 _controlfp(fpuState
, _MCW_RC
);
999 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1003 SuspendContext(NULL
);
1004 for(i
= 0;i
< device
->NumContexts
;i
++)
1006 ALCcontext
*Context
= device
->Contexts
[i
];
1010 SuspendContext(Context
);
1012 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
1014 source
= Context
->SourceMap
.array
[pos
].value
;
1015 if(source
->state
== AL_PLAYING
)
1017 source
->state
= AL_STOPPED
;
1018 source
->BuffersPlayed
= source
->BuffersInQueue
;
1019 source
->position
= 0;
1020 source
->position_fraction
= 0;
1023 ProcessContext(Context
);
1026 device
->Connected
= ALC_FALSE
;
1027 ProcessContext(NULL
);