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
32 #include "alListener.h"
33 #include "alAuxEffectSlot.h"
37 #include "mixer_defs.h"
46 ALfloat ConeScale
= 1.0f
;
48 /* Localized Z scalar for mono sources */
49 ALfloat ZScale
= 1.0f
;
52 static ResamplerFunc
SelectResampler(enum Resampler Resampler
, ALuint increment
)
54 if(increment
== FRACTIONONE
)
55 return Resample_copy32_C
;
59 return Resample_point32_C
;
61 return Resample_lerp32_C
;
63 return Resample_cubic32_C
;
65 /* Shouldn't happen */
69 return Resample_point32_C
;
73 static DryMixerFunc
SelectHrtfMixer(void)
76 if((CPUCapFlags
&CPU_CAP_SSE
))
77 return MixDirect_Hrtf_SSE
;
80 if((CPUCapFlags
&CPU_CAP_NEON
))
81 return MixDirect_Hrtf_Neon
;
84 return MixDirect_Hrtf_C
;
87 static DryMixerFunc
SelectDirectMixer(void)
90 if((CPUCapFlags
&CPU_CAP_SSE
))
97 static WetMixerFunc
SelectSendMixer(void)
100 if((CPUCapFlags
&CPU_CAP_SSE
))
108 static __inline ALvoid
aluMatrixVector(ALfloat
*vector
, ALfloat w
, ALfloat (*RESTRICT matrix
)[4])
111 vector
[0], vector
[1], vector
[2], w
114 vector
[0] = temp
[0]*matrix
[0][0] + temp
[1]*matrix
[1][0] + temp
[2]*matrix
[2][0] + temp
[3]*matrix
[3][0];
115 vector
[1] = temp
[0]*matrix
[0][1] + temp
[1]*matrix
[1][1] + temp
[2]*matrix
[2][1] + temp
[3]*matrix
[3][1];
116 vector
[2] = temp
[0]*matrix
[0][2] + temp
[1]*matrix
[1][2] + temp
[2]*matrix
[2][2] + temp
[3]*matrix
[3][2];
120 static ALvoid
CalcListenerParams(ALlistener
*Listener
)
122 ALfloat N
[3], V
[3], U
[3], P
[3];
125 N
[0] = Listener
->Forward
[0];
126 N
[1] = Listener
->Forward
[1];
127 N
[2] = Listener
->Forward
[2];
129 V
[0] = Listener
->Up
[0];
130 V
[1] = Listener
->Up
[1];
131 V
[2] = Listener
->Up
[2];
133 /* Build and normalize right-vector */
134 aluCrossproduct(N
, V
, U
);
137 Listener
->Params
.Matrix
[0][0] = U
[0];
138 Listener
->Params
.Matrix
[0][1] = V
[0];
139 Listener
->Params
.Matrix
[0][2] = -N
[0];
140 Listener
->Params
.Matrix
[0][3] = 0.0f
;
141 Listener
->Params
.Matrix
[1][0] = U
[1];
142 Listener
->Params
.Matrix
[1][1] = V
[1];
143 Listener
->Params
.Matrix
[1][2] = -N
[1];
144 Listener
->Params
.Matrix
[1][3] = 0.0f
;
145 Listener
->Params
.Matrix
[2][0] = U
[2];
146 Listener
->Params
.Matrix
[2][1] = V
[2];
147 Listener
->Params
.Matrix
[2][2] = -N
[2];
148 Listener
->Params
.Matrix
[2][3] = 0.0f
;
149 Listener
->Params
.Matrix
[3][0] = 0.0f
;
150 Listener
->Params
.Matrix
[3][1] = 0.0f
;
151 Listener
->Params
.Matrix
[3][2] = 0.0f
;
152 Listener
->Params
.Matrix
[3][3] = 1.0f
;
154 P
[0] = Listener
->Position
[0];
155 P
[1] = Listener
->Position
[1];
156 P
[2] = Listener
->Position
[2];
157 aluMatrixVector(P
, 1.0f
, Listener
->Params
.Matrix
);
158 Listener
->Params
.Matrix
[3][0] = -P
[0];
159 Listener
->Params
.Matrix
[3][1] = -P
[1];
160 Listener
->Params
.Matrix
[3][2] = -P
[2];
162 Listener
->Params
.Velocity
[0] = Listener
->Velocity
[0];
163 Listener
->Params
.Velocity
[1] = Listener
->Velocity
[1];
164 Listener
->Params
.Velocity
[2] = Listener
->Velocity
[2];
165 aluMatrixVector(Listener
->Params
.Velocity
, 0.0f
, Listener
->Params
.Matrix
);
168 ALvoid
CalcNonAttnSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
170 static const struct ChanMap MonoMap
[1] = { { FrontCenter
, 0.0f
} };
171 static const struct ChanMap StereoMap
[2] = {
172 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
173 { FrontRight
, 30.0f
* F_PI
/180.0f
}
175 static const struct ChanMap StereoWideMap
[2] = {
176 { FrontLeft
, -90.0f
* F_PI
/180.0f
},
177 { FrontRight
, 90.0f
* F_PI
/180.0f
}
179 static const struct ChanMap RearMap
[2] = {
180 { BackLeft
, -150.0f
* F_PI
/180.0f
},
181 { BackRight
, 150.0f
* F_PI
/180.0f
}
183 static const struct ChanMap QuadMap
[4] = {
184 { FrontLeft
, -45.0f
* F_PI
/180.0f
},
185 { FrontRight
, 45.0f
* F_PI
/180.0f
},
186 { BackLeft
, -135.0f
* F_PI
/180.0f
},
187 { BackRight
, 135.0f
* F_PI
/180.0f
}
189 static const struct ChanMap X51Map
[6] = {
190 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
191 { FrontRight
, 30.0f
* F_PI
/180.0f
},
192 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
194 { BackLeft
, -110.0f
* F_PI
/180.0f
},
195 { BackRight
, 110.0f
* F_PI
/180.0f
}
197 static const struct ChanMap X61Map
[7] = {
198 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
199 { FrontRight
, 30.0f
* F_PI
/180.0f
},
200 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
202 { BackCenter
, 180.0f
* F_PI
/180.0f
},
203 { SideLeft
, -90.0f
* F_PI
/180.0f
},
204 { SideRight
, 90.0f
* F_PI
/180.0f
}
206 static const struct ChanMap X71Map
[8] = {
207 { FrontLeft
, -30.0f
* F_PI
/180.0f
},
208 { FrontRight
, 30.0f
* F_PI
/180.0f
},
209 { FrontCenter
, 0.0f
* F_PI
/180.0f
},
211 { BackLeft
, -150.0f
* F_PI
/180.0f
},
212 { BackRight
, 150.0f
* F_PI
/180.0f
},
213 { SideLeft
, -90.0f
* F_PI
/180.0f
},
214 { SideRight
, 90.0f
* F_PI
/180.0f
}
217 ALCdevice
*Device
= ALContext
->Device
;
218 ALfloat SourceVolume
,ListenerGain
,MinVolume
,MaxVolume
;
219 ALbufferlistitem
*BufferListItem
;
220 enum FmtChannels Channels
;
221 ALfloat (*SrcMatrix
)[MaxChannels
];
222 ALfloat DryGain
, DryGainHF
;
223 ALfloat WetGain
[MAX_SENDS
];
224 ALfloat WetGainHF
[MAX_SENDS
];
225 ALint NumSends
, Frequency
;
226 const struct ChanMap
*chans
= NULL
;
227 enum Resampler Resampler
;
228 ALint num_channels
= 0;
229 ALboolean DirectChannels
;
230 ALfloat hwidth
= 0.0f
;
235 /* Get device properties */
236 NumSends
= Device
->NumAuxSends
;
237 Frequency
= Device
->Frequency
;
239 /* Get listener properties */
240 ListenerGain
= ALContext
->Listener
->Gain
;
242 /* Get source properties */
243 SourceVolume
= ALSource
->Gain
;
244 MinVolume
= ALSource
->MinGain
;
245 MaxVolume
= ALSource
->MaxGain
;
246 Pitch
= ALSource
->Pitch
;
247 Resampler
= ALSource
->Resampler
;
248 DirectChannels
= ALSource
->DirectChannels
;
250 /* Calculate the stepping value */
252 BufferListItem
= ALSource
->queue
;
253 while(BufferListItem
!= NULL
)
256 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
258 ALsizei maxstep
= BUFFERSIZE
;
259 maxstep
-= ResamplerPadding
[Resampler
] +
260 ResamplerPrePadding
[Resampler
] + 1;
261 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
263 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
264 if(Pitch
> (ALfloat
)maxstep
)
265 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
268 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
269 if(ALSource
->Params
.Step
== 0)
270 ALSource
->Params
.Step
= 1;
272 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
274 Channels
= ALBuffer
->FmtChannels
;
277 BufferListItem
= BufferListItem
->next
;
279 if(!DirectChannels
&& Device
->Hrtf
)
280 ALSource
->Params
.DryMix
= SelectHrtfMixer();
282 ALSource
->Params
.DryMix
= SelectDirectMixer();
283 ALSource
->Params
.WetMix
= SelectSendMixer();
285 /* Calculate gains */
286 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
287 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
288 DryGainHF
= ALSource
->DirectGainHF
;
289 for(i
= 0;i
< NumSends
;i
++)
291 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
292 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
293 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
296 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
297 for(i
= 0;i
< MaxChannels
;i
++)
299 for(c
= 0;c
< MaxChannels
;c
++)
300 SrcMatrix
[i
][c
] = 0.0f
;
310 if(!(Device
->Flags
&DEVICE_WIDE_STEREO
))
314 chans
= StereoWideMap
;
315 hwidth
= 60.0f
* F_PI
/180.0f
;
346 if(DirectChannels
!= AL_FALSE
)
348 for(c
= 0;c
< num_channels
;c
++)
350 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
352 enum Channel chan
= Device
->Speaker2Chan
[i
];
353 if(chan
== chans
[c
].channel
)
355 SrcMatrix
[c
][chan
] = DryGain
;
361 else if(Device
->Hrtf
)
363 for(c
= 0;c
< num_channels
;c
++)
365 if(chans
[c
].channel
== LFE
)
368 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][0] = 0;
369 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][1] = 0;
370 for(i
= 0;i
< HRIR_LENGTH
;i
++)
372 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][0] = 0.0f
;
373 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][1] = 0.0f
;
378 /* Get the static HRIR coefficients and delays for this
380 GetLerpedHrtfCoeffs(Device
->Hrtf
,
381 0.0f
, chans
[c
].angle
, DryGain
,
382 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
],
383 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
]);
386 ALSource
->Hrtf
.Counter
= 0;
387 ALSource
->Params
.Direct
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
389 ALSource
->Params
.Direct
.hrtfState
= &ALSource
->Hrtf
;
393 DryGain
*= lerp(1.0f
, 1.0f
/sqrtf((float)Device
->NumChan
), hwidth
/F_PI
);
394 for(c
= 0;c
< num_channels
;c
++)
396 /* Special-case LFE */
397 if(chans
[c
].channel
== LFE
)
399 SrcMatrix
[c
][chans
[c
].channel
] = DryGain
;
402 ComputeAngleGains(Device
, chans
[c
].angle
, hwidth
, DryGain
,
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
)
414 ALSource
->Params
.Send
[i
].Slot
= Slot
;
415 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
418 /* Update filter coefficients. Calculations based on the I3DL2
420 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
422 /* We use two chained one-pole filters, so we need to take the
423 * square root of the squared gain, which is the same as the base
425 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
426 for(i
= 0;i
< NumSends
;i
++)
428 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
429 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
433 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
435 const ALCdevice
*Device
= ALContext
->Device
;
436 ALfloat Velocity
[3],Direction
[3],Position
[3],SourceToListener
[3];
437 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
438 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
439 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
440 ALfloat DopplerFactor
, SpeedOfSound
;
441 ALfloat AirAbsorptionFactor
;
442 ALfloat RoomAirAbsorption
[MAX_SENDS
];
443 ALbufferlistitem
*BufferListItem
;
445 ALfloat RoomAttenuation
[MAX_SENDS
];
446 ALfloat MetersPerUnit
;
447 ALfloat RoomRolloffBase
;
448 ALfloat RoomRolloff
[MAX_SENDS
];
449 ALfloat DecayDistance
[MAX_SENDS
];
452 ALboolean DryGainHFAuto
;
453 ALfloat WetGain
[MAX_SENDS
];
454 ALfloat WetGainHF
[MAX_SENDS
];
455 ALboolean WetGainAuto
;
456 ALboolean WetGainHFAuto
;
457 enum Resampler Resampler
;
465 for(i
= 0;i
< MAX_SENDS
;i
++)
468 /* Get context/device properties */
469 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
470 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
471 NumSends
= Device
->NumAuxSends
;
472 Frequency
= Device
->Frequency
;
474 /* Get listener properties */
475 ListenerGain
= ALContext
->Listener
->Gain
;
476 MetersPerUnit
= ALContext
->Listener
->MetersPerUnit
;
478 /* Get source properties */
479 SourceVolume
= ALSource
->Gain
;
480 MinVolume
= ALSource
->MinGain
;
481 MaxVolume
= ALSource
->MaxGain
;
482 Pitch
= ALSource
->Pitch
;
483 Resampler
= ALSource
->Resampler
;
484 Position
[0] = ALSource
->Position
[0];
485 Position
[1] = ALSource
->Position
[1];
486 Position
[2] = ALSource
->Position
[2];
487 Direction
[0] = ALSource
->Orientation
[0];
488 Direction
[1] = ALSource
->Orientation
[1];
489 Direction
[2] = ALSource
->Orientation
[2];
490 Velocity
[0] = ALSource
->Velocity
[0];
491 Velocity
[1] = ALSource
->Velocity
[1];
492 Velocity
[2] = ALSource
->Velocity
[2];
493 MinDist
= ALSource
->RefDistance
;
494 MaxDist
= ALSource
->MaxDistance
;
495 Rolloff
= ALSource
->RollOffFactor
;
496 InnerAngle
= ALSource
->InnerAngle
;
497 OuterAngle
= ALSource
->OuterAngle
;
498 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
499 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
500 WetGainAuto
= ALSource
->WetGainAuto
;
501 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
502 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
503 for(i
= 0;i
< NumSends
;i
++)
505 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
508 Slot
= Device
->DefaultSlot
;
509 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
512 RoomRolloff
[i
] = 0.0f
;
513 DecayDistance
[i
] = 0.0f
;
514 RoomAirAbsorption
[i
] = 1.0f
;
516 else if(Slot
->AuxSendAuto
)
518 RoomRolloff
[i
] = RoomRolloffBase
;
519 if(IsReverbEffect(Slot
->effect
.type
))
521 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
522 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
523 SPEEDOFSOUNDMETRESPERSEC
;
524 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
528 DecayDistance
[i
] = 0.0f
;
529 RoomAirAbsorption
[i
] = 1.0f
;
534 /* If the slot's auxiliary send auto is off, the data sent to the
535 * effect slot is the same as the dry path, sans filter effects */
536 RoomRolloff
[i
] = Rolloff
;
537 DecayDistance
[i
] = 0.0f
;
538 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
541 ALSource
->Params
.Send
[i
].Slot
= Slot
;
544 /* Transform source to listener space (convert to head relative) */
545 if(ALSource
->HeadRelative
== AL_FALSE
)
547 ALfloat (*RESTRICT Matrix
)[4] = ALContext
->Listener
->Params
.Matrix
;
548 /* Transform source vectors */
549 aluMatrixVector(Position
, 1.0f
, Matrix
);
550 aluMatrixVector(Direction
, 0.0f
, Matrix
);
551 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
555 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
556 /* Offset the source velocity to be relative of the listener velocity */
557 Velocity
[0] += ListenerVel
[0];
558 Velocity
[1] += ListenerVel
[1];
559 Velocity
[2] += ListenerVel
[2];
562 SourceToListener
[0] = -Position
[0];
563 SourceToListener
[1] = -Position
[1];
564 SourceToListener
[2] = -Position
[2];
565 aluNormalize(SourceToListener
);
566 aluNormalize(Direction
);
568 /* Calculate distance attenuation */
569 Distance
= sqrtf(aluDotproduct(Position
, Position
));
570 ClampedDist
= Distance
;
573 for(i
= 0;i
< NumSends
;i
++)
574 RoomAttenuation
[i
] = 1.0f
;
575 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
576 ALContext
->DistanceModel
)
578 case InverseDistanceClamped
:
579 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
580 if(MaxDist
< MinDist
)
583 case InverseDistance
:
586 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
587 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
588 for(i
= 0;i
< NumSends
;i
++)
590 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
591 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
596 case LinearDistanceClamped
:
597 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
598 if(MaxDist
< MinDist
)
602 if(MaxDist
!= MinDist
)
604 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
605 Attenuation
= maxf(Attenuation
, 0.0f
);
606 for(i
= 0;i
< NumSends
;i
++)
608 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
609 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
614 case ExponentDistanceClamped
:
615 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
616 if(MaxDist
< MinDist
)
619 case ExponentDistance
:
620 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
622 Attenuation
= powf(ClampedDist
/MinDist
, -Rolloff
);
623 for(i
= 0;i
< NumSends
;i
++)
624 RoomAttenuation
[i
] = powf(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
628 case DisableDistance
:
629 ClampedDist
= MinDist
;
633 /* Source Gain + Attenuation */
634 DryGain
= SourceVolume
* Attenuation
;
635 for(i
= 0;i
< NumSends
;i
++)
636 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
638 /* Distance-based air absorption */
639 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
641 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
642 DryGainHF
*= powf(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
643 for(i
= 0;i
< NumSends
;i
++)
644 WetGainHF
[i
] *= powf(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
649 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
651 /* Apply a decay-time transformation to the wet path, based on the
652 * attenuation of the dry path.
654 * Using the apparent distance, based on the distance attenuation, the
655 * initial decay of the reverb effect is calculated and applied to the
658 for(i
= 0;i
< NumSends
;i
++)
660 if(DecayDistance
[i
] > 0.0f
)
661 WetGain
[i
] *= powf(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
665 /* Calculate directional soundcones */
666 Angle
= acosf(aluDotproduct(Direction
,SourceToListener
)) * ConeScale
* (360.0f
/F_PI
);
667 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
669 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
670 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
671 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
673 else if(Angle
> OuterAngle
)
675 ConeVolume
= ALSource
->OuterGain
;
676 ConeHF
= ALSource
->OuterGainHF
;
684 DryGain
*= ConeVolume
;
687 for(i
= 0;i
< NumSends
;i
++)
688 WetGain
[i
] *= ConeVolume
;
694 for(i
= 0;i
< NumSends
;i
++)
695 WetGainHF
[i
] *= ConeHF
;
698 /* Clamp to Min/Max Gain */
699 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
700 for(i
= 0;i
< NumSends
;i
++)
701 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
703 /* Apply gain and frequency filters */
704 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
705 DryGainHF
*= ALSource
->DirectGainHF
;
706 for(i
= 0;i
< NumSends
;i
++)
708 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
709 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
712 /* Calculate velocity-based doppler effect */
713 if(DopplerFactor
> 0.0f
)
715 const ALfloat
*ListenerVel
= ALContext
->Listener
->Params
.Velocity
;
718 if(SpeedOfSound
< 1.0f
)
720 DopplerFactor
*= 1.0f
/SpeedOfSound
;
724 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
725 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
727 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
728 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
731 BufferListItem
= ALSource
->queue
;
732 while(BufferListItem
!= NULL
)
735 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
737 /* Calculate fixed-point stepping value, based on the pitch, buffer
738 * frequency, and output frequency. */
739 ALsizei maxstep
= BUFFERSIZE
;
740 maxstep
-= ResamplerPadding
[Resampler
] +
741 ResamplerPrePadding
[Resampler
] + 1;
742 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
744 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
745 if(Pitch
> (ALfloat
)maxstep
)
746 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
749 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
750 if(ALSource
->Params
.Step
== 0)
751 ALSource
->Params
.Step
= 1;
753 ALSource
->Params
.Resample
= SelectResampler(Resampler
, ALSource
->Params
.Step
);
757 BufferListItem
= BufferListItem
->next
;
760 ALSource
->Params
.DryMix
= SelectHrtfMixer();
762 ALSource
->Params
.DryMix
= SelectDirectMixer();
763 ALSource
->Params
.WetMix
= SelectSendMixer();
767 /* Use a binaural HRTF algorithm for stereo headphone playback */
768 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
770 if(Distance
> FLT_EPSILON
)
772 ALfloat invlen
= 1.0f
/Distance
;
773 Position
[0] *= invlen
;
774 Position
[1] *= invlen
;
775 Position
[2] *= invlen
;
777 /* Calculate elevation and azimuth only when the source is not at
778 * the listener. This prevents +0 and -0 Z from producing
779 * inconsistent panning. Also, clamp Y in case FP precision errors
780 * cause it to land outside of -1..+1. */
781 ev
= asinf(clampf(Position
[1], -1.0f
, 1.0f
));
782 az
= atan2f(Position
[0], -Position
[2]*ZScale
);
785 /* Check to see if the HRIR is already moving. */
786 if(ALSource
->Hrtf
.Moving
)
788 /* Calculate the normalized HRTF transition factor (delta). */
789 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Gain
, DryGain
,
790 ALSource
->Params
.Direct
.Hrtf
.Dir
, Position
);
791 /* If the delta is large enough, get the moving HRIR target
792 * coefficients, target delays, steppping values, and counter. */
795 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
796 ev
, az
, DryGain
, delta
,
797 ALSource
->Hrtf
.Counter
,
798 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
799 ALSource
->Params
.Direct
.Hrtf
.Delay
[0],
800 ALSource
->Params
.Direct
.Hrtf
.CoeffStep
,
801 ALSource
->Params
.Direct
.Hrtf
.DelayStep
);
802 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
803 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
804 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
805 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
810 /* Get the initial (static) HRIR coefficients and delays. */
811 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
812 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
813 ALSource
->Params
.Direct
.Hrtf
.Delay
[0]);
814 ALSource
->Hrtf
.Counter
= 0;
815 ALSource
->Hrtf
.Moving
= AL_TRUE
;
816 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
817 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
818 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
819 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
821 ALSource
->Params
.Direct
.Hrtf
.IrSize
= GetHrtfIrSize(Device
->Hrtf
);
823 ALSource
->Params
.Direct
.hrtfState
= &ALSource
->Hrtf
;
827 ALfloat (*Matrix
)[MaxChannels
] = ALSource
->Params
.Direct
.Gains
;
828 ALfloat DirGain
= 0.0f
;
831 for(i
= 0;i
< MaxChannels
;i
++)
833 for(j
= 0;j
< MaxChannels
;j
++)
837 /* Normalize the length, and compute panned gains. */
838 if(Distance
> FLT_EPSILON
)
840 ALfloat invlen
= 1.0f
/Distance
;
841 Position
[0] *= invlen
;
842 Position
[1] *= invlen
;
843 Position
[2] *= invlen
;
845 DirGain
= sqrtf(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
846 ComputeAngleGains(Device
, atan2f(Position
[0], -Position
[2]*ZScale
), 0.0f
,
847 DryGain
*DirGain
, Matrix
[0]);
850 /* Adjustment for vertical offsets. Not the greatest, but simple
852 AmbientGain
= DryGain
* sqrtf(1.0f
/Device
->NumChan
) * (1.0f
-DirGain
);
853 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
855 enum Channel chan
= Device
->Speaker2Chan
[i
];
856 Matrix
[0][chan
] = maxf(Matrix
[0][chan
], AmbientGain
);
859 for(i
= 0;i
< NumSends
;i
++)
860 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
862 /* Update filter coefficients. */
863 cw
= cosf(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
865 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
866 for(i
= 0;i
< NumSends
;i
++)
868 ALfloat a
= lpCoeffCalc(WetGainHF
[i
], cw
);
869 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
874 static __inline ALfloat
aluF2F(ALfloat val
)
876 static __inline ALint
aluF2I(ALfloat val
)
878 if(val
> 1.0f
) return 2147483647;
879 if(val
< -1.0f
) return -2147483647-1;
880 return fastf2i((ALfloat
)(val
*2147483647.0));
882 static __inline ALuint
aluF2UI(ALfloat val
)
883 { return aluF2I(val
)+2147483648u; }
884 static __inline ALshort
aluF2S(ALfloat val
)
885 { return aluF2I(val
)>>16; }
886 static __inline ALushort
aluF2US(ALfloat val
)
887 { return aluF2S(val
)+32768; }
888 static __inline ALbyte
aluF2B(ALfloat val
)
889 { return aluF2I(val
)>>24; }
890 static __inline ALubyte
aluF2UB(ALfloat val
)
891 { return aluF2B(val
)+128; }
893 #define DECL_TEMPLATE(T, func) \
894 static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \
895 ALuint SamplesToDo) \
897 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
898 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
899 const enum Channel *ChanMap = device->DevChannels; \
902 for(j = 0;j < numchans;j++) \
904 T *RESTRICT out = buffer + j; \
905 enum Channel chan = ChanMap[j]; \
907 for(i = 0;i < SamplesToDo;i++) \
908 out[i*numchans] = func(DryBuffer[chan][i]); \
910 return SamplesToDo*numchans*sizeof(T); \
913 DECL_TEMPLATE(ALfloat
, aluF2F
)
914 DECL_TEMPLATE(ALuint
, aluF2UI
)
915 DECL_TEMPLATE(ALint
, aluF2I
)
916 DECL_TEMPLATE(ALushort
, aluF2US
)
917 DECL_TEMPLATE(ALshort
, aluF2S
)
918 DECL_TEMPLATE(ALubyte
, aluF2UB
)
919 DECL_TEMPLATE(ALbyte
, aluF2B
)
924 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
927 ALeffectslot
**slot
, **slot_end
;
928 ALsource
**src
, **src_end
;
933 SetMixerFPUMode(&oldMode
);
937 SamplesToDo
= minu(size
, BUFFERSIZE
);
938 for(c
= 0;c
< MaxChannels
;c
++)
939 memset(device
->DryBuffer
[c
], 0, SamplesToDo
*sizeof(ALfloat
));
941 ALCdevice_Lock(device
);
942 ctx
= device
->ContextList
;
945 ALenum DeferUpdates
= ctx
->DeferUpdates
;
946 ALenum UpdateSources
= AL_FALSE
;
949 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
952 CalcListenerParams(ctx
->Listener
);
954 /* source processing */
955 src
= ctx
->ActiveSources
;
956 src_end
= src
+ ctx
->ActiveSourceCount
;
957 while(src
!= src_end
)
959 if((*src
)->state
!= AL_PLAYING
)
961 --(ctx
->ActiveSourceCount
);
966 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
968 ALsource_Update(*src
, ctx
);
970 MixSource(*src
, device
, SamplesToDo
);
974 /* effect slot processing */
975 slot
= ctx
->ActiveEffectSlots
;
976 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
977 while(slot
!= slot_end
)
979 ALfloat offset
= (*slot
)->ClickRemoval
[0];
980 if(offset
< (1.0f
/32768.0f
))
982 else for(i
= 0;i
< SamplesToDo
;i
++)
984 (*slot
)->WetBuffer
[0][i
] += offset
;
985 offset
-= offset
* (1.0f
/256.0f
);
987 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
988 (*slot
)->PendingClicks
[0] = 0.0f
;
990 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
991 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
993 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
994 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
996 for(i
= 0;i
< SamplesToDo
;i
++)
997 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1005 slot
= &device
->DefaultSlot
;
1008 ALfloat offset
= (*slot
)->ClickRemoval
[0];
1009 if(offset
< (1.0f
/32768.0f
))
1011 else for(i
= 0;i
< SamplesToDo
;i
++)
1013 (*slot
)->WetBuffer
[0][i
] += offset
;
1014 offset
-= offset
* (1.0f
/256.0f
);
1016 (*slot
)->ClickRemoval
[0] = offset
+ (*slot
)->PendingClicks
[0];
1017 (*slot
)->PendingClicks
[0] = 0.0f
;
1019 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1020 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
1022 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1023 (*slot
)->WetBuffer
[0], device
->DryBuffer
);
1025 for(i
= 0;i
< SamplesToDo
;i
++)
1026 (*slot
)->WetBuffer
[0][i
] = 0.0f
;
1028 ALCdevice_Unlock(device
);
1030 /* Click-removal. Could do better; this only really handles immediate
1031 * changes between updates where a predictive sample could be
1032 * generated. Delays caused by effects and HRTF aren't caught. */
1033 if(device
->FmtChans
== DevFmtMono
)
1035 ALfloat offset
= device
->ClickRemoval
[FrontCenter
];
1036 if(offset
< (1.0f
/32768.0f
))
1038 else for(i
= 0;i
< SamplesToDo
;i
++)
1040 device
->DryBuffer
[FrontCenter
][i
] += offset
;
1041 offset
-= offset
* (1.0f
/256.0f
);
1043 device
->ClickRemoval
[FrontCenter
] = offset
+ device
->PendingClicks
[FrontCenter
];
1044 device
->PendingClicks
[FrontCenter
] = 0.0f
;
1046 else if(device
->FmtChans
== DevFmtStereo
)
1048 /* Assumes the first two channels are FrontLeft and FrontRight */
1049 for(c
= 0;c
< 2;c
++)
1051 ALfloat offset
= device
->ClickRemoval
[c
];
1052 if(offset
< (1.0f
/32768.0f
))
1054 else for(i
= 0;i
< SamplesToDo
;i
++)
1056 device
->DryBuffer
[c
][i
] += offset
;
1057 offset
-= offset
* (1.0f
/256.0f
);
1059 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1060 device
->PendingClicks
[c
] = 0.0f
;
1065 for(i
= 0;i
< SamplesToDo
;i
++)
1067 samples
[0] = device
->DryBuffer
[FrontLeft
][i
];
1068 samples
[1] = device
->DryBuffer
[FrontRight
][i
];
1069 bs2b_cross_feed(device
->Bs2b
, samples
);
1070 device
->DryBuffer
[FrontLeft
][i
] = samples
[0];
1071 device
->DryBuffer
[FrontRight
][i
] = samples
[1];
1077 for(c
= 0;c
< MaxChannels
;c
++)
1079 ALfloat offset
= device
->ClickRemoval
[c
];
1080 if(offset
< (1.0f
/32768.0f
))
1082 else for(i
= 0;i
< SamplesToDo
;i
++)
1084 device
->DryBuffer
[c
][i
] += offset
;
1085 offset
-= offset
* (1.0f
/256.0f
);
1087 device
->ClickRemoval
[c
] = offset
+ device
->PendingClicks
[c
];
1088 device
->PendingClicks
[c
] = 0.0f
;
1095 switch(device
->FmtType
)
1098 bytes
= Write_ALbyte(device
, buffer
, SamplesToDo
);
1101 bytes
= Write_ALubyte(device
, buffer
, SamplesToDo
);
1104 bytes
= Write_ALshort(device
, buffer
, SamplesToDo
);
1107 bytes
= Write_ALushort(device
, buffer
, SamplesToDo
);
1110 bytes
= Write_ALint(device
, buffer
, SamplesToDo
);
1113 bytes
= Write_ALuint(device
, buffer
, SamplesToDo
);
1116 bytes
= Write_ALfloat(device
, buffer
, SamplesToDo
);
1120 buffer
= (ALubyte
*)buffer
+ bytes
;
1123 size
-= SamplesToDo
;
1126 RestoreFPUMode(&oldMode
);
1130 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1132 ALCcontext
*Context
;
1134 ALCdevice_Lock(device
);
1135 device
->Connected
= ALC_FALSE
;
1137 Context
= device
->ContextList
;
1140 ALsource
**src
, **src_end
;
1142 src
= Context
->ActiveSources
;
1143 src_end
= src
+ Context
->ActiveSourceCount
;
1144 while(src
!= src_end
)
1146 if((*src
)->state
== AL_PLAYING
)
1148 (*src
)->state
= AL_STOPPED
;
1149 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1150 (*src
)->position
= 0;
1151 (*src
)->position_fraction
= 0;
1155 Context
->ActiveSourceCount
= 0;
1157 Context
= Context
->next
;
1159 ALCdevice_Unlock(device
);