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"
46 ALfloat ConeScale
= 0.5f
;
48 /* Localized Z scalar for mono sources */
49 ALfloat ZScale
= 1.0f
;
52 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
55 vector
[0], vector
[1], vector
[2], w
58 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
59 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
60 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
64 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
66 static const struct ChanMap MonoMap
[1] = { { FRONT_CENTER
, 0.0f
} };
67 static const struct ChanMap StereoMap
[2] = {
68 { FRONT_LEFT
, -30.0f
* F_PI
/180.0f
},
69 { FRONT_RIGHT
, 30.0f
* F_PI
/180.0f
}
71 static const struct ChanMap RearMap
[2] = {
72 { BACK_LEFT
, -150.0f
* F_PI
/180.0f
},
73 { BACK_RIGHT
, 150.0f
* F_PI
/180.0f
}
75 static const struct ChanMap QuadMap
[4] = {
76 { FRONT_LEFT
, -45.0f
* F_PI
/180.0f
},
77 { FRONT_RIGHT
, 45.0f
* F_PI
/180.0f
},
78 { BACK_LEFT
, -135.0f
* F_PI
/180.0f
},
79 { BACK_RIGHT
, 135.0f
* F_PI
/180.0f
}
81 static const struct ChanMap X51Map
[6] = {
82 { FRONT_LEFT
, -30.0f
* F_PI
/180.0f
},
83 { FRONT_RIGHT
, 30.0f
* F_PI
/180.0f
},
84 { FRONT_CENTER
, 0.0f
* F_PI
/180.0f
},
86 { BACK_LEFT
, -110.0f
* F_PI
/180.0f
},
87 { BACK_RIGHT
, 110.0f
* F_PI
/180.0f
}
89 static const struct ChanMap X61Map
[7] = {
90 { FRONT_LEFT
, -30.0f
* F_PI
/180.0f
},
91 { FRONT_RIGHT
, 30.0f
* F_PI
/180.0f
},
92 { FRONT_CENTER
, 0.0f
* F_PI
/180.0f
},
94 { BACK_CENTER
, 180.0f
* F_PI
/180.0f
},
95 { SIDE_LEFT
, -90.0f
* F_PI
/180.0f
},
96 { SIDE_RIGHT
, 90.0f
* F_PI
/180.0f
}
98 static const struct ChanMap X71Map
[8] = {
99 { FRONT_LEFT
, -30.0f
* F_PI
/180.0f
},
100 { FRONT_RIGHT
, 30.0f
* F_PI
/180.0f
},
101 { FRONT_CENTER
, 0.0f
* F_PI
/180.0f
},
103 { BACK_LEFT
, -150.0f
* F_PI
/180.0f
},
104 { BACK_RIGHT
, 150.0f
* F_PI
/180.0f
},
105 { SIDE_LEFT
, -90.0f
* F_PI
/180.0f
},
106 { SIDE_RIGHT
, 90.0f
* F_PI
/180.0f
}
109 ALCdevice
*Device
= ALContext
->Device
;
110 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
111 ALbufferlistitem
*BufferListItem
;
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
*ChannelGain
;
119 const struct ChanMap
*chans
= NULL
;
120 enum Resampler Resampler
;
121 ALint num_channels
= 0;
122 ALboolean DirectChannels
;
128 /* Get device properties */
129 NumSends
= Device
->NumAuxSends
;
130 Frequency
= Device
->Frequency
;
132 /* Get listener properties */
133 ListenerGain
= ALContext
->Listener
.Gain
;
135 /* Get source properties */
136 SourceVolume
= ALSource
->flGain
;
137 MinVolume
= ALSource
->flMinGain
;
138 MaxVolume
= ALSource
->flMaxGain
;
139 Pitch
= ALSource
->flPitch
;
140 Resampler
= ALSource
->Resampler
;
141 DirectChannels
= ALSource
->DirectChannels
;
143 /* Calculate the stepping value */
145 BufferListItem
= ALSource
->queue
;
146 while(BufferListItem
!= NULL
)
149 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
151 ALsizei maxstep
= STACK_DATA_SIZE
/sizeof(ALfloat
) /
152 ALSource
->NumChannels
;
153 maxstep
-= ResamplerPadding
[Resampler
] +
154 ResamplerPrePadding
[Resampler
] + 1;
155 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
157 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
158 if(Pitch
> (ALfloat
)maxstep
)
159 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
162 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
163 if(ALSource
->Params
.Step
== 0)
164 ALSource
->Params
.Step
= 1;
167 Channels
= ALBuffer
->FmtChannels
;
170 BufferListItem
= BufferListItem
->next
;
172 if(!DirectChannels
&& Device
->Hrtf
)
173 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
174 PointResampler
: Resampler
);
176 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
177 PointResampler
: Resampler
);
179 /* Calculate gains */
180 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
181 DryGain
*= ALSource
->DirectGain
;
182 DryGainHF
= ALSource
->DirectGainHF
;
183 for(i
= 0;i
< NumSends
;i
++)
185 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
186 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
;
187 WetGainHF
[i
] = ALSource
->Send
[i
].WetGainHF
;
190 SrcMatrix
= ALSource
->Params
.DryGains
;
191 for(i
= 0;i
< MAXCHANNELS
;i
++)
193 for(c
= 0;c
< MAXCHANNELS
;c
++)
194 SrcMatrix
[i
][c
] = 0.0f
;
203 if(!DirectChannels
&& (Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
205 DryGain
*= aluSqrt(2.0f
/4.0f
);
208 pos
= aluCart2LUTpos(aluCos(RearMap
[c
].angle
),
209 aluSin(RearMap
[c
].angle
));
210 ChannelGain
= Device
->PanningLUT
[pos
];
212 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
214 enum Channel chan
= Device
->Speaker2Chan
[i
];
215 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
250 if(DirectChannels
!= AL_FALSE
)
252 for(c
= 0;c
< num_channels
;c
++)
253 SrcMatrix
[c
][chans
[c
].channel
] += DryGain
* ListenerGain
;
255 else if(Device
->Hrtf
)
257 for(c
= 0;c
< num_channels
;c
++)
259 if(chans
[c
].channel
== LFE
)
262 ALSource
->Params
.HrtfDelay
[c
][0] = 0;
263 ALSource
->Params
.HrtfDelay
[c
][1] = 0;
264 for(i
= 0;i
< HRIR_LENGTH
;i
++)
266 ALSource
->Params
.HrtfCoeffs
[c
][i
][0] = 0.0f
;
267 ALSource
->Params
.HrtfCoeffs
[c
][i
][1] = 0.0f
;
272 /* Get the static HRIR coefficients and delays for this
274 GetLerpedHrtfCoeffs(Device
->Hrtf
,
275 0.0f
, F_PI
/180.0f
* chans
[c
].angle
,
276 DryGain
*ListenerGain
,
277 ALSource
->Params
.HrtfCoeffs
[c
],
278 ALSource
->Params
.HrtfDelay
[c
]);
280 ALSource
->HrtfCounter
= 0;
285 for(c
= 0;c
< num_channels
;c
++)
287 if(chans
[c
].channel
== LFE
) /* Special-case LFE */
289 SrcMatrix
[c
][LFE
] += DryGain
* ListenerGain
;
292 pos
= aluCart2LUTpos(aluCos(chans
[c
].angle
), aluSin(chans
[c
].angle
));
293 ChannelGain
= Device
->PanningLUT
[pos
];
295 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
297 enum Channel chan
= Device
->Speaker2Chan
[i
];
298 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
303 for(i
= 0;i
< NumSends
;i
++)
305 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
308 Slot
= Device
->DefaultSlot
;
309 if(Slot
&& Slot
->effect
.type
== AL_EFFECT_NULL
)
311 ALSource
->Params
.Send
[i
].Slot
= Slot
;
312 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
315 /* Update filter coefficients. Calculations based on the I3DL2
317 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
319 /* We use two chained one-pole filters, so we need to take the
320 * square root of the squared gain, which is the same as the base
322 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
323 for(i
= 0;i
< NumSends
;i
++)
325 /* We use a one-pole filter, so we need to take the squared gain */
326 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
327 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
331 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
333 const ALCdevice
*Device
= ALContext
->Device
;
334 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
335 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
336 ALfloat Velocity
[3],ListenerVel
[3];
337 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
338 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
339 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
340 ALfloat AirAbsorptionFactor
;
341 ALfloat RoomAirAbsorption
[MAX_SENDS
];
342 ALbufferlistitem
*BufferListItem
;
343 ALfloat Attenuation
, EffectiveDist
;
344 ALfloat RoomAttenuation
[MAX_SENDS
];
345 ALfloat MetersPerUnit
;
346 ALfloat RoomRolloffBase
;
347 ALfloat RoomRolloff
[MAX_SENDS
];
348 ALfloat DecayDistance
[MAX_SENDS
];
351 ALboolean DryGainHFAuto
;
352 ALfloat WetGain
[MAX_SENDS
];
353 ALfloat WetGainHF
[MAX_SENDS
];
354 ALboolean WetGainAuto
;
355 ALboolean WetGainHFAuto
;
356 enum Resampler Resampler
;
364 for(i
= 0;i
< MAX_SENDS
;i
++)
367 //Get context properties
368 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
369 DopplerVelocity
= ALContext
->DopplerVelocity
;
370 SpeedOfSound
= ALContext
->flSpeedOfSound
;
371 NumSends
= Device
->NumAuxSends
;
372 Frequency
= Device
->Frequency
;
374 //Get listener properties
375 ListenerGain
= ALContext
->Listener
.Gain
;
376 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
377 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
378 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
379 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
381 //Get source properties
382 SourceVolume
= ALSource
->flGain
;
383 MinVolume
= ALSource
->flMinGain
;
384 MaxVolume
= ALSource
->flMaxGain
;
385 Pitch
= ALSource
->flPitch
;
386 Resampler
= ALSource
->Resampler
;
387 Position
[0] = ALSource
->vPosition
[0];
388 Position
[1] = ALSource
->vPosition
[1];
389 Position
[2] = ALSource
->vPosition
[2];
390 Direction
[0] = ALSource
->vOrientation
[0];
391 Direction
[1] = ALSource
->vOrientation
[1];
392 Direction
[2] = ALSource
->vOrientation
[2];
393 Velocity
[0] = ALSource
->vVelocity
[0];
394 Velocity
[1] = ALSource
->vVelocity
[1];
395 Velocity
[2] = ALSource
->vVelocity
[2];
396 MinDist
= ALSource
->flRefDistance
;
397 MaxDist
= ALSource
->flMaxDistance
;
398 Rolloff
= ALSource
->flRollOffFactor
;
399 InnerAngle
= ALSource
->flInnerAngle
* ConeScale
;
400 OuterAngle
= ALSource
->flOuterAngle
* ConeScale
;
401 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
402 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
403 WetGainAuto
= ALSource
->WetGainAuto
;
404 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
405 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
406 for(i
= 0;i
< NumSends
;i
++)
408 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
411 Slot
= Device
->DefaultSlot
;
412 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
415 RoomRolloff
[i
] = 0.0f
;
416 DecayDistance
[i
] = 0.0f
;
417 RoomAirAbsorption
[i
] = 1.0f
;
419 else if(Slot
->AuxSendAuto
)
421 RoomRolloff
[i
] = RoomRolloffBase
;
422 if(IsReverbEffect(Slot
->effect
.type
))
424 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
425 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
426 SPEEDOFSOUNDMETRESPERSEC
;
427 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
431 DecayDistance
[i
] = 0.0f
;
432 RoomAirAbsorption
[i
] = 1.0f
;
437 /* If the slot's auxiliary send auto is off, the data sent to the
438 * effect slot is the same as the dry path, sans filter effects */
439 RoomRolloff
[i
] = Rolloff
;
440 DecayDistance
[i
] = 0.0f
;
441 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
444 ALSource
->Params
.Send
[i
].Slot
= Slot
;
447 //1. Translate Listener to origin (convert to head relative)
448 if(ALSource
->bHeadRelative
== AL_FALSE
)
450 ALfloat Matrix
[4][4];
454 for(i2
= 0;i2
< 4;i2
++)
455 Matrix
[i
][i2
] = ALContext
->Listener
.Matrix
[i
][i2
];
458 /* Translate position */
459 Position
[0] -= ALContext
->Listener
.Position
[0];
460 Position
[1] -= ALContext
->Listener
.Position
[1];
461 Position
[2] -= ALContext
->Listener
.Position
[2];
463 /* Transform source vectors into listener space */
464 aluMatrixVector(Position
, 1.0f
, Matrix
);
465 aluMatrixVector(Direction
, 0.0f
, Matrix
);
466 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
470 ListenerVel
[0] = 0.0f
;
471 ListenerVel
[1] = 0.0f
;
472 ListenerVel
[2] = 0.0f
;
475 SourceToListener
[0] = -Position
[0];
476 SourceToListener
[1] = -Position
[1];
477 SourceToListener
[2] = -Position
[2];
478 aluNormalize(SourceToListener
);
479 aluNormalize(Direction
);
481 //2. Calculate distance attenuation
482 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
483 ClampedDist
= Distance
;
486 for(i
= 0;i
< NumSends
;i
++)
487 RoomAttenuation
[i
] = 1.0f
;
488 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
489 ALContext
->DistanceModel
)
491 case InverseDistanceClamped
:
492 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
493 if(MaxDist
< MinDist
)
496 case InverseDistance
:
499 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
500 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
501 for(i
= 0;i
< NumSends
;i
++)
503 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
504 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
509 case LinearDistanceClamped
:
510 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
511 if(MaxDist
< MinDist
)
515 if(MaxDist
!= MinDist
)
517 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
518 Attenuation
= maxf(Attenuation
, 0.0f
);
519 for(i
= 0;i
< NumSends
;i
++)
521 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
522 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
527 case ExponentDistanceClamped
:
528 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
529 if(MaxDist
< MinDist
)
532 case ExponentDistance
:
533 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
535 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
536 for(i
= 0;i
< NumSends
;i
++)
537 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
541 case DisableDistance
:
545 // Source Gain + Attenuation
546 DryGain
= SourceVolume
* Attenuation
;
547 for(i
= 0;i
< NumSends
;i
++)
548 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
550 // Distance-based air absorption
551 EffectiveDist
= 0.0f
;
552 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
553 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
554 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
556 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*EffectiveDist
);
557 for(i
= 0;i
< NumSends
;i
++)
558 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
],
559 AirAbsorptionFactor
*EffectiveDist
);
564 /* Apply a decay-time transformation to the wet path, based on the
565 * attenuation of the dry path.
567 * Using the approximate (effective) source to listener distance, the
568 * initial decay of the reverb effect is calculated and applied to the
571 for(i
= 0;i
< NumSends
;i
++)
573 if(DecayDistance
[i
] > 0.0f
)
574 WetGain
[i
] *= aluPow(0.001f
/* -60dB */,
575 EffectiveDist
/ DecayDistance
[i
]);
579 /* Calculate directional soundcones */
580 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0f
/F_PI
);
581 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
583 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
584 ConeVolume
= lerp(1.0f
, ALSource
->flOuterGain
, scale
);
585 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
587 else if(Angle
> OuterAngle
)
589 ConeVolume
= ALSource
->flOuterGain
;
590 ConeHF
= ALSource
->OuterGainHF
;
598 DryGain
*= ConeVolume
;
601 for(i
= 0;i
< NumSends
;i
++)
602 WetGain
[i
] *= ConeVolume
;
608 for(i
= 0;i
< NumSends
;i
++)
609 WetGainHF
[i
] *= ConeHF
;
612 // Clamp to Min/Max Gain
613 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
614 for(i
= 0;i
< NumSends
;i
++)
615 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
617 // Apply filter gains and filters
618 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
619 DryGainHF
*= ALSource
->DirectGainHF
;
620 for(i
= 0;i
< NumSends
;i
++)
622 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
* ListenerGain
;
623 WetGainHF
[i
] *= ALSource
->Send
[i
].WetGainHF
;
626 // Calculate Velocity
627 if(DopplerFactor
!= 0.0f
)
630 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
633 VSS
= aluDotproduct(Velocity
, SourceToListener
);
634 if(VSS
>= MaxVelocity
)
635 VSS
= (MaxVelocity
- 1.0f
);
636 else if(VSS
<= -MaxVelocity
)
637 VSS
= -MaxVelocity
+ 1.0f
;
639 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
640 if(VLS
>= MaxVelocity
)
641 VLS
= (MaxVelocity
- 1.0f
);
642 else if(VLS
<= -MaxVelocity
)
643 VLS
= -MaxVelocity
+ 1.0f
;
645 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
646 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
649 BufferListItem
= ALSource
->queue
;
650 while(BufferListItem
!= NULL
)
653 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
655 ALsizei maxstep
= STACK_DATA_SIZE
/sizeof(ALfloat
) /
656 ALSource
->NumChannels
;
657 maxstep
-= ResamplerPadding
[Resampler
] +
658 ResamplerPrePadding
[Resampler
] + 1;
659 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
661 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
662 if(Pitch
> (ALfloat
)maxstep
)
663 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
666 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
667 if(ALSource
->Params
.Step
== 0)
668 ALSource
->Params
.Step
= 1;
673 BufferListItem
= BufferListItem
->next
;
676 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
677 PointResampler
: Resampler
);
679 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
680 PointResampler
: Resampler
);
684 // Use a binaural HRTF algorithm for stereo headphone playback
685 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
689 ALfloat invlen
= 1.0f
/Distance
;
690 Position
[0] *= invlen
;
691 Position
[1] *= invlen
;
692 Position
[2] *= invlen
;
694 // Calculate elevation and azimuth only when the source is not at
695 // the listener. This prevents +0 and -0 Z from producing
696 // inconsistent panning.
697 ev
= aluAsin(Position
[1]);
698 az
= aluAtan2(Position
[0], -Position
[2]*ZScale
);
701 // Check to see if the HRIR is already moving.
702 if(ALSource
->HrtfMoving
)
704 // Calculate the normalized HRTF transition factor (delta).
705 delta
= CalcHrtfDelta(ALSource
->Params
.HrtfGain
, DryGain
,
706 ALSource
->Params
.HrtfDir
, Position
);
707 // If the delta is large enough, get the moving HRIR target
708 // coefficients, target delays, steppping values, and counter.
711 ALSource
->HrtfCounter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
712 ev
, az
, DryGain
, delta
,
713 ALSource
->HrtfCounter
,
714 ALSource
->Params
.HrtfCoeffs
[0],
715 ALSource
->Params
.HrtfDelay
[0],
716 ALSource
->Params
.HrtfCoeffStep
,
717 ALSource
->Params
.HrtfDelayStep
);
718 ALSource
->Params
.HrtfGain
= DryGain
;
719 ALSource
->Params
.HrtfDir
[0] = Position
[0];
720 ALSource
->Params
.HrtfDir
[1] = Position
[1];
721 ALSource
->Params
.HrtfDir
[2] = Position
[2];
726 // Get the initial (static) HRIR coefficients and delays.
727 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
728 ALSource
->Params
.HrtfCoeffs
[0],
729 ALSource
->Params
.HrtfDelay
[0]);
730 ALSource
->HrtfCounter
= 0;
731 ALSource
->Params
.HrtfGain
= DryGain
;
732 ALSource
->Params
.HrtfDir
[0] = Position
[0];
733 ALSource
->Params
.HrtfDir
[1] = Position
[1];
734 ALSource
->Params
.HrtfDir
[2] = Position
[2];
739 // Use energy-preserving panning algorithm for multi-speaker playback
740 ALfloat DirGain
, AmbientGain
;
741 const ALfloat
*ChannelGain
;
745 length
= maxf(Distance
, MinDist
);
748 ALfloat invlen
= 1.0f
/length
;
749 Position
[0] *= invlen
;
750 Position
[1] *= invlen
;
751 Position
[2] *= invlen
;
754 pos
= aluCart2LUTpos(-Position
[2]*ZScale
, Position
[0]);
755 ChannelGain
= Device
->PanningLUT
[pos
];
757 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
758 // elevation adjustment for directional gain. this sucks, but
759 // has low complexity
760 AmbientGain
= aluSqrt(1.0f
/Device
->NumChan
);
761 for(i
= 0;i
< MAXCHANNELS
;i
++)
764 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
765 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
767 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
769 enum Channel chan
= Device
->Speaker2Chan
[i
];
770 ALfloat gain
= lerp(AmbientGain
, ChannelGain
[chan
], DirGain
);
771 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
774 for(i
= 0;i
< NumSends
;i
++)
775 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
];
777 /* Update filter coefficients. */
778 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
780 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
781 for(i
= 0;i
< NumSends
;i
++)
783 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
784 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
789 static __inline ALfloat
aluF2F(ALfloat val
)
791 static __inline ALint
aluF2I(ALfloat val
)
793 if(val
> 1.0f
) return 2147483647;
794 if(val
< -1.0f
) return -2147483647-1;
795 return fastf2i((ALfloat
)(val
*2147483647.0));
797 static __inline ALuint
aluF2UI(ALfloat val
)
798 { return aluF2I(val
)+2147483648u; }
799 static __inline ALshort
aluF2S(ALfloat val
)
800 { return aluF2I(val
)>>16; }
801 static __inline ALushort
aluF2US(ALfloat val
)
802 { return aluF2S(val
)+32768; }
803 static __inline ALbyte
aluF2B(ALfloat val
)
804 { return aluF2I(val
)>>24; }
805 static __inline ALubyte
aluF2UB(ALfloat val
)
806 { return aluF2B(val
)+128; }
808 #define DECL_TEMPLATE(T, N, func) \
809 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
810 ALuint SamplesToDo) \
812 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
813 const enum Channel *ChanMap = device->DevChannels; \
816 for(i = 0;i < SamplesToDo;i++) \
818 for(j = 0;j < N;j++) \
819 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
823 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
824 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
825 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
826 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
827 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
829 DECL_TEMPLATE(ALuint
, 1, aluF2UI
)
830 DECL_TEMPLATE(ALuint
, 4, aluF2UI
)
831 DECL_TEMPLATE(ALuint
, 6, aluF2UI
)
832 DECL_TEMPLATE(ALuint
, 7, aluF2UI
)
833 DECL_TEMPLATE(ALuint
, 8, aluF2UI
)
835 DECL_TEMPLATE(ALint
, 1, aluF2I
)
836 DECL_TEMPLATE(ALint
, 4, aluF2I
)
837 DECL_TEMPLATE(ALint
, 6, aluF2I
)
838 DECL_TEMPLATE(ALint
, 7, aluF2I
)
839 DECL_TEMPLATE(ALint
, 8, aluF2I
)
841 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
842 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
843 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
844 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
845 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
847 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
848 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
849 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
850 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
851 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
853 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
854 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
855 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
856 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
857 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
859 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
860 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
861 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
862 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
863 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
867 #define DECL_TEMPLATE(T, N, func) \
868 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
869 ALuint SamplesToDo) \
871 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
872 const enum Channel *ChanMap = device->DevChannels; \
877 for(i = 0;i < SamplesToDo;i++) \
880 samples[0] = DryBuffer[i][ChanMap[0]]; \
881 samples[1] = DryBuffer[i][ChanMap[1]]; \
882 bs2b_cross_feed(device->Bs2b, samples); \
883 *(buffer++) = func(samples[0]); \
884 *(buffer++) = func(samples[1]); \
889 for(i = 0;i < SamplesToDo;i++) \
891 for(j = 0;j < N;j++) \
892 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
897 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
898 DECL_TEMPLATE(ALuint
, 2, aluF2UI
)
899 DECL_TEMPLATE(ALint
, 2, aluF2I
)
900 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
901 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
902 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
903 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
907 #define DECL_TEMPLATE(T) \
908 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
910 switch(device->FmtChans) \
913 Write_##T##_1(device, buffer, SamplesToDo); \
916 Write_##T##_2(device, buffer, SamplesToDo); \
919 Write_##T##_4(device, buffer, SamplesToDo); \
922 case DevFmtX51Side: \
923 Write_##T##_6(device, buffer, SamplesToDo); \
926 Write_##T##_7(device, buffer, SamplesToDo); \
929 Write_##T##_8(device, buffer, SamplesToDo); \
934 DECL_TEMPLATE(ALfloat
)
935 DECL_TEMPLATE(ALuint
)
937 DECL_TEMPLATE(ALushort
)
938 DECL_TEMPLATE(ALshort
)
939 DECL_TEMPLATE(ALubyte
)
940 DECL_TEMPLATE(ALbyte
)
944 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
947 ALeffectslot
**slot
, **slot_end
;
948 ALsource
**src
, **src_end
;
953 fpuState
= SetMixerFPUMode();
957 /* Setup variables */
958 SamplesToDo
= minu(size
, BUFFERSIZE
);
960 /* Clear mixing buffer */
961 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
964 ctx
= device
->ContextList
;
967 ALenum DeferUpdates
= ctx
->DeferUpdates
;
968 ALenum UpdateSources
= AL_FALSE
;
971 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
973 src
= ctx
->ActiveSources
;
974 src_end
= src
+ ctx
->ActiveSourceCount
;
975 while(src
!= src_end
)
977 if((*src
)->state
!= AL_PLAYING
)
979 --(ctx
->ActiveSourceCount
);
984 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
986 ALsource_Update(*src
, ctx
);
988 MixSource(*src
, device
, SamplesToDo
);
992 /* effect slot processing */
993 slot
= ctx
->ActiveEffectSlots
;
994 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
995 while(slot
!= slot_end
)
997 for(c
= 0;c
< SamplesToDo
;c
++)
999 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
1000 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
1002 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
1003 (*slot
)->PendingClicks
[0] = 0.0f
;
1005 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1006 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
1008 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1009 (*slot
)->WetBuffer
, device
->DryBuffer
);
1011 for(i
= 0;i
< SamplesToDo
;i
++)
1012 (*slot
)->WetBuffer
[i
] = 0.0f
;
1020 slot
= &device
->DefaultSlot
;
1023 for(c
= 0;c
< SamplesToDo
;c
++)
1025 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
1026 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
1028 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
1029 (*slot
)->PendingClicks
[0] = 0.0f
;
1031 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1032 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
1034 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1035 (*slot
)->WetBuffer
, device
->DryBuffer
);
1037 for(i
= 0;i
< SamplesToDo
;i
++)
1038 (*slot
)->WetBuffer
[i
] = 0.0f
;
1040 UnlockDevice(device
);
1042 //Post processing loop
1043 if(device
->FmtChans
== DevFmtMono
)
1045 for(i
= 0;i
< SamplesToDo
;i
++)
1047 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
1048 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] * (1.0f
/256.0f
);
1050 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
1051 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
1053 else if(device
->FmtChans
== DevFmtStereo
)
1055 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
1056 for(i
= 0;i
< SamplesToDo
;i
++)
1058 for(c
= 0;c
< 2;c
++)
1060 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1061 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1064 for(c
= 0;c
< 2;c
++)
1066 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1067 device
->PendingClicks
[c
] = 0.0f
;
1072 for(i
= 0;i
< SamplesToDo
;i
++)
1074 for(c
= 0;c
< MAXCHANNELS
;c
++)
1076 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1077 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1080 for(c
= 0;c
< MAXCHANNELS
;c
++)
1082 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1083 device
->PendingClicks
[c
] = 0.0f
;
1089 switch(device
->FmtType
)
1092 Write_ALbyte(device
, buffer
, SamplesToDo
);
1095 Write_ALubyte(device
, buffer
, SamplesToDo
);
1098 Write_ALshort(device
, buffer
, SamplesToDo
);
1101 Write_ALushort(device
, buffer
, SamplesToDo
);
1104 Write_ALint(device
, buffer
, SamplesToDo
);
1107 Write_ALuint(device
, buffer
, SamplesToDo
);
1110 Write_ALfloat(device
, buffer
, SamplesToDo
);
1115 size
-= SamplesToDo
;
1118 RestoreFPUMode(fpuState
);
1122 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1124 ALCcontext
*Context
;
1127 device
->Connected
= ALC_FALSE
;
1129 Context
= device
->ContextList
;
1132 ALsource
**src
, **src_end
;
1134 src
= Context
->ActiveSources
;
1135 src_end
= src
+ Context
->ActiveSourceCount
;
1136 while(src
!= src_end
)
1138 if((*src
)->state
== AL_PLAYING
)
1140 (*src
)->state
= AL_STOPPED
;
1141 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1142 (*src
)->position
= 0;
1143 (*src
)->position_fraction
= 0;
1147 Context
->ActiveSourceCount
= 0;
1149 Context
= Context
->next
;
1151 UnlockDevice(device
);