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"
39 #include "mixer_defs.h"
48 ALfloat ConeScale
= 1.0f
;
50 /* Localized Z scalar for mono sources */
51 ALfloat ZScale
= 1.0f
;
54 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
56 if(increment
== FRACTIONONE
)
57 return Resample_point32_C
;
61 return Resample_point32_C
;
64 if((CPUCapFlags
&CPU_CAP_SSE
))
65 return Resample_lerp32_SSE
;
67 return Resample_lerp32_C
;
70 if((CPUCapFlags
&CPU_CAP_SSE
))
71 return Resample_cubic32_SSE
;
73 return Resample_cubic32_C
;
75 /* Shouldn't happen */
79 return Resample_point32_C
;
83 static DryMixerFunc
SelectHrtfMixer(void)
86 if((CPUCapFlags
&CPU_CAP_SSE
))
87 return MixDirect_Hrtf_SSE
;
90 if((CPUCapFlags
&CPU_CAP_NEON
))
91 return MixDirect_Hrtf_Neon
;
94 return MixDirect_Hrtf_C
;
97 static DryMixerFunc
SelectDirectMixer(void)
100 if((CPUCapFlags
&CPU_CAP_SSE
))
101 return MixDirect_SSE
;
107 static WetMixerFunc
SelectSendMixer(void)
110 if((CPUCapFlags
&CPU_CAP_SSE
))
118 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
,ALfloat w
,ALfloat matrix
[4][4])
121 vector
[0], vector
[1], vector
[2], w
124 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
125 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
126 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
130 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
132 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
133 static const struct ChanMap StereoMap
[2] = {
134 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
135 { FrontRight
, 30.0f
* F_PI
/180.0f
}
137 static const struct ChanMap StereoWideMap
[2] = {
138 { FrontLeft
, -90.0f
* F_PI
/180.0f
},
139 { FrontRight
, 90.0f
* F_PI
/180.0f
}
141 static const struct ChanMap RearMap
[2] = {
142 { BackLeft
, -150.0f
* F_PI
/180.0f
},
143 { BackRight
, 150.0f
* F_PI
/180.0f
}
145 static const struct ChanMap QuadMap
[4] = {
146 { FrontLeft
, -45.0f
* F_PI
/180.0f
},
147 { FrontRight
, 45.0f
* F_PI
/180.0f
},
148 { BackLeft
, -135.0f
* F_PI
/180.0f
},
149 { BackRight
, 135.0f
* F_PI
/180.0f
}
151 static const struct ChanMap X51Map
[6] = {
152 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
153 { FrontRight
, 30.0f
* F_PI
/180.0f
},
154 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
156 { BackLeft
, -110.0f
* F_PI
/180.0f
},
157 { BackRight
, 110.0f
* F_PI
/180.0f
}
159 static const struct ChanMap X61Map
[7] = {
160 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
161 { FrontRight
, 30.0f
* F_PI
/180.0f
},
162 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
164 { BackCenter
, 180.0f
* F_PI
/180.0f
},
165 { SideLeft
, -90.0f
* F_PI
/180.0f
},
166 { SideRight
, 90.0f
* F_PI
/180.0f
}
168 static const struct ChanMap X71Map
[8] = {
169 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
170 { FrontRight
, 30.0f
* F_PI
/180.0f
},
171 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
173 { BackLeft
, -150.0f
* F_PI
/180.0f
},
174 { BackRight
, 150.0f
* F_PI
/180.0f
},
175 { SideLeft
, -90.0f
* F_PI
/180.0f
},
176 { SideRight
, 90.0f
* F_PI
/180.0f
}
179 ALCdevice
*Device
= ALContext
->Device
;
180 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
181 ALbufferlistitem
*BufferListItem
;
182 enum FmtChannels Channels
;
183 ALfloat (*SrcMatrix
)[MaxChannels
];
184 ALfloat DryGain
, DryGainHF
;
185 ALfloat WetGain
[MAX_SENDS
];
186 ALfloat WetGainHF
[MAX_SENDS
];
187 ALint NumSends
, Frequency
;
188 const struct ChanMap
*chans
= NULL
;
189 enum Resampler Resampler
;
190 ALint num_channels
= 0;
191 ALboolean DirectChannels
;
192 ALfloat hwidth
= 0.0f
;
197 /* Get device properties */
198 NumSends
= Device
->NumAuxSends
;
199 Frequency
= Device
->Frequency
;
201 /* Get listener properties */
202 ListenerGain
= ALContext
->Listener
.Gain
;
204 /* Get source properties */
205 SourceVolume
= ALSource
->Gain
;
206 MinVolume
= ALSource
->MinGain
;
207 MaxVolume
= ALSource
->MaxGain
;
208 Pitch
= ALSource
->Pitch
;
209 Resampler
= ALSource
->Resampler
;
210 DirectChannels
= ALSource
->DirectChannels
;
212 /* Calculate the stepping value */
214 BufferListItem
= ALSource
->queue
;
215 while(BufferListItem
!= NULL
)
218 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
220 ALsizei maxstep
= BUFFERSIZE
/ ALSource
->NumChannels
;
221 maxstep
-= ResamplerPadding
[Resampler
] +
222 ResamplerPrePadding
[Resampler
] + 1;
223 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
225 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
226 if(Pitch
> (ALfloat
)maxstep
)
227 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
230 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
231 if(ALSource
->Params
.Step
== 0)
232 ALSource
->Params
.Step
= 1;
234 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
236 Channels
= ALBuffer
->FmtChannels
;
239 BufferListItem
= BufferListItem
->next
;
241 if(!DirectChannels
&& Device
->Hrtf
)
242 ALSource
->Params
.DryMix
= SelectHrtfMixer();
244 ALSource
->Params
.DryMix
= SelectDirectMixer();
245 ALSource
->Params
.WetMix
= SelectSendMixer();
247 /* Calculate gains */
248 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
249 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
250 DryGainHF
= ALSource
->DirectGainHF
;
251 for(i
= 0;i
< NumSends
;i
++)
253 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
254 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
255 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
258 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
259 for(i
= 0;i
< MaxChannels
;i
++)
261 for(c
= 0;c
< MaxChannels
;c
++)
262 SrcMatrix
[i
][c
] = 0.0f
;
272 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
276 chans
= StereoWideMap
;
277 hwidth
= 60.0f
* F_PI
/180.0f
;
308 if(DirectChannels
!= AL_FALSE
)
310 for(c
= 0;c
< num_channels
;c
++)
312 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
314 enum Channel chan
= Device
->Speaker2Chan
[i
];
315 if(chan
== chans
[c
].channel
)
317 SrcMatrix
[c
][chan
] += DryGain
;
323 else if(Device
->Hrtf
)
325 for(c
= 0;c
< num_channels
;c
++)
327 if(chans
[c
].channel
== LFE
)
330 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][0] = 0;
331 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][1] = 0;
332 for(i
= 0;i
< HRIR_LENGTH
;i
++)
334 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][0] = 0.0f
;
335 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][1] = 0.0f
;
340 /* Get the static HRIR coefficients and delays for this
342 GetLerpedHrtfCoeffs(Device
->Hrtf
,
343 0.0f
, chans
[c
].angle
, DryGain
,
344 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
],
345 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
]);
348 ALSource
->Hrtf
.Counter
= 0;
352 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf(Device
->NumChan
), hwidth
/(F_PI
*2.0f
));
353 for(c
= 0;c
< num_channels
;c
++)
355 /* Special-case LFE */
356 if(chans
[c
].channel
== LFE
)
358 SrcMatrix
[c
][chans
[c
].channel
] = DryGain
;
361 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
365 for(i
= 0;i
< NumSends
;i
++)
367 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
370 Slot
= Device
->DefaultSlot
;
371 if(Slot
&& Slot
->effect
.type
== AL_EFFECT_NULL
)
373 ALSource
->Params
.Send
[i
].Slot
= Slot
;
374 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
377 /* Update filter coefficients. Calculations based on the I3DL2
379 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
381 /* We use two chained one-pole filters, so we need to take the
382 * square root of the squared gain, which is the same as the base
384 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
385 for(i
= 0;i
< NumSends
;i
++)
387 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
388 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
392 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
394 const ALCdevice
*Device
= ALContext
->Device
;
395 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
396 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
397 ALfloat Velocity
[3],ListenerVel
[3];
398 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
399 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
400 ALfloat DopplerFactor
, SpeedOfSound
;
401 ALfloat AirAbsorptionFactor
;
402 ALfloat RoomAirAbsorption
[MAX_SENDS
];
403 ALbufferlistitem
*BufferListItem
;
405 ALfloat RoomAttenuation
[MAX_SENDS
];
406 ALfloat MetersPerUnit
;
407 ALfloat RoomRolloffBase
;
408 ALfloat RoomRolloff
[MAX_SENDS
];
409 ALfloat DecayDistance
[MAX_SENDS
];
412 ALboolean DryGainHFAuto
;
413 ALfloat WetGain
[MAX_SENDS
];
414 ALfloat WetGainHF
[MAX_SENDS
];
415 ALboolean WetGainAuto
;
416 ALboolean WetGainHFAuto
;
417 enum Resampler Resampler
;
418 ALfloat Matrix
[4][4];
426 for(i
= 0;i
< MAX_SENDS
;i
++)
429 /* Get context/device properties */
430 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
431 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
432 NumSends
= Device
->NumAuxSends
;
433 Frequency
= Device
->Frequency
;
435 /* Get listener properties */
436 ListenerGain
= ALContext
->Listener
.Gain
;
437 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
438 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
439 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
440 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
444 Matrix
[i
][j
] = ALContext
->Listener
.Matrix
[i
][j
];
447 /* Get source properties */
448 SourceVolume
= ALSource
->Gain
;
449 MinVolume
= ALSource
->MinGain
;
450 MaxVolume
= ALSource
->MaxGain
;
451 Pitch
= ALSource
->Pitch
;
452 Resampler
= ALSource
->Resampler
;
453 Position
[0] = ALSource
->Position
[0];
454 Position
[1] = ALSource
->Position
[1];
455 Position
[2] = ALSource
->Position
[2];
456 Direction
[0] = ALSource
->Orientation
[0];
457 Direction
[1] = ALSource
->Orientation
[1];
458 Direction
[2] = ALSource
->Orientation
[2];
459 Velocity
[0] = ALSource
->Velocity
[0];
460 Velocity
[1] = ALSource
->Velocity
[1];
461 Velocity
[2] = ALSource
->Velocity
[2];
462 MinDist
= ALSource
->RefDistance
;
463 MaxDist
= ALSource
->MaxDistance
;
464 Rolloff
= ALSource
->RollOffFactor
;
465 InnerAngle
= ALSource
->InnerAngle
;
466 OuterAngle
= ALSource
->OuterAngle
;
467 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
468 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
469 WetGainAuto
= ALSource
->WetGainAuto
;
470 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
471 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
472 for(i
= 0;i
< NumSends
;i
++)
474 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
477 Slot
= Device
->DefaultSlot
;
478 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
481 RoomRolloff
[i
] = 0.0f
;
482 DecayDistance
[i
] = 0.0f
;
483 RoomAirAbsorption
[i
] = 1.0f
;
485 else if(Slot
->AuxSendAuto
)
487 RoomRolloff
[i
] = RoomRolloffBase
;
488 if(IsReverbEffect(Slot
->effect
.type
))
490 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
491 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
492 SPEEDOFSOUNDMETRESPERSEC
;
493 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
497 DecayDistance
[i
] = 0.0f
;
498 RoomAirAbsorption
[i
] = 1.0f
;
503 /* If the slot's auxiliary send auto is off, the data sent to the
504 * effect slot is the same as the dry path, sans filter effects */
505 RoomRolloff
[i
] = Rolloff
;
506 DecayDistance
[i
] = 0.0f
;
507 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
510 ALSource
->Params
.Send
[i
].Slot
= Slot
;
513 /* Transform source to listener space (convert to head relative) */
514 if(ALSource
->HeadRelative
== AL_FALSE
)
516 /* Translate position */
517 Position
[0] -= ALContext
->Listener
.Position
[0];
518 Position
[1] -= ALContext
->Listener
.Position
[1];
519 Position
[2] -= ALContext
->Listener
.Position
[2];
521 /* Transform source vectors */
522 aluMatrixVector(Position
, 1.0f
, Matrix
);
523 aluMatrixVector(Direction
, 0.0f
, Matrix
);
524 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
525 /* Transform listener velocity */
526 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
530 /* Transform listener velocity from world space to listener space */
531 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
532 /* Offset the source velocity to be relative of the listener velocity */
533 Velocity
[0] += ListenerVel
[0];
534 Velocity
[1] += ListenerVel
[1];
535 Velocity
[2] += ListenerVel
[2];
538 SourceToListener
[0] = -Position
[0];
539 SourceToListener
[1] = -Position
[1];
540 SourceToListener
[2] = -Position
[2];
541 aluNormalize(SourceToListener
);
542 aluNormalize(Direction
);
544 /* Calculate distance attenuation */
545 Distance
= sqrtf(aluDotproduct(Position
, Position
));
546 ClampedDist
= Distance
;
549 for(i
= 0;i
< NumSends
;i
++)
550 RoomAttenuation
[i
] = 1.0f
;
551 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
552 ALContext
->DistanceModel
)
554 case InverseDistanceClamped
:
555 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
556 if(MaxDist
< MinDist
)
559 case InverseDistance
:
562 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
563 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
564 for(i
= 0;i
< NumSends
;i
++)
566 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
567 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
572 case LinearDistanceClamped
:
573 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
574 if(MaxDist
< MinDist
)
578 if(MaxDist
!= MinDist
)
580 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
581 Attenuation
= maxf(Attenuation
, 0.0f
);
582 for(i
= 0;i
< NumSends
;i
++)
584 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
585 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
590 case ExponentDistanceClamped
:
591 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
592 if(MaxDist
< MinDist
)
595 case ExponentDistance
:
596 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
598 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
599 for(i
= 0;i
< NumSends
;i
++)
600 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
604 case DisableDistance
:
605 ClampedDist
= MinDist
;
609 /* Source Gain + Attenuation */
610 DryGain
= SourceVolume
* Attenuation
;
611 for(i
= 0;i
< NumSends
;i
++)
612 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
614 /* Distance-based air absorption */
615 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
617 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
618 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
619 for(i
= 0;i
< NumSends
;i
++)
620 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
625 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
627 /* Apply a decay-time transformation to the wet path, based on the
628 * attenuation of the dry path.
630 * Using the apparent distance, based on the distance attenuation, the
631 * initial decay of the reverb effect is calculated and applied to the
634 for(i
= 0;i
< NumSends
;i
++)
636 if(DecayDistance
[i
] > 0.0f
)
637 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
641 /* Calculate directional soundcones */
642 Angle
= acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
* (360.0f
/F_PI
);
643 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
645 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
646 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
647 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
649 else if(Angle
> OuterAngle
)
651 ConeVolume
= ALSource
->OuterGain
;
652 ConeHF
= ALSource
->OuterGainHF
;
660 DryGain
*= ConeVolume
;
663 for(i
= 0;i
< NumSends
;i
++)
664 WetGain
[i
] *= ConeVolume
;
670 for(i
= 0;i
< NumSends
;i
++)
671 WetGainHF
[i
] *= ConeHF
;
674 /* Clamp to Min/Max Gain */
675 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
676 for(i
= 0;i
< NumSends
;i
++)
677 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
679 /* Apply gain and frequency filters */
680 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
681 DryGainHF
*= ALSource
->DirectGainHF
;
682 for(i
= 0;i
< NumSends
;i
++)
684 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
685 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
688 /* Calculate velocity-based doppler effect */
689 if(DopplerFactor
> 0.0f
)
693 if(SpeedOfSound
< 1.0f
)
695 DopplerFactor
*= 1.0f
/SpeedOfSound
;
699 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
700 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
702 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
703 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
706 BufferListItem
= ALSource
->queue
;
707 while(BufferListItem
!= NULL
)
710 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
712 /* Calculate fixed-point stepping value, based on the pitch, buffer
713 * frequency, and output frequency. */
714 ALsizei maxstep
= BUFFERSIZE
/ ALSource
->NumChannels
;
715 maxstep
-= ResamplerPadding
[Resampler
] +
716 ResamplerPrePadding
[Resampler
] + 1;
717 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
719 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
720 if(Pitch
> (ALfloat
)maxstep
)
721 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
724 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
725 if(ALSource
->Params
.Step
== 0)
726 ALSource
->Params
.Step
= 1;
728 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
732 BufferListItem
= BufferListItem
->next
;
735 ALSource
->Params
.DryMix
= SelectHrtfMixer();
737 ALSource
->Params
.DryMix
= SelectDirectMixer();
738 ALSource
->Params
.WetMix
= SelectSendMixer();
742 /* Use a binaural HRTF algorithm for stereo headphone playback */
743 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
747 ALfloat invlen
= 1.0f
/Distance
;
748 Position
[0] *= invlen
;
749 Position
[1] *= invlen
;
750 Position
[2] *= invlen
;
752 /* Calculate elevation and azimuth only when the source is not at
753 * the listener. This prevents +0 and -0 Z from producing
754 * inconsistent panning. Also, clamp Y in case FP precision errors
755 * cause it to land outside of -1..+1. */
756 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
757 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
760 /* Check to see if the HRIR is already moving. */
761 if(ALSource
->Hrtf
.Moving
)
763 /* Calculate the normalized HRTF transition factor (delta). */
764 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Gain
, DryGain
,
765 ALSource
->Params
.Direct
.Hrtf
.Dir
, Position
);
766 /* If the delta is large enough, get the moving HRIR target
767 * coefficients, target delays, steppping values, and counter. */
770 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
771 ev
, az
, DryGain
, delta
,
772 ALSource
->Hrtf
.Counter
,
773 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
774 ALSource
->Params
.Direct
.Hrtf
.Delay
[0],
775 ALSource
->Params
.Direct
.Hrtf
.CoeffStep
,
776 ALSource
->Params
.Direct
.Hrtf
.DelayStep
);
777 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
778 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
779 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
780 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
785 /* Get the initial (static) HRIR coefficients and delays. */
786 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
787 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
788 ALSource
->Params
.Direct
.Hrtf
.Delay
[0]);
789 ALSource
->Hrtf
.Counter
= 0;
790 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
791 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
792 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
793 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
798 ALfloat (*Matrix
)[MaxChannels
] = ALSource
->Params
.Direct
.Gains
;
799 ALfloat DirGain
= 0.0f
;
802 for(i
= 0;i
< MaxChannels
;i
++)
804 for(j
= 0;j
< MaxChannels
;j
++)
808 /* Normalize the length, and compute panned gains. */
811 ALfloat invlen
= 1.0f
/Distance
;
812 Position
[0] *= invlen
;
813 Position
[1] *= invlen
;
814 Position
[2] *= invlen
;
816 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
817 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
818 DryGain
*DirGain
, Matrix
[0]);
821 /* Adjustment for vertical offsets. Not the greatest, but simple
823 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
824 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
826 enum Channel chan
= Device
->Speaker2Chan
[i
];
827 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
830 for(i
= 0;i
< NumSends
;i
++)
831 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
833 /* Update filter coefficients. */
834 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
836 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
837 for(i
= 0;i
< NumSends
;i
++)
839 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
840 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
845 static __inline ALfloat
aluF2F(ALfloat val
)
847 static __inline ALint
aluF2I(ALfloat val
)
849 if(val
> 1.0f
) return 2147483647;
850 if(val
< -1.0f
) return -2147483647-1;
851 return fastf2i((ALfloat
)(val
*2147483647.0));
853 static __inline ALuint
aluF2UI(ALfloat val
)
854 { return aluF2I(val
)+2147483648u; }
855 static __inline ALshort
aluF2S(ALfloat val
)
856 { return aluF2I(val
)>>16; }
857 static __inline ALushort
aluF2US(ALfloat val
)
858 { return aluF2S(val
)+32768; }
859 static __inline ALbyte
aluF2B(ALfloat val
)
860 { return aluF2I(val
)>>24; }
861 static __inline ALubyte
aluF2UB(ALfloat val
)
862 { return aluF2B(val
)+128; }
864 #define DECL_TEMPLATE(T, func) \
865 static void Write_##T(ALCdevice *device, T *RESTRICT buffer, \
866 ALuint SamplesToDo) \
868 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
869 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
870 const enum Channel *ChanMap = device->DevChannels; \
873 for(j = 0;j < numchans;j++) \
875 T *RESTRICT out = buffer + j; \
876 enum Channel chan = ChanMap[j]; \
878 for(i = 0;i < SamplesToDo;i++) \
879 out[i*numchans] = func(DryBuffer[chan][i]); \
883 DECL_TEMPLATE(ALfloat
, aluF2F
)
884 DECL_TEMPLATE(ALuint
, aluF2UI
)
885 DECL_TEMPLATE(ALint
, aluF2I
)
886 DECL_TEMPLATE(ALushort
, aluF2US
)
887 DECL_TEMPLATE(ALshort
, aluF2S
)
888 DECL_TEMPLATE(ALubyte
, aluF2UB
)
889 DECL_TEMPLATE(ALbyte
, aluF2B
)
894 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
897 ALeffectslot
**slot
, **slot_end
;
898 ALsource
**src
, **src_end
;
903 SetMixerFPUMode(&oldMode
);
907 SamplesToDo
= minu(size
, BUFFERSIZE
);
908 for(c
= 0;c
< MaxChannels
;c
++)
909 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
911 ALCdevice_Lock(device
);
912 ctx
= device
->ContextList
;
915 ALenum DeferUpdates
= ctx
->DeferUpdates
;
916 ALenum UpdateSources
= AL_FALSE
;
919 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
921 /* source processing */
922 src
= ctx
->ActiveSources
;
923 src_end
= src
+ ctx
->ActiveSourceCount
;
924 while(src
!= src_end
)
926 if((*src
)->state
!= AL_PLAYING
)
928 --(ctx
->ActiveSourceCount
);
933 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
935 ALsource_Update(*src
, ctx
);
937 MixSource(*src
, device
, SamplesToDo
);
941 /* effect slot processing */
942 slot
= ctx
->ActiveEffectSlots
;
943 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
944 while(slot
!= slot_end
)
946 ALfloat offset
= (*slot
)->ClickRemoval
[0];
947 if(offset
< (1.0f
/32768.0f
))
949 else for(i
= 0;i
< SamplesToDo
;i
++)
951 (*slot
)->WetBuffer
[0][i
] += offset
;
952 offset
-= offset
* (1.0f
/256.0f
);
954 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
955 (*slot
)->PendingClicks
[0] = 0.0f
;
957 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
958 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
960 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
961 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
963 for(i
= 0;i
< SamplesToDo
;i
++)
964 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
972 slot
= &device
->DefaultSlot
;
975 ALfloat offset
= (*slot
)->ClickRemoval
[0];
976 if(offset
< (1.0f
/32768.0f
))
978 else for(i
= 0;i
< SamplesToDo
;i
++)
980 (*slot
)->WetBuffer
[0][i
] += offset
;
981 offset
-= offset
* (1.0f
/256.0f
);
983 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
984 (*slot
)->PendingClicks
[0] = 0.0f
;
986 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
987 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
989 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
990 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
992 for(i
= 0;i
< SamplesToDo
;i
++)
993 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
995 ALCdevice_Unlock(device
);
997 /* Click-removal. Could do better; this only really handles immediate
998 * changes between updates where a predictive sample could be
999 * generated. Delays caused by effects and HRTF aren't caught. */
1000 if(device
->FmtChans
== DevFmtMono
)
1002 ALfloat offset
= device
->ClickRemoval
[FrontCenter
];
1003 if(offset
< (1.0f
/32768.0f
))
1005 else for(i
= 0;i
< SamplesToDo
;i
++)
1007 device
->DryBuffer
[FrontCenter
][i
] += offset
;
1008 offset
-= offset
* (1.0f
/256.0f
);
1010 device
->ClickRemoval
[FrontCenter
] = offset
+ device
->PendingClicks
[FrontCenter
];
1011 device
->PendingClicks
[FrontCenter
] = 0.0f
;
1013 else if(device
->FmtChans
== DevFmtStereo
)
1015 /* Assumes the first two channels are FrontLeft and FrontRight */
1016 for(c
= 0;c
< 2;c
++)
1018 ALfloat offset
= device
->ClickRemoval
[c
];
1019 if(offset
< (1.0f
/32768.0f
))
1021 else for(i
= 0;i
< SamplesToDo
;i
++)
1023 device
->DryBuffer
[c
][i
] += offset
;
1024 offset
-= offset
* (1.0f
/256.0f
);
1026 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1027 device
->PendingClicks
[c
] = 0.0f
;
1032 for(i
= 0;i
< SamplesToDo
;i
++)
1034 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1035 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1036 bs2b_cross_feed(device
->Bs2b
, samples
);
1037 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1038 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1044 for(c
= 0;c
< MaxChannels
;c
++)
1046 ALfloat offset
= device
->ClickRemoval
[c
];
1047 if(offset
< (1.0f
/32768.0f
))
1049 else for(i
= 0;i
< SamplesToDo
;i
++)
1051 device
->DryBuffer
[c
][i
] += offset
;
1052 offset
-= offset
* (1.0f
/256.0f
);
1054 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1055 device
->PendingClicks
[c
] = 0.0f
;
1061 switch(device
->FmtType
)
1064 Write_ALbyte(device
, buffer
, SamplesToDo
);
1067 Write_ALubyte(device
, buffer
, SamplesToDo
);
1070 Write_ALshort(device
, buffer
, SamplesToDo
);
1073 Write_ALushort(device
, buffer
, SamplesToDo
);
1076 Write_ALint(device
, buffer
, SamplesToDo
);
1079 Write_ALuint(device
, buffer
, SamplesToDo
);
1082 Write_ALfloat(device
, buffer
, SamplesToDo
);
1087 size
-= SamplesToDo
;
1090 RestoreFPUMode(&oldMode
);
1094 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1096 ALCcontext
*Context
;
1098 ALCdevice_Lock(device
);
1099 device
->Connected
= ALC_FALSE
;
1101 Context
= device
->ContextList
;
1104 ALsource
**src
, **src_end
;
1106 src
= Context
->ActiveSources
;
1107 src_end
= src
+ Context
->ActiveSourceCount
;
1108 while(src
!= src_end
)
1110 if((*src
)->state
== AL_PLAYING
)
1112 (*src
)->state
= AL_STOPPED
;
1113 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1114 (*src
)->position
= 0;
1115 (*src
)->position_fraction
= 0;
1119 Context
->ActiveSourceCount
= 0;
1121 Context
= Context
->next
;
1123 ALCdevice_Unlock(device
);