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"
41 ALfloat ConeScale
= 0.5f
;
43 /* Localized Z scalar for mono sources */
44 ALfloat ZScale
= 1.0f
;
47 static __inline ALvoid
aluCrossproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
, ALfloat
*outVector
)
49 outVector
[0] = inVector1
[1]*inVector2
[2] - inVector1
[2]*inVector2
[1];
50 outVector
[1] = inVector1
[2]*inVector2
[0] - inVector1
[0]*inVector2
[2];
51 outVector
[2] = inVector1
[0]*inVector2
[1] - inVector1
[1]*inVector2
[0];
54 static __inline ALfloat
aluDotproduct(const ALfloat
*inVector1
, const ALfloat
*inVector2
)
56 return inVector1
[0]*inVector2
[0] + inVector1
[1]*inVector2
[1] +
57 inVector1
[2]*inVector2
[2];
60 static __inline ALvoid
aluNormalize(ALfloat
*inVector
)
62 ALfloat length
, inverse_length
;
64 length
= aluSqrt(aluDotproduct(inVector
, inVector
));
67 inverse_length
= 1.0f
/length
;
68 inVector
[0] *= inverse_length
;
69 inVector
[1] *= inverse_length
;
70 inVector
[2] *= inverse_length
;
74 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
77 vector
[0], vector
[1], vector
[2], w
80 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
81 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
82 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
86 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
88 static const ALfloat angles_Mono
[1] = { 0.0f
};
89 static const ALfloat angles_Stereo
[2] = { -30.0f
, 30.0f
};
90 static const ALfloat angles_Rear
[2] = { -150.0f
, 150.0f
};
91 static const ALfloat angles_Quad
[4] = { -45.0f
, 45.0f
, -135.0f
, 135.0f
};
92 static const ALfloat angles_X51
[6] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
94 static const ALfloat angles_X61
[7] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
95 180.0f
, -90.0f
, 90.0f
};
96 static const ALfloat angles_X71
[8] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
97 -110.0f
, 110.0f
, -90.0f
, 90.0f
};
99 static const enum Channel chans_Mono
[1] = { FRONT_CENTER
};
100 static const enum Channel chans_Stereo
[2] = { FRONT_LEFT
, FRONT_RIGHT
};
101 static const enum Channel chans_Rear
[2] = { BACK_LEFT
, BACK_RIGHT
};
102 static const enum Channel chans_Quad
[4] = { FRONT_LEFT
, FRONT_RIGHT
,
103 BACK_LEFT
, BACK_RIGHT
};
104 static const enum Channel chans_X51
[6] = { FRONT_LEFT
, FRONT_RIGHT
,
106 BACK_LEFT
, BACK_RIGHT
};
107 static const enum Channel chans_X61
[7] = { FRONT_LEFT
, FRONT_RIGHT
,
108 FRONT_CENTER
, LFE
, BACK_CENTER
,
109 SIDE_LEFT
, SIDE_RIGHT
};
110 static const enum Channel chans_X71
[8] = { FRONT_LEFT
, FRONT_RIGHT
,
112 BACK_LEFT
, BACK_RIGHT
,
113 SIDE_LEFT
, SIDE_RIGHT
};
115 ALCdevice
*Device
= ALContext
->Device
;
116 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
117 ALbufferlistitem
*BufferListItem
;
118 enum DevFmtChannels DevChans
;
119 enum FmtChannels Channels
;
120 ALfloat (*SrcMatrix
)[MAXCHANNELS
];
121 ALfloat DryGain
, DryGainHF
;
122 ALfloat WetGain
[MAX_SENDS
];
123 ALfloat WetGainHF
[MAX_SENDS
];
124 ALint NumSends
, Frequency
;
125 const ALfloat
*SpeakerGain
;
126 const ALfloat
*angles
= NULL
;
127 const enum Channel
*chans
= NULL
;
128 enum Resampler Resampler
;
129 ALint num_channels
= 0;
130 ALboolean VirtualChannels
;
136 /* Get device properties */
137 DevChans
= ALContext
->Device
->FmtChans
;
138 NumSends
= ALContext
->Device
->NumAuxSends
;
139 Frequency
= ALContext
->Device
->Frequency
;
141 /* Get listener properties */
142 ListenerGain
= ALContext
->Listener
.Gain
;
144 /* Get source properties */
145 SourceVolume
= ALSource
->flGain
;
146 MinVolume
= ALSource
->flMinGain
;
147 MaxVolume
= ALSource
->flMaxGain
;
148 Pitch
= ALSource
->flPitch
;
149 Resampler
= ALSource
->Resampler
;
150 VirtualChannels
= ALSource
->VirtualChannels
;
152 /* Calculate the stepping value */
154 BufferListItem
= ALSource
->queue
;
155 while(BufferListItem
!= NULL
)
158 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
160 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
161 ALSource
->SampleSize
;
162 maxstep
-= ResamplerPadding
[Resampler
] +
163 ResamplerPrePadding
[Resampler
] + 1;
164 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
166 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
167 if(Pitch
> (ALfloat
)maxstep
)
168 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
171 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
172 if(ALSource
->Params
.Step
== 0)
173 ALSource
->Params
.Step
= 1;
176 Channels
= ALBuffer
->FmtChannels
;
178 if(ALSource
->VirtualChannels
&& (Device
->Flags
&DEVICE_USE_HRTF
))
179 ALSource
->Params
.DoMix
= SelectHrtfMixer(ALBuffer
,
180 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
183 ALSource
->Params
.DoMix
= SelectMixer(ALBuffer
,
184 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
188 BufferListItem
= BufferListItem
->next
;
191 /* Calculate gains */
192 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
193 DryGain
*= ALSource
->DirectGain
;
194 DryGainHF
= ALSource
->DirectGainHF
;
195 for(i
= 0;i
< NumSends
;i
++)
197 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
198 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
;
199 WetGainHF
[i
] = ALSource
->Send
[i
].WetGainHF
;
202 SrcMatrix
= ALSource
->Params
.DryGains
;
203 for(i
= 0;i
< MAXCHANNELS
;i
++)
205 for(c
= 0;c
< MAXCHANNELS
;c
++)
206 SrcMatrix
[i
][c
] = 0.0f
;
211 angles
= angles_Mono
;
216 if(VirtualChannels
&& (ALContext
->Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
218 DryGain
*= aluSqrt(2.0f
/4.0f
);
221 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* angles_Rear
[c
]),
222 aluSin(F_PI
/180.0f
* angles_Rear
[c
]));
223 SpeakerGain
= Device
->PanningLUT
[pos
];
225 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
227 enum Channel chan
= Device
->Speaker2Chan
[i
];
228 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
233 angles
= angles_Stereo
;
234 chans
= chans_Stereo
;
239 angles
= angles_Rear
;
245 angles
= angles_Quad
;
269 if(VirtualChannels
== AL_FALSE
)
271 for(c
= 0;c
< num_channels
;c
++)
272 SrcMatrix
[c
][chans
[c
]] += DryGain
* ListenerGain
;
274 else if((Device
->Flags
&DEVICE_USE_HRTF
))
276 for(c
= 0;c
< num_channels
;c
++)
281 ALSource
->Params
.HrtfDelay
[c
][0] = 0;
282 ALSource
->Params
.HrtfDelay
[c
][1] = 0;
283 for(i
= 0;i
< HRIR_LENGTH
;i
++)
285 ALSource
->Params
.HrtfCoeffs
[c
][i
][0] = 0.0f
;
286 ALSource
->Params
.HrtfCoeffs
[c
][i
][1] = 0.0f
;
291 /* Get the static HRIR coefficients and delays for this
293 GetLerpedHrtfCoeffs(ALContext
->Device
->Hrtf
,
294 0.0f
, F_PI
/180.0f
* angles
[c
],
295 DryGain
*ListenerGain
,
296 ALSource
->Params
.HrtfCoeffs
[c
],
297 ALSource
->Params
.HrtfDelay
[c
]);
299 ALSource
->HrtfCounter
= 0;
304 for(c
= 0;c
< num_channels
;c
++)
306 if(chans
[c
] == LFE
) /* Special-case LFE */
308 SrcMatrix
[c
][LFE
] += DryGain
* ListenerGain
;
311 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* angles
[c
]),
312 aluSin(F_PI
/180.0f
* angles
[c
]));
313 SpeakerGain
= Device
->PanningLUT
[pos
];
315 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
317 enum Channel chan
= Device
->Speaker2Chan
[i
];
318 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
323 for(i
= 0;i
< NumSends
;i
++)
325 ALSource
->Params
.Send
[i
].Slot
= ALSource
->Send
[i
].Slot
;
326 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
329 /* Update filter coefficients. Calculations based on the I3DL2
331 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
333 /* We use two chained one-pole filters, so we need to take the
334 * square root of the squared gain, which is the same as the base
336 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
337 for(i
= 0;i
< NumSends
;i
++)
339 /* We use a one-pole filter, so we need to take the squared gain */
340 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
341 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
345 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
347 const ALCdevice
*Device
= ALContext
->Device
;
348 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
349 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
350 ALfloat Velocity
[3],ListenerVel
[3];
351 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
352 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
353 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
354 ALfloat AirAbsorptionFactor
;
355 ALfloat RoomAirAbsorption
[MAX_SENDS
];
356 ALbufferlistitem
*BufferListItem
;
357 ALfloat Attenuation
, EffectiveDist
;
358 ALfloat RoomAttenuation
[MAX_SENDS
];
359 ALfloat MetersPerUnit
;
360 ALfloat RoomRolloffBase
;
361 ALfloat RoomRolloff
[MAX_SENDS
];
362 ALfloat DecayDistance
[MAX_SENDS
];
365 ALboolean DryGainHFAuto
;
366 ALfloat WetGain
[MAX_SENDS
];
367 ALfloat WetGainHF
[MAX_SENDS
];
368 ALboolean WetGainAuto
;
369 ALboolean WetGainHFAuto
;
370 enum Resampler Resampler
;
378 for(i
= 0;i
< MAX_SENDS
;i
++)
381 //Get context properties
382 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
383 DopplerVelocity
= ALContext
->DopplerVelocity
;
384 SpeedOfSound
= ALContext
->flSpeedOfSound
;
385 NumSends
= Device
->NumAuxSends
;
386 Frequency
= Device
->Frequency
;
388 //Get listener properties
389 ListenerGain
= ALContext
->Listener
.Gain
;
390 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
391 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
392 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
393 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
395 //Get source properties
396 SourceVolume
= ALSource
->flGain
;
397 MinVolume
= ALSource
->flMinGain
;
398 MaxVolume
= ALSource
->flMaxGain
;
399 Pitch
= ALSource
->flPitch
;
400 Resampler
= ALSource
->Resampler
;
401 Position
[0] = ALSource
->vPosition
[0];
402 Position
[1] = ALSource
->vPosition
[1];
403 Position
[2] = ALSource
->vPosition
[2];
404 Direction
[0] = ALSource
->vOrientation
[0];
405 Direction
[1] = ALSource
->vOrientation
[1];
406 Direction
[2] = ALSource
->vOrientation
[2];
407 Velocity
[0] = ALSource
->vVelocity
[0];
408 Velocity
[1] = ALSource
->vVelocity
[1];
409 Velocity
[2] = ALSource
->vVelocity
[2];
410 MinDist
= ALSource
->flRefDistance
;
411 MaxDist
= ALSource
->flMaxDistance
;
412 Rolloff
= ALSource
->flRollOffFactor
;
413 InnerAngle
= ALSource
->flInnerAngle
* ConeScale
;
414 OuterAngle
= ALSource
->flOuterAngle
* ConeScale
;
415 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
416 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
417 WetGainAuto
= ALSource
->WetGainAuto
;
418 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
419 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
420 for(i
= 0;i
< NumSends
;i
++)
422 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
424 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
426 RoomRolloff
[i
] = 0.0f
;
427 DecayDistance
[i
] = 0.0f
;
428 RoomAirAbsorption
[i
] = 1.0f
;
430 else if(Slot
->AuxSendAuto
)
432 RoomRolloff
[i
] = RoomRolloffBase
;
433 if(IsReverbEffect(Slot
->effect
.type
))
435 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
436 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
437 SPEEDOFSOUNDMETRESPERSEC
;
438 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
442 DecayDistance
[i
] = 0.0f
;
443 RoomAirAbsorption
[i
] = 1.0f
;
448 /* If the slot's auxiliary send auto is off, the data sent to the
449 * effect slot is the same as the dry path, sans filter effects */
450 RoomRolloff
[i
] = Rolloff
;
451 DecayDistance
[i
] = 0.0f
;
452 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
455 ALSource
->Params
.Send
[i
].Slot
= Slot
;
458 //1. Translate Listener to origin (convert to head relative)
459 if(ALSource
->bHeadRelative
== AL_FALSE
)
461 ALfloat U
[3],V
[3],N
[3];
462 ALfloat Matrix
[4][4];
464 // Build transform matrix
465 N
[0] = ALContext
->Listener
.Forward
[0]; // At-vector
466 N
[1] = ALContext
->Listener
.Forward
[1];
467 N
[2] = ALContext
->Listener
.Forward
[2];
468 aluNormalize(N
); // Normalized At-vector
469 V
[0] = ALContext
->Listener
.Up
[0]; // Up-vector
470 V
[1] = ALContext
->Listener
.Up
[1];
471 V
[2] = ALContext
->Listener
.Up
[2];
472 aluNormalize(V
); // Normalized Up-vector
473 aluCrossproduct(N
, V
, U
); // Right-vector
474 aluNormalize(U
); // Normalized Right-vector
475 Matrix
[0][0] = U
[0]; Matrix
[0][1] = V
[0]; Matrix
[0][2] = -N
[0]; Matrix
[0][3] = 0.0f
;
476 Matrix
[1][0] = U
[1]; Matrix
[1][1] = V
[1]; Matrix
[1][2] = -N
[1]; Matrix
[1][3] = 0.0f
;
477 Matrix
[2][0] = U
[2]; Matrix
[2][1] = V
[2]; Matrix
[2][2] = -N
[2]; Matrix
[2][3] = 0.0f
;
478 Matrix
[3][0] = 0.0f
; Matrix
[3][1] = 0.0f
; Matrix
[3][2] = 0.0f
; Matrix
[3][3] = 1.0f
;
480 // Translate position
481 Position
[0] -= ALContext
->Listener
.Position
[0];
482 Position
[1] -= ALContext
->Listener
.Position
[1];
483 Position
[2] -= ALContext
->Listener
.Position
[2];
485 // Transform source position and direction into listener space
486 aluMatrixVector(Position
, 1.0f
, Matrix
);
487 aluMatrixVector(Direction
, 0.0f
, Matrix
);
488 // Transform source and listener velocity into listener space
489 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
490 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
493 ListenerVel
[0] = ListenerVel
[1] = ListenerVel
[2] = 0.0f
;
495 SourceToListener
[0] = -Position
[0];
496 SourceToListener
[1] = -Position
[1];
497 SourceToListener
[2] = -Position
[2];
498 aluNormalize(SourceToListener
);
499 aluNormalize(Direction
);
501 //2. Calculate distance attenuation
502 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
503 ClampedDist
= Distance
;
506 for(i
= 0;i
< NumSends
;i
++)
507 RoomAttenuation
[i
] = 1.0f
;
508 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
509 ALContext
->DistanceModel
)
511 case InverseDistanceClamped
:
512 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
513 if(MaxDist
< MinDist
)
516 case InverseDistance
:
519 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
520 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
521 for(i
= 0;i
< NumSends
;i
++)
523 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
524 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
529 case LinearDistanceClamped
:
530 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
531 if(MaxDist
< MinDist
)
535 if(MaxDist
!= MinDist
)
537 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
538 Attenuation
= maxf(Attenuation
, 0.0f
);
539 for(i
= 0;i
< NumSends
;i
++)
541 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
542 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
547 case ExponentDistanceClamped
:
548 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
549 if(MaxDist
< MinDist
)
552 case ExponentDistance
:
553 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
555 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
556 for(i
= 0;i
< NumSends
;i
++)
557 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
561 case DisableDistance
:
565 // Source Gain + Attenuation
566 DryGain
= SourceVolume
* Attenuation
;
567 for(i
= 0;i
< NumSends
;i
++)
568 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
570 // Distance-based air absorption
571 EffectiveDist
= 0.0f
;
572 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
573 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
574 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
576 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*EffectiveDist
);
577 for(i
= 0;i
< NumSends
;i
++)
578 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
],
579 AirAbsorptionFactor
*EffectiveDist
);
584 /* Apply a decay-time transformation to the wet path, based on the
585 * attenuation of the dry path.
587 * Using the approximate (effective) source to listener distance, the
588 * initial decay of the reverb effect is calculated and applied to the
591 for(i
= 0;i
< NumSends
;i
++)
593 if(DecayDistance
[i
] > 0.0f
)
594 WetGain
[i
] *= aluPow(0.001f
/* -60dB */,
595 EffectiveDist
/ DecayDistance
[i
]);
599 /* Calculate directional soundcones */
600 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0f
/F_PI
);
601 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
603 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
604 ConeVolume
= lerp(1.0f
, ALSource
->flOuterGain
, scale
);
605 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
607 else if(Angle
> OuterAngle
)
609 ConeVolume
= ALSource
->flOuterGain
;
610 ConeHF
= ALSource
->OuterGainHF
;
618 DryGain
*= ConeVolume
;
621 for(i
= 0;i
< NumSends
;i
++)
622 WetGain
[i
] *= ConeVolume
;
628 for(i
= 0;i
< NumSends
;i
++)
629 WetGainHF
[i
] *= ConeHF
;
632 // Clamp to Min/Max Gain
633 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
634 for(i
= 0;i
< NumSends
;i
++)
635 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
637 // Apply filter gains and filters
638 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
639 DryGainHF
*= ALSource
->DirectGainHF
;
640 for(i
= 0;i
< NumSends
;i
++)
642 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
* ListenerGain
;
643 WetGainHF
[i
] *= ALSource
->Send
[i
].WetGainHF
;
646 // Calculate Velocity
647 if(DopplerFactor
!= 0.0f
)
650 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
653 VSS
= aluDotproduct(Velocity
, SourceToListener
);
654 if(VSS
>= MaxVelocity
)
655 VSS
= (MaxVelocity
- 1.0f
);
656 else if(VSS
<= -MaxVelocity
)
657 VSS
= -MaxVelocity
+ 1.0f
;
659 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
660 if(VLS
>= MaxVelocity
)
661 VLS
= (MaxVelocity
- 1.0f
);
662 else if(VLS
<= -MaxVelocity
)
663 VLS
= -MaxVelocity
+ 1.0f
;
665 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
666 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
669 BufferListItem
= ALSource
->queue
;
670 while(BufferListItem
!= NULL
)
673 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
675 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
676 ALSource
->SampleSize
;
677 maxstep
-= ResamplerPadding
[Resampler
] +
678 ResamplerPrePadding
[Resampler
] + 1;
679 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
681 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
682 if(Pitch
> (ALfloat
)maxstep
)
683 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
686 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
687 if(ALSource
->Params
.Step
== 0)
688 ALSource
->Params
.Step
= 1;
691 if((Device
->Flags
&DEVICE_USE_HRTF
))
692 ALSource
->Params
.DoMix
= SelectHrtfMixer(ALBuffer
,
693 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
696 ALSource
->Params
.DoMix
= SelectMixer(ALBuffer
,
697 (ALSource
->Params
.Step
==FRACTIONONE
) ? POINT_RESAMPLER
:
701 BufferListItem
= BufferListItem
->next
;
704 if((Device
->Flags
&DEVICE_USE_HRTF
))
706 // Use a binaural HRTF algorithm for stereo headphone playback
707 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
711 ALfloat invlen
= 1.0f
/Distance
;
712 Position
[0] *= invlen
;
713 Position
[1] *= invlen
;
714 Position
[2] *= invlen
;
716 // Calculate elevation and azimuth only when the source is not at
717 // the listener. This prevents +0 and -0 Z from producing
718 // inconsistent panning.
719 ev
= aluAsin(Position
[1]);
720 az
= aluAtan2(Position
[0], -Position
[2]*ZScale
);
723 // Check to see if the HRIR is already moving.
724 if(ALSource
->HrtfMoving
)
726 // Calculate the normalized HRTF transition factor (delta).
727 delta
= CalcHrtfDelta(ALSource
->Params
.HrtfGain
, DryGain
,
728 ALSource
->Params
.HrtfDir
, Position
);
729 // If the delta is large enough, get the moving HRIR target
730 // coefficients, target delays, steppping values, and counter.
733 ALSource
->HrtfCounter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
734 ev
, az
, DryGain
, delta
,
735 ALSource
->HrtfCounter
,
736 ALSource
->Params
.HrtfCoeffs
[0],
737 ALSource
->Params
.HrtfDelay
[0],
738 ALSource
->Params
.HrtfCoeffStep
,
739 ALSource
->Params
.HrtfDelayStep
);
740 ALSource
->Params
.HrtfGain
= DryGain
;
741 ALSource
->Params
.HrtfDir
[0] = Position
[0];
742 ALSource
->Params
.HrtfDir
[1] = Position
[1];
743 ALSource
->Params
.HrtfDir
[2] = Position
[2];
748 // Get the initial (static) HRIR coefficients and delays.
749 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
750 ALSource
->Params
.HrtfCoeffs
[0],
751 ALSource
->Params
.HrtfDelay
[0]);
752 ALSource
->HrtfCounter
= 0;
753 ALSource
->Params
.HrtfGain
= DryGain
;
754 ALSource
->Params
.HrtfDir
[0] = Position
[0];
755 ALSource
->Params
.HrtfDir
[1] = Position
[1];
756 ALSource
->Params
.HrtfDir
[2] = Position
[2];
761 // Use energy-preserving panning algorithm for multi-speaker playback
762 ALfloat DirGain
, AmbientGain
;
763 const ALfloat
*SpeakerGain
;
767 length
= maxf(Distance
, MinDist
);
770 ALfloat invlen
= 1.0f
/length
;
771 Position
[0] *= invlen
;
772 Position
[1] *= invlen
;
773 Position
[2] *= invlen
;
776 pos
= aluCart2LUTpos(-Position
[2]*ZScale
, Position
[0]);
777 SpeakerGain
= Device
->PanningLUT
[pos
];
779 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
780 // elevation adjustment for directional gain. this sucks, but
781 // has low complexity
782 AmbientGain
= aluSqrt(1.0f
/Device
->NumChan
);
783 for(i
= 0;i
< MAXCHANNELS
;i
++)
786 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
787 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
789 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
791 enum Channel chan
= Device
->Speaker2Chan
[i
];
792 ALfloat gain
= lerp(AmbientGain
, SpeakerGain
[chan
], DirGain
);
793 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
796 for(i
= 0;i
< NumSends
;i
++)
797 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
];
799 /* Update filter coefficients. */
800 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
802 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
803 for(i
= 0;i
< NumSends
;i
++)
805 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
806 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
811 static __inline ALfloat
aluF2F(ALfloat val
)
813 static __inline ALshort
aluF2S(ALfloat val
)
815 if(val
> 1.0f
) return 32767;
816 if(val
< -1.0f
) return -32768;
817 return fastf2i(val
*32767.0f
);
819 static __inline ALushort
aluF2US(ALfloat val
)
820 { return aluF2S(val
)+32768; }
821 static __inline ALbyte
aluF2B(ALfloat val
)
822 { return aluF2S(val
)>>8; }
823 static __inline ALubyte
aluF2UB(ALfloat val
)
824 { return aluF2US(val
)>>8; }
826 #define DECL_TEMPLATE(T, N, func) \
827 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
828 ALuint SamplesToDo) \
830 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
831 const enum Channel *ChanMap = device->DevChannels; \
834 for(i = 0;i < SamplesToDo;i++) \
836 for(j = 0;j < N;j++) \
837 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
841 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
842 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
843 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
844 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
845 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
847 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
848 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
849 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
850 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
851 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
853 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
854 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
855 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
856 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
857 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
859 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
860 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
861 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
862 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
863 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
865 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
866 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
867 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
868 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
869 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
873 #define DECL_TEMPLATE(T, N, func) \
874 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
875 ALuint SamplesToDo) \
877 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
878 const enum Channel *ChanMap = device->DevChannels; \
883 for(i = 0;i < SamplesToDo;i++) \
886 samples[0] = DryBuffer[i][ChanMap[0]]; \
887 samples[1] = DryBuffer[i][ChanMap[1]]; \
888 bs2b_cross_feed(device->Bs2b, samples); \
889 *(buffer++) = func(samples[0]); \
890 *(buffer++) = func(samples[1]); \
895 for(i = 0;i < SamplesToDo;i++) \
897 for(j = 0;j < N;j++) \
898 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
903 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
904 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
905 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
906 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
907 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
911 #define DECL_TEMPLATE(T) \
912 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
914 switch(device->FmtChans) \
917 Write_##T##_1(device, buffer, SamplesToDo); \
920 Write_##T##_2(device, buffer, SamplesToDo); \
923 Write_##T##_4(device, buffer, SamplesToDo); \
926 case DevFmtX51Side: \
927 Write_##T##_6(device, buffer, SamplesToDo); \
930 Write_##T##_7(device, buffer, SamplesToDo); \
933 Write_##T##_8(device, buffer, SamplesToDo); \
938 DECL_TEMPLATE(ALfloat
)
939 DECL_TEMPLATE(ALushort
)
940 DECL_TEMPLATE(ALshort
)
941 DECL_TEMPLATE(ALubyte
)
942 DECL_TEMPLATE(ALbyte
)
946 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
949 ALeffectslot
**slot
, **slot_end
;
950 ALsource
**src
, **src_end
;
955 fpuState
= SetMixerFPUMode();
959 /* Setup variables */
960 SamplesToDo
= minu(size
, BUFFERSIZE
);
962 /* Clear mixing buffer */
963 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
966 ctx
= device
->ContextList
;
969 ALenum DeferUpdates
= ctx
->DeferUpdates
;
970 ALenum UpdateSources
= AL_FALSE
;
973 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
975 src
= ctx
->ActiveSources
;
976 src_end
= src
+ ctx
->ActiveSourceCount
;
977 while(src
!= src_end
)
979 if((*src
)->state
!= AL_PLAYING
)
981 --(ctx
->ActiveSourceCount
);
986 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
988 ALsource_Update(*src
, ctx
);
990 MixSource(*src
, device
, SamplesToDo
);
994 /* effect slot processing */
995 slot
= ctx
->ActiveEffectSlots
;
996 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
997 while(slot
!= slot_end
)
999 for(c
= 0;c
< SamplesToDo
;c
++)
1001 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
1002 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
1004 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
1005 (*slot
)->PendingClicks
[0] = 0.0f
;
1007 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1008 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
1010 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1011 (*slot
)->WetBuffer
, device
->DryBuffer
);
1013 for(i
= 0;i
< SamplesToDo
;i
++)
1014 (*slot
)->WetBuffer
[i
] = 0.0f
;
1021 UnlockDevice(device
);
1023 //Post processing loop
1024 if(device
->FmtChans
== DevFmtMono
)
1026 for(i
= 0;i
< SamplesToDo
;i
++)
1028 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
1029 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] * (1.0f
/256.0f
);
1031 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
1032 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
1034 else if(device
->FmtChans
== DevFmtStereo
)
1036 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
1037 for(i
= 0;i
< SamplesToDo
;i
++)
1039 for(c
= 0;c
< 2;c
++)
1041 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1042 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1045 for(c
= 0;c
< 2;c
++)
1047 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1048 device
->PendingClicks
[c
] = 0.0f
;
1053 for(i
= 0;i
< SamplesToDo
;i
++)
1055 for(c
= 0;c
< MAXCHANNELS
;c
++)
1057 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1058 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1061 for(c
= 0;c
< MAXCHANNELS
;c
++)
1063 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1064 device
->PendingClicks
[c
] = 0.0f
;
1070 switch(device
->FmtType
)
1073 Write_ALbyte(device
, buffer
, SamplesToDo
);
1076 Write_ALubyte(device
, buffer
, SamplesToDo
);
1079 Write_ALshort(device
, buffer
, SamplesToDo
);
1082 Write_ALushort(device
, buffer
, SamplesToDo
);
1085 Write_ALfloat(device
, buffer
, SamplesToDo
);
1090 size
-= SamplesToDo
;
1093 RestoreFPUMode(fpuState
);
1097 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1099 ALCcontext
*Context
;
1102 device
->Connected
= ALC_FALSE
;
1104 Context
= device
->ContextList
;
1107 ALsource
**src
, **src_end
;
1109 src
= Context
->ActiveSources
;
1110 src_end
= src
+ Context
->ActiveSourceCount
;
1111 while(src
!= src_end
)
1113 if((*src
)->state
== AL_PLAYING
)
1115 (*src
)->state
= AL_STOPPED
;
1116 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1117 (*src
)->position
= 0;
1118 (*src
)->position_fraction
= 0;
1122 Context
->ActiveSourceCount
= 0;
1124 Context
= Context
->next
;
1126 UnlockDevice(device
);