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
->Gain
;
137 MinVolume
= ALSource
->MinGain
;
138 MaxVolume
= ALSource
->MaxGain
;
139 Pitch
= ALSource
->Pitch
;
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;
166 if(ALSource
->Params
.Step
== FRACTIONONE
)
167 Resampler
= PointResampler
;
169 Channels
= ALBuffer
->FmtChannels
;
172 BufferListItem
= BufferListItem
->next
;
174 if(!DirectChannels
&& Device
->Hrtf
)
175 ALSource
->Params
.DryMix
= SelectHrtfMixer(Resampler
);
177 ALSource
->Params
.DryMix
= SelectDirectMixer(Resampler
);
178 ALSource
->Params
.WetMix
= SelectSendMixer(Resampler
);
180 /* Calculate gains */
181 DryGain
= clampf(SourceVolume
, MinVolume
, MaxVolume
);
182 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
183 DryGainHF
= ALSource
->DirectGainHF
;
184 for(i
= 0;i
< NumSends
;i
++)
186 WetGain
[i
] = clampf(SourceVolume
, MinVolume
, MaxVolume
);
187 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
188 WetGainHF
[i
] = ALSource
->Send
[i
].GainHF
;
191 SrcMatrix
= ALSource
->Params
.Direct
.Gains
;
192 for(i
= 0;i
< MAXCHANNELS
;i
++)
194 for(c
= 0;c
< MAXCHANNELS
;c
++)
195 SrcMatrix
[i
][c
] = 0.0f
;
204 if(!DirectChannels
&& (Device
->Flags
&DEVICE_DUPLICATE_STEREO
))
206 DryGain
*= aluSqrt(2.0f
/4.0f
);
209 pos
= aluCart2LUTpos(aluSin(RearMap
[c
].angle
),
210 aluCos(RearMap
[c
].angle
));
211 ChannelGain
= Device
->PanningLUT
[pos
];
213 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
215 enum Channel chan
= Device
->Speaker2Chan
[i
];
216 SrcMatrix
[c
][chan
] += DryGain
* ChannelGain
[chan
];
250 if(DirectChannels
!= AL_FALSE
)
252 for(c
= 0;c
< num_channels
;c
++)
254 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
256 enum Channel chan
= Device
->Speaker2Chan
[i
];
257 if(chan
== chans
[c
].channel
)
259 SrcMatrix
[c
][chan
] += DryGain
;
265 else if(Device
->Hrtf
)
267 for(c
= 0;c
< num_channels
;c
++)
269 if(chans
[c
].channel
== LFE
)
272 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][0] = 0;
273 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
][1] = 0;
274 for(i
= 0;i
< HRIR_LENGTH
;i
++)
276 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][0] = 0.0f
;
277 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
][i
][1] = 0.0f
;
282 /* Get the static HRIR coefficients and delays for this
284 GetLerpedHrtfCoeffs(Device
->Hrtf
,
285 0.0f
, chans
[c
].angle
, DryGain
,
286 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[c
],
287 ALSource
->Params
.Direct
.Hrtf
.Delay
[c
]);
290 ALSource
->Hrtf
.Counter
= 0;
294 for(c
= 0;c
< num_channels
;c
++)
296 /* Special-case LFE */
297 if(chans
[c
].channel
== LFE
)
299 SrcMatrix
[c
][LFE
] += DryGain
;
302 pos
= aluCart2LUTpos(aluSin(chans
[c
].angle
), aluCos(chans
[c
].angle
));
303 ChannelGain
= Device
->PanningLUT
[pos
];
305 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
307 enum Channel chan
= Device
->Speaker2Chan
[i
];
308 SrcMatrix
[c
][chan
] += DryGain
* ChannelGain
[chan
];
312 for(i
= 0;i
< NumSends
;i
++)
314 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
317 Slot
= Device
->DefaultSlot
;
318 if(Slot
&& Slot
->effect
.type
== AL_EFFECT_NULL
)
320 ALSource
->Params
.Slot
[i
] = Slot
;
321 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
324 /* Update filter coefficients. Calculations based on the I3DL2
326 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
328 /* We use two chained one-pole filters, so we need to take the
329 * square root of the squared gain, which is the same as the base
331 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
332 for(i
= 0;i
< NumSends
;i
++)
334 /* We use a one-pole filter, so we need to take the squared gain */
335 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
336 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
340 ALvoid
CalcSourceParams(ALsource
*ALSource
, const ALCcontext
*ALContext
)
342 const ALCdevice
*Device
= ALContext
->Device
;
343 ALfloat InnerAngle
,OuterAngle
,Angle
,Distance
,ClampedDist
;
344 ALfloat Direction
[3],Position
[3],SourceToListener
[3];
345 ALfloat Velocity
[3],ListenerVel
[3];
346 ALfloat MinVolume
,MaxVolume
,MinDist
,MaxDist
,Rolloff
;
347 ALfloat ConeVolume
,ConeHF
,SourceVolume
,ListenerGain
;
348 ALfloat DopplerFactor
, SpeedOfSound
;
349 ALfloat AirAbsorptionFactor
;
350 ALfloat RoomAirAbsorption
[MAX_SENDS
];
351 ALbufferlistitem
*BufferListItem
;
353 ALfloat RoomAttenuation
[MAX_SENDS
];
354 ALfloat MetersPerUnit
;
355 ALfloat RoomRolloffBase
;
356 ALfloat RoomRolloff
[MAX_SENDS
];
357 ALfloat DecayDistance
[MAX_SENDS
];
360 ALboolean DryGainHFAuto
;
361 ALfloat WetGain
[MAX_SENDS
];
362 ALfloat WetGainHF
[MAX_SENDS
];
363 ALboolean WetGainAuto
;
364 ALboolean WetGainHFAuto
;
365 enum Resampler Resampler
;
366 ALfloat Matrix
[4][4];
374 for(i
= 0;i
< MAX_SENDS
;i
++)
377 /* Get context/device properties */
378 DopplerFactor
= ALContext
->DopplerFactor
* ALSource
->DopplerFactor
;
379 SpeedOfSound
= ALContext
->SpeedOfSound
* ALContext
->DopplerVelocity
;
380 NumSends
= Device
->NumAuxSends
;
381 Frequency
= Device
->Frequency
;
383 /* Get listener properties */
384 ListenerGain
= ALContext
->Listener
.Gain
;
385 MetersPerUnit
= ALContext
->Listener
.MetersPerUnit
;
386 ListenerVel
[0] = ALContext
->Listener
.Velocity
[0];
387 ListenerVel
[1] = ALContext
->Listener
.Velocity
[1];
388 ListenerVel
[2] = ALContext
->Listener
.Velocity
[2];
392 Matrix
[i
][j
] = ALContext
->Listener
.Matrix
[i
][j
];
395 /* Get source properties */
396 SourceVolume
= ALSource
->Gain
;
397 MinVolume
= ALSource
->MinGain
;
398 MaxVolume
= ALSource
->MaxGain
;
399 Pitch
= ALSource
->Pitch
;
400 Resampler
= ALSource
->Resampler
;
401 Position
[0] = ALSource
->Position
[0];
402 Position
[1] = ALSource
->Position
[1];
403 Position
[2] = ALSource
->Position
[2];
404 Direction
[0] = ALSource
->Orientation
[0];
405 Direction
[1] = ALSource
->Orientation
[1];
406 Direction
[2] = ALSource
->Orientation
[2];
407 Velocity
[0] = ALSource
->Velocity
[0];
408 Velocity
[1] = ALSource
->Velocity
[1];
409 Velocity
[2] = ALSource
->Velocity
[2];
410 MinDist
= ALSource
->RefDistance
;
411 MaxDist
= ALSource
->MaxDistance
;
412 Rolloff
= ALSource
->RollOffFactor
;
413 InnerAngle
= ALSource
->InnerAngle
* ConeScale
;
414 OuterAngle
= ALSource
->OuterAngle
* ConeScale
;
415 AirAbsorptionFactor
= ALSource
->AirAbsorptionFactor
;
416 DryGainHFAuto
= ALSource
->DryGainHFAuto
;
417 WetGainAuto
= ALSource
->WetGainAuto
;
418 WetGainHFAuto
= ALSource
->WetGainHFAuto
;
419 RoomRolloffBase
= ALSource
->RoomRolloffFactor
;
420 for(i
= 0;i
< NumSends
;i
++)
422 ALeffectslot
*Slot
= ALSource
->Send
[i
].Slot
;
425 Slot
= Device
->DefaultSlot
;
426 if(!Slot
|| Slot
->effect
.type
== AL_EFFECT_NULL
)
429 RoomRolloff
[i
] = 0.0f
;
430 DecayDistance
[i
] = 0.0f
;
431 RoomAirAbsorption
[i
] = 1.0f
;
433 else if(Slot
->AuxSendAuto
)
435 RoomRolloff
[i
] = RoomRolloffBase
;
436 if(IsReverbEffect(Slot
->effect
.type
))
438 RoomRolloff
[i
] += Slot
->effect
.Reverb
.RoomRolloffFactor
;
439 DecayDistance
[i
] = Slot
->effect
.Reverb
.DecayTime
*
440 SPEEDOFSOUNDMETRESPERSEC
;
441 RoomAirAbsorption
[i
] = Slot
->effect
.Reverb
.AirAbsorptionGainHF
;
445 DecayDistance
[i
] = 0.0f
;
446 RoomAirAbsorption
[i
] = 1.0f
;
451 /* If the slot's auxiliary send auto is off, the data sent to the
452 * effect slot is the same as the dry path, sans filter effects */
453 RoomRolloff
[i
] = Rolloff
;
454 DecayDistance
[i
] = 0.0f
;
455 RoomAirAbsorption
[i
] = AIRABSORBGAINHF
;
458 ALSource
->Params
.Slot
[i
] = Slot
;
461 /* Transform source to listener space (convert to head relative) */
462 if(ALSource
->HeadRelative
== AL_FALSE
)
464 /* Translate position */
465 Position
[0] -= ALContext
->Listener
.Position
[0];
466 Position
[1] -= ALContext
->Listener
.Position
[1];
467 Position
[2] -= ALContext
->Listener
.Position
[2];
469 /* Transform source vectors */
470 aluMatrixVector(Position
, 1.0f
, Matrix
);
471 aluMatrixVector(Direction
, 0.0f
, Matrix
);
472 aluMatrixVector(Velocity
, 0.0f
, Matrix
);
473 /* Transform listener velocity */
474 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
478 /* Transform listener velocity from world space to listener space */
479 aluMatrixVector(ListenerVel
, 0.0f
, Matrix
);
480 /* Offset the source velocity to be relative of the listener velocity */
481 Velocity
[0] += ListenerVel
[0];
482 Velocity
[1] += ListenerVel
[1];
483 Velocity
[2] += ListenerVel
[2];
486 SourceToListener
[0] = -Position
[0];
487 SourceToListener
[1] = -Position
[1];
488 SourceToListener
[2] = -Position
[2];
489 aluNormalize(SourceToListener
);
490 aluNormalize(Direction
);
492 /* Calculate distance attenuation */
493 Distance
= aluSqrt(aluDotproduct(Position
, Position
));
494 ClampedDist
= Distance
;
497 for(i
= 0;i
< NumSends
;i
++)
498 RoomAttenuation
[i
] = 1.0f
;
499 switch(ALContext
->SourceDistanceModel
? ALSource
->DistanceModel
:
500 ALContext
->DistanceModel
)
502 case InverseDistanceClamped
:
503 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
504 if(MaxDist
< MinDist
)
507 case InverseDistance
:
510 if((MinDist
+ (Rolloff
* (ClampedDist
- MinDist
))) > 0.0f
)
511 Attenuation
= MinDist
/ (MinDist
+ (Rolloff
* (ClampedDist
- MinDist
)));
512 for(i
= 0;i
< NumSends
;i
++)
514 if((MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
))) > 0.0f
)
515 RoomAttenuation
[i
] = MinDist
/ (MinDist
+ (RoomRolloff
[i
] * (ClampedDist
- MinDist
)));
520 case LinearDistanceClamped
:
521 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
522 if(MaxDist
< MinDist
)
526 if(MaxDist
!= MinDist
)
528 Attenuation
= 1.0f
- (Rolloff
*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
529 Attenuation
= maxf(Attenuation
, 0.0f
);
530 for(i
= 0;i
< NumSends
;i
++)
532 RoomAttenuation
[i
] = 1.0f
- (RoomRolloff
[i
]*(ClampedDist
-MinDist
)/(MaxDist
- MinDist
));
533 RoomAttenuation
[i
] = maxf(RoomAttenuation
[i
], 0.0f
);
538 case ExponentDistanceClamped
:
539 ClampedDist
= clampf(ClampedDist
, MinDist
, MaxDist
);
540 if(MaxDist
< MinDist
)
543 case ExponentDistance
:
544 if(ClampedDist
> 0.0f
&& MinDist
> 0.0f
)
546 Attenuation
= aluPow(ClampedDist
/MinDist
, -Rolloff
);
547 for(i
= 0;i
< NumSends
;i
++)
548 RoomAttenuation
[i
] = aluPow(ClampedDist
/MinDist
, -RoomRolloff
[i
]);
552 case DisableDistance
:
553 ClampedDist
= MinDist
;
557 /* Source Gain + Attenuation */
558 DryGain
= SourceVolume
* Attenuation
;
559 for(i
= 0;i
< NumSends
;i
++)
560 WetGain
[i
] = SourceVolume
* RoomAttenuation
[i
];
562 /* Distance-based air absorption */
563 if(AirAbsorptionFactor
> 0.0f
&& ClampedDist
> MinDist
)
565 ALfloat meters
= maxf(ClampedDist
-MinDist
, 0.0f
) * MetersPerUnit
;
566 DryGainHF
*= aluPow(AIRABSORBGAINHF
, AirAbsorptionFactor
*meters
);
567 for(i
= 0;i
< NumSends
;i
++)
568 WetGainHF
[i
] *= aluPow(RoomAirAbsorption
[i
], AirAbsorptionFactor
*meters
);
573 ALfloat ApparentDist
= 1.0f
/maxf(Attenuation
, 0.00001f
) - 1.0f
;
575 /* Apply a decay-time transformation to the wet path, based on the
576 * attenuation of the dry path.
578 * Using the apparent distance, based on the distance attenuation, the
579 * initial decay of the reverb effect is calculated and applied to the
582 for(i
= 0;i
< NumSends
;i
++)
584 if(DecayDistance
[i
] > 0.0f
)
585 WetGain
[i
] *= aluPow(0.001f
/*-60dB*/, ApparentDist
/DecayDistance
[i
]);
589 /* Calculate directional soundcones */
590 Angle
= aluAcos(aluDotproduct(Direction
,SourceToListener
)) * (180.0f
/F_PI
);
591 if(Angle
> InnerAngle
&& Angle
<= OuterAngle
)
593 ALfloat scale
= (Angle
-InnerAngle
) / (OuterAngle
-InnerAngle
);
594 ConeVolume
= lerp(1.0f
, ALSource
->OuterGain
, scale
);
595 ConeHF
= lerp(1.0f
, ALSource
->OuterGainHF
, scale
);
597 else if(Angle
> OuterAngle
)
599 ConeVolume
= ALSource
->OuterGain
;
600 ConeHF
= ALSource
->OuterGainHF
;
608 DryGain
*= ConeVolume
;
611 for(i
= 0;i
< NumSends
;i
++)
612 WetGain
[i
] *= ConeVolume
;
618 for(i
= 0;i
< NumSends
;i
++)
619 WetGainHF
[i
] *= ConeHF
;
622 /* Clamp to Min/Max Gain */
623 DryGain
= clampf(DryGain
, MinVolume
, MaxVolume
);
624 for(i
= 0;i
< NumSends
;i
++)
625 WetGain
[i
] = clampf(WetGain
[i
], MinVolume
, MaxVolume
);
627 /* Apply gain and frequency filters */
628 DryGain
*= ALSource
->DirectGain
* ListenerGain
;
629 DryGainHF
*= ALSource
->DirectGainHF
;
630 for(i
= 0;i
< NumSends
;i
++)
632 WetGain
[i
] *= ALSource
->Send
[i
].Gain
* ListenerGain
;
633 WetGainHF
[i
] *= ALSource
->Send
[i
].GainHF
;
636 /* Calculate velocity-based doppler effect */
637 if(DopplerFactor
> 0.0f
)
641 if(SpeedOfSound
< 1.0f
)
643 DopplerFactor
*= 1.0f
/SpeedOfSound
;
647 VSS
= aluDotproduct(Velocity
, SourceToListener
) * DopplerFactor
;
648 VLS
= aluDotproduct(ListenerVel
, SourceToListener
) * DopplerFactor
;
650 Pitch
*= clampf(SpeedOfSound
-VLS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
) /
651 clampf(SpeedOfSound
-VSS
, 1.0f
, SpeedOfSound
*2.0f
- 1.0f
);
654 BufferListItem
= ALSource
->queue
;
655 while(BufferListItem
!= NULL
)
658 if((ALBuffer
=BufferListItem
->buffer
) != NULL
)
660 /* Calculate fixed-point stepping value, based on the pitch, buffer
661 * frequency, and output frequency. */
662 ALsizei maxstep
= STACK_DATA_SIZE
/sizeof(ALfloat
) /
663 ALSource
->NumChannels
;
664 maxstep
-= ResamplerPadding
[Resampler
] +
665 ResamplerPrePadding
[Resampler
] + 1;
666 maxstep
= mini(maxstep
, INT_MAX
>>FRACTIONBITS
);
668 Pitch
= Pitch
* ALBuffer
->Frequency
/ Frequency
;
669 if(Pitch
> (ALfloat
)maxstep
)
670 ALSource
->Params
.Step
= maxstep
<<FRACTIONBITS
;
673 ALSource
->Params
.Step
= fastf2i(Pitch
*FRACTIONONE
);
674 if(ALSource
->Params
.Step
== 0)
675 ALSource
->Params
.Step
= 1;
677 if(ALSource
->Params
.Step
== FRACTIONONE
)
678 Resampler
= PointResampler
;
682 BufferListItem
= BufferListItem
->next
;
685 ALSource
->Params
.DryMix
= SelectHrtfMixer(Resampler
);
687 ALSource
->Params
.DryMix
= SelectDirectMixer(Resampler
);
688 ALSource
->Params
.WetMix
= SelectSendMixer(Resampler
);
692 /* Use a binaural HRTF algorithm for stereo headphone playback */
693 ALfloat delta
, ev
= 0.0f
, az
= 0.0f
;
697 ALfloat invlen
= 1.0f
/Distance
;
698 Position
[0] *= invlen
;
699 Position
[1] *= invlen
;
700 Position
[2] *= invlen
;
702 /* Calculate elevation and azimuth only when the source is not at
703 * the listener. This prevents +0 and -0 Z from producing
704 * inconsistent panning. */
705 ev
= aluAsin(Position
[1]);
706 az
= aluAtan2(Position
[0], -Position
[2]*ZScale
);
709 /* Check to see if the HRIR is already moving. */
710 if(ALSource
->Hrtf
.Moving
)
712 /* Calculate the normalized HRTF transition factor (delta). */
713 delta
= CalcHrtfDelta(ALSource
->Params
.Direct
.Hrtf
.Gain
, DryGain
,
714 ALSource
->Params
.Direct
.Hrtf
.Dir
, Position
);
715 /* If the delta is large enough, get the moving HRIR target
716 * coefficients, target delays, steppping values, and counter. */
719 ALSource
->Hrtf
.Counter
= GetMovingHrtfCoeffs(Device
->Hrtf
,
720 ev
, az
, DryGain
, delta
,
721 ALSource
->Hrtf
.Counter
,
722 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
723 ALSource
->Params
.Direct
.Hrtf
.Delay
[0],
724 ALSource
->Params
.Direct
.Hrtf
.CoeffStep
,
725 ALSource
->Params
.Direct
.Hrtf
.DelayStep
);
726 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
727 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
728 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
729 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
734 /* Get the initial (static) HRIR coefficients and delays. */
735 GetLerpedHrtfCoeffs(Device
->Hrtf
, ev
, az
, DryGain
,
736 ALSource
->Params
.Direct
.Hrtf
.Coeffs
[0],
737 ALSource
->Params
.Direct
.Hrtf
.Delay
[0]);
738 ALSource
->Hrtf
.Counter
= 0;
739 ALSource
->Params
.Direct
.Hrtf
.Gain
= DryGain
;
740 ALSource
->Params
.Direct
.Hrtf
.Dir
[0] = Position
[0];
741 ALSource
->Params
.Direct
.Hrtf
.Dir
[1] = Position
[1];
742 ALSource
->Params
.Direct
.Hrtf
.Dir
[2] = Position
[2];
747 /* Use a lookup table for panning multi-speaker playback. */
748 ALfloat DirGain
, AmbientGain
;
749 const ALfloat
*ChannelGain
;
753 /* Normalize the length based on the source's min distance. Sources
754 * closer than this will not pan as much. */
755 length
= maxf(Distance
, MinDist
);
758 ALfloat invlen
= 1.0f
/length
;
759 Position
[0] *= invlen
;
760 Position
[1] *= invlen
;
761 Position
[2] *= invlen
;
764 pos
= aluCart2LUTpos(Position
[0], -Position
[2]*ZScale
);
765 ChannelGain
= Device
->PanningLUT
[pos
];
767 /* Adjustment for partial panning. Not the greatest, but simple
769 DirGain
= aluSqrt(Position
[0]*Position
[0] + Position
[2]*Position
[2]);
770 AmbientGain
= aluSqrt(1.0f
/Device
->NumChan
);
771 for(i
= 0;i
< MAXCHANNELS
;i
++)
773 for(j
= 0;j
< MAXCHANNELS
;j
++)
774 ALSource
->Params
.Direct
.Gains
[i
][j
] = 0.0f
;
776 for(i
= 0;i
< (ALint
)Device
->NumChan
;i
++)
778 enum Channel chan
= Device
->Speaker2Chan
[i
];
779 ALfloat gain
= lerp(AmbientGain
, ChannelGain
[chan
], DirGain
);
780 ALSource
->Params
.Direct
.Gains
[0][chan
] = DryGain
* gain
;
783 for(i
= 0;i
< NumSends
;i
++)
784 ALSource
->Params
.Send
[i
].Gain
= WetGain
[i
];
786 /* Update filter coefficients. */
787 cw
= aluCos(F_PI
*2.0f
* LOWPASSFREQREF
/ Frequency
);
789 ALSource
->Params
.Direct
.iirFilter
.coeff
= lpCoeffCalc(DryGainHF
, cw
);
790 for(i
= 0;i
< NumSends
;i
++)
792 ALfloat a
= lpCoeffCalc(WetGainHF
[i
]*WetGainHF
[i
], cw
);
793 ALSource
->Params
.Send
[i
].iirFilter
.coeff
= a
;
798 static __inline ALfloat
aluF2F(ALfloat val
)
800 static __inline ALint
aluF2I(ALfloat val
)
802 if(val
> 1.0f
) return 2147483647;
803 if(val
< -1.0f
) return -2147483647-1;
804 return fastf2i((ALfloat
)(val
*2147483647.0));
806 static __inline ALuint
aluF2UI(ALfloat val
)
807 { return aluF2I(val
)+2147483648u; }
808 static __inline ALshort
aluF2S(ALfloat val
)
809 { return aluF2I(val
)>>16; }
810 static __inline ALushort
aluF2US(ALfloat val
)
811 { return aluF2S(val
)+32768; }
812 static __inline ALbyte
aluF2B(ALfloat val
)
813 { return aluF2I(val
)>>24; }
814 static __inline ALubyte
aluF2UB(ALfloat val
)
815 { return aluF2B(val
)+128; }
817 #define DECL_TEMPLATE(T, N, func) \
818 static void Write_##T##_##N(ALCdevice *device, T *RESTRICT buffer, \
819 ALuint SamplesToDo) \
821 ALfloat (*RESTRICT DryBuffer)[MAXCHANNELS] = device->DryBuffer; \
822 const enum Channel *ChanMap = device->DevChannels; \
825 for(j = 0;j < N;j++) \
827 T *RESTRICT out = buffer + j; \
828 enum Channel chan = ChanMap[j]; \
830 for(i = 0;i < SamplesToDo;i++) \
831 out[i*N] = func(DryBuffer[i][chan]); \
835 DECL_TEMPLATE(ALfloat
, 1, aluF2F
)
836 DECL_TEMPLATE(ALfloat
, 2, aluF2F
)
837 DECL_TEMPLATE(ALfloat
, 4, aluF2F
)
838 DECL_TEMPLATE(ALfloat
, 6, aluF2F
)
839 DECL_TEMPLATE(ALfloat
, 7, aluF2F
)
840 DECL_TEMPLATE(ALfloat
, 8, aluF2F
)
842 DECL_TEMPLATE(ALuint
, 1, aluF2UI
)
843 DECL_TEMPLATE(ALuint
, 2, aluF2UI
)
844 DECL_TEMPLATE(ALuint
, 4, aluF2UI
)
845 DECL_TEMPLATE(ALuint
, 6, aluF2UI
)
846 DECL_TEMPLATE(ALuint
, 7, aluF2UI
)
847 DECL_TEMPLATE(ALuint
, 8, aluF2UI
)
849 DECL_TEMPLATE(ALint
, 1, aluF2I
)
850 DECL_TEMPLATE(ALint
, 2, aluF2I
)
851 DECL_TEMPLATE(ALint
, 4, aluF2I
)
852 DECL_TEMPLATE(ALint
, 6, aluF2I
)
853 DECL_TEMPLATE(ALint
, 7, aluF2I
)
854 DECL_TEMPLATE(ALint
, 8, aluF2I
)
856 DECL_TEMPLATE(ALushort
, 1, aluF2US
)
857 DECL_TEMPLATE(ALushort
, 2, aluF2US
)
858 DECL_TEMPLATE(ALushort
, 4, aluF2US
)
859 DECL_TEMPLATE(ALushort
, 6, aluF2US
)
860 DECL_TEMPLATE(ALushort
, 7, aluF2US
)
861 DECL_TEMPLATE(ALushort
, 8, aluF2US
)
863 DECL_TEMPLATE(ALshort
, 1, aluF2S
)
864 DECL_TEMPLATE(ALshort
, 2, aluF2S
)
865 DECL_TEMPLATE(ALshort
, 4, aluF2S
)
866 DECL_TEMPLATE(ALshort
, 6, aluF2S
)
867 DECL_TEMPLATE(ALshort
, 7, aluF2S
)
868 DECL_TEMPLATE(ALshort
, 8, aluF2S
)
870 DECL_TEMPLATE(ALubyte
, 1, aluF2UB
)
871 DECL_TEMPLATE(ALubyte
, 2, aluF2UB
)
872 DECL_TEMPLATE(ALubyte
, 4, aluF2UB
)
873 DECL_TEMPLATE(ALubyte
, 6, aluF2UB
)
874 DECL_TEMPLATE(ALubyte
, 7, aluF2UB
)
875 DECL_TEMPLATE(ALubyte
, 8, aluF2UB
)
877 DECL_TEMPLATE(ALbyte
, 1, aluF2B
)
878 DECL_TEMPLATE(ALbyte
, 2, aluF2B
)
879 DECL_TEMPLATE(ALbyte
, 4, aluF2B
)
880 DECL_TEMPLATE(ALbyte
, 6, aluF2B
)
881 DECL_TEMPLATE(ALbyte
, 7, aluF2B
)
882 DECL_TEMPLATE(ALbyte
, 8, aluF2B
)
886 #define DECL_TEMPLATE(T) \
887 static void Write_##T(ALCdevice *device, T *buffer, ALuint SamplesToDo) \
889 switch(device->FmtChans) \
892 Write_##T##_1(device, buffer, SamplesToDo); \
895 Write_##T##_2(device, buffer, SamplesToDo); \
898 Write_##T##_4(device, buffer, SamplesToDo); \
901 case DevFmtX51Side: \
902 Write_##T##_6(device, buffer, SamplesToDo); \
905 Write_##T##_7(device, buffer, SamplesToDo); \
908 Write_##T##_8(device, buffer, SamplesToDo); \
913 DECL_TEMPLATE(ALfloat
)
914 DECL_TEMPLATE(ALuint
)
916 DECL_TEMPLATE(ALushort
)
917 DECL_TEMPLATE(ALshort
)
918 DECL_TEMPLATE(ALubyte
)
919 DECL_TEMPLATE(ALbyte
)
923 ALvoid
aluMixData(ALCdevice
*device
, ALvoid
*buffer
, ALsizei size
)
926 ALeffectslot
**slot
, **slot_end
;
927 ALsource
**src
, **src_end
;
932 fpuState
= SetMixerFPUMode();
936 SamplesToDo
= minu(size
, BUFFERSIZE
);
937 memset(device
->DryBuffer
, 0, SamplesToDo
*MAXCHANNELS
*sizeof(ALfloat
));
940 ctx
= device
->ContextList
;
943 ALenum DeferUpdates
= ctx
->DeferUpdates
;
944 ALenum UpdateSources
= AL_FALSE
;
947 UpdateSources
= ExchangeInt(&ctx
->UpdateSources
, AL_FALSE
);
949 /* source processing */
950 src
= ctx
->ActiveSources
;
951 src_end
= src
+ ctx
->ActiveSourceCount
;
952 while(src
!= src_end
)
954 if((*src
)->state
!= AL_PLAYING
)
956 --(ctx
->ActiveSourceCount
);
961 if(!DeferUpdates
&& (ExchangeInt(&(*src
)->NeedsUpdate
, AL_FALSE
) ||
963 ALsource_Update(*src
, ctx
);
965 MixSource(*src
, device
, SamplesToDo
);
969 /* effect slot processing */
970 slot
= ctx
->ActiveEffectSlots
;
971 slot_end
= slot
+ ctx
->ActiveEffectSlotCount
;
972 while(slot
!= slot_end
)
974 for(c
= 0;c
< SamplesToDo
;c
++)
976 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
977 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
979 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
980 (*slot
)->PendingClicks
[0] = 0.0f
;
982 if(!DeferUpdates
&& ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
983 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
985 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
986 (*slot
)->WetBuffer
, device
->DryBuffer
);
988 for(i
= 0;i
< SamplesToDo
;i
++)
989 (*slot
)->WetBuffer
[i
] = 0.0f
;
997 slot
= &device
->DefaultSlot
;
1000 for(c
= 0;c
< SamplesToDo
;c
++)
1002 (*slot
)->WetBuffer
[c
] += (*slot
)->ClickRemoval
[0];
1003 (*slot
)->ClickRemoval
[0] -= (*slot
)->ClickRemoval
[0] * (1.0f
/256.0f
);
1005 (*slot
)->ClickRemoval
[0] += (*slot
)->PendingClicks
[0];
1006 (*slot
)->PendingClicks
[0] = 0.0f
;
1008 if(ExchangeInt(&(*slot
)->NeedsUpdate
, AL_FALSE
))
1009 ALeffectState_Update((*slot
)->EffectState
, device
, *slot
);
1011 ALeffectState_Process((*slot
)->EffectState
, SamplesToDo
,
1012 (*slot
)->WetBuffer
, device
->DryBuffer
);
1014 for(i
= 0;i
< SamplesToDo
;i
++)
1015 (*slot
)->WetBuffer
[i
] = 0.0f
;
1017 UnlockDevice(device
);
1019 /* Click-removal. Could do better; this only really handles immediate
1020 * changes between updates where a predictive sample could be
1021 * generated. Delays caused by effects and HRTF aren't caught. */
1022 if(device
->FmtChans
== DevFmtMono
)
1024 for(i
= 0;i
< SamplesToDo
;i
++)
1026 device
->DryBuffer
[i
][FRONT_CENTER
] += device
->ClickRemoval
[FRONT_CENTER
];
1027 device
->ClickRemoval
[FRONT_CENTER
] -= device
->ClickRemoval
[FRONT_CENTER
] * (1.0f
/256.0f
);
1029 device
->ClickRemoval
[FRONT_CENTER
] += device
->PendingClicks
[FRONT_CENTER
];
1030 device
->PendingClicks
[FRONT_CENTER
] = 0.0f
;
1032 else if(device
->FmtChans
== DevFmtStereo
)
1034 /* Assumes the first two channels are FRONT_LEFT and FRONT_RIGHT */
1035 for(i
= 0;i
< SamplesToDo
;i
++)
1037 for(c
= 0;c
< 2;c
++)
1039 device
->DryBuffer
[i
][c
] += device
->ClickRemoval
[c
];
1040 device
->ClickRemoval
[c
] -= device
->ClickRemoval
[c
] * (1.0f
/256.0f
);
1043 for(c
= 0;c
< 2;c
++)
1045 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1046 device
->PendingClicks
[c
] = 0.0f
;
1050 for(i
= 0;i
< SamplesToDo
;i
++)
1051 bs2b_cross_feed(device
->Bs2b
, &device
->DryBuffer
[i
][0]);
1056 for(i
= 0;i
< SamplesToDo
;i
++)
1058 for(c
= 0;c
< MAXCHANNELS
;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
< MAXCHANNELS
;c
++)
1066 device
->ClickRemoval
[c
] += device
->PendingClicks
[c
];
1067 device
->PendingClicks
[c
] = 0.0f
;
1073 switch(device
->FmtType
)
1076 Write_ALbyte(device
, buffer
, SamplesToDo
);
1079 Write_ALubyte(device
, buffer
, SamplesToDo
);
1082 Write_ALshort(device
, buffer
, SamplesToDo
);
1085 Write_ALushort(device
, buffer
, SamplesToDo
);
1088 Write_ALint(device
, buffer
, SamplesToDo
);
1091 Write_ALuint(device
, buffer
, SamplesToDo
);
1094 Write_ALfloat(device
, buffer
, SamplesToDo
);
1099 size
-= SamplesToDo
;
1102 RestoreFPUMode(fpuState
);
1106 ALvoid
aluHandleDisconnect(ALCdevice
*device
)
1108 ALCcontext
*Context
;
1111 device
->Connected
= ALC_FALSE
;
1113 Context
= device
->ContextList
;
1116 ALsource
**src
, **src_end
;
1118 src
= Context
->ActiveSources
;
1119 src_end
= src
+ Context
->ActiveSourceCount
;
1120 while(src
!= src_end
)
1122 if((*src
)->state
== AL_PLAYING
)
1124 (*src
)->state
= AL_STOPPED
;
1125 (*src
)->BuffersPlayed
= (*src
)->BuffersInQueue
;
1126 (*src
)->position
= 0;
1127 (*src
)->position_fraction
= 0;
1131 Context
->ActiveSourceCount
= 0;
1133 Context
= Context
->next
;
1135 UnlockDevice(device
);