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] = { { FRONT_LEFT
, -30.0f
},
68 { FRONT_RIGHT
, 30.0f
} };
69 static const struct ChanMap RearMap
[2] = { { BACK_LEFT
, -150.0f
},
70 { BACK_RIGHT
, 150.0f
} };
71 static const struct ChanMap QuadMap
[4] = { { FRONT_LEFT
, -45.0f
},
72 { FRONT_RIGHT
, 45.0f
},
73 { BACK_LEFT
, -135.0f
},
74 { BACK_RIGHT
, 135.0f
} };
75 static const struct ChanMap X51Map
[6] = { { FRONT_LEFT
, -30.0f
},
76 { FRONT_RIGHT
, 30.0f
},
77 { FRONT_CENTER
, 0.0f
},
79 { BACK_LEFT
, -110.0f
},
80 { BACK_RIGHT
, 110.0f
} };
81 static const struct ChanMap X61Map
[7] = { { FRONT_LEFT
, -30.0f
},
82 { FRONT_RIGHT
, 30.0f
},
83 { FRONT_CENTER
, 0.0f
},
85 { BACK_CENTER
, 180.0f
},
86 { SIDE_LEFT
, -90.0f
},
87 { SIDE_RIGHT
, 90.0f
} };
88 static const struct ChanMap X71Map
[8] = { { FRONT_LEFT
, -30.0f
},
89 { FRONT_RIGHT
, 30.0f
},
90 { FRONT_CENTER
, 0.0f
},
92 { BACK_LEFT
, -110.0f
},
93 { BACK_RIGHT
, 110.0f
},
94 { SIDE_LEFT
, -90.0f
},
95 { SIDE_RIGHT
, 90.0f
} };
97 ALCdevice
*Device
= ALContext
->Device
;
98 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
99 ALbufferlistitem
*BufferListItem
;
100 enum DevFmtChannels DevChans
;
101 enum FmtChannels Channels
;
102 ALfloat (*SrcMatrix
)[MAXCHANNELS
];
103 ALfloat DryGain
, DryGainHF
;
104 ALfloat WetGain
[MAX_SENDS
];
105 ALfloat WetGainHF
[MAX_SENDS
];
106 ALint NumSends
, Frequency
;
107 const ALfloat
*SpeakerGain
;
108 const struct ChanMap
*chans
= NULL
;
109 enum Resampler Resampler
;
110 ALint num_channels
= 0;
111 ALboolean VirtualChannels
;
117 /* Get device properties */
118 DevChans
= Device
->FmtChans
;
119 NumSends
= Device
->NumAuxSends
;
120 Frequency
= Device
->Frequency
;
122 /* Get listener properties */
123 ListenerGain
= ALContext
->Listener
.Gain
;
125 /* Get source properties */
126 SourceVolume
= ALSource
->flGain
;
127 MinVolume
= ALSource
->flMinGain
;
128 MaxVolume
= ALSource
->flMaxGain
;
129 Pitch
= ALSource
->flPitch
;
130 Resampler
= ALSource
->Resampler
;
131 VirtualChannels
= ALSource
->VirtualChannels
;
133 /* Calculate the stepping value */
135 BufferListItem
= ALSource
->queue
;
136 while(BufferListItem
!= NULL
)
139 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
141 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
142 ALSource
->SampleSize
;
143 maxstep
-= ResamplerPadding
[Resampler
] +
144 ResamplerPrePadding
[Resampler
] + 1;
145 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
147 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
148 if(Pitch
> (ALfloat
)maxstep
)
149 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
152 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
153 if(ALSource
->Params
.Step
== 0)
154 ALSource
->Params
.Step
= 1;
157 Channels
= ALBuffer
->FmtChannels
;
160 BufferListItem
= BufferListItem
->next
;
162 if(VirtualChannels
&& Device
->Hrtf
)
163 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
164 POINT_RESAMPLER
: Resampler
);
166 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
167 POINT_RESAMPLER
: Resampler
);
169 /* Calculate gains */
170 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
171 DryGain
*= ALSource
->DirectGain
;
172 DryGainHF
= ALSource
->DirectGainHF
;
173 for(i
= 0;i
< NumSends
;i
++)
175 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
176 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
;
177 WetGainHF
[i
] = ALSource
->Send
[i
].WetGainHF
;
180 SrcMatrix
= ALSource
->Params
.DryGains
;
181 for(i
= 0;i
< MAXCHANNELS
;i
++)
183 for(c
= 0;c
< MAXCHANNELS
;c
++)
184 SrcMatrix
[i
][c
] = 0.0f
;
193 if(VirtualChannels
&& (Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
195 DryGain
*= aluSqrt(2.0f
/4.0f
);
198 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* RearMap
[c
].angle
),
199 aluSin(F_PI
/180.0f
* RearMap
[c
].angle
));
200 SpeakerGain
= Device
->PanningLUT
[pos
];
202 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
204 enum Channel chan
= Device
->Speaker2Chan
[i
];
205 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
240 if(VirtualChannels
== AL_FALSE
)
242 for(c
= 0;c
< num_channels
;c
++)
243 SrcMatrix
[c
][chans
[c
].channel
] += DryGain
* ListenerGain
;
245 else if(Device
->Hrtf
)
247 for(c
= 0;c
< num_channels
;c
++)
249 if(chans
[c
].channel
== LFE
)
252 ALSource
->Params
.HrtfDelay
[c
][0] = 0;
253 ALSource
->Params
.HrtfDelay
[c
][1] = 0;
254 for(i
= 0;i
< HRIR_LENGTH
;i
++)
256 ALSource
->Params
.HrtfCoeffs
[c
][i
][0] = 0.0f
;
257 ALSource
->Params
.HrtfCoeffs
[c
][i
][1] = 0.0f
;
262 /* Get the static HRIR coefficients and delays for this
264 GetLerpedHrtfCoeffs(Device
->Hrtf
,
265 0.0f
, F_PI
/180.0f
* chans
[c
].angle
,
266 DryGain
*ListenerGain
,
267 ALSource
->Params
.HrtfCoeffs
[c
],
268 ALSource
->Params
.HrtfDelay
[c
]);
270 ALSource
->HrtfCounter
= 0;
275 for(c
= 0;c
< num_channels
;c
++)
277 if(chans
[c
].channel
== LFE
) /* Special-case LFE */
279 SrcMatrix
[c
][LFE
] += DryGain
* ListenerGain
;
282 pos
= aluCart2LUTpos(aluCos(F_PI
/180.0f
* chans
[c
].angle
),
283 aluSin(F_PI
/180.0f
* chans
[c
].angle
));
284 SpeakerGain
= Device
->PanningLUT
[pos
];
286 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
288 enum Channel chan
= Device
->Speaker2Chan
[i
];
289 SrcMatrix
[c
][chan
] += DryGain
* ListenerGain
*
294 for(i
= 0;i
< NumSends
;i
++)
296 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
299 Slot
= Device
->DefaultSlot
;
300 ALSource
->Params
.Send
[i
].Slot
= Slot
;
301 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
] * ListenerGain
;
304 /* Update filter coefficients. Calculations based on the I3DL2
306 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
308 /* We use two chained one-pole filters, so we need to take the
309 * square root of the squared gain, which is the same as the base
311 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
312 for(i
= 0;i
< NumSends
;i
++)
314 /* We use a one-pole filter, so we need to take the squared gain */
315 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
316 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
320 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
322 const ALCdevice
*Device
= ALContext
->Device
;
323 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
324 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
325 ALfloat Velocity
[3],ListenerVel
[3];
326 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
327 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
328 ALfloat DopplerFactor
, DopplerVelocity
, SpeedOfSound
;
329 ALfloat AirAbsorptionFactor
;
330 ALfloat RoomAirAbsorption
[MAX_SENDS
];
331 ALbufferlistitem
*BufferListItem
;
332 ALfloat Attenuation
, EffectiveDist
;
333 ALfloat RoomAttenuation
[MAX_SENDS
];
334 ALfloat MetersPerUnit
;
335 ALfloat RoomRolloffBase
;
336 ALfloat RoomRolloff
[MAX_SENDS
];
337 ALfloat DecayDistance
[MAX_SENDS
];
340 ALboolean DryGainHFAuto
;
341 ALfloat WetGain
[MAX_SENDS
];
342 ALfloat WetGainHF
[MAX_SENDS
];
343 ALboolean WetGainAuto
;
344 ALboolean WetGainHFAuto
;
345 enum Resampler Resampler
;
353 for(i
= 0;i
< MAX_SENDS
;i
++)
356 //Get context properties
357 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
358 DopplerVelocity
= ALContext
->DopplerVelocity
;
359 SpeedOfSound
= ALContext
->flSpeedOfSound
;
360 NumSends
= Device
->NumAuxSends
;
361 Frequency
= Device
->Frequency
;
363 //Get listener properties
364 ListenerGain
= ALContext
->Listener
.Gain
;
365 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
366 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
367 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
368 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
370 //Get source properties
371 SourceVolume
= ALSource
->flGain
;
372 MinVolume
= ALSource
->flMinGain
;
373 MaxVolume
= ALSource
->flMaxGain
;
374 Pitch
= ALSource
->flPitch
;
375 Resampler
= ALSource
->Resampler
;
376 Position
[0] = ALSource
->vPosition
[0];
377 Position
[1] = ALSource
->vPosition
[1];
378 Position
[2] = ALSource
->vPosition
[2];
379 Direction
[0] = ALSource
->vOrientation
[0];
380 Direction
[1] = ALSource
->vOrientation
[1];
381 Direction
[2] = ALSource
->vOrientation
[2];
382 Velocity
[0] = ALSource
->vVelocity
[0];
383 Velocity
[1] = ALSource
->vVelocity
[1];
384 Velocity
[2] = ALSource
->vVelocity
[2];
385 MinDist
= ALSource
->flRefDistance
;
386 MaxDist
= ALSource
->flMaxDistance
;
387 Rolloff
= ALSource
->flRollOffFactor
;
388 InnerAngle
= ALSource
->flInnerAngle
* ConeScale
;
389 OuterAngle
= ALSource
->flOuterAngle
* ConeScale
;
390 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
391 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
392 WetGainAuto
= ALSource
->WetGainAuto
;
393 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
394 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
395 for(i
= 0;i
< NumSends
;i
++)
397 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
400 Slot
= Device
->DefaultSlot
;
401 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
403 RoomRolloff
[i
] = 0.0f
;
404 DecayDistance
[i
] = 0.0f
;
405 RoomAirAbsorption
[i
] = 1.0f
;
407 else if(Slot
->AuxSendAuto
)
409 RoomRolloff
[i
] = RoomRolloffBase
;
410 if(IsReverbEffect(Slot
->effect
.type
))
412 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
413 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
414 SPEEDOFSOUNDMETRESPERSEC
;
415 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
419 DecayDistance
[i
] = 0.0f
;
420 RoomAirAbsorption
[i
] = 1.0f
;
425 /* If the slot's auxiliary send auto is off, the data sent to the
426 * effect slot is the same as the dry path, sans filter effects */
427 RoomRolloff
[i
] = Rolloff
;
428 DecayDistance
[i
] = 0.0f
;
429 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
432 ALSource
->Params
.Send
[i
].Slot
= Slot
;
435 //1. Translate Listener to origin (convert to head relative)
436 if(ALSource
->bHeadRelative
== AL_FALSE
)
438 ALfloat Matrix
[4][4];
442 for(i2
= 0;i2
< 4;i2
++)
443 Matrix
[i
][i2
] = ALContext
->Listener
.Matrix
[i
][i2
];
446 /* Translate position */
447 Position
[0] -= ALContext
->Listener
.Position
[0];
448 Position
[1] -= ALContext
->Listener
.Position
[1];
449 Position
[2] -= ALContext
->Listener
.Position
[2];
451 /* Transform source vectors into listener space */
452 aluMatrixVector(Position
, 1.0f
, Matrix
);
453 aluMatrixVector(Direction
, 0.0f
, Matrix
);
454 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
458 ListenerVel
[0] = 0.0f
;
459 ListenerVel
[1] = 0.0f
;
460 ListenerVel
[2] = 0.0f
;
463 SourceToListener
[0] = -Position
[0];
464 SourceToListener
[1] = -Position
[1];
465 SourceToListener
[2] = -Position
[2];
466 aluNormalize(SourceToListener
);
467 aluNormalize(Direction
);
469 //2. Calculate distance attenuation
470 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
471 ClampedDist
= Distance
;
474 for(i
= 0;i
< NumSends
;i
++)
475 RoomAttenuation
[i
] = 1.0f
;
476 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
477 ALContext
->DistanceModel
)
479 case InverseDistanceClamped
:
480 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
481 if(MaxDist
< MinDist
)
484 case InverseDistance
:
487 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
488 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
489 for(i
= 0;i
< NumSends
;i
++)
491 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
492 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
497 case LinearDistanceClamped
:
498 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
499 if(MaxDist
< MinDist
)
503 if(MaxDist
!= MinDist
)
505 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
506 Attenuation
= maxf(Attenuation
, 0.0f
);
507 for(i
= 0;i
< NumSends
;i
++)
509 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
510 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
515 case ExponentDistanceClamped
:
516 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
517 if(MaxDist
< MinDist
)
520 case ExponentDistance
:
521 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
523 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
524 for(i
= 0;i
< NumSends
;i
++)
525 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
529 case DisableDistance
:
533 // Source Gain + Attenuation
534 DryGain
= SourceVolume
* Attenuation
;
535 for(i
= 0;i
< NumSends
;i
++)
536 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
538 // Distance-based air absorption
539 EffectiveDist
= 0.0f
;
540 if(MinDist
> 0.0f
&& Attenuation
< 1.0f
)
541 EffectiveDist
= (MinDist
/Attenuation
- MinDist
)*MetersPerUnit
;
542 if(AirAbsorptionFactor
> 0.0f
&& EffectiveDist
> 0.0f
)
544 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*EffectiveDist
);
545 for(i
= 0;i
< NumSends
;i
++)
546 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
],
547 AirAbsorptionFactor
*EffectiveDist
);
552 /* Apply a decay-time transformation to the wet path, based on the
553 * attenuation of the dry path.
555 * Using the approximate (effective) source to listener distance, the
556 * initial decay of the reverb effect is calculated and applied to the
559 for(i
= 0;i
< NumSends
;i
++)
561 if(DecayDistance
[i
] > 0.0f
)
562 WetGain
[i
] *= aluPow(0.001f
/* -60dB */,
563 EffectiveDist
/ DecayDistance
[i
]);
567 /* Calculate directional soundcones */
568 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0f
/F_PI
);
569 if(Angle
>= InnerAngle
&& Angle
<= OuterAngle
)
571 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
572 ConeVolume
= lerp(1.0f
, ALSource
->flOuterGain
, scale
);
573 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
575 else if(Angle
> OuterAngle
)
577 ConeVolume
= ALSource
->flOuterGain
;
578 ConeHF
= ALSource
->OuterGainHF
;
586 DryGain
*= ConeVolume
;
589 for(i
= 0;i
< NumSends
;i
++)
590 WetGain
[i
] *= ConeVolume
;
596 for(i
= 0;i
< NumSends
;i
++)
597 WetGainHF
[i
] *= ConeHF
;
600 // Clamp to Min/Max Gain
601 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
602 for(i
= 0;i
< NumSends
;i
++)
603 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
605 // Apply filter gains and filters
606 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
607 DryGainHF
*= ALSource
->DirectGainHF
;
608 for(i
= 0;i
< NumSends
;i
++)
610 WetGain
[i
] *= ALSource
->Send
[i
].WetGain
* ListenerGain
;
611 WetGainHF
[i
] *= ALSource
->Send
[i
].WetGainHF
;
614 // Calculate Velocity
615 if(DopplerFactor
!= 0.0f
)
618 ALfloat MaxVelocity
= (SpeedOfSound
*DopplerVelocity
) /
621 VSS
= aluDotproduct(Velocity
, SourceToListener
);
622 if(VSS
>= MaxVelocity
)
623 VSS
= (MaxVelocity
- 1.0f
);
624 else if(VSS
<= -MaxVelocity
)
625 VSS
= -MaxVelocity
+ 1.0f
;
627 VLS
= aluDotproduct(ListenerVel
, SourceToListener
);
628 if(VLS
>= MaxVelocity
)
629 VLS
= (MaxVelocity
- 1.0f
);
630 else if(VLS
<= -MaxVelocity
)
631 VLS
= -MaxVelocity
+ 1.0f
;
633 Pitch
*= ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VLS
)) /
634 ((SpeedOfSound
*DopplerVelocity
) - (DopplerFactor
*VSS
));
637 BufferListItem
= ALSource
->queue
;
638 while(BufferListItem
!= NULL
)
641 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
643 ALint maxstep
= STACK_DATA_SIZE
/ ALSource
->NumChannels
/
644 ALSource
->SampleSize
;
645 maxstep
-= ResamplerPadding
[Resampler
] +
646 ResamplerPrePadding
[Resampler
] + 1;
647 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
649 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
650 if(Pitch
> (ALfloat
)maxstep
)
651 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
654 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
655 if(ALSource
->Params
.Step
== 0)
656 ALSource
->Params
.Step
= 1;
661 BufferListItem
= BufferListItem
->next
;
664 ALSource
->Params
.DoMix
= SelectHrtfMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
665 POINT_RESAMPLER
: Resampler
);
667 ALSource
->Params
.DoMix
= SelectMixer((ALSource
->Params
.Step
==FRACTIONONE
) ?
668 POINT_RESAMPLER
: Resampler
);
672 // Use a binaural HRTF algorithm for stereo headphone playback
673 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
677 ALfloat invlen
= 1.0f
/Distance
;
678 Position
[0] *= invlen
;
679 Position
[1] *= invlen
;
680 Position
[2] *= invlen
;
682 // Calculate elevation and azimuth only when the source is not at
683 // the listener. This prevents +0 and -0 Z from producing
684 // inconsistent panning.
685 ev
= aluAsin(Position
[1]);
686 az
= aluAtan2(Position
[0], -Position
[2]*ZScale
);
689 // Check to see if the HRIR is already moving.
690 if(ALSource
->HrtfMoving
)
692 // Calculate the normalized HRTF transition factor (delta).
693 delta
= CalcHrtfDelta(ALSource
->Params
.HrtfGain
, DryGain
,
694 ALSource
->Params
.HrtfDir
, Position
);
695 // If the delta is large enough, get the moving HRIR target
696 // coefficients, target delays, steppping values, and counter.
699 ALSource
->HrtfCounter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
700 ev
, az
, DryGain
, delta
,
701 ALSource
->HrtfCounter
,
702 ALSource
->Params
.HrtfCoeffs
[0],
703 ALSource
->Params
.HrtfDelay
[0],
704 ALSource
->Params
.HrtfCoeffStep
,
705 ALSource
->Params
.HrtfDelayStep
);
706 ALSource
->Params
.HrtfGain
= DryGain
;
707 ALSource
->Params
.HrtfDir
[0] = Position
[0];
708 ALSource
->Params
.HrtfDir
[1] = Position
[1];
709 ALSource
->Params
.HrtfDir
[2] = Position
[2];
714 // Get the initial (static) HRIR coefficients and delays.
715 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
716 ALSource
->Params
.HrtfCoeffs
[0],
717 ALSource
->Params
.HrtfDelay
[0]);
718 ALSource
->HrtfCounter
= 0;
719 ALSource
->Params
.HrtfGain
= DryGain
;
720 ALSource
->Params
.HrtfDir
[0] = Position
[0];
721 ALSource
->Params
.HrtfDir
[1] = Position
[1];
722 ALSource
->Params
.HrtfDir
[2] = Position
[2];
727 // Use energy-preserving panning algorithm for multi-speaker playback
728 ALfloat DirGain
, AmbientGain
;
729 const ALfloat
*SpeakerGain
;
733 length
= maxf(Distance
, MinDist
);
736 ALfloat invlen
= 1.0f
/length
;
737 Position
[0] *= invlen
;
738 Position
[1] *= invlen
;
739 Position
[2] *= invlen
;
742 pos
= aluCart2LUTpos(-Position
[2]*ZScale
, Position
[0]);
743 SpeakerGain
= Device
->PanningLUT
[pos
];
745 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
746 // elevation adjustment for directional gain. this sucks, but
747 // has low complexity
748 AmbientGain
= aluSqrt(1.0f
/Device
->NumChan
);
749 for(i
= 0;i
< MAXCHANNELS
;i
++)
752 for(i2
= 0;i2
< MAXCHANNELS
;i2
++)
753 ALSource
->Params
.DryGains
[i
][i2
] = 0.0f
;
755 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
757 enum Channel chan
= Device
->Speaker2Chan
[i
];
758 ALfloat gain
= lerp(AmbientGain
, SpeakerGain
[chan
], DirGain
);
759 ALSource
->Params
.DryGains
[0][chan
] = DryGain
* gain
;
762 for(i
= 0;i
< NumSends
;i
++)
763 ALSource
->Params
.Send
[i
].WetGain
= WetGain
[i
];
765 /* Update filter coefficients. */
766 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
768 ALSource
->Params
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
769 for(i
= 0;i
< NumSends
;i
++)
771 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
772 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
777 static __inline ALfloat
aluF2F(ALfloat val
)
779 static __inline ALshort
aluF2S(ALfloat val
)
781 if(val
> 1.0f
) return 32767;
782 if(val
< -1.0f
) return -32768;
783 return fastf2i(val
*32767.0f
);
785 static __inline ALushort
aluF2US(ALfloat val
)
786 { return aluF2S(val
)+32768; }
787 static __inline ALbyte
aluF2B(ALfloat val
)
788 { return aluF2S(val
)>>8; }
789 static __inline ALubyte
aluF2UB(ALfloat val
)
790 { return aluF2US(val
)>>8; }
792 #define DECL_TEMPLATE(T, N, func) \
793 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
794 ALuint SamplesToDo) \
796 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
797 const enum Channel *ChanMap = device->DevChannels; \
800 for(i = 0;i < SamplesToDo;i++) \
802 for(j = 0;j < N;j++) \
803 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
807 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
808 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
809 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
810 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
811 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
813 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
814 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
815 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
816 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
817 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
819 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
820 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
821 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
822 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
823 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
825 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
826 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
827 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
828 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
829 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
831 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
832 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
833 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
834 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
835 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
839 #define DECL_TEMPLATE(T, N, func) \
840 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
841 ALuint SamplesToDo) \
843 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
844 const enum Channel *ChanMap = device->DevChannels; \
849 for(i = 0;i < SamplesToDo;i++) \
852 samples[0] = DryBuffer[i][ChanMap[0]]; \
853 samples[1] = DryBuffer[i][ChanMap[1]]; \
854 bs2b_cross_feed(device->Bs2b, samples); \
855 *(buffer++) = func(samples[0]); \
856 *(buffer++) = func(samples[1]); \
861 for(i = 0;i < SamplesToDo;i++) \
863 for(j = 0;j < N;j++) \
864 *(buffer++) = func(DryBuffer[i][ChanMap[j]]); \
869 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
870 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
871 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
872 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
873 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
877 #define DECL_TEMPLATE(T) \
878 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
880 switch(device->FmtChans) \
883 Write_##T##_1(device, buffer, SamplesToDo); \
886 Write_##T##_2(device, buffer, SamplesToDo); \
889 Write_##T##_4(device, buffer, SamplesToDo); \
892 case DevFmtX51Side: \
893 Write_##T##_6(device, buffer, SamplesToDo); \
896 Write_##T##_7(device, buffer, SamplesToDo); \
899 Write_##T##_8(device, buffer, SamplesToDo); \
904 DECL_TEMPLATE(ALfloat
)
905 DECL_TEMPLATE(ALushort
)
906 DECL_TEMPLATE(ALshort
)
907 DECL_TEMPLATE(ALubyte
)
908 DECL_TEMPLATE(ALbyte
)
912 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
915 ALeffectslot
**slot
, **slot_end
;
916 ALsource
**src
, **src_end
;
921 fpuState
= SetMixerFPUMode();
925 /* Setup variables */
926 SamplesToDo
= minu(size
, BUFFERSIZE
);
928 /* Clear mixing buffer */
929 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
932 ctx
= device
->ContextList
;
935 ALenum DeferUpdates
= ctx
->DeferUpdates
;
936 ALenum UpdateSources
= AL_FALSE
;
939 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
941 src
= ctx
->ActiveSources
;
942 src_end
= src
+ ctx
->ActiveSourceCount
;
943 while(src
!= src_end
)
945 if((*src
)->state
!= AL_PLAYING
)
947 --(ctx
->ActiveSourceCount
);
952 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
954 ALsource_Update(*src
, ctx
);
956 MixSource(*src
, device
, SamplesToDo
);
960 /* effect slot processing */
961 slot
= ctx
->ActiveEffectSlots
;
962 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
963 while(slot
!= slot_end
)
965 for(c
= 0;c
< SamplesToDo
;c
++)
967 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
968 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
970 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
971 (*slot
)->PendingClicks
[0] = 0.0f
;
973 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
974 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
976 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
977 (*slot
)->WetBuffer
, device
->DryBuffer
);
979 for(i
= 0;i
< SamplesToDo
;i
++)
980 (*slot
)->WetBuffer
[i
] = 0.0f
;
988 slot
= &device
->DefaultSlot
;
989 for(c
= 0;c
< SamplesToDo
;c
++)
991 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
992 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
994 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
995 (*slot
)->PendingClicks
[0] = 0.0f
;
997 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
998 ALeffectState_Update((*slot
)->EffectState
, ctx
, *slot
);
1000 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1001 (*slot
)->WetBuffer
, device
->DryBuffer
);
1003 for(i
= 0;i
< SamplesToDo
;i
++)
1004 (*slot
)->WetBuffer
[i
] = 0.0f
;
1005 UnlockDevice(device
);
1007 //Post processing loop
1008 if(device
->FmtChans
== DevFmtMono
)
1010 for(i
= 0;i
< SamplesToDo
;i
++)
1012 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
1013 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] * (1.0f
/256.0f
);
1015 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
1016 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
1018 else if(device
->FmtChans
== DevFmtStereo
)
1020 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
1021 for(i
= 0;i
< SamplesToDo
;i
++)
1023 for(c
= 0;c
< 2;c
++)
1025 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1026 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1029 for(c
= 0;c
< 2;c
++)
1031 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1032 device
->PendingClicks
[c
] = 0.0f
;
1037 for(i
= 0;i
< SamplesToDo
;i
++)
1039 for(c
= 0;c
< MAXCHANNELS
;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
< MAXCHANNELS
;c
++)
1047 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1048 device
->PendingClicks
[c
] = 0.0f
;
1054 switch(device
->FmtType
)
1057 Write_ALbyte(device
, buffer
, SamplesToDo
);
1060 Write_ALubyte(device
, buffer
, SamplesToDo
);
1063 Write_ALshort(device
, buffer
, SamplesToDo
);
1066 Write_ALushort(device
, buffer
, SamplesToDo
);
1069 Write_ALfloat(device
, buffer
, SamplesToDo
);
1074 size
-= SamplesToDo
;
1077 RestoreFPUMode(fpuState
);
1081 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1083 ALCcontext
*Context
;
1086 device
->Connected
= ALC_FALSE
;
1088 Context
= device
->ContextList
;
1091 ALsource
**src
, **src_end
;
1093 src
= Context
->ActiveSources
;
1094 src_end
= src
+ Context
->ActiveSourceCount
;
1095 while(src
!= src_end
)
1097 if((*src
)->state
== AL_PLAYING
)
1099 (*src
)->state
= AL_STOPPED
;
1100 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1101 (*src
)->position
= 0;
1102 (*src
)->position_fraction
= 0;
1106 Context
->ActiveSourceCount
= 0;
1108 Context
= Context
->next
;
1110 UnlockDevice(device
);