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 static const ALfloat angles_Mono
[1] = { 0.0f
};
82 static const ALfloat angles_Stereo
[2] = { -30.0f
, 30.0f
};
83 static const ALfloat angles_Rear
[2] = { -150.0f
, 150.0f
};
84 static const ALfloat angles_Quad
[4] = { -45.0f
, 45.0f
, -135.0f
, 135.0f
};
85 static const ALfloat angles_X51
[6] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
87 static const ALfloat angles_X61
[7] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
88 180.0f
, -90.0f
, 90.0f
};
89 static const ALfloat angles_X71
[8] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
90 -110.0f
, 110.0f
, -90.0f
, 90.0f
};
92 static const enum Channel chans_Mono
[1] = { FRONT_CENTER
};
93 static const enum Channel chans_Stereo
[2] = { FRONT_LEFT
, FRONT_RIGHT
};
94 static const enum Channel chans_Rear
[2] = { BACK_LEFT
, BACK_RIGHT
};
95 static const enum Channel chans_Quad
[4] = { FRONT_LEFT
, FRONT_RIGHT
,
96 BACK_LEFT
, BACK_RIGHT
};
97 static const enum Channel chans_X51
[6] = { FRONT_LEFT
, FRONT_RIGHT
,
99 BACK_LEFT
, BACK_RIGHT
};
100 static const enum Channel chans_X61
[7] = { FRONT_LEFT
, FRONT_RIGHT
,
101 FRONT_CENTER
, LFE
, BACK_CENTER
,
102 SIDE_LEFT
, SIDE_RIGHT
};
103 static const enum Channel chans_X71
[8] = { FRONT_LEFT
, FRONT_RIGHT
,
105 BACK_LEFT
, BACK_RIGHT
,
106 SIDE_LEFT
, SIDE_RIGHT
};
108 ALCdevice
*Device
= ALContext
->Device
;
109 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
110 ALbufferlistitem
*BufferListItem
;
111 enum DevFmtChannels DevChans
;
112 enum FmtChannels Channels
;
113 ALfloat (*SrcMatrix
)[MAXCHANNELS
];
114 ALfloat DryGain
, DryGainHF
;
115 ALfloat WetGain
[MAX_SENDS
];
116 ALfloat WetGainHF
[MAX_SENDS
];
117 ALint NumSends
, Frequency
;
118 const ALfloat
*SpeakerGain
;
119 const ALfloat
*angles
= NULL
;
120 const enum Channel
*chans
= NULL
;
121 enum Resampler Resampler
;
122 ALint num_channels
= 0;
123 ALboolean VirtualChannels
;
129 /* Get device properties */
130 DevChans
= ALContext
->Device
->FmtChans
;
131 NumSends
= ALContext
->Device
->NumAuxSends
;
132 Frequency
= ALContext
->Device
->Frequency
;
134 /* Get listener properties */
135 ListenerGain
= ALContext
->Listener
.Gain
;
137 /* Get source properties */
138 SourceVolume
= ALSource
->flGain
;
139 MinVolume
= ALSource
->flMinGain
;
140 MaxVolume
= ALSource
->flMaxGain
;
141 Pitch
= ALSource
->flPitch
;
142 Resampler
= ALSource
->Resampler
;
143 VirtualChannels
= ALSource
->VirtualChannels
;
145 /* Calculate the stepping value */
147 BufferListItem
= ALSource
->queue
;
148 while(BufferListItem
!= NULL
)
151 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
153 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
154 ALSource
->SampleSize
;
155 maxstep
-= ResamplerPadding
[Resampler
] +
156 ResamplerPrePadding
[Resampler
] + 1;
157 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
159 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
160 if(Pitch
> (ALfloat
)maxstep
)
161 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
164 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
165 if(ALSource
->Params
.Step
== 0)
166 ALSource
->Params
.Step
= 1;
169 Channels
= ALBuffer
->FmtChannels
;
171 if(ALSource
->VirtualChannels
&& (Device
->Flags
&DEVICE_USE_HRTF
))
172 ALSource
->Params
.DoMix
= SelectHrtfMixer(ALBuffer
,
173 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
176 ALSource
->Params
.DoMix
= SelectMixer(ALBuffer
,
177 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
181 BufferListItem
= BufferListItem
->next
;
184 /* Calculate gains */
185 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
187 switch(ALSource
->DirectFilter
.type
)
189 case AL_FILTER_LOWPASS
:
190 DryGain
*= ALSource
->DirectFilter
.Gain
;
191 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
194 for(i
= 0;i
< NumSends
;i
++)
196 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
198 switch(ALSource
->Send
[i
].WetFilter
.type
)
200 case AL_FILTER_LOWPASS
:
201 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
202 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
207 SrcMatrix
= ALSource
->Params
.DryGains
;
208 for(i
= 0;i
< MAXCHANNELS
;i
++)
210 for(c
= 0;c
< MAXCHANNELS
;c
++)
211 SrcMatrix
[i
][c
] = 0.0f
;
216 angles
= angles_Mono
;
221 if(VirtualChannels
&& (ALContext
->Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
223 DryGain
*= aluSqrt(2.0f
/4.0f
);
226 pos
= aluCart2LUTpos(cos(angles_Rear
[c
] * (M_PI
/180.0)),
227 sin(angles_Rear
[c
] * (M_PI
/180.0)));
228 SpeakerGain
= Device
->PanningLUT
[pos
];
230 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
232 enum Channel chan
= Device
->Speaker2Chan
[i
];
233 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
238 angles
= angles_Stereo
;
239 chans
= chans_Stereo
;
244 angles
= angles_Rear
;
250 angles
= angles_Quad
;
274 if(VirtualChannels
== AL_FALSE
)
276 for(c
= 0;c
< num_channels
;c
++)
277 SrcMatrix
[c
][chans
[c
]] += DryGain
* ListenerGain
;
279 else if((Device
->Flags
&DEVICE_USE_HRTF
))
281 for(c
= 0;c
< num_channels
;c
++)
286 ALSource
->Params
.HrtfDelay
[c
][0] = 0;
287 ALSource
->Params
.HrtfDelay
[c
][1] = 0;
288 for(i
= 0;i
< HRIR_LENGTH
;i
++)
290 ALSource
->Params
.HrtfCoeffs
[c
][i
][0] = 0.0f
;
291 ALSource
->Params
.HrtfCoeffs
[c
][i
][1] = 0.0f
;
296 /* Get the static HRIR coefficients and delays for this
298 GetLerpedHrtfCoeffs(0.0, angles
[c
] * (M_PI
/180.0),
299 DryGain
*ListenerGain
,
300 ALSource
->Params
.HrtfCoeffs
[c
],
301 ALSource
->Params
.HrtfDelay
[c
]);
303 ALSource
->HrtfCounter
= 0;
308 for(c
= 0;c
< num_channels
;c
++)
310 if(chans
[c
] == LFE
) /* Special-case LFE */
312 SrcMatrix
[c
][LFE
] += DryGain
* ListenerGain
;
315 pos
= aluCart2LUTpos(cos(angles
[c
] * (M_PI
/180.0)),
316 sin(angles
[c
] * (M_PI
/180.0)));
317 SpeakerGain
= Device
->PanningLUT
[pos
];
319 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
321 enum Channel chan
= Device
->Speaker2Chan
[i
];
322 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
327 for(i
= 0;i
< NumSends
;i
++)
329 ALSource
->Params
.Send
[i
].Slot
= ALSource
->Send
[i
].Slot
;
330 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
333 /* Update filter coefficients. Calculations based on the I3DL2
335 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
337 /* We use two chained one-pole filters, so we need to take the
338 * square root of the squared gain, which is the same as the base
340 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
341 for(i
= 0;i
< NumSends
;i
++)
343 /* We use a one-pole filter, so we need to take the squared gain */
344 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
345 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
349 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
351 const ALCdevice
*Device
= ALContext
->Device
;
352 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
353 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
354 ALfloat Velocity
[3],ListenerVel
[3];
355 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
356 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
357 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
358 ALfloat AirAbsorptionFactor
;
359 ALfloat RoomAirAbsorption
[MAX_SENDS
];
360 ALbufferlistitem
*BufferListItem
;
361 ALfloat Attenuation
, EffectiveDist
;
362 ALfloat RoomAttenuation
[MAX_SENDS
];
363 ALfloat MetersPerUnit
;
364 ALfloat RoomRolloffBase
;
365 ALfloat RoomRolloff
[MAX_SENDS
];
366 ALfloat DecayDistance
[MAX_SENDS
];
369 ALboolean DryGainHFAuto
;
370 ALfloat WetGain
[MAX_SENDS
];
371 ALfloat WetGainHF
[MAX_SENDS
];
372 ALboolean WetGainAuto
;
373 ALboolean WetGainHFAuto
;
374 enum Resampler Resampler
;
382 for(i
= 0;i
< MAX_SENDS
;i
++)
385 //Get context properties
386 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
387 DopplerVelocity
= ALContext
->DopplerVelocity
;
388 SpeedOfSound
= ALContext
->flSpeedOfSound
;
389 NumSends
= Device
->NumAuxSends
;
390 Frequency
= Device
->Frequency
;
392 //Get listener properties
393 ListenerGain
= ALContext
->Listener
.Gain
;
394 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
395 memcpy(ListenerVel
, ALContext
->Listener
.Velocity
, sizeof(ALContext
->Listener
.Velocity
));
397 //Get source properties
398 SourceVolume
= ALSource
->flGain
;
399 MinVolume
= ALSource
->flMinGain
;
400 MaxVolume
= ALSource
->flMaxGain
;
401 Pitch
= ALSource
->flPitch
;
402 Resampler
= ALSource
->Resampler
;
403 memcpy(Position
, ALSource
->vPosition
, sizeof(ALSource
->vPosition
));
404 memcpy(Direction
, ALSource
->vOrientation
, sizeof(ALSource
->vOrientation
));
405 memcpy(Velocity
, ALSource
->vVelocity
, sizeof(ALSource
->vVelocity
));
406 MinDist
= ALSource
->flRefDistance
;
407 MaxDist
= ALSource
->flMaxDistance
;
408 Rolloff
= ALSource
->flRollOffFactor
;
409 InnerAngle
= ALSource
->flInnerAngle
* ConeScale
;
410 OuterAngle
= ALSource
->flOuterAngle
* ConeScale
;
411 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
412 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
413 WetGainAuto
= ALSource
->WetGainAuto
;
414 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
415 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
416 for(i
= 0;i
< NumSends
;i
++)
418 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
420 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
422 RoomRolloff
[i
] = 0.0f
;
423 DecayDistance
[i
] = 0.0f
;
424 RoomAirAbsorption
[i
] = 1.0f
;
426 else if(Slot
->AuxSendAuto
)
428 RoomRolloff
[i
] = RoomRolloffBase
;
429 if(IsReverbEffect(Slot
->effect
.type
))
431 RoomRolloff
[i
] += Slot
->effect
.Params
.Reverb
.RoomRolloffFactor
;
432 DecayDistance
[i
] = Slot
->effect
.Params
.Reverb
.DecayTime
*
433 SPEEDOFSOUNDMETRESPERSEC
;
434 RoomAirAbsorption
[i
] = Slot
->effect
.Params
.Reverb
.AirAbsorptionGainHF
;
438 DecayDistance
[i
] = 0.0f
;
439 RoomAirAbsorption
[i
] = 1.0f
;
444 /* If the slot's auxiliary send auto is off, the data sent to the
445 * effect slot is the same as the dry path, sans filter effects */
446 RoomRolloff
[i
] = Rolloff
;
447 DecayDistance
[i
] = 0.0f
;
448 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
451 ALSource
->Params
.Send
[i
].Slot
= Slot
;
454 //1. Translate Listener to origin (convert to head relative)
455 if(ALSource
->bHeadRelative
== AL_FALSE
)
457 ALfloat U
[3],V
[3],N
[3];
458 ALfloat Matrix
[4][4];
460 // Build transform matrix
461 memcpy(N
, ALContext
->Listener
.Forward
, sizeof(N
)); // At-vector
462 aluNormalize(N
); // Normalized At-vector
463 memcpy(V
, ALContext
->Listener
.Up
, sizeof(V
)); // Up-vector
464 aluNormalize(V
); // Normalized Up-vector
465 aluCrossproduct(N
, V
, U
); // Right-vector
466 aluNormalize(U
); // Normalized Right-vector
467 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
468 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
469 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
470 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
472 // Translate position
473 Position
[0] -= ALContext
->Listener
.Position
[0];
474 Position
[1] -= ALContext
->Listener
.Position
[1];
475 Position
[2] -= ALContext
->Listener
.Position
[2];
477 // Transform source position and direction into listener space
478 aluMatrixVector(Position
, 1.0f
, Matrix
);
479 aluMatrixVector(Direction
, 0.0f
, Matrix
);
480 // Transform source and listener velocity into listener space
481 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
482 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
485 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
487 SourceToListener
[0] = -Position
[0];
488 SourceToListener
[1] = -Position
[1];
489 SourceToListener
[2] = -Position
[2];
490 aluNormalize(SourceToListener
);
491 aluNormalize(Direction
);
493 //2. Calculate distance attenuation
494 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
495 ClampedDist
= Distance
;
498 for(i
= 0;i
< NumSends
;i
++)
499 RoomAttenuation
[i
] = 1.0f
;
500 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
501 ALContext
->DistanceModel
)
503 case InverseDistanceClamped
:
504 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
505 if(MaxDist
< MinDist
)
508 case InverseDistance
:
511 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
512 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
513 for(i
= 0;i
< NumSends
;i
++)
515 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
516 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
521 case LinearDistanceClamped
:
522 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
523 if(MaxDist
< MinDist
)
527 if(MaxDist
!= MinDist
)
529 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
530 Attenuation
= maxf(Attenuation
, 0.0f
);
531 for(i
= 0;i
< NumSends
;i
++)
533 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
534 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
539 case ExponentDistanceClamped
:
540 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
541 if(MaxDist
< MinDist
)
544 case ExponentDistance
:
545 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
547 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
548 for(i
= 0;i
< NumSends
;i
++)
549 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
553 case DisableDistance
:
557 // Source Gain + Attenuation
558 DryGain
= SourceVolume
* Attenuation
;
559 for(i
= 0;i
< NumSends
;i
++)
560 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
562 // Distance-based air absorption
563 EffectiveDist
= 0.0f
;
564 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
565 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
566 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
568 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*EffectiveDist
);
569 for(i
= 0;i
< NumSends
;i
++)
570 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
],
571 AirAbsorptionFactor
*EffectiveDist
);
574 //3. Apply directional soundcones
575 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0/M_PI
);
576 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
578 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
579 ConeVolume
= lerp(1.0, ALSource
->flOuterGain
, scale
);
580 ConeHF
= lerp(1.0, ALSource
->OuterGainHF
, scale
);
582 else if(Angle
> OuterAngle
)
584 ConeVolume
= ALSource
->flOuterGain
;
585 ConeHF
= ALSource
->OuterGainHF
;
593 DryGain
*= ConeVolume
;
596 for(i
= 0;i
< NumSends
;i
++)
597 WetGain
[i
] *= ConeVolume
;
603 for(i
= 0;i
< NumSends
;i
++)
604 WetGainHF
[i
] *= ConeHF
;
607 // Clamp to Min/Max Gain
608 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
609 for(i
= 0;i
< NumSends
;i
++)
610 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
612 // Apply filter gains and filters
613 switch(ALSource
->DirectFilter
.type
)
615 case AL_FILTER_LOWPASS
:
616 DryGain
*= ALSource
->DirectFilter
.Gain
;
617 DryGainHF
*= ALSource
->DirectFilter
.GainHF
;
620 DryGain
*= ListenerGain
;
621 for(i
= 0;i
< NumSends
;i
++)
623 switch(ALSource
->Send
[i
].WetFilter
.type
)
625 case AL_FILTER_LOWPASS
:
626 WetGain
[i
] *= ALSource
->Send
[i
].WetFilter
.Gain
;
627 WetGainHF
[i
] *= ALSource
->Send
[i
].WetFilter
.GainHF
;
630 WetGain
[i
] *= ListenerGain
;
635 /* Apply a decay-time transformation to the wet path, based on the
636 * attenuation of the dry path.
638 * Using the approximate (effective) source to listener distance, the
639 * initial decay of the reverb effect is calculated and applied to the
642 for(i
= 0;i
< NumSends
;i
++)
644 if(DecayDistance
[i
] > 0.0f
)
645 WetGain
[i
] *= aluPow(0.001f
/* -60dB */,
646 EffectiveDist
/ DecayDistance
[i
]);
650 // Calculate Velocity
651 if(DopplerFactor
!= 0.0f
)
654 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
657 VSS
= aluDotproduct(Velocity
, SourceToListener
);
658 if(VSS
>= MaxVelocity
)
659 VSS
= (MaxVelocity
- 1.0f
);
660 else if(VSS
<= -MaxVelocity
)
661 VSS
= -MaxVelocity
+ 1.0f
;
663 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
664 if(VLS
>= MaxVelocity
)
665 VLS
= (MaxVelocity
- 1.0f
);
666 else if(VLS
<= -MaxVelocity
)
667 VLS
= -MaxVelocity
+ 1.0f
;
669 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
670 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
673 BufferListItem
= ALSource
->queue
;
674 while(BufferListItem
!= NULL
)
677 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
679 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
680 ALSource
->SampleSize
;
681 maxstep
-= ResamplerPadding
[Resampler
] +
682 ResamplerPrePadding
[Resampler
] + 1;
683 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
685 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
686 if(Pitch
> (ALfloat
)maxstep
)
687 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
690 ALSource
->Params
.Step
= Pitch
*FRACTIONONE
;
691 if(ALSource
->Params
.Step
== 0)
692 ALSource
->Params
.Step
= 1;
695 if((Device
->Flags
&DEVICE_USE_HRTF
))
696 ALSource
->Params
.DoMix
= SelectHrtfMixer(ALBuffer
,
697 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
700 ALSource
->Params
.DoMix
= SelectMixer(ALBuffer
,
701 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
705 BufferListItem
= BufferListItem
->next
;
708 if((Device
->Flags
&DEVICE_USE_HRTF
))
710 // Use a binaural HRTF algorithm for stereo headphone playback
711 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
715 ALfloat invlen
= 1.0f
/Distance
;
716 Position
[0] *= invlen
;
717 Position
[1] *= invlen
;
718 Position
[2] *= invlen
;
720 // Calculate elevation and azimuth only when the source is not at
721 // the listener. This prevents +0 and -0 Z from producing
722 // inconsistent panning.
723 ev
= asin(Position
[1]);
724 az
= atan2(Position
[0], -Position
[2]*ZScale
);
727 // Check to see if the HRIR is already moving.
728 if(ALSource
->HrtfMoving
)
730 // Calculate the normalized HRTF transition factor (delta).
731 delta
= CalcHrtfDelta(ALSource
->Params
.HrtfGain
, DryGain
,
732 ALSource
->Params
.HrtfDir
, Position
);
733 // If the delta is large enough, get the moving HRIR target
734 // coefficients, target delays, steppping values, and counter.
737 ALSource
->HrtfCounter
= GetMovingHrtfCoeffs(ev
, az
, DryGain
,
738 delta
, ALSource
->HrtfCounter
,
739 ALSource
->Params
.HrtfCoeffs
[0],
740 ALSource
->Params
.HrtfDelay
[0],
741 ALSource
->Params
.HrtfCoeffStep
,
742 ALSource
->Params
.HrtfDelayStep
);
743 ALSource
->Params
.HrtfGain
= DryGain
;
744 ALSource
->Params
.HrtfDir
[0] = Position
[0];
745 ALSource
->Params
.HrtfDir
[1] = Position
[1];
746 ALSource
->Params
.HrtfDir
[2] = Position
[2];
751 // Get the initial (static) HRIR coefficients and delays.
752 GetLerpedHrtfCoeffs(ev
, az
, DryGain
,
753 ALSource
->Params
.HrtfCoeffs
[0],
754 ALSource
->Params
.HrtfDelay
[0]);
755 ALSource
->HrtfCounter
= 0;
756 ALSource
->Params
.HrtfGain
= DryGain
;
757 ALSource
->Params
.HrtfDir
[0] = Position
[0];
758 ALSource
->Params
.HrtfDir
[1] = Position
[1];
759 ALSource
->Params
.HrtfDir
[2] = Position
[2];
764 // Use energy-preserving panning algorithm for multi-speaker playback
765 ALfloat DirGain
, AmbientGain
;
766 const ALfloat
*SpeakerGain
;
770 length
= maxf(Distance
, MinDist
);
773 ALfloat invlen
= 1.0f
/length
;
774 Position
[0] *= invlen
;
775 Position
[1] *= invlen
;
776 Position
[2] *= invlen
;
779 pos
= aluCart2LUTpos(-Position
[2]*ZScale
, Position
[0]);
780 SpeakerGain
= Device
->PanningLUT
[pos
];
782 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
783 // elevation adjustment for directional gain. this sucks, but
784 // has low complexity
785 AmbientGain
= aluSqrt(1.0/Device
->NumChan
);
786 for(i
= 0;i
< MAXCHANNELS
;i
++)
789 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
790 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
792 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
794 enum Channel chan
= Device
->Speaker2Chan
[i
];
795 ALfloat gain
= lerp(AmbientGain
, SpeakerGain
[chan
], DirGain
);
796 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
799 for(i
= 0;i
< NumSends
;i
++)
800 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
];
802 /* Update filter coefficients. */
803 cw
= cos(2.0*M_PI
* LOWPASSFREQCUTOFF
/ Frequency
);
805 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
806 for(i
= 0;i
< NumSends
;i
++)
808 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
809 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
814 static __inline ALfloat
aluF2F(ALfloat val
)
816 static __inline ALshort
aluF2S(ALfloat val
)
818 if(val
> 1.0f
) return 32767;
819 if(val
< -1.0f
) return -32768;
820 return (ALint
)(val
*32767.0f
);
822 static __inline ALushort
aluF2US(ALfloat val
)
823 { return aluF2S(val
)+32768; }
824 static __inline ALbyte
aluF2B(ALfloat val
)
825 { return aluF2S(val
)>>8; }
826 static __inline ALubyte
aluF2UB(ALfloat val
)
827 { return aluF2US(val
)>>8; }
829 #define DECL_TEMPLATE(T, N, func) \
830 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
831 ALuint SamplesToDo) \
833 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
834 const enum Channel *ChanMap = device->DevChannels; \
837 for(i = 0;i < SamplesToDo;i++) \
839 for(j = 0;j < N;j++) \
840 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
844 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
845 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
846 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
847 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
848 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
850 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
851 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
852 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
853 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
854 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
856 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
857 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
858 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
859 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
860 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
862 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
863 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
864 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
865 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
866 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
868 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
869 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
870 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
871 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
872 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
876 #define DECL_TEMPLATE(T, N, func) \
877 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
878 ALuint SamplesToDo) \
880 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
881 const enum Channel *ChanMap = device->DevChannels; \
886 for(i = 0;i < SamplesToDo;i++) \
889 samples[0] = DryBuffer[i][ChanMap[0]]; \
890 samples[1] = DryBuffer[i][ChanMap[1]]; \
891 bs2b_cross_feed(device->Bs2b, samples); \
892 *(buffer++) = func(samples[0]); \
893 *(buffer++) = func(samples[1]); \
898 for(i = 0;i < SamplesToDo;i++) \
900 for(j = 0;j < N;j++) \
901 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
906 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
907 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
908 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
909 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
910 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
914 #define DECL_TEMPLATE(T) \
915 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
917 switch(device->FmtChans) \
920 Write_##T##_1(device, buffer, SamplesToDo); \
923 Write_##T##_2(device, buffer, SamplesToDo); \
926 Write_##T##_4(device, buffer, SamplesToDo); \
929 case DevFmtX51Side: \
930 Write_##T##_6(device, buffer, SamplesToDo); \
933 Write_##T##_7(device, buffer, SamplesToDo); \
936 Write_##T##_8(device, buffer, SamplesToDo); \
941 DECL_TEMPLATE(ALfloat
)
942 DECL_TEMPLATE(ALushort
)
943 DECL_TEMPLATE(ALshort
)
944 DECL_TEMPLATE(ALubyte
)
945 DECL_TEMPLATE(ALbyte
)
949 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
952 ALeffectslot
*ALEffectSlot
;
953 ALsource
**src
, **src_end
;
959 #if defined(HAVE_FESETROUND)
960 fpuState
= fegetround();
961 fesetround(FE_TOWARDZERO
);
962 #elif defined(HAVE__CONTROLFP)
963 fpuState
= _controlfp(0, 0);
964 (void)_controlfp(_RC_CHOP
, _MCW_RC
);
971 /* Setup variables */
972 SamplesToDo
= minu(size
, BUFFERSIZE
);
974 /* Clear mixing buffer */
975 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
978 ctx
= device
->ContextList
;
981 ALenum DeferUpdates
= ctx
->DeferUpdates
;
982 ALenum UpdateSources
= AL_FALSE
;
985 UpdateSources
= Exchange_ALenum(&ctx
->UpdateSources
, AL_FALSE
);
987 src
= ctx
->ActiveSources
;
988 src_end
= src
+ ctx
->ActiveSourceCount
;
989 while(src
!= src_end
)
991 if((*src
)->state
!= AL_PLAYING
)
993 --(ctx
->ActiveSourceCount
);
998 if(!DeferUpdates
&& (Exchange_ALenum(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
1000 ALsource_Update(*src
, ctx
);
1002 MixSource(*src
, device
, SamplesToDo
);
1006 /* effect slot processing */
1007 for(e
= 0;e
< ctx
->EffectSlotMap
.size
;e
++)
1009 ALEffectSlot
= ctx
->EffectSlotMap
.array
[e
].value
;
1011 for(i
= 0;i
< SamplesToDo
;i
++)
1013 ALEffectSlot
->WetBuffer
[i
] += ALEffectSlot
->ClickRemoval
[0];
1014 ALEffectSlot
->ClickRemoval
[0] -= ALEffectSlot
->ClickRemoval
[0] / 256.0f
;
1016 for(i
= 0;i
< 1;i
++)
1018 ALEffectSlot
->ClickRemoval
[i
] += ALEffectSlot
->PendingClicks
[i
];
1019 ALEffectSlot
->PendingClicks
[i
] = 0.0f
;
1022 if(!DeferUpdates
&& Exchange_ALenum(&ALEffectSlot
->NeedsUpdate
, AL_FALSE
))
1023 ALEffect_Update(ALEffectSlot
->EffectState
, ctx
, ALEffectSlot
);
1025 ALEffect_Process(ALEffectSlot
->EffectState
, ALEffectSlot
,
1026 SamplesToDo
, ALEffectSlot
->WetBuffer
,
1029 for(i
= 0;i
< SamplesToDo
;i
++)
1030 ALEffectSlot
->WetBuffer
[i
] = 0.0f
;
1035 UnlockDevice(device
);
1037 //Post processing loop
1038 if(device
->FmtChans
== DevFmtMono
)
1040 for(i
= 0;i
< SamplesToDo
;i
++)
1042 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
1043 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] / 256.0f
;
1045 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
1046 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
1048 else if(device
->FmtChans
== DevFmtStereo
)
1050 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
1051 for(i
= 0;i
< SamplesToDo
;i
++)
1053 for(c
= 0;c
< 2;c
++)
1055 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1056 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
1059 for(c
= 0;c
< 2;c
++)
1061 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1062 device
->PendingClicks
[c
] = 0.0f
;
1067 for(i
= 0;i
< SamplesToDo
;i
++)
1069 for(c
= 0;c
< MAXCHANNELS
;c
++)
1071 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1072 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] / 256.0f
;
1075 for(c
= 0;c
< MAXCHANNELS
;c
++)
1077 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1078 device
->PendingClicks
[c
] = 0.0f
;
1084 switch(device
->FmtType
)
1087 Write_ALbyte(device
, buffer
, SamplesToDo
);
1090 Write_ALubyte(device
, buffer
, SamplesToDo
);
1093 Write_ALshort(device
, buffer
, SamplesToDo
);
1096 Write_ALushort(device
, buffer
, SamplesToDo
);
1099 Write_ALfloat(device
, buffer
, SamplesToDo
);
1104 size
-= SamplesToDo
;
1107 #if defined(HAVE_FESETROUND)
1108 fesetround(fpuState
);
1109 #elif defined(HAVE__CONTROLFP)
1110 _controlfp(fpuState
, _MCW_RC
);
1115 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1117 ALCcontext
*Context
;
1120 Context
= device
->ContextList
;
1126 LockUIntMapRead(&Context
->SourceMap
);
1127 for(pos
= 0;pos
< Context
->SourceMap
.size
;pos
++)
1129 source
= Context
->SourceMap
.array
[pos
].value
;
1130 if(source
->state
== AL_PLAYING
)
1132 source
->state
= AL_STOPPED
;
1133 source
->BuffersPlayed
= source
->BuffersInQueue
;
1134 source
->position
= 0;
1135 source
->position_fraction
= 0;
1138 UnlockUIntMapRead(&Context
->SourceMap
);
1140 Context
= Context
->next
;
1143 device
->Connected
= ALC_FALSE
;
1144 UnlockDevice(device
);