Move a couple methods to where they're used
[openal-soft.git] / Alc / ALu.c
blobcb180ee34b91d08526873e6947967b1a979642b5
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 "AL/al.h"
31 #include "AL/alc.h"
32 #include "alSource.h"
33 #include "alBuffer.h"
34 #include "alListener.h"
35 #include "alAuxEffectSlot.h"
36 #include "alu.h"
37 #include "bs2b.h"
39 #include "mixer_defs.h"
42 struct ChanMap {
43 enum Channel channel;
44 ALfloat angle;
47 /* Cone scalar */
48 ALfloat ConeScale = 1.0f;
50 /* Localized Z scalar for mono sources */
51 ALfloat ZScale = 1.0f;
54 static DryMixerFunc SelectDirectMixer(void)
56 #ifdef HAVE_SSE
57 if((CPUCapFlags&CPU_CAP_SSE))
58 return MixDirect_SSE;
59 #endif
60 #ifdef HAVE_NEON
61 if((CPUCapFlags&CPU_CAP_NEON))
62 return MixDirect_Neon;
63 #endif
65 return MixDirect_C;
68 static DryMixerFunc SelectHrtfMixer(void)
70 #ifdef HAVE_SSE
71 if((CPUCapFlags&CPU_CAP_SSE))
72 return MixDirect_Hrtf_SSE;
73 #endif
74 #ifdef HAVE_NEON
75 if((CPUCapFlags&CPU_CAP_NEON))
76 return MixDirect_Hrtf_Neon;
77 #endif
79 return MixDirect_Hrtf_C;
82 static WetMixerFunc SelectSendMixer(void)
84 #ifdef HAVE_SSE
85 if((CPUCapFlags&CPU_CAP_SSE))
86 return MixSend_SSE;
87 #endif
88 #ifdef HAVE_NEON
89 if((CPUCapFlags&CPU_CAP_NEON))
90 return MixSend_Neon;
91 #endif
93 return MixSend_C;
97 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
99 ALfloat temp[4] = {
100 vector[0], vector[1], vector[2], w
103 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
104 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
105 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
109 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
111 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
112 static const struct ChanMap StereoMap[2] = {
113 { FrontLeft, -30.0f * F_PI/180.0f },
114 { FrontRight, 30.0f * F_PI/180.0f }
116 static const struct ChanMap StereoWideMap[2] = {
117 { FrontLeft, -90.0f * F_PI/180.0f },
118 { FrontRight, 90.0f * F_PI/180.0f }
120 static const struct ChanMap RearMap[2] = {
121 { BackLeft, -150.0f * F_PI/180.0f },
122 { BackRight, 150.0f * F_PI/180.0f }
124 static const struct ChanMap QuadMap[4] = {
125 { FrontLeft, -45.0f * F_PI/180.0f },
126 { FrontRight, 45.0f * F_PI/180.0f },
127 { BackLeft, -135.0f * F_PI/180.0f },
128 { BackRight, 135.0f * F_PI/180.0f }
130 static const struct ChanMap X51Map[6] = {
131 { FrontLeft, -30.0f * F_PI/180.0f },
132 { FrontRight, 30.0f * F_PI/180.0f },
133 { FrontCenter, 0.0f * F_PI/180.0f },
134 { LFE, 0.0f },
135 { BackLeft, -110.0f * F_PI/180.0f },
136 { BackRight, 110.0f * F_PI/180.0f }
138 static const struct ChanMap X61Map[7] = {
139 { FrontLeft, -30.0f * F_PI/180.0f },
140 { FrontRight, 30.0f * F_PI/180.0f },
141 { FrontCenter, 0.0f * F_PI/180.0f },
142 { LFE, 0.0f },
143 { BackCenter, 180.0f * F_PI/180.0f },
144 { SideLeft, -90.0f * F_PI/180.0f },
145 { SideRight, 90.0f * F_PI/180.0f }
147 static const struct ChanMap X71Map[8] = {
148 { FrontLeft, -30.0f * F_PI/180.0f },
149 { FrontRight, 30.0f * F_PI/180.0f },
150 { FrontCenter, 0.0f * F_PI/180.0f },
151 { LFE, 0.0f },
152 { BackLeft, -150.0f * F_PI/180.0f },
153 { BackRight, 150.0f * F_PI/180.0f },
154 { SideLeft, -90.0f * F_PI/180.0f },
155 { SideRight, 90.0f * F_PI/180.0f }
158 ALCdevice *Device = ALContext->Device;
159 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
160 ALbufferlistitem *BufferListItem;
161 enum FmtChannels Channels;
162 ALfloat (*SrcMatrix)[MaxChannels];
163 ALfloat DryGain, DryGainHF;
164 ALfloat WetGain[MAX_SENDS];
165 ALfloat WetGainHF[MAX_SENDS];
166 ALint NumSends, Frequency;
167 const struct ChanMap *chans = NULL;
168 enum Resampler Resampler;
169 ALint num_channels = 0;
170 ALboolean DirectChannels;
171 ALfloat hwidth = 0.0f;
172 ALfloat Pitch;
173 ALfloat cw;
174 ALint i, c;
176 /* Get device properties */
177 NumSends = Device->NumAuxSends;
178 Frequency = Device->Frequency;
180 /* Get listener properties */
181 ListenerGain = ALContext->Listener.Gain;
183 /* Get source properties */
184 SourceVolume = ALSource->Gain;
185 MinVolume = ALSource->MinGain;
186 MaxVolume = ALSource->MaxGain;
187 Pitch = ALSource->Pitch;
188 Resampler = ALSource->Resampler;
189 DirectChannels = ALSource->DirectChannels;
191 /* Calculate the stepping value */
192 Channels = FmtMono;
193 BufferListItem = ALSource->queue;
194 while(BufferListItem != NULL)
196 ALbuffer *ALBuffer;
197 if((ALBuffer=BufferListItem->buffer) != NULL)
199 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
200 maxstep -= ResamplerPadding[Resampler] +
201 ResamplerPrePadding[Resampler] + 1;
202 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
204 Pitch = Pitch * ALBuffer->Frequency / Frequency;
205 if(Pitch > (ALfloat)maxstep)
206 ALSource->Params.Step = maxstep<<FRACTIONBITS;
207 else
209 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
210 if(ALSource->Params.Step == 0)
211 ALSource->Params.Step = 1;
214 Channels = ALBuffer->FmtChannels;
215 break;
217 BufferListItem = BufferListItem->next;
219 if(!DirectChannels && Device->Hrtf)
220 ALSource->Params.DryMix = SelectHrtfMixer();
221 else
222 ALSource->Params.DryMix = SelectDirectMixer();
223 ALSource->Params.WetMix = SelectSendMixer();
225 /* Calculate gains */
226 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
227 DryGain *= ALSource->DirectGain * ListenerGain;
228 DryGainHF = ALSource->DirectGainHF;
229 for(i = 0;i < NumSends;i++)
231 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
232 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
233 WetGainHF[i] = ALSource->Send[i].GainHF;
236 SrcMatrix = ALSource->Params.Direct.Gains;
237 for(i = 0;i < MaxChannels;i++)
239 for(c = 0;c < MaxChannels;c++)
240 SrcMatrix[i][c] = 0.0f;
242 switch(Channels)
244 case FmtMono:
245 chans = MonoMap;
246 num_channels = 1;
247 break;
249 case FmtStereo:
250 if(!(Device->Flags&DEVICE_WIDE_STEREO))
251 chans = StereoMap;
252 else
254 chans = StereoWideMap;
255 hwidth = 60.0f * F_PI/180.0f;
257 num_channels = 2;
258 break;
260 case FmtRear:
261 chans = RearMap;
262 num_channels = 2;
263 break;
265 case FmtQuad:
266 chans = QuadMap;
267 num_channels = 4;
268 break;
270 case FmtX51:
271 chans = X51Map;
272 num_channels = 6;
273 break;
275 case FmtX61:
276 chans = X61Map;
277 num_channels = 7;
278 break;
280 case FmtX71:
281 chans = X71Map;
282 num_channels = 8;
283 break;
286 if(DirectChannels != AL_FALSE)
288 for(c = 0;c < num_channels;c++)
290 for(i = 0;i < (ALint)Device->NumChan;i++)
292 enum Channel chan = Device->Speaker2Chan[i];
293 if(chan == chans[c].channel)
295 SrcMatrix[c][chan] += DryGain;
296 break;
301 else if(Device->Hrtf)
303 for(c = 0;c < num_channels;c++)
305 if(chans[c].channel == LFE)
307 /* Skip LFE */
308 ALSource->Params.Direct.Hrtf.Delay[c][0] = 0;
309 ALSource->Params.Direct.Hrtf.Delay[c][1] = 0;
310 for(i = 0;i < HRIR_LENGTH;i++)
312 ALSource->Params.Direct.Hrtf.Coeffs[c][i][0] = 0.0f;
313 ALSource->Params.Direct.Hrtf.Coeffs[c][i][1] = 0.0f;
316 else
318 /* Get the static HRIR coefficients and delays for this
319 * channel. */
320 GetLerpedHrtfCoeffs(Device->Hrtf,
321 0.0f, chans[c].angle, DryGain,
322 ALSource->Params.Direct.Hrtf.Coeffs[c],
323 ALSource->Params.Direct.Hrtf.Delay[c]);
326 ALSource->Hrtf.Counter = 0;
328 else
330 DryGain *= lerp(1.0f, 1.0f/sqrtf(Device->NumChan), hwidth/(F_PI*2.0f));
331 for(c = 0;c < num_channels;c++)
333 /* Special-case LFE */
334 if(chans[c].channel == LFE)
336 SrcMatrix[c][chans[c].channel] = DryGain;
337 continue;
339 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
340 SrcMatrix[c]);
343 for(i = 0;i < NumSends;i++)
345 ALeffectslot *Slot = ALSource->Send[i].Slot;
347 if(!Slot && i == 0)
348 Slot = Device->DefaultSlot;
349 if(Slot && Slot->effect.type == AL_EFFECT_NULL)
350 Slot = NULL;
351 ALSource->Params.Send[i].Slot = Slot;
352 ALSource->Params.Send[i].Gain = WetGain[i];
355 /* Update filter coefficients. Calculations based on the I3DL2
356 * spec. */
357 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
359 /* We use two chained one-pole filters, so we need to take the
360 * square root of the squared gain, which is the same as the base
361 * gain. */
362 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
363 for(i = 0;i < NumSends;i++)
365 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
366 ALSource->Params.Send[i].iirFilter.coeff = a;
370 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
372 const ALCdevice *Device = ALContext->Device;
373 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
374 ALfloat Direction[3],Position[3],SourceToListener[3];
375 ALfloat Velocity[3],ListenerVel[3];
376 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
377 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
378 ALfloat DopplerFactor, SpeedOfSound;
379 ALfloat AirAbsorptionFactor;
380 ALfloat RoomAirAbsorption[MAX_SENDS];
381 ALbufferlistitem *BufferListItem;
382 ALfloat Attenuation;
383 ALfloat RoomAttenuation[MAX_SENDS];
384 ALfloat MetersPerUnit;
385 ALfloat RoomRolloffBase;
386 ALfloat RoomRolloff[MAX_SENDS];
387 ALfloat DecayDistance[MAX_SENDS];
388 ALfloat DryGain;
389 ALfloat DryGainHF;
390 ALboolean DryGainHFAuto;
391 ALfloat WetGain[MAX_SENDS];
392 ALfloat WetGainHF[MAX_SENDS];
393 ALboolean WetGainAuto;
394 ALboolean WetGainHFAuto;
395 enum Resampler Resampler;
396 ALfloat Matrix[4][4];
397 ALfloat Pitch;
398 ALuint Frequency;
399 ALint NumSends;
400 ALfloat cw;
401 ALint i, j;
403 DryGainHF = 1.0f;
404 for(i = 0;i < MAX_SENDS;i++)
405 WetGainHF[i] = 1.0f;
407 /* Get context/device properties */
408 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
409 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
410 NumSends = Device->NumAuxSends;
411 Frequency = Device->Frequency;
413 /* Get listener properties */
414 ListenerGain = ALContext->Listener.Gain;
415 MetersPerUnit = ALContext->Listener.MetersPerUnit;
416 ListenerVel[0] = ALContext->Listener.Velocity[0];
417 ListenerVel[1] = ALContext->Listener.Velocity[1];
418 ListenerVel[2] = ALContext->Listener.Velocity[2];
419 for(i = 0;i < 4;i++)
421 for(j = 0;j < 4;j++)
422 Matrix[i][j] = ALContext->Listener.Matrix[i][j];
425 /* Get source properties */
426 SourceVolume = ALSource->Gain;
427 MinVolume = ALSource->MinGain;
428 MaxVolume = ALSource->MaxGain;
429 Pitch = ALSource->Pitch;
430 Resampler = ALSource->Resampler;
431 Position[0] = ALSource->Position[0];
432 Position[1] = ALSource->Position[1];
433 Position[2] = ALSource->Position[2];
434 Direction[0] = ALSource->Orientation[0];
435 Direction[1] = ALSource->Orientation[1];
436 Direction[2] = ALSource->Orientation[2];
437 Velocity[0] = ALSource->Velocity[0];
438 Velocity[1] = ALSource->Velocity[1];
439 Velocity[2] = ALSource->Velocity[2];
440 MinDist = ALSource->RefDistance;
441 MaxDist = ALSource->MaxDistance;
442 Rolloff = ALSource->RollOffFactor;
443 InnerAngle = ALSource->InnerAngle;
444 OuterAngle = ALSource->OuterAngle;
445 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
446 DryGainHFAuto = ALSource->DryGainHFAuto;
447 WetGainAuto = ALSource->WetGainAuto;
448 WetGainHFAuto = ALSource->WetGainHFAuto;
449 RoomRolloffBase = ALSource->RoomRolloffFactor;
450 for(i = 0;i < NumSends;i++)
452 ALeffectslot *Slot = ALSource->Send[i].Slot;
454 if(!Slot && i == 0)
455 Slot = Device->DefaultSlot;
456 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
458 Slot = NULL;
459 RoomRolloff[i] = 0.0f;
460 DecayDistance[i] = 0.0f;
461 RoomAirAbsorption[i] = 1.0f;
463 else if(Slot->AuxSendAuto)
465 RoomRolloff[i] = RoomRolloffBase;
466 if(IsReverbEffect(Slot->effect.type))
468 RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor;
469 DecayDistance[i] = Slot->effect.Reverb.DecayTime *
470 SPEEDOFSOUNDMETRESPERSEC;
471 RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF;
473 else
475 DecayDistance[i] = 0.0f;
476 RoomAirAbsorption[i] = 1.0f;
479 else
481 /* If the slot's auxiliary send auto is off, the data sent to the
482 * effect slot is the same as the dry path, sans filter effects */
483 RoomRolloff[i] = Rolloff;
484 DecayDistance[i] = 0.0f;
485 RoomAirAbsorption[i] = AIRABSORBGAINHF;
488 ALSource->Params.Send[i].Slot = Slot;
491 /* Transform source to listener space (convert to head relative) */
492 if(ALSource->HeadRelative == AL_FALSE)
494 /* Translate position */
495 Position[0] -= ALContext->Listener.Position[0];
496 Position[1] -= ALContext->Listener.Position[1];
497 Position[2] -= ALContext->Listener.Position[2];
499 /* Transform source vectors */
500 aluMatrixVector(Position, 1.0f, Matrix);
501 aluMatrixVector(Direction, 0.0f, Matrix);
502 aluMatrixVector(Velocity, 0.0f, Matrix);
503 /* Transform listener velocity */
504 aluMatrixVector(ListenerVel, 0.0f, Matrix);
506 else
508 /* Transform listener velocity from world space to listener space */
509 aluMatrixVector(ListenerVel, 0.0f, Matrix);
510 /* Offset the source velocity to be relative of the listener velocity */
511 Velocity[0] += ListenerVel[0];
512 Velocity[1] += ListenerVel[1];
513 Velocity[2] += ListenerVel[2];
516 SourceToListener[0] = -Position[0];
517 SourceToListener[1] = -Position[1];
518 SourceToListener[2] = -Position[2];
519 aluNormalize(SourceToListener);
520 aluNormalize(Direction);
522 /* Calculate distance attenuation */
523 Distance = sqrtf(aluDotproduct(Position, Position));
524 ClampedDist = Distance;
526 Attenuation = 1.0f;
527 for(i = 0;i < NumSends;i++)
528 RoomAttenuation[i] = 1.0f;
529 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
530 ALContext->DistanceModel)
532 case InverseDistanceClamped:
533 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
534 if(MaxDist < MinDist)
535 break;
536 /*fall-through*/
537 case InverseDistance:
538 if(MinDist > 0.0f)
540 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
541 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
542 for(i = 0;i < NumSends;i++)
544 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
545 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
548 break;
550 case LinearDistanceClamped:
551 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
552 if(MaxDist < MinDist)
553 break;
554 /*fall-through*/
555 case LinearDistance:
556 if(MaxDist != MinDist)
558 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
559 Attenuation = maxf(Attenuation, 0.0f);
560 for(i = 0;i < NumSends;i++)
562 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
563 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
566 break;
568 case ExponentDistanceClamped:
569 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
570 if(MaxDist < MinDist)
571 break;
572 /*fall-through*/
573 case ExponentDistance:
574 if(ClampedDist > 0.0f && MinDist > 0.0f)
576 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
577 for(i = 0;i < NumSends;i++)
578 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
580 break;
582 case DisableDistance:
583 ClampedDist = MinDist;
584 break;
587 /* Source Gain + Attenuation */
588 DryGain = SourceVolume * Attenuation;
589 for(i = 0;i < NumSends;i++)
590 WetGain[i] = SourceVolume * RoomAttenuation[i];
592 /* Distance-based air absorption */
593 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
595 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
596 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
597 for(i = 0;i < NumSends;i++)
598 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
601 if(WetGainAuto)
603 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
605 /* Apply a decay-time transformation to the wet path, based on the
606 * attenuation of the dry path.
608 * Using the apparent distance, based on the distance attenuation, the
609 * initial decay of the reverb effect is calculated and applied to the
610 * wet path.
612 for(i = 0;i < NumSends;i++)
614 if(DecayDistance[i] > 0.0f)
615 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
619 /* Calculate directional soundcones */
620 Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI);
621 if(Angle > InnerAngle && Angle <= OuterAngle)
623 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
624 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
625 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
627 else if(Angle > OuterAngle)
629 ConeVolume = ALSource->OuterGain;
630 ConeHF = ALSource->OuterGainHF;
632 else
634 ConeVolume = 1.0f;
635 ConeHF = 1.0f;
638 DryGain *= ConeVolume;
639 if(WetGainAuto)
641 for(i = 0;i < NumSends;i++)
642 WetGain[i] *= ConeVolume;
644 if(DryGainHFAuto)
645 DryGainHF *= ConeHF;
646 if(WetGainHFAuto)
648 for(i = 0;i < NumSends;i++)
649 WetGainHF[i] *= ConeHF;
652 /* Clamp to Min/Max Gain */
653 DryGain = clampf(DryGain, MinVolume, MaxVolume);
654 for(i = 0;i < NumSends;i++)
655 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
657 /* Apply gain and frequency filters */
658 DryGain *= ALSource->DirectGain * ListenerGain;
659 DryGainHF *= ALSource->DirectGainHF;
660 for(i = 0;i < NumSends;i++)
662 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
663 WetGainHF[i] *= ALSource->Send[i].GainHF;
666 /* Calculate velocity-based doppler effect */
667 if(DopplerFactor > 0.0f)
669 ALfloat VSS, VLS;
671 if(SpeedOfSound < 1.0f)
673 DopplerFactor *= 1.0f/SpeedOfSound;
674 SpeedOfSound = 1.0f;
677 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
678 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
680 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
681 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
684 BufferListItem = ALSource->queue;
685 while(BufferListItem != NULL)
687 ALbuffer *ALBuffer;
688 if((ALBuffer=BufferListItem->buffer) != NULL)
690 /* Calculate fixed-point stepping value, based on the pitch, buffer
691 * frequency, and output frequency. */
692 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
693 maxstep -= ResamplerPadding[Resampler] +
694 ResamplerPrePadding[Resampler] + 1;
695 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
697 Pitch = Pitch * ALBuffer->Frequency / Frequency;
698 if(Pitch > (ALfloat)maxstep)
699 ALSource->Params.Step = maxstep<<FRACTIONBITS;
700 else
702 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
703 if(ALSource->Params.Step == 0)
704 ALSource->Params.Step = 1;
707 break;
709 BufferListItem = BufferListItem->next;
711 if(Device->Hrtf)
712 ALSource->Params.DryMix = SelectHrtfMixer();
713 else
714 ALSource->Params.DryMix = SelectDirectMixer();
715 ALSource->Params.WetMix = SelectSendMixer();
717 if(Device->Hrtf)
719 /* Use a binaural HRTF algorithm for stereo headphone playback */
720 ALfloat delta, ev = 0.0f, az = 0.0f;
722 if(Distance > 0.0f)
724 ALfloat invlen = 1.0f/Distance;
725 Position[0] *= invlen;
726 Position[1] *= invlen;
727 Position[2] *= invlen;
729 /* Calculate elevation and azimuth only when the source is not at
730 * the listener. This prevents +0 and -0 Z from producing
731 * inconsistent panning. Also, clamp Y in case FP precision errors
732 * cause it to land outside of -1..+1. */
733 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
734 az = atan2f(Position[0], -Position[2]*ZScale);
737 /* Check to see if the HRIR is already moving. */
738 if(ALSource->Hrtf.Moving)
740 /* Calculate the normalized HRTF transition factor (delta). */
741 delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Gain, DryGain,
742 ALSource->Params.Direct.Hrtf.Dir, Position);
743 /* If the delta is large enough, get the moving HRIR target
744 * coefficients, target delays, steppping values, and counter. */
745 if(delta > 0.001f)
747 ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
748 ev, az, DryGain, delta,
749 ALSource->Hrtf.Counter,
750 ALSource->Params.Direct.Hrtf.Coeffs[0],
751 ALSource->Params.Direct.Hrtf.Delay[0],
752 ALSource->Params.Direct.Hrtf.CoeffStep,
753 ALSource->Params.Direct.Hrtf.DelayStep);
754 ALSource->Params.Direct.Hrtf.Gain = DryGain;
755 ALSource->Params.Direct.Hrtf.Dir[0] = Position[0];
756 ALSource->Params.Direct.Hrtf.Dir[1] = Position[1];
757 ALSource->Params.Direct.Hrtf.Dir[2] = Position[2];
760 else
762 /* Get the initial (static) HRIR coefficients and delays. */
763 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
764 ALSource->Params.Direct.Hrtf.Coeffs[0],
765 ALSource->Params.Direct.Hrtf.Delay[0]);
766 ALSource->Hrtf.Counter = 0;
767 ALSource->Params.Direct.Hrtf.Gain = DryGain;
768 ALSource->Params.Direct.Hrtf.Dir[0] = Position[0];
769 ALSource->Params.Direct.Hrtf.Dir[1] = Position[1];
770 ALSource->Params.Direct.Hrtf.Dir[2] = Position[2];
773 else
775 ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
776 ALfloat DirGain = 0.0f;
777 ALfloat AmbientGain;
779 for(i = 0;i < MaxChannels;i++)
781 for(j = 0;j < MaxChannels;j++)
782 Matrix[i][j] = 0.0f;
785 /* Normalize the length, and compute panned gains. */
786 if(Distance > 0.0f)
788 ALfloat invlen = 1.0f/Distance;
789 Position[0] *= invlen;
790 Position[1] *= invlen;
791 Position[2] *= invlen;
793 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
794 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
795 DryGain*DirGain, Matrix[0]);
798 /* Adjustment for vertical offsets. Not the greatest, but simple
799 * enough. */
800 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
801 for(i = 0;i < (ALint)Device->NumChan;i++)
803 enum Channel chan = Device->Speaker2Chan[i];
804 Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
807 for(i = 0;i < NumSends;i++)
808 ALSource->Params.Send[i].Gain = WetGain[i];
810 /* Update filter coefficients. */
811 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
813 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
814 for(i = 0;i < NumSends;i++)
816 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
817 ALSource->Params.Send[i].iirFilter.coeff = a;
822 static __inline ALfloat aluF2F(ALfloat val)
823 { return val; }
824 static __inline ALint aluF2I(ALfloat val)
826 if(val > 1.0f) return 2147483647;
827 if(val < -1.0f) return -2147483647-1;
828 return fastf2i((ALfloat)(val*2147483647.0));
830 static __inline ALuint aluF2UI(ALfloat val)
831 { return aluF2I(val)+2147483648u; }
832 static __inline ALshort aluF2S(ALfloat val)
833 { return aluF2I(val)>>16; }
834 static __inline ALushort aluF2US(ALfloat val)
835 { return aluF2S(val)+32768; }
836 static __inline ALbyte aluF2B(ALfloat val)
837 { return aluF2I(val)>>24; }
838 static __inline ALubyte aluF2UB(ALfloat val)
839 { return aluF2B(val)+128; }
841 #define DECL_TEMPLATE(T, func) \
842 static void Write_##T(ALCdevice *device, T *RESTRICT buffer, \
843 ALuint SamplesToDo) \
845 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
846 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
847 const enum Channel *ChanMap = device->DevChannels; \
848 ALuint i, j; \
850 for(j = 0;j < numchans;j++) \
852 T *RESTRICT out = buffer + j; \
853 enum Channel chan = ChanMap[j]; \
855 for(i = 0;i < SamplesToDo;i++) \
856 out[i*numchans] = func(DryBuffer[chan][i]); \
860 DECL_TEMPLATE(ALfloat, aluF2F)
861 DECL_TEMPLATE(ALuint, aluF2UI)
862 DECL_TEMPLATE(ALint, aluF2I)
863 DECL_TEMPLATE(ALushort, aluF2US)
864 DECL_TEMPLATE(ALshort, aluF2S)
865 DECL_TEMPLATE(ALubyte, aluF2UB)
866 DECL_TEMPLATE(ALbyte, aluF2B)
868 #undef DECL_TEMPLATE
871 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
873 ALuint SamplesToDo;
874 ALeffectslot **slot, **slot_end;
875 ALsource **src, **src_end;
876 ALCcontext *ctx;
877 int fpuState;
878 ALuint i, c;
880 fpuState = SetMixerFPUMode();
882 while(size > 0)
884 SamplesToDo = minu(size, BUFFERSIZE);
885 for(c = 0;c < MaxChannels;c++)
886 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
888 ALCdevice_Lock(device);
889 ctx = device->ContextList;
890 while(ctx)
892 ALenum DeferUpdates = ctx->DeferUpdates;
893 ALenum UpdateSources = AL_FALSE;
895 if(!DeferUpdates)
896 UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE);
898 /* source processing */
899 src = ctx->ActiveSources;
900 src_end = src + ctx->ActiveSourceCount;
901 while(src != src_end)
903 if((*src)->state != AL_PLAYING)
905 --(ctx->ActiveSourceCount);
906 *src = *(--src_end);
907 continue;
910 if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
911 UpdateSources))
912 ALsource_Update(*src, ctx);
914 MixSource(*src, device, SamplesToDo);
915 src++;
918 /* effect slot processing */
919 slot = ctx->ActiveEffectSlots;
920 slot_end = slot + ctx->ActiveEffectSlotCount;
921 while(slot != slot_end)
923 for(c = 0;c < SamplesToDo;c++)
925 (*slot)->WetBuffer[c] += (*slot)->ClickRemoval[0];
926 (*slot)->ClickRemoval[0] -= (*slot)->ClickRemoval[0] * (1.0f/256.0f);
928 (*slot)->ClickRemoval[0] += (*slot)->PendingClicks[0];
929 (*slot)->PendingClicks[0] = 0.0f;
931 if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
932 ALeffectState_Update((*slot)->EffectState, device, *slot);
934 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
935 (*slot)->WetBuffer, device->DryBuffer);
937 for(i = 0;i < SamplesToDo;i++)
938 (*slot)->WetBuffer[i] = 0.0f;
940 slot++;
943 ctx = ctx->next;
946 slot = &device->DefaultSlot;
947 if(*slot != NULL)
949 for(c = 0;c < SamplesToDo;c++)
951 (*slot)->WetBuffer[c] += (*slot)->ClickRemoval[0];
952 (*slot)->ClickRemoval[0] -= (*slot)->ClickRemoval[0] * (1.0f/256.0f);
954 (*slot)->ClickRemoval[0] += (*slot)->PendingClicks[0];
955 (*slot)->PendingClicks[0] = 0.0f;
957 if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
958 ALeffectState_Update((*slot)->EffectState, device, *slot);
960 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
961 (*slot)->WetBuffer, device->DryBuffer);
963 for(i = 0;i < SamplesToDo;i++)
964 (*slot)->WetBuffer[i] = 0.0f;
966 ALCdevice_Unlock(device);
968 /* Click-removal. Could do better; this only really handles immediate
969 * changes between updates where a predictive sample could be
970 * generated. Delays caused by effects and HRTF aren't caught. */
971 if(device->FmtChans == DevFmtMono)
973 for(i = 0;i < SamplesToDo;i++)
975 device->DryBuffer[FrontCenter][i] += device->ClickRemoval[FrontCenter];
976 device->ClickRemoval[FrontCenter] -= device->ClickRemoval[FrontCenter] * (1.0f/256.0f);
978 device->ClickRemoval[FrontCenter] += device->PendingClicks[FrontCenter];
979 device->PendingClicks[FrontCenter] = 0.0f;
981 else if(device->FmtChans == DevFmtStereo)
983 /* Assumes the first two channels are FrontLeft and FrontRight */
984 for(c = 0;c < 2;c++)
986 ALfloat offset = device->ClickRemoval[c];
987 for(i = 0;i < SamplesToDo;i++)
989 device->DryBuffer[c][i] += offset;
990 offset -= offset * (1.0f/256.0f);
992 device->ClickRemoval[c] = offset + device->PendingClicks[c];
993 device->PendingClicks[c] = 0.0f;
995 if(device->Bs2b)
997 float samples[2];
998 for(i = 0;i < SamplesToDo;i++)
1000 samples[0] = device->DryBuffer[FrontLeft][i];
1001 samples[1] = device->DryBuffer[FrontRight][i];
1002 bs2b_cross_feed(device->Bs2b, samples);
1003 device->DryBuffer[FrontLeft][i] = samples[0];
1004 device->DryBuffer[FrontRight][i] = samples[1];
1008 else
1010 for(c = 0;c < MaxChannels;c++)
1012 ALfloat offset = device->ClickRemoval[c];
1013 for(i = 0;i < SamplesToDo;i++)
1015 device->DryBuffer[c][i] += offset;
1016 offset -= offset * (1.0f/256.0f);
1018 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1019 device->PendingClicks[c] = 0.0f;
1023 if(buffer)
1025 switch(device->FmtType)
1027 case DevFmtByte:
1028 Write_ALbyte(device, buffer, SamplesToDo);
1029 break;
1030 case DevFmtUByte:
1031 Write_ALubyte(device, buffer, SamplesToDo);
1032 break;
1033 case DevFmtShort:
1034 Write_ALshort(device, buffer, SamplesToDo);
1035 break;
1036 case DevFmtUShort:
1037 Write_ALushort(device, buffer, SamplesToDo);
1038 break;
1039 case DevFmtInt:
1040 Write_ALint(device, buffer, SamplesToDo);
1041 break;
1042 case DevFmtUInt:
1043 Write_ALuint(device, buffer, SamplesToDo);
1044 break;
1045 case DevFmtFloat:
1046 Write_ALfloat(device, buffer, SamplesToDo);
1047 break;
1051 size -= SamplesToDo;
1054 RestoreFPUMode(fpuState);
1058 ALvoid aluHandleDisconnect(ALCdevice *device)
1060 ALCcontext *Context;
1062 ALCdevice_Lock(device);
1063 device->Connected = ALC_FALSE;
1065 Context = device->ContextList;
1066 while(Context)
1068 ALsource **src, **src_end;
1070 src = Context->ActiveSources;
1071 src_end = src + Context->ActiveSourceCount;
1072 while(src != src_end)
1074 if((*src)->state == AL_PLAYING)
1076 (*src)->state = AL_STOPPED;
1077 (*src)->BuffersPlayed = (*src)->BuffersInQueue;
1078 (*src)->position = 0;
1079 (*src)->position_fraction = 0;
1081 src++;
1083 Context->ActiveSourceCount = 0;
1085 Context = Context->next;
1087 ALCdevice_Unlock(device);