Make a decimal value a float type
[openal-soft.git] / Alc / ALu.c
blobe0e5f8a314223c213d997dd519608e4ff411a018
1 /**
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
21 #include "config.h"
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <assert.h>
29 #include "alMain.h"
30 #include "alSource.h"
31 #include "alBuffer.h"
32 #include "alListener.h"
33 #include "alAuxEffectSlot.h"
34 #include "alu.h"
35 #include "bs2b.h"
37 #include "mixer_defs.h"
40 struct ChanMap {
41 enum Channel channel;
42 ALfloat angle;
45 /* Cone scalar */
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;
56 switch(Resampler)
58 case PointResampler:
59 return Resample_point32_C;
60 case LinearResampler:
61 return Resample_lerp32_C;
62 case CubicResampler:
63 return Resample_cubic32_C;
64 case ResamplerMax:
65 /* Shouldn't happen */
66 break;
69 return Resample_point32_C;
73 static DryMixerFunc SelectHrtfMixer(void)
75 #ifdef HAVE_SSE
76 if((CPUCapFlags&CPU_CAP_SSE))
77 return MixDirect_Hrtf_SSE;
78 #endif
79 #ifdef HAVE_NEON
80 if((CPUCapFlags&CPU_CAP_NEON))
81 return MixDirect_Hrtf_Neon;
82 #endif
84 return MixDirect_Hrtf_C;
87 static DryMixerFunc SelectDirectMixer(void)
89 #ifdef HAVE_SSE
90 if((CPUCapFlags&CPU_CAP_SSE))
91 return MixDirect_SSE;
92 #endif
94 return MixDirect_C;
97 static WetMixerFunc SelectSendMixer(void)
99 #ifdef HAVE_SSE
100 if((CPUCapFlags&CPU_CAP_SSE))
101 return MixSend_SSE;
102 #endif
104 return MixSend_C;
108 static __inline void aluCrossproduct(const ALfloat *inVector1, const ALfloat *inVector2, ALfloat *outVector)
110 outVector[0] = inVector1[1]*inVector2[2] - inVector1[2]*inVector2[1];
111 outVector[1] = inVector1[2]*inVector2[0] - inVector1[0]*inVector2[2];
112 outVector[2] = inVector1[0]*inVector2[1] - inVector1[1]*inVector2[0];
115 static __inline ALfloat aluDotproduct(const ALfloat *inVector1, const ALfloat *inVector2)
117 return inVector1[0]*inVector2[0] + inVector1[1]*inVector2[1] +
118 inVector1[2]*inVector2[2];
121 static __inline void aluNormalize(ALfloat *inVector)
123 ALfloat lengthsqr = aluDotproduct(inVector, inVector);
124 if(lengthsqr > 0.0f)
126 ALfloat inv_length = 1.0f/sqrtf(lengthsqr);
127 inVector[0] *= inv_length;
128 inVector[1] *= inv_length;
129 inVector[2] *= inv_length;
133 static __inline ALvoid aluMatrixVector(ALfloat *vector, ALfloat w, ALfloat (*RESTRICT matrix)[4])
135 ALfloat temp[4] = {
136 vector[0], vector[1], vector[2], w
139 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
140 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
141 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
145 static ALvoid CalcListenerParams(ALlistener *Listener)
147 ALfloat N[3], V[3], U[3], P[3];
149 /* AT then UP */
150 N[0] = Listener->Forward[0];
151 N[1] = Listener->Forward[1];
152 N[2] = Listener->Forward[2];
153 aluNormalize(N);
154 V[0] = Listener->Up[0];
155 V[1] = Listener->Up[1];
156 V[2] = Listener->Up[2];
157 aluNormalize(V);
158 /* Build and normalize right-vector */
159 aluCrossproduct(N, V, U);
160 aluNormalize(U);
162 Listener->Params.Matrix[0][0] = U[0];
163 Listener->Params.Matrix[0][1] = V[0];
164 Listener->Params.Matrix[0][2] = -N[0];
165 Listener->Params.Matrix[0][3] = 0.0f;
166 Listener->Params.Matrix[1][0] = U[1];
167 Listener->Params.Matrix[1][1] = V[1];
168 Listener->Params.Matrix[1][2] = -N[1];
169 Listener->Params.Matrix[1][3] = 0.0f;
170 Listener->Params.Matrix[2][0] = U[2];
171 Listener->Params.Matrix[2][1] = V[2];
172 Listener->Params.Matrix[2][2] = -N[2];
173 Listener->Params.Matrix[2][3] = 0.0f;
174 Listener->Params.Matrix[3][0] = 0.0f;
175 Listener->Params.Matrix[3][1] = 0.0f;
176 Listener->Params.Matrix[3][2] = 0.0f;
177 Listener->Params.Matrix[3][3] = 1.0f;
179 P[0] = Listener->Position[0];
180 P[1] = Listener->Position[1];
181 P[2] = Listener->Position[2];
182 aluMatrixVector(P, 1.0f, Listener->Params.Matrix);
183 Listener->Params.Matrix[3][0] = -P[0];
184 Listener->Params.Matrix[3][1] = -P[1];
185 Listener->Params.Matrix[3][2] = -P[2];
187 Listener->Params.Velocity[0] = Listener->Velocity[0];
188 Listener->Params.Velocity[1] = Listener->Velocity[1];
189 Listener->Params.Velocity[2] = Listener->Velocity[2];
190 aluMatrixVector(Listener->Params.Velocity, 0.0f, Listener->Params.Matrix);
193 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
195 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
196 static const struct ChanMap StereoMap[2] = {
197 { FrontLeft, -30.0f * F_PI/180.0f },
198 { FrontRight, 30.0f * F_PI/180.0f }
200 static const struct ChanMap StereoWideMap[2] = {
201 { FrontLeft, -90.0f * F_PI/180.0f },
202 { FrontRight, 90.0f * F_PI/180.0f }
204 static const struct ChanMap RearMap[2] = {
205 { BackLeft, -150.0f * F_PI/180.0f },
206 { BackRight, 150.0f * F_PI/180.0f }
208 static const struct ChanMap QuadMap[4] = {
209 { FrontLeft, -45.0f * F_PI/180.0f },
210 { FrontRight, 45.0f * F_PI/180.0f },
211 { BackLeft, -135.0f * F_PI/180.0f },
212 { BackRight, 135.0f * F_PI/180.0f }
214 static const struct ChanMap X51Map[6] = {
215 { FrontLeft, -30.0f * F_PI/180.0f },
216 { FrontRight, 30.0f * F_PI/180.0f },
217 { FrontCenter, 0.0f * F_PI/180.0f },
218 { LFE, 0.0f },
219 { BackLeft, -110.0f * F_PI/180.0f },
220 { BackRight, 110.0f * F_PI/180.0f }
222 static const struct ChanMap X61Map[7] = {
223 { FrontLeft, -30.0f * F_PI/180.0f },
224 { FrontRight, 30.0f * F_PI/180.0f },
225 { FrontCenter, 0.0f * F_PI/180.0f },
226 { LFE, 0.0f },
227 { BackCenter, 180.0f * F_PI/180.0f },
228 { SideLeft, -90.0f * F_PI/180.0f },
229 { SideRight, 90.0f * F_PI/180.0f }
231 static const struct ChanMap X71Map[8] = {
232 { FrontLeft, -30.0f * F_PI/180.0f },
233 { FrontRight, 30.0f * F_PI/180.0f },
234 { FrontCenter, 0.0f * F_PI/180.0f },
235 { LFE, 0.0f },
236 { BackLeft, -150.0f * F_PI/180.0f },
237 { BackRight, 150.0f * F_PI/180.0f },
238 { SideLeft, -90.0f * F_PI/180.0f },
239 { SideRight, 90.0f * F_PI/180.0f }
242 ALCdevice *Device = ALContext->Device;
243 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
244 ALbufferlistitem *BufferListItem;
245 enum FmtChannels Channels;
246 ALfloat (*SrcMatrix)[MaxChannels];
247 ALfloat DryGain, DryGainHF;
248 ALfloat WetGain[MAX_SENDS];
249 ALfloat WetGainHF[MAX_SENDS];
250 ALint NumSends, Frequency;
251 const struct ChanMap *chans = NULL;
252 enum Resampler Resampler;
253 ALint num_channels = 0;
254 ALboolean DirectChannels;
255 ALfloat hwidth = 0.0f;
256 ALfloat Pitch;
257 ALfloat cw;
258 ALint i, c;
260 /* Get device properties */
261 NumSends = Device->NumAuxSends;
262 Frequency = Device->Frequency;
264 /* Get listener properties */
265 ListenerGain = ALContext->Listener->Gain;
267 /* Get source properties */
268 SourceVolume = ALSource->Gain;
269 MinVolume = ALSource->MinGain;
270 MaxVolume = ALSource->MaxGain;
271 Pitch = ALSource->Pitch;
272 Resampler = ALSource->Resampler;
273 DirectChannels = ALSource->DirectChannels;
275 /* Calculate the stepping value */
276 Channels = FmtMono;
277 BufferListItem = ALSource->queue;
278 while(BufferListItem != NULL)
280 ALbuffer *ALBuffer;
281 if((ALBuffer=BufferListItem->buffer) != NULL)
283 ALsizei maxstep = BUFFERSIZE;
284 maxstep -= ResamplerPadding[Resampler] +
285 ResamplerPrePadding[Resampler] + 1;
286 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
288 Pitch = Pitch * ALBuffer->Frequency / Frequency;
289 if(Pitch > (ALfloat)maxstep)
290 ALSource->Params.Step = maxstep<<FRACTIONBITS;
291 else
293 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
294 if(ALSource->Params.Step == 0)
295 ALSource->Params.Step = 1;
297 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
299 Channels = ALBuffer->FmtChannels;
300 break;
302 BufferListItem = BufferListItem->next;
304 if(!DirectChannels && Device->Hrtf)
305 ALSource->Params.DryMix = SelectHrtfMixer();
306 else
307 ALSource->Params.DryMix = SelectDirectMixer();
308 ALSource->Params.WetMix = SelectSendMixer();
310 /* Calculate gains */
311 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
312 DryGain *= ALSource->DirectGain * ListenerGain;
313 DryGainHF = ALSource->DirectGainHF;
314 for(i = 0;i < NumSends;i++)
316 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
317 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
318 WetGainHF[i] = ALSource->Send[i].GainHF;
321 SrcMatrix = ALSource->Params.Direct.Gains;
322 for(i = 0;i < MaxChannels;i++)
324 for(c = 0;c < MaxChannels;c++)
325 SrcMatrix[i][c] = 0.0f;
327 switch(Channels)
329 case FmtMono:
330 chans = MonoMap;
331 num_channels = 1;
332 break;
334 case FmtStereo:
335 if(!(Device->Flags&DEVICE_WIDE_STEREO))
336 chans = StereoMap;
337 else
339 chans = StereoWideMap;
340 hwidth = 60.0f * F_PI/180.0f;
342 num_channels = 2;
343 break;
345 case FmtRear:
346 chans = RearMap;
347 num_channels = 2;
348 break;
350 case FmtQuad:
351 chans = QuadMap;
352 num_channels = 4;
353 break;
355 case FmtX51:
356 chans = X51Map;
357 num_channels = 6;
358 break;
360 case FmtX61:
361 chans = X61Map;
362 num_channels = 7;
363 break;
365 case FmtX71:
366 chans = X71Map;
367 num_channels = 8;
368 break;
371 if(DirectChannels != AL_FALSE)
373 for(c = 0;c < num_channels;c++)
375 for(i = 0;i < (ALint)Device->NumChan;i++)
377 enum Channel chan = Device->Speaker2Chan[i];
378 if(chan == chans[c].channel)
380 SrcMatrix[c][chan] = DryGain;
381 break;
386 else if(Device->Hrtf)
388 for(c = 0;c < num_channels;c++)
390 if(chans[c].channel == LFE)
392 /* Skip LFE */
393 ALSource->Params.Direct.Hrtf.Params.Delay[c][0] = 0;
394 ALSource->Params.Direct.Hrtf.Params.Delay[c][1] = 0;
395 for(i = 0;i < HRIR_LENGTH;i++)
397 ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][0] = 0.0f;
398 ALSource->Params.Direct.Hrtf.Params.Coeffs[c][i][1] = 0.0f;
401 else
403 /* Get the static HRIR coefficients and delays for this
404 * channel. */
405 GetLerpedHrtfCoeffs(Device->Hrtf,
406 0.0f, chans[c].angle, DryGain,
407 ALSource->Params.Direct.Hrtf.Params.Coeffs[c],
408 ALSource->Params.Direct.Hrtf.Params.Delay[c]);
411 ALSource->Hrtf.Counter = 0;
412 ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
414 ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
416 else
418 DryGain *= lerp(1.0f, 1.0f/sqrtf((float)Device->NumChan), hwidth/F_PI);
419 for(c = 0;c < num_channels;c++)
421 /* Special-case LFE */
422 if(chans[c].channel == LFE)
424 SrcMatrix[c][chans[c].channel] = DryGain;
425 continue;
427 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
428 SrcMatrix[c]);
432 ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
433 ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
434 ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
435 for(i = 0;i < NumSends;i++)
437 ALeffectslot *Slot = ALSource->Send[i].Slot;
439 if(!Slot && i == 0)
440 Slot = Device->DefaultSlot;
441 if(Slot && Slot->effect.type == AL_EFFECT_NULL)
442 Slot = NULL;
443 ALSource->Params.Send[i].Slot = Slot;
444 ALSource->Params.Send[i].Gain = WetGain[i];
447 /* Update filter coefficients. Calculations based on the I3DL2
448 * spec. */
449 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
451 /* We use two chained one-pole filters, so we need to take the
452 * square root of the squared gain, which is the same as the base
453 * gain. */
454 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
455 for(i = 0;i < NumSends;i++)
457 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
458 ALSource->Params.Send[i].iirFilter.coeff = a;
462 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
464 ALCdevice *Device = ALContext->Device;
465 ALfloat Velocity[3],Direction[3],Position[3],SourceToListener[3];
466 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
467 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
468 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
469 ALfloat DopplerFactor, SpeedOfSound;
470 ALfloat AirAbsorptionFactor;
471 ALfloat RoomAirAbsorption[MAX_SENDS];
472 ALbufferlistitem *BufferListItem;
473 ALfloat Attenuation;
474 ALfloat RoomAttenuation[MAX_SENDS];
475 ALfloat MetersPerUnit;
476 ALfloat RoomRolloffBase;
477 ALfloat RoomRolloff[MAX_SENDS];
478 ALfloat DecayDistance[MAX_SENDS];
479 ALfloat DryGain;
480 ALfloat DryGainHF;
481 ALboolean DryGainHFAuto;
482 ALfloat WetGain[MAX_SENDS];
483 ALfloat WetGainHF[MAX_SENDS];
484 ALboolean WetGainAuto;
485 ALboolean WetGainHFAuto;
486 enum Resampler Resampler;
487 ALfloat Pitch;
488 ALuint Frequency;
489 ALint NumSends;
490 ALfloat cw;
491 ALint i, j;
493 DryGainHF = 1.0f;
494 for(i = 0;i < MAX_SENDS;i++)
495 WetGainHF[i] = 1.0f;
497 /* Get context/device properties */
498 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
499 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
500 NumSends = Device->NumAuxSends;
501 Frequency = Device->Frequency;
503 /* Get listener properties */
504 ListenerGain = ALContext->Listener->Gain;
505 MetersPerUnit = ALContext->Listener->MetersPerUnit;
507 /* Get source properties */
508 SourceVolume = ALSource->Gain;
509 MinVolume = ALSource->MinGain;
510 MaxVolume = ALSource->MaxGain;
511 Pitch = ALSource->Pitch;
512 Resampler = ALSource->Resampler;
513 Position[0] = ALSource->Position[0];
514 Position[1] = ALSource->Position[1];
515 Position[2] = ALSource->Position[2];
516 Direction[0] = ALSource->Orientation[0];
517 Direction[1] = ALSource->Orientation[1];
518 Direction[2] = ALSource->Orientation[2];
519 Velocity[0] = ALSource->Velocity[0];
520 Velocity[1] = ALSource->Velocity[1];
521 Velocity[2] = ALSource->Velocity[2];
522 MinDist = ALSource->RefDistance;
523 MaxDist = ALSource->MaxDistance;
524 Rolloff = ALSource->RollOffFactor;
525 InnerAngle = ALSource->InnerAngle;
526 OuterAngle = ALSource->OuterAngle;
527 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
528 DryGainHFAuto = ALSource->DryGainHFAuto;
529 WetGainAuto = ALSource->WetGainAuto;
530 WetGainHFAuto = ALSource->WetGainHFAuto;
531 RoomRolloffBase = ALSource->RoomRolloffFactor;
533 ALSource->Params.Direct.OutBuffer = Device->DryBuffer;
534 ALSource->Params.Direct.ClickRemoval = Device->ClickRemoval;
535 ALSource->Params.Direct.PendingClicks = Device->PendingClicks;
536 for(i = 0;i < NumSends;i++)
538 ALeffectslot *Slot = ALSource->Send[i].Slot;
540 if(!Slot && i == 0)
541 Slot = Device->DefaultSlot;
542 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
544 Slot = NULL;
545 RoomRolloff[i] = 0.0f;
546 DecayDistance[i] = 0.0f;
547 RoomAirAbsorption[i] = 1.0f;
549 else if(Slot->AuxSendAuto)
551 RoomRolloff[i] = RoomRolloffBase;
552 if(IsReverbEffect(Slot->effect.type))
554 RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor;
555 DecayDistance[i] = Slot->effect.Reverb.DecayTime *
556 SPEEDOFSOUNDMETRESPERSEC;
557 RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF;
559 else
561 DecayDistance[i] = 0.0f;
562 RoomAirAbsorption[i] = 1.0f;
565 else
567 /* If the slot's auxiliary send auto is off, the data sent to the
568 * effect slot is the same as the dry path, sans filter effects */
569 RoomRolloff[i] = Rolloff;
570 DecayDistance[i] = 0.0f;
571 RoomAirAbsorption[i] = AIRABSORBGAINHF;
574 ALSource->Params.Send[i].Slot = Slot;
577 /* Transform source to listener space (convert to head relative) */
578 if(ALSource->HeadRelative == AL_FALSE)
580 ALfloat (*RESTRICT Matrix)[4] = ALContext->Listener->Params.Matrix;
581 /* Transform source vectors */
582 aluMatrixVector(Position, 1.0f, Matrix);
583 aluMatrixVector(Direction, 0.0f, Matrix);
584 aluMatrixVector(Velocity, 0.0f, Matrix);
586 else
588 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
589 /* Offset the source velocity to be relative of the listener velocity */
590 Velocity[0] += ListenerVel[0];
591 Velocity[1] += ListenerVel[1];
592 Velocity[2] += ListenerVel[2];
595 SourceToListener[0] = -Position[0];
596 SourceToListener[1] = -Position[1];
597 SourceToListener[2] = -Position[2];
598 aluNormalize(SourceToListener);
599 aluNormalize(Direction);
601 /* Calculate distance attenuation */
602 Distance = sqrtf(aluDotproduct(Position, Position));
603 ClampedDist = Distance;
605 Attenuation = 1.0f;
606 for(i = 0;i < NumSends;i++)
607 RoomAttenuation[i] = 1.0f;
608 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
609 ALContext->DistanceModel)
611 case InverseDistanceClamped:
612 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
613 if(MaxDist < MinDist)
614 break;
615 /*fall-through*/
616 case InverseDistance:
617 if(MinDist > 0.0f)
619 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
620 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
621 for(i = 0;i < NumSends;i++)
623 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
624 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
627 break;
629 case LinearDistanceClamped:
630 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
631 if(MaxDist < MinDist)
632 break;
633 /*fall-through*/
634 case LinearDistance:
635 if(MaxDist != MinDist)
637 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
638 Attenuation = maxf(Attenuation, 0.0f);
639 for(i = 0;i < NumSends;i++)
641 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
642 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
645 break;
647 case ExponentDistanceClamped:
648 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
649 if(MaxDist < MinDist)
650 break;
651 /*fall-through*/
652 case ExponentDistance:
653 if(ClampedDist > 0.0f && MinDist > 0.0f)
655 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
656 for(i = 0;i < NumSends;i++)
657 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
659 break;
661 case DisableDistance:
662 ClampedDist = MinDist;
663 break;
666 /* Source Gain + Attenuation */
667 DryGain = SourceVolume * Attenuation;
668 for(i = 0;i < NumSends;i++)
669 WetGain[i] = SourceVolume * RoomAttenuation[i];
671 /* Distance-based air absorption */
672 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
674 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
675 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
676 for(i = 0;i < NumSends;i++)
677 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
680 if(WetGainAuto)
682 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
684 /* Apply a decay-time transformation to the wet path, based on the
685 * attenuation of the dry path.
687 * Using the apparent distance, based on the distance attenuation, the
688 * initial decay of the reverb effect is calculated and applied to the
689 * wet path.
691 for(i = 0;i < NumSends;i++)
693 if(DecayDistance[i] > 0.0f)
694 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
698 /* Calculate directional soundcones */
699 Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI);
700 if(Angle > InnerAngle && Angle <= OuterAngle)
702 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
703 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
704 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
706 else if(Angle > OuterAngle)
708 ConeVolume = ALSource->OuterGain;
709 ConeHF = ALSource->OuterGainHF;
711 else
713 ConeVolume = 1.0f;
714 ConeHF = 1.0f;
717 DryGain *= ConeVolume;
718 if(WetGainAuto)
720 for(i = 0;i < NumSends;i++)
721 WetGain[i] *= ConeVolume;
723 if(DryGainHFAuto)
724 DryGainHF *= ConeHF;
725 if(WetGainHFAuto)
727 for(i = 0;i < NumSends;i++)
728 WetGainHF[i] *= ConeHF;
731 /* Clamp to Min/Max Gain */
732 DryGain = clampf(DryGain, MinVolume, MaxVolume);
733 for(i = 0;i < NumSends;i++)
734 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
736 /* Apply gain and frequency filters */
737 DryGain *= ALSource->DirectGain * ListenerGain;
738 DryGainHF *= ALSource->DirectGainHF;
739 for(i = 0;i < NumSends;i++)
741 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
742 WetGainHF[i] *= ALSource->Send[i].GainHF;
745 /* Calculate velocity-based doppler effect */
746 if(DopplerFactor > 0.0f)
748 const ALfloat *ListenerVel = ALContext->Listener->Params.Velocity;
749 ALfloat VSS, VLS;
751 if(SpeedOfSound < 1.0f)
753 DopplerFactor *= 1.0f/SpeedOfSound;
754 SpeedOfSound = 1.0f;
757 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
758 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
760 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
761 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
764 BufferListItem = ALSource->queue;
765 while(BufferListItem != NULL)
767 ALbuffer *ALBuffer;
768 if((ALBuffer=BufferListItem->buffer) != NULL)
770 /* Calculate fixed-point stepping value, based on the pitch, buffer
771 * frequency, and output frequency. */
772 ALsizei maxstep = BUFFERSIZE;
773 maxstep -= ResamplerPadding[Resampler] +
774 ResamplerPrePadding[Resampler] + 1;
775 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
777 Pitch = Pitch * ALBuffer->Frequency / Frequency;
778 if(Pitch > (ALfloat)maxstep)
779 ALSource->Params.Step = maxstep<<FRACTIONBITS;
780 else
782 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
783 if(ALSource->Params.Step == 0)
784 ALSource->Params.Step = 1;
786 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
788 break;
790 BufferListItem = BufferListItem->next;
792 if(Device->Hrtf)
793 ALSource->Params.DryMix = SelectHrtfMixer();
794 else
795 ALSource->Params.DryMix = SelectDirectMixer();
796 ALSource->Params.WetMix = SelectSendMixer();
798 if(Device->Hrtf)
800 /* Use a binaural HRTF algorithm for stereo headphone playback */
801 ALfloat delta, ev = 0.0f, az = 0.0f;
803 if(Distance > FLT_EPSILON)
805 ALfloat invlen = 1.0f/Distance;
806 Position[0] *= invlen;
807 Position[1] *= invlen;
808 Position[2] *= invlen;
810 /* Calculate elevation and azimuth only when the source is not at
811 * the listener. This prevents +0 and -0 Z from producing
812 * inconsistent panning. Also, clamp Y in case FP precision errors
813 * cause it to land outside of -1..+1. */
814 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
815 az = atan2f(Position[0], -Position[2]*ZScale);
818 /* Check to see if the HRIR is already moving. */
819 if(ALSource->Hrtf.Moving)
821 /* Calculate the normalized HRTF transition factor (delta). */
822 delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Params.Gain, DryGain,
823 ALSource->Params.Direct.Hrtf.Params.Dir, Position);
824 /* If the delta is large enough, get the moving HRIR target
825 * coefficients, target delays, steppping values, and counter. */
826 if(delta > 0.001f)
828 ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
829 ev, az, DryGain, delta,
830 ALSource->Hrtf.Counter,
831 ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
832 ALSource->Params.Direct.Hrtf.Params.Delay[0],
833 ALSource->Params.Direct.Hrtf.Params.CoeffStep,
834 ALSource->Params.Direct.Hrtf.Params.DelayStep);
835 ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
836 ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
837 ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
838 ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
841 else
843 /* Get the initial (static) HRIR coefficients and delays. */
844 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
845 ALSource->Params.Direct.Hrtf.Params.Coeffs[0],
846 ALSource->Params.Direct.Hrtf.Params.Delay[0]);
847 ALSource->Hrtf.Counter = 0;
848 ALSource->Hrtf.Moving = AL_TRUE;
849 ALSource->Params.Direct.Hrtf.Params.Gain = DryGain;
850 ALSource->Params.Direct.Hrtf.Params.Dir[0] = Position[0];
851 ALSource->Params.Direct.Hrtf.Params.Dir[1] = Position[1];
852 ALSource->Params.Direct.Hrtf.Params.Dir[2] = Position[2];
854 ALSource->Params.Direct.Hrtf.Params.IrSize = GetHrtfIrSize(Device->Hrtf);
856 ALSource->Params.Direct.Hrtf.State = &ALSource->Hrtf;
858 else
860 ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
861 ALfloat DirGain = 0.0f;
862 ALfloat AmbientGain;
864 for(i = 0;i < MaxChannels;i++)
866 for(j = 0;j < MaxChannels;j++)
867 Matrix[i][j] = 0.0f;
870 /* Normalize the length, and compute panned gains. */
871 if(Distance > FLT_EPSILON)
873 ALfloat invlen = 1.0f/Distance;
874 Position[0] *= invlen;
875 Position[1] *= invlen;
876 Position[2] *= invlen;
878 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
879 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
880 DryGain*DirGain, Matrix[0]);
883 /* Adjustment for vertical offsets. Not the greatest, but simple
884 * enough. */
885 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
886 for(i = 0;i < (ALint)Device->NumChan;i++)
888 enum Channel chan = Device->Speaker2Chan[i];
889 Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
892 for(i = 0;i < NumSends;i++)
893 ALSource->Params.Send[i].Gain = WetGain[i];
895 /* Update filter coefficients. */
896 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
898 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
899 for(i = 0;i < NumSends;i++)
901 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
902 ALSource->Params.Send[i].iirFilter.coeff = a;
907 static __inline ALfloat aluF2F(ALfloat val)
908 { return val; }
909 static __inline ALint aluF2I(ALfloat val)
911 /* Clamp the value between -1 and +1. This handles that without branching. */
912 val = val+1.0f - fabsf(val-1.0f);
913 val = (val-2.0f + fabsf(val+2.0f)) * 0.25f;
914 /* Convert to a signed integer, between -2147483647 and +2147483647. */
915 return fastf2i((ALfloat)(val*2147483647.0));
917 static __inline ALuint aluF2UI(ALfloat val)
918 { return aluF2I(val)+2147483648u; }
919 static __inline ALshort aluF2S(ALfloat val)
920 { return aluF2I(val)>>16; }
921 static __inline ALushort aluF2US(ALfloat val)
922 { return aluF2S(val)+32768; }
923 static __inline ALbyte aluF2B(ALfloat val)
924 { return aluF2I(val)>>24; }
925 static __inline ALubyte aluF2UB(ALfloat val)
926 { return aluF2B(val)+128; }
928 #define DECL_TEMPLATE(T, func) \
929 static int Write_##T(ALCdevice *device, T *RESTRICT buffer, \
930 ALuint SamplesToDo) \
932 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
933 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
934 const enum Channel *ChanMap = device->DevChannels; \
935 ALuint i, j; \
937 for(j = 0;j < numchans;j++) \
939 T *RESTRICT out = buffer + j; \
940 enum Channel chan = ChanMap[j]; \
942 for(i = 0;i < SamplesToDo;i++) \
943 out[i*numchans] = func(DryBuffer[chan][i]); \
945 return SamplesToDo*numchans*sizeof(T); \
948 DECL_TEMPLATE(ALfloat, aluF2F)
949 DECL_TEMPLATE(ALuint, aluF2UI)
950 DECL_TEMPLATE(ALint, aluF2I)
951 DECL_TEMPLATE(ALushort, aluF2US)
952 DECL_TEMPLATE(ALshort, aluF2S)
953 DECL_TEMPLATE(ALubyte, aluF2UB)
954 DECL_TEMPLATE(ALbyte, aluF2B)
956 #undef DECL_TEMPLATE
959 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
961 ALuint SamplesToDo;
962 ALeffectslot **slot, **slot_end;
963 ALsource **src, **src_end;
964 ALCcontext *ctx;
965 FPUCtl oldMode;
966 ALuint i, c;
968 SetMixerFPUMode(&oldMode);
970 while(size > 0)
972 SamplesToDo = minu(size, BUFFERSIZE);
973 for(c = 0;c < MaxChannels;c++)
974 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
976 ALCdevice_Lock(device);
977 ctx = device->ContextList;
978 while(ctx)
980 ALenum DeferUpdates = ctx->DeferUpdates;
981 ALenum UpdateSources = AL_FALSE;
983 if(!DeferUpdates)
984 UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE);
986 if(UpdateSources)
987 CalcListenerParams(ctx->Listener);
989 /* source processing */
990 src = ctx->ActiveSources;
991 src_end = src + ctx->ActiveSourceCount;
992 while(src != src_end)
994 if((*src)->state != AL_PLAYING)
996 --(ctx->ActiveSourceCount);
997 *src = *(--src_end);
998 continue;
1001 if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
1002 UpdateSources))
1003 ALsource_Update(*src, ctx);
1005 MixSource(*src, device, SamplesToDo);
1006 src++;
1009 /* effect slot processing */
1010 slot = ctx->ActiveEffectSlots;
1011 slot_end = slot + ctx->ActiveEffectSlotCount;
1012 while(slot != slot_end)
1014 ALfloat offset = (*slot)->ClickRemoval[0];
1015 if(offset < (1.0f/32768.0f))
1016 offset = 0.0f;
1017 else for(i = 0;i < SamplesToDo;i++)
1019 (*slot)->WetBuffer[0][i] += offset;
1020 offset -= offset * (1.0f/256.0f);
1022 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
1023 (*slot)->PendingClicks[0] = 0.0f;
1025 if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
1026 ALeffectState_Update((*slot)->EffectState, device, *slot);
1028 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
1029 (*slot)->WetBuffer[0], device->DryBuffer);
1031 for(i = 0;i < SamplesToDo;i++)
1032 (*slot)->WetBuffer[0][i] = 0.0f;
1034 slot++;
1037 ctx = ctx->next;
1040 slot = &device->DefaultSlot;
1041 if(*slot != NULL)
1043 ALfloat offset = (*slot)->ClickRemoval[0];
1044 if(offset < (1.0f/32768.0f))
1045 offset = 0.0f;
1046 else for(i = 0;i < SamplesToDo;i++)
1048 (*slot)->WetBuffer[0][i] += offset;
1049 offset -= offset * (1.0f/256.0f);
1051 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
1052 (*slot)->PendingClicks[0] = 0.0f;
1054 if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
1055 ALeffectState_Update((*slot)->EffectState, device, *slot);
1057 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
1058 (*slot)->WetBuffer[0], device->DryBuffer);
1060 for(i = 0;i < SamplesToDo;i++)
1061 (*slot)->WetBuffer[0][i] = 0.0f;
1063 ALCdevice_Unlock(device);
1065 /* Click-removal. Could do better; this only really handles immediate
1066 * changes between updates where a predictive sample could be
1067 * generated. Delays caused by effects and HRTF aren't caught. */
1068 if(device->FmtChans == DevFmtMono)
1070 ALfloat offset = device->ClickRemoval[FrontCenter];
1071 if(offset < (1.0f/32768.0f))
1072 offset = 0.0f;
1073 else for(i = 0;i < SamplesToDo;i++)
1075 device->DryBuffer[FrontCenter][i] += offset;
1076 offset -= offset * (1.0f/256.0f);
1078 device->ClickRemoval[FrontCenter] = offset + device->PendingClicks[FrontCenter];
1079 device->PendingClicks[FrontCenter] = 0.0f;
1081 else if(device->FmtChans == DevFmtStereo)
1083 /* Assumes the first two channels are FrontLeft and FrontRight */
1084 for(c = 0;c < 2;c++)
1086 ALfloat offset = device->ClickRemoval[c];
1087 if(offset < (1.0f/32768.0f))
1088 offset = 0.0f;
1089 else for(i = 0;i < SamplesToDo;i++)
1091 device->DryBuffer[c][i] += offset;
1092 offset -= offset * (1.0f/256.0f);
1094 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1095 device->PendingClicks[c] = 0.0f;
1097 if(device->Bs2b)
1099 float samples[2];
1100 for(i = 0;i < SamplesToDo;i++)
1102 samples[0] = device->DryBuffer[FrontLeft][i];
1103 samples[1] = device->DryBuffer[FrontRight][i];
1104 bs2b_cross_feed(device->Bs2b, samples);
1105 device->DryBuffer[FrontLeft][i] = samples[0];
1106 device->DryBuffer[FrontRight][i] = samples[1];
1110 else
1112 for(c = 0;c < MaxChannels;c++)
1114 ALfloat offset = device->ClickRemoval[c];
1115 if(offset < (1.0f/32768.0f))
1116 offset = 0.0f;
1117 else for(i = 0;i < SamplesToDo;i++)
1119 device->DryBuffer[c][i] += offset;
1120 offset -= offset * (1.0f/256.0f);
1122 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1123 device->PendingClicks[c] = 0.0f;
1127 if(buffer)
1129 int bytes = 0;
1130 switch(device->FmtType)
1132 case DevFmtByte:
1133 bytes = Write_ALbyte(device, buffer, SamplesToDo);
1134 break;
1135 case DevFmtUByte:
1136 bytes = Write_ALubyte(device, buffer, SamplesToDo);
1137 break;
1138 case DevFmtShort:
1139 bytes = Write_ALshort(device, buffer, SamplesToDo);
1140 break;
1141 case DevFmtUShort:
1142 bytes = Write_ALushort(device, buffer, SamplesToDo);
1143 break;
1144 case DevFmtInt:
1145 bytes = Write_ALint(device, buffer, SamplesToDo);
1146 break;
1147 case DevFmtUInt:
1148 bytes = Write_ALuint(device, buffer, SamplesToDo);
1149 break;
1150 case DevFmtFloat:
1151 bytes = Write_ALfloat(device, buffer, SamplesToDo);
1152 break;
1155 buffer = (ALubyte*)buffer + bytes;
1158 size -= SamplesToDo;
1161 RestoreFPUMode(&oldMode);
1165 ALvoid aluHandleDisconnect(ALCdevice *device)
1167 ALCcontext *Context;
1169 ALCdevice_Lock(device);
1170 device->Connected = ALC_FALSE;
1172 Context = device->ContextList;
1173 while(Context)
1175 ALsource **src, **src_end;
1177 src = Context->ActiveSources;
1178 src_end = src + Context->ActiveSourceCount;
1179 while(src != src_end)
1181 if((*src)->state == AL_PLAYING)
1183 (*src)->state = AL_STOPPED;
1184 (*src)->BuffersPlayed = (*src)->BuffersInQueue;
1185 (*src)->position = 0;
1186 (*src)->position_fraction = 0;
1188 src++;
1190 Context->ActiveSourceCount = 0;
1192 Context = Context->next;
1194 ALCdevice_Unlock(device);