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
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
50 vector
[0], vector
[1], vector
[2], w
53 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
54 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
55 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
59 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
61 static const ALfloat angles_Mono
[1] = { 0.0f
};
62 static const ALfloat angles_Stereo
[2] = { -30.0f
, 30.0f
};
63 static const ALfloat angles_Rear
[2] = { -150.0f
, 150.0f
};
64 static const ALfloat angles_Quad
[4] = { -45.0f
, 45.0f
, -135.0f
, 135.0f
};
65 static const ALfloat angles_X51
[6] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
67 static const ALfloat angles_X61
[7] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
68 180.0f
, -90.0f
, 90.0f
};
69 static const ALfloat angles_X71
[8] = { -30.0f
, 30.0f
, 0.0f
, 0.0f
,
70 -110.0f
, 110.0f
, -90.0f
, 90.0f
};
72 static const enum Channel chans_Mono
[1] = { FRONT_CENTER
};
73 static const enum Channel chans_Stereo
[2] = { FRONT_LEFT
, FRONT_RIGHT
};
74 static const enum Channel chans_Rear
[2] = { BACK_LEFT
, BACK_RIGHT
};
75 static const enum Channel chans_Quad
[4] = { FRONT_LEFT
, FRONT_RIGHT
,
76 BACK_LEFT
, BACK_RIGHT
};
77 static const enum Channel chans_X51
[6] = { FRONT_LEFT
, FRONT_RIGHT
,
79 BACK_LEFT
, BACK_RIGHT
};
80 static const enum Channel chans_X61
[7] = { FRONT_LEFT
, FRONT_RIGHT
,
81 FRONT_CENTER
, LFE
, BACK_CENTER
,
82 SIDE_LEFT
, SIDE_RIGHT
};
83 static const enum Channel chans_X71
[8] = { FRONT_LEFT
, FRONT_RIGHT
,
85 BACK_LEFT
, BACK_RIGHT
,
86 SIDE_LEFT
, SIDE_RIGHT
};
88 ALCdevice
*Device
= ALContext
->Device
;
89 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
90 ALbufferlistitem
*BufferListItem
;
91 enum DevFmtChannels DevChans
;
92 enum FmtChannels Channels
;
93 ALfloat (*SrcMatrix
)[MAXCHANNELS
];
94 ALfloat DryGain
, DryGainHF
;
95 ALfloat WetGain
[MAX_SENDS
];
96 ALfloat WetGainHF
[MAX_SENDS
];
97 ALint NumSends
, Frequency
;
98 const ALfloat
*SpeakerGain
;
99 const ALfloat
*angles
= NULL
;
100 const enum Channel
*chans
= NULL
;
101 enum Resampler Resampler
;
102 ALint num_channels
= 0;
103 ALboolean VirtualChannels
;
109 /* Get device properties */
110 DevChans
= Device
->FmtChans
;
111 NumSends
= Device
->NumAuxSends
;
112 Frequency
= Device
->Frequency
;
114 /* Get listener properties */
115 ListenerGain
= ALContext
->Listener
.Gain
;
117 /* Get source properties */
118 SourceVolume
= ALSource
->flGain
;
119 MinVolume
= ALSource
->flMinGain
;
120 MaxVolume
= ALSource
->flMaxGain
;
121 Pitch
= ALSource
->flPitch
;
122 Resampler
= ALSource
->Resampler
;
123 VirtualChannels
= ALSource
->VirtualChannels
;
125 /* Calculate the stepping value */
127 BufferListItem
= ALSource
->queue
;
128 while(BufferListItem
!= NULL
)
131 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
133 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
134 ALSource
->SampleSize
;
135 maxstep
-= ResamplerPadding
[Resampler
] +
136 ResamplerPrePadding
[Resampler
] + 1;
137 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
139 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
140 if(Pitch
> (ALfloat
)maxstep
)
141 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
144 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
145 if(ALSource
->Params
.Step
== 0)
146 ALSource
->Params
.Step
= 1;
149 Channels
= ALBuffer
->FmtChannels
;
152 BufferListItem
= BufferListItem
->next
;
154 if(VirtualChannels
&& Device
->Hrtf
)
155 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
156 POINT_RESAMPLER
: Resampler
);
158 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
159 POINT_RESAMPLER
: Resampler
);
161 /* Calculate gains */
162 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
163 DryGain
*= ALSource
->DirectGain
;
164 DryGainHF
= ALSource
->DirectGainHF
;
165 for(i
= 0;i
< NumSends
;i
++)
167 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
168 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
;
169 WetGainHF
[i
] = ALSource
->Send
[i
].WetGainHF
;
172 SrcMatrix
= ALSource
->Params
.DryGains
;
173 for(i
= 0;i
< MAXCHANNELS
;i
++)
175 for(c
= 0;c
< MAXCHANNELS
;c
++)
176 SrcMatrix
[i
][c
] = 0.0f
;
181 angles
= angles_Mono
;
186 if(VirtualChannels
&& (Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
188 DryGain
*= aluSqrt(2.0f
/4.0f
);
191 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* angles_Rear
[c
]),
192 aluSin(F_PI
/180.0f
* angles_Rear
[c
]));
193 SpeakerGain
= Device
->PanningLUT
[pos
];
195 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
197 enum Channel chan
= Device
->Speaker2Chan
[i
];
198 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
203 angles
= angles_Stereo
;
204 chans
= chans_Stereo
;
209 angles
= angles_Rear
;
215 angles
= angles_Quad
;
239 if(VirtualChannels
== AL_FALSE
)
241 for(c
= 0;c
< num_channels
;c
++)
242 SrcMatrix
[c
][chans
[c
]] += DryGain
* ListenerGain
;
244 else if(Device
->Hrtf
)
246 for(c
= 0;c
< num_channels
;c
++)
251 ALSource
->Params
.HrtfDelay
[c
][0] = 0;
252 ALSource
->Params
.HrtfDelay
[c
][1] = 0;
253 for(i
= 0;i
< HRIR_LENGTH
;i
++)
255 ALSource
->Params
.HrtfCoeffs
[c
][i
][0] = 0.0f
;
256 ALSource
->Params
.HrtfCoeffs
[c
][i
][1] = 0.0f
;
261 /* Get the static HRIR coefficients and delays for this
263 GetLerpedHrtfCoeffs(Device
->Hrtf
,
264 0.0f
, F_PI
/180.0f
* angles
[c
],
265 DryGain
*ListenerGain
,
266 ALSource
->Params
.HrtfCoeffs
[c
],
267 ALSource
->Params
.HrtfDelay
[c
]);
269 ALSource
->HrtfCounter
= 0;
274 for(c
= 0;c
< num_channels
;c
++)
276 if(chans
[c
] == LFE
) /* Special-case LFE */
278 SrcMatrix
[c
][LFE
] += DryGain
* ListenerGain
;
281 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* angles
[c
]),
282 aluSin(F_PI
/180.0f
* angles
[c
]));
283 SpeakerGain
= Device
->PanningLUT
[pos
];
285 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
287 enum Channel chan
= Device
->Speaker2Chan
[i
];
288 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
293 for(i
= 0;i
< NumSends
;i
++)
295 ALSource
->Params
.Send
[i
].Slot
= ALSource
->Send
[i
].Slot
;
296 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
299 /* Update filter coefficients. Calculations based on the I3DL2
301 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
303 /* We use two chained one-pole filters, so we need to take the
304 * square root of the squared gain, which is the same as the base
306 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
307 for(i
= 0;i
< NumSends
;i
++)
309 /* We use a one-pole filter, so we need to take the squared gain */
310 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
311 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
315 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
317 const ALCdevice
*Device
= ALContext
->Device
;
318 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
319 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
320 ALfloat Velocity
[3],ListenerVel
[3];
321 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
322 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
323 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
324 ALfloat AirAbsorptionFactor
;
325 ALfloat RoomAirAbsorption
[MAX_SENDS
];
326 ALbufferlistitem
*BufferListItem
;
327 ALfloat Attenuation
, EffectiveDist
;
328 ALfloat RoomAttenuation
[MAX_SENDS
];
329 ALfloat MetersPerUnit
;
330 ALfloat RoomRolloffBase
;
331 ALfloat RoomRolloff
[MAX_SENDS
];
332 ALfloat DecayDistance
[MAX_SENDS
];
335 ALboolean DryGainHFAuto
;
336 ALfloat WetGain
[MAX_SENDS
];
337 ALfloat WetGainHF
[MAX_SENDS
];
338 ALboolean WetGainAuto
;
339 ALboolean WetGainHFAuto
;
340 enum Resampler Resampler
;
348 for(i
= 0;i
< MAX_SENDS
;i
++)
351 //Get context properties
352 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
353 DopplerVelocity
= ALContext
->DopplerVelocity
;
354 SpeedOfSound
= ALContext
->flSpeedOfSound
;
355 NumSends
= Device
->NumAuxSends
;
356 Frequency
= Device
->Frequency
;
358 //Get listener properties
359 ListenerGain
= ALContext
->Listener
.Gain
;
360 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
361 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
362 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
363 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
365 //Get source properties
366 SourceVolume
= ALSource
->flGain
;
367 MinVolume
= ALSource
->flMinGain
;
368 MaxVolume
= ALSource
->flMaxGain
;
369 Pitch
= ALSource
->flPitch
;
370 Resampler
= ALSource
->Resampler
;
371 Position
[0] = ALSource
->vPosition
[0];
372 Position
[1] = ALSource
->vPosition
[1];
373 Position
[2] = ALSource
->vPosition
[2];
374 Direction
[0] = ALSource
->vOrientation
[0];
375 Direction
[1] = ALSource
->vOrientation
[1];
376 Direction
[2] = ALSource
->vOrientation
[2];
377 Velocity
[0] = ALSource
->vVelocity
[0];
378 Velocity
[1] = ALSource
->vVelocity
[1];
379 Velocity
[2] = ALSource
->vVelocity
[2];
380 MinDist
= ALSource
->flRefDistance
;
381 MaxDist
= ALSource
->flMaxDistance
;
382 Rolloff
= ALSource
->flRollOffFactor
;
383 InnerAngle
= ALSource
->flInnerAngle
* ConeScale
;
384 OuterAngle
= ALSource
->flOuterAngle
* ConeScale
;
385 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
386 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
387 WetGainAuto
= ALSource
->WetGainAuto
;
388 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
389 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
390 for(i
= 0;i
< NumSends
;i
++)
392 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
394 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
396 RoomRolloff
[i
] = 0.0f
;
397 DecayDistance
[i
] = 0.0f
;
398 RoomAirAbsorption
[i
] = 1.0f
;
400 else if(Slot
->AuxSendAuto
)
402 RoomRolloff
[i
] = RoomRolloffBase
;
403 if(IsReverbEffect(Slot
->effect
.type
))
405 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
406 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
407 SPEEDOFSOUNDMETRESPERSEC
;
408 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
412 DecayDistance
[i
] = 0.0f
;
413 RoomAirAbsorption
[i
] = 1.0f
;
418 /* If the slot's auxiliary send auto is off, the data sent to the
419 * effect slot is the same as the dry path, sans filter effects */
420 RoomRolloff
[i
] = Rolloff
;
421 DecayDistance
[i
] = 0.0f
;
422 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
425 ALSource
->Params
.Send
[i
].Slot
= Slot
;
428 //1. Translate Listener to origin (convert to head relative)
429 if(ALSource
->bHeadRelative
== AL_FALSE
)
431 ALfloat Matrix
[4][4];
435 for(i2
= 0;i2
< 4;i2
++)
436 Matrix
[i
][i2
] = ALContext
->Listener
.Matrix
[i
][i2
];
439 /* Translate position */
440 Position
[0] -= ALContext
->Listener
.Position
[0];
441 Position
[1] -= ALContext
->Listener
.Position
[1];
442 Position
[2] -= ALContext
->Listener
.Position
[2];
444 /* Transform source vectors into listener space */
445 aluMatrixVector(Position
, 1.0f
, Matrix
);
446 aluMatrixVector(Direction
, 0.0f
, Matrix
);
447 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
451 ListenerVel
[0] = 0.0f
;
452 ListenerVel
[1] = 0.0f
;
453 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
));
464 ClampedDist
= Distance
;
467 for(i
= 0;i
< NumSends
;i
++)
468 RoomAttenuation
[i
] = 1.0f
;
469 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
470 ALContext
->DistanceModel
)
472 case InverseDistanceClamped
:
473 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
474 if(MaxDist
< MinDist
)
477 case InverseDistance
:
480 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
481 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
482 for(i
= 0;i
< NumSends
;i
++)
484 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
485 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
490 case LinearDistanceClamped
:
491 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
492 if(MaxDist
< MinDist
)
496 if(MaxDist
!= MinDist
)
498 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
499 Attenuation
= maxf(Attenuation
, 0.0f
);
500 for(i
= 0;i
< NumSends
;i
++)
502 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
503 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
508 case ExponentDistanceClamped
:
509 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
510 if(MaxDist
< MinDist
)
513 case ExponentDistance
:
514 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
516 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
517 for(i
= 0;i
< NumSends
;i
++)
518 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
522 case DisableDistance
:
526 // Source Gain + Attenuation
527 DryGain
= SourceVolume
* Attenuation
;
528 for(i
= 0;i
< NumSends
;i
++)
529 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
531 // Distance-based air absorption
532 EffectiveDist
= 0.0f
;
533 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
534 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
535 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
537 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*EffectiveDist
);
538 for(i
= 0;i
< NumSends
;i
++)
539 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
],
540 AirAbsorptionFactor
*EffectiveDist
);
545 /* Apply a decay-time transformation to the wet path, based on the
546 * attenuation of the dry path.
548 * Using the approximate (effective) source to listener distance, the
549 * initial decay of the reverb effect is calculated and applied to the
552 for(i
= 0;i
< NumSends
;i
++)
554 if(DecayDistance
[i
] > 0.0f
)
555 WetGain
[i
] *= aluPow(0.001f
/* -60dB */,
556 EffectiveDist
/ DecayDistance
[i
]);
560 /* Calculate directional soundcones */
561 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0f
/F_PI
);
562 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
564 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
565 ConeVolume
= lerp(1.0f
, ALSource
->flOuterGain
, scale
);
566 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
568 else if(Angle
> OuterAngle
)
570 ConeVolume
= ALSource
->flOuterGain
;
571 ConeHF
= ALSource
->OuterGainHF
;
579 DryGain
*= ConeVolume
;
582 for(i
= 0;i
< NumSends
;i
++)
583 WetGain
[i
] *= ConeVolume
;
589 for(i
= 0;i
< NumSends
;i
++)
590 WetGainHF
[i
] *= ConeHF
;
593 // Clamp to Min/Max Gain
594 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
595 for(i
= 0;i
< NumSends
;i
++)
596 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
598 // Apply filter gains and filters
599 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
600 DryGainHF
*= ALSource
->DirectGainHF
;
601 for(i
= 0;i
< NumSends
;i
++)
603 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
* ListenerGain
;
604 WetGainHF
[i
] *= ALSource
->Send
[i
].WetGainHF
;
607 // Calculate Velocity
608 if(DopplerFactor
!= 0.0f
)
611 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
614 VSS
= aluDotproduct(Velocity
, SourceToListener
);
615 if(VSS
>= MaxVelocity
)
616 VSS
= (MaxVelocity
- 1.0f
);
617 else if(VSS
<= -MaxVelocity
)
618 VSS
= -MaxVelocity
+ 1.0f
;
620 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
621 if(VLS
>= MaxVelocity
)
622 VLS
= (MaxVelocity
- 1.0f
);
623 else if(VLS
<= -MaxVelocity
)
624 VLS
= -MaxVelocity
+ 1.0f
;
626 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
627 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
630 BufferListItem
= ALSource
->queue
;
631 while(BufferListItem
!= NULL
)
634 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
636 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
637 ALSource
->SampleSize
;
638 maxstep
-= ResamplerPadding
[Resampler
] +
639 ResamplerPrePadding
[Resampler
] + 1;
640 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
642 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
643 if(Pitch
> (ALfloat
)maxstep
)
644 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
647 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
648 if(ALSource
->Params
.Step
== 0)
649 ALSource
->Params
.Step
= 1;
654 BufferListItem
= BufferListItem
->next
;
657 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
658 POINT_RESAMPLER
: Resampler
);
660 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
661 POINT_RESAMPLER
: Resampler
);
665 // Use a binaural HRTF algorithm for stereo headphone playback
666 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
670 ALfloat invlen
= 1.0f
/Distance
;
671 Position
[0] *= invlen
;
672 Position
[1] *= invlen
;
673 Position
[2] *= invlen
;
675 // Calculate elevation and azimuth only when the source is not at
676 // the listener. This prevents +0 and -0 Z from producing
677 // inconsistent panning.
678 ev
= aluAsin(Position
[1]);
679 az
= aluAtan2(Position
[0], -Position
[2]*ZScale
);
682 // Check to see if the HRIR is already moving.
683 if(ALSource
->HrtfMoving
)
685 // Calculate the normalized HRTF transition factor (delta).
686 delta
= CalcHrtfDelta(ALSource
->Params
.HrtfGain
, DryGain
,
687 ALSource
->Params
.HrtfDir
, Position
);
688 // If the delta is large enough, get the moving HRIR target
689 // coefficients, target delays, steppping values, and counter.
692 ALSource
->HrtfCounter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
693 ev
, az
, DryGain
, delta
,
694 ALSource
->HrtfCounter
,
695 ALSource
->Params
.HrtfCoeffs
[0],
696 ALSource
->Params
.HrtfDelay
[0],
697 ALSource
->Params
.HrtfCoeffStep
,
698 ALSource
->Params
.HrtfDelayStep
);
699 ALSource
->Params
.HrtfGain
= DryGain
;
700 ALSource
->Params
.HrtfDir
[0] = Position
[0];
701 ALSource
->Params
.HrtfDir
[1] = Position
[1];
702 ALSource
->Params
.HrtfDir
[2] = Position
[2];
707 // Get the initial (static) HRIR coefficients and delays.
708 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
709 ALSource
->Params
.HrtfCoeffs
[0],
710 ALSource
->Params
.HrtfDelay
[0]);
711 ALSource
->HrtfCounter
= 0;
712 ALSource
->Params
.HrtfGain
= DryGain
;
713 ALSource
->Params
.HrtfDir
[0] = Position
[0];
714 ALSource
->Params
.HrtfDir
[1] = Position
[1];
715 ALSource
->Params
.HrtfDir
[2] = Position
[2];
720 // Use energy-preserving panning algorithm for multi-speaker playback
721 ALfloat DirGain
, AmbientGain
;
722 const ALfloat
*SpeakerGain
;
726 length
= maxf(Distance
, MinDist
);
729 ALfloat invlen
= 1.0f
/length
;
730 Position
[0] *= invlen
;
731 Position
[1] *= invlen
;
732 Position
[2] *= invlen
;
735 pos
= aluCart2LUTpos(-Position
[2]*ZScale
, Position
[0]);
736 SpeakerGain
= Device
->PanningLUT
[pos
];
738 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
739 // elevation adjustment for directional gain. this sucks, but
740 // has low complexity
741 AmbientGain
= aluSqrt(1.0f
/Device
->NumChan
);
742 for(i
= 0;i
< MAXCHANNELS
;i
++)
745 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
746 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
748 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
750 enum Channel chan
= Device
->Speaker2Chan
[i
];
751 ALfloat gain
= lerp(AmbientGain
, SpeakerGain
[chan
], DirGain
);
752 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
755 for(i
= 0;i
< NumSends
;i
++)
756 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
];
758 /* Update filter coefficients. */
759 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
761 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
762 for(i
= 0;i
< NumSends
;i
++)
764 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
765 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
770 static __inline ALfloat
aluF2F(ALfloat val
)
772 static __inline ALshort
aluF2S(ALfloat val
)
774 if(val
> 1.0f
) return 32767;
775 if(val
< -1.0f
) return -32768;
776 return fastf2i(val
*32767.0f
);
778 static __inline ALushort
aluF2US(ALfloat val
)
779 { return aluF2S(val
)+32768; }
780 static __inline ALbyte
aluF2B(ALfloat val
)
781 { return aluF2S(val
)>>8; }
782 static __inline ALubyte
aluF2UB(ALfloat val
)
783 { return aluF2US(val
)>>8; }
785 #define DECL_TEMPLATE(T, N, func) \
786 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
787 ALuint SamplesToDo) \
789 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
790 const enum Channel *ChanMap = device->DevChannels; \
793 for(i = 0;i < SamplesToDo;i++) \
795 for(j = 0;j < N;j++) \
796 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
800 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
801 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
802 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
803 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
804 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
806 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
807 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
808 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
809 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
810 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
812 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
813 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
814 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
815 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
816 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
818 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
819 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
820 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
821 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
822 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
824 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
825 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
826 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
827 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
828 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
832 #define DECL_TEMPLATE(T, N, func) \
833 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
834 ALuint SamplesToDo) \
836 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
837 const enum Channel *ChanMap = device->DevChannels; \
842 for(i = 0;i < SamplesToDo;i++) \
845 samples[0] = DryBuffer[i][ChanMap[0]]; \
846 samples[1] = DryBuffer[i][ChanMap[1]]; \
847 bs2b_cross_feed(device->Bs2b, samples); \
848 *(buffer++) = func(samples[0]); \
849 *(buffer++) = func(samples[1]); \
854 for(i = 0;i < SamplesToDo;i++) \
856 for(j = 0;j < N;j++) \
857 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
862 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
863 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
864 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
865 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
866 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
870 #define DECL_TEMPLATE(T) \
871 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
873 switch(device->FmtChans) \
876 Write_##T##_1(device, buffer, SamplesToDo); \
879 Write_##T##_2(device, buffer, SamplesToDo); \
882 Write_##T##_4(device, buffer, SamplesToDo); \
885 case DevFmtX51Side: \
886 Write_##T##_6(device, buffer, SamplesToDo); \
889 Write_##T##_7(device, buffer, SamplesToDo); \
892 Write_##T##_8(device, buffer, SamplesToDo); \
897 DECL_TEMPLATE(ALfloat
)
898 DECL_TEMPLATE(ALushort
)
899 DECL_TEMPLATE(ALshort
)
900 DECL_TEMPLATE(ALubyte
)
901 DECL_TEMPLATE(ALbyte
)
905 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
908 ALeffectslot
**slot
, **slot_end
;
909 ALsource
**src
, **src_end
;
914 fpuState
= SetMixerFPUMode();
918 /* Setup variables */
919 SamplesToDo
= minu(size
, BUFFERSIZE
);
921 /* Clear mixing buffer */
922 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
925 ctx
= device
->ContextList
;
928 ALenum DeferUpdates
= ctx
->DeferUpdates
;
929 ALenum UpdateSources
= AL_FALSE
;
932 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
934 src
= ctx
->ActiveSources
;
935 src_end
= src
+ ctx
->ActiveSourceCount
;
936 while(src
!= src_end
)
938 if((*src
)->state
!= AL_PLAYING
)
940 --(ctx
->ActiveSourceCount
);
945 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
947 ALsource_Update(*src
, ctx
);
949 MixSource(*src
, device
, SamplesToDo
);
953 /* effect slot processing */
954 slot
= ctx
->ActiveEffectSlots
;
955 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
956 while(slot
!= slot_end
)
958 for(c
= 0;c
< SamplesToDo
;c
++)
960 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
961 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
963 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
964 (*slot
)->PendingClicks
[0] = 0.0f
;
966 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
967 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
969 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
970 (*slot
)->WetBuffer
, device
->DryBuffer
);
972 for(i
= 0;i
< SamplesToDo
;i
++)
973 (*slot
)->WetBuffer
[i
] = 0.0f
;
980 UnlockDevice(device
);
982 //Post processing loop
983 if(device
->FmtChans
== DevFmtMono
)
985 for(i
= 0;i
< SamplesToDo
;i
++)
987 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
988 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] * (1.0f
/256.0f
);
990 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
991 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
993 else if(device
->FmtChans
== DevFmtStereo
)
995 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
996 for(i
= 0;i
< SamplesToDo
;i
++)
1000 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1001 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1004 for(c
= 0;c
< 2;c
++)
1006 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1007 device
->PendingClicks
[c
] = 0.0f
;
1012 for(i
= 0;i
< SamplesToDo
;i
++)
1014 for(c
= 0;c
< MAXCHANNELS
;c
++)
1016 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1017 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1020 for(c
= 0;c
< MAXCHANNELS
;c
++)
1022 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1023 device
->PendingClicks
[c
] = 0.0f
;
1029 switch(device
->FmtType
)
1032 Write_ALbyte(device
, buffer
, SamplesToDo
);
1035 Write_ALubyte(device
, buffer
, SamplesToDo
);
1038 Write_ALshort(device
, buffer
, SamplesToDo
);
1041 Write_ALushort(device
, buffer
, SamplesToDo
);
1044 Write_ALfloat(device
, buffer
, SamplesToDo
);
1049 size
-= SamplesToDo
;
1052 RestoreFPUMode(fpuState
);
1056 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1058 ALCcontext
*Context
;
1061 device
->Connected
= ALC_FALSE
;
1063 Context
= device
->ContextList
;
1066 ALsource
**src
, **src_end
;
1068 src
= Context
->ActiveSources
;
1069 src_end
= src
+ Context
->ActiveSourceCount
;
1070 while(src
!= src_end
)
1072 if((*src
)->state
== AL_PLAYING
)
1074 (*src
)->state
= AL_STOPPED
;
1075 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1076 (*src
)->position
= 0;
1077 (*src
)->position_fraction
= 0;
1081 Context
->ActiveSourceCount
= 0;
1083 Context
= Context
->next
;
1085 UnlockDevice(device
);