Ensure the device's default effect slot is properly aligned
[openal-soft.git] / Alc / ALu.c
blob7f906232a8102ee5115d2174368f00bf98271f0c
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 ResamplerFunc SelectResampler(enum Resampler Resampler, ALuint increment)
56 if(increment == FRACTIONONE)
57 return Resample_point32_C;
58 switch(Resampler)
60 case PointResampler:
61 return Resample_point32_C;
62 case LinearResampler:
63 return Resample_lerp32_C;
64 case CubicResampler:
65 return Resample_cubic32_C;
66 case ResamplerMax:
67 /* Shouldn't happen */
68 break;
71 return Resample_point32_C;
75 static DryMixerFunc SelectHrtfMixer(void)
77 #ifdef HAVE_SSE
78 if((CPUCapFlags&CPU_CAP_SSE))
79 return MixDirect_Hrtf_SSE;
80 #endif
81 #ifdef HAVE_NEON
82 if((CPUCapFlags&CPU_CAP_NEON))
83 return MixDirect_Hrtf_Neon;
84 #endif
86 return MixDirect_Hrtf_C;
89 static DryMixerFunc SelectDirectMixer(void)
91 #ifdef HAVE_SSE
92 if((CPUCapFlags&CPU_CAP_SSE))
93 return MixDirect_SSE;
94 #endif
96 return MixDirect_C;
99 static WetMixerFunc SelectSendMixer(void)
101 #ifdef HAVE_SSE
102 if((CPUCapFlags&CPU_CAP_SSE))
103 return MixSend_SSE;
104 #endif
106 return MixSend_C;
110 static __inline ALvoid aluMatrixVector(ALfloat *vector,ALfloat w,ALfloat matrix[4][4])
112 ALfloat temp[4] = {
113 vector[0], vector[1], vector[2], w
116 vector[0] = temp[0]*matrix[0][0] + temp[1]*matrix[1][0] + temp[2]*matrix[2][0] + temp[3]*matrix[3][0];
117 vector[1] = temp[0]*matrix[0][1] + temp[1]*matrix[1][1] + temp[2]*matrix[2][1] + temp[3]*matrix[3][1];
118 vector[2] = temp[0]*matrix[0][2] + temp[1]*matrix[1][2] + temp[2]*matrix[2][2] + temp[3]*matrix[3][2];
122 ALvoid CalcNonAttnSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
124 static const struct ChanMap MonoMap[1] = { { FrontCenter, 0.0f } };
125 static const struct ChanMap StereoMap[2] = {
126 { FrontLeft, -30.0f * F_PI/180.0f },
127 { FrontRight, 30.0f * F_PI/180.0f }
129 static const struct ChanMap StereoWideMap[2] = {
130 { FrontLeft, -90.0f * F_PI/180.0f },
131 { FrontRight, 90.0f * F_PI/180.0f }
133 static const struct ChanMap RearMap[2] = {
134 { BackLeft, -150.0f * F_PI/180.0f },
135 { BackRight, 150.0f * F_PI/180.0f }
137 static const struct ChanMap QuadMap[4] = {
138 { FrontLeft, -45.0f * F_PI/180.0f },
139 { FrontRight, 45.0f * F_PI/180.0f },
140 { BackLeft, -135.0f * F_PI/180.0f },
141 { BackRight, 135.0f * F_PI/180.0f }
143 static const struct ChanMap X51Map[6] = {
144 { FrontLeft, -30.0f * F_PI/180.0f },
145 { FrontRight, 30.0f * F_PI/180.0f },
146 { FrontCenter, 0.0f * F_PI/180.0f },
147 { LFE, 0.0f },
148 { BackLeft, -110.0f * F_PI/180.0f },
149 { BackRight, 110.0f * F_PI/180.0f }
151 static const struct ChanMap X61Map[7] = {
152 { FrontLeft, -30.0f * F_PI/180.0f },
153 { FrontRight, 30.0f * F_PI/180.0f },
154 { FrontCenter, 0.0f * F_PI/180.0f },
155 { LFE, 0.0f },
156 { BackCenter, 180.0f * F_PI/180.0f },
157 { SideLeft, -90.0f * F_PI/180.0f },
158 { SideRight, 90.0f * F_PI/180.0f }
160 static const struct ChanMap X71Map[8] = {
161 { FrontLeft, -30.0f * F_PI/180.0f },
162 { FrontRight, 30.0f * F_PI/180.0f },
163 { FrontCenter, 0.0f * F_PI/180.0f },
164 { LFE, 0.0f },
165 { BackLeft, -150.0f * F_PI/180.0f },
166 { BackRight, 150.0f * F_PI/180.0f },
167 { SideLeft, -90.0f * F_PI/180.0f },
168 { SideRight, 90.0f * F_PI/180.0f }
171 ALCdevice *Device = ALContext->Device;
172 ALfloat SourceVolume,ListenerGain,MinVolume,MaxVolume;
173 ALbufferlistitem *BufferListItem;
174 enum FmtChannels Channels;
175 ALfloat (*SrcMatrix)[MaxChannels];
176 ALfloat DryGain, DryGainHF;
177 ALfloat WetGain[MAX_SENDS];
178 ALfloat WetGainHF[MAX_SENDS];
179 ALint NumSends, Frequency;
180 const struct ChanMap *chans = NULL;
181 enum Resampler Resampler;
182 ALint num_channels = 0;
183 ALboolean DirectChannels;
184 ALfloat hwidth = 0.0f;
185 ALfloat Pitch;
186 ALfloat cw;
187 ALint i, c;
189 /* Get device properties */
190 NumSends = Device->NumAuxSends;
191 Frequency = Device->Frequency;
193 /* Get listener properties */
194 ListenerGain = ALContext->Listener.Gain;
196 /* Get source properties */
197 SourceVolume = ALSource->Gain;
198 MinVolume = ALSource->MinGain;
199 MaxVolume = ALSource->MaxGain;
200 Pitch = ALSource->Pitch;
201 Resampler = ALSource->Resampler;
202 DirectChannels = ALSource->DirectChannels;
204 /* Calculate the stepping value */
205 Channels = FmtMono;
206 BufferListItem = ALSource->queue;
207 while(BufferListItem != NULL)
209 ALbuffer *ALBuffer;
210 if((ALBuffer=BufferListItem->buffer) != NULL)
212 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
213 maxstep -= ResamplerPadding[Resampler] +
214 ResamplerPrePadding[Resampler] + 1;
215 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
217 Pitch = Pitch * ALBuffer->Frequency / Frequency;
218 if(Pitch > (ALfloat)maxstep)
219 ALSource->Params.Step = maxstep<<FRACTIONBITS;
220 else
222 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
223 if(ALSource->Params.Step == 0)
224 ALSource->Params.Step = 1;
226 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
228 Channels = ALBuffer->FmtChannels;
229 break;
231 BufferListItem = BufferListItem->next;
233 if(!DirectChannels && Device->Hrtf)
234 ALSource->Params.DryMix = SelectHrtfMixer();
235 else
236 ALSource->Params.DryMix = SelectDirectMixer();
237 ALSource->Params.WetMix = SelectSendMixer();
239 /* Calculate gains */
240 DryGain = clampf(SourceVolume, MinVolume, MaxVolume);
241 DryGain *= ALSource->DirectGain * ListenerGain;
242 DryGainHF = ALSource->DirectGainHF;
243 for(i = 0;i < NumSends;i++)
245 WetGain[i] = clampf(SourceVolume, MinVolume, MaxVolume);
246 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
247 WetGainHF[i] = ALSource->Send[i].GainHF;
250 SrcMatrix = ALSource->Params.Direct.Gains;
251 for(i = 0;i < MaxChannels;i++)
253 for(c = 0;c < MaxChannels;c++)
254 SrcMatrix[i][c] = 0.0f;
256 switch(Channels)
258 case FmtMono:
259 chans = MonoMap;
260 num_channels = 1;
261 break;
263 case FmtStereo:
264 if(!(Device->Flags&DEVICE_WIDE_STEREO))
265 chans = StereoMap;
266 else
268 chans = StereoWideMap;
269 hwidth = 60.0f * F_PI/180.0f;
271 num_channels = 2;
272 break;
274 case FmtRear:
275 chans = RearMap;
276 num_channels = 2;
277 break;
279 case FmtQuad:
280 chans = QuadMap;
281 num_channels = 4;
282 break;
284 case FmtX51:
285 chans = X51Map;
286 num_channels = 6;
287 break;
289 case FmtX61:
290 chans = X61Map;
291 num_channels = 7;
292 break;
294 case FmtX71:
295 chans = X71Map;
296 num_channels = 8;
297 break;
300 if(DirectChannels != AL_FALSE)
302 for(c = 0;c < num_channels;c++)
304 for(i = 0;i < (ALint)Device->NumChan;i++)
306 enum Channel chan = Device->Speaker2Chan[i];
307 if(chan == chans[c].channel)
309 SrcMatrix[c][chan] += DryGain;
310 break;
315 else if(Device->Hrtf)
317 for(c = 0;c < num_channels;c++)
319 if(chans[c].channel == LFE)
321 /* Skip LFE */
322 ALSource->Params.Direct.Hrtf.Delay[c][0] = 0;
323 ALSource->Params.Direct.Hrtf.Delay[c][1] = 0;
324 for(i = 0;i < HRIR_LENGTH;i++)
326 ALSource->Params.Direct.Hrtf.Coeffs[c][i][0] = 0.0f;
327 ALSource->Params.Direct.Hrtf.Coeffs[c][i][1] = 0.0f;
330 else
332 /* Get the static HRIR coefficients and delays for this
333 * channel. */
334 GetLerpedHrtfCoeffs(Device->Hrtf,
335 0.0f, chans[c].angle, DryGain,
336 ALSource->Params.Direct.Hrtf.Coeffs[c],
337 ALSource->Params.Direct.Hrtf.Delay[c]);
340 ALSource->Hrtf.Counter = 0;
342 else
344 DryGain *= lerp(1.0f, 1.0f/sqrtf(Device->NumChan), hwidth/(F_PI*2.0f));
345 for(c = 0;c < num_channels;c++)
347 /* Special-case LFE */
348 if(chans[c].channel == LFE)
350 SrcMatrix[c][chans[c].channel] = DryGain;
351 continue;
353 ComputeAngleGains(Device, chans[c].angle, hwidth, DryGain,
354 SrcMatrix[c]);
357 for(i = 0;i < NumSends;i++)
359 ALeffectslot *Slot = ALSource->Send[i].Slot;
361 if(!Slot && i == 0)
362 Slot = Device->DefaultSlot;
363 if(Slot && Slot->effect.type == AL_EFFECT_NULL)
364 Slot = NULL;
365 ALSource->Params.Send[i].Slot = Slot;
366 ALSource->Params.Send[i].Gain = WetGain[i];
369 /* Update filter coefficients. Calculations based on the I3DL2
370 * spec. */
371 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
373 /* We use two chained one-pole filters, so we need to take the
374 * square root of the squared gain, which is the same as the base
375 * gain. */
376 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
377 for(i = 0;i < NumSends;i++)
379 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
380 ALSource->Params.Send[i].iirFilter.coeff = a;
384 ALvoid CalcSourceParams(ALsource *ALSource, const ALCcontext *ALContext)
386 const ALCdevice *Device = ALContext->Device;
387 ALfloat InnerAngle,OuterAngle,Angle,Distance,ClampedDist;
388 ALfloat Direction[3],Position[3],SourceToListener[3];
389 ALfloat Velocity[3],ListenerVel[3];
390 ALfloat MinVolume,MaxVolume,MinDist,MaxDist,Rolloff;
391 ALfloat ConeVolume,ConeHF,SourceVolume,ListenerGain;
392 ALfloat DopplerFactor, SpeedOfSound;
393 ALfloat AirAbsorptionFactor;
394 ALfloat RoomAirAbsorption[MAX_SENDS];
395 ALbufferlistitem *BufferListItem;
396 ALfloat Attenuation;
397 ALfloat RoomAttenuation[MAX_SENDS];
398 ALfloat MetersPerUnit;
399 ALfloat RoomRolloffBase;
400 ALfloat RoomRolloff[MAX_SENDS];
401 ALfloat DecayDistance[MAX_SENDS];
402 ALfloat DryGain;
403 ALfloat DryGainHF;
404 ALboolean DryGainHFAuto;
405 ALfloat WetGain[MAX_SENDS];
406 ALfloat WetGainHF[MAX_SENDS];
407 ALboolean WetGainAuto;
408 ALboolean WetGainHFAuto;
409 enum Resampler Resampler;
410 ALfloat Matrix[4][4];
411 ALfloat Pitch;
412 ALuint Frequency;
413 ALint NumSends;
414 ALfloat cw;
415 ALint i, j;
417 DryGainHF = 1.0f;
418 for(i = 0;i < MAX_SENDS;i++)
419 WetGainHF[i] = 1.0f;
421 /* Get context/device properties */
422 DopplerFactor = ALContext->DopplerFactor * ALSource->DopplerFactor;
423 SpeedOfSound = ALContext->SpeedOfSound * ALContext->DopplerVelocity;
424 NumSends = Device->NumAuxSends;
425 Frequency = Device->Frequency;
427 /* Get listener properties */
428 ListenerGain = ALContext->Listener.Gain;
429 MetersPerUnit = ALContext->Listener.MetersPerUnit;
430 ListenerVel[0] = ALContext->Listener.Velocity[0];
431 ListenerVel[1] = ALContext->Listener.Velocity[1];
432 ListenerVel[2] = ALContext->Listener.Velocity[2];
433 for(i = 0;i < 4;i++)
435 for(j = 0;j < 4;j++)
436 Matrix[i][j] = ALContext->Listener.Matrix[i][j];
439 /* Get source properties */
440 SourceVolume = ALSource->Gain;
441 MinVolume = ALSource->MinGain;
442 MaxVolume = ALSource->MaxGain;
443 Pitch = ALSource->Pitch;
444 Resampler = ALSource->Resampler;
445 Position[0] = ALSource->Position[0];
446 Position[1] = ALSource->Position[1];
447 Position[2] = ALSource->Position[2];
448 Direction[0] = ALSource->Orientation[0];
449 Direction[1] = ALSource->Orientation[1];
450 Direction[2] = ALSource->Orientation[2];
451 Velocity[0] = ALSource->Velocity[0];
452 Velocity[1] = ALSource->Velocity[1];
453 Velocity[2] = ALSource->Velocity[2];
454 MinDist = ALSource->RefDistance;
455 MaxDist = ALSource->MaxDistance;
456 Rolloff = ALSource->RollOffFactor;
457 InnerAngle = ALSource->InnerAngle;
458 OuterAngle = ALSource->OuterAngle;
459 AirAbsorptionFactor = ALSource->AirAbsorptionFactor;
460 DryGainHFAuto = ALSource->DryGainHFAuto;
461 WetGainAuto = ALSource->WetGainAuto;
462 WetGainHFAuto = ALSource->WetGainHFAuto;
463 RoomRolloffBase = ALSource->RoomRolloffFactor;
464 for(i = 0;i < NumSends;i++)
466 ALeffectslot *Slot = ALSource->Send[i].Slot;
468 if(!Slot && i == 0)
469 Slot = Device->DefaultSlot;
470 if(!Slot || Slot->effect.type == AL_EFFECT_NULL)
472 Slot = NULL;
473 RoomRolloff[i] = 0.0f;
474 DecayDistance[i] = 0.0f;
475 RoomAirAbsorption[i] = 1.0f;
477 else if(Slot->AuxSendAuto)
479 RoomRolloff[i] = RoomRolloffBase;
480 if(IsReverbEffect(Slot->effect.type))
482 RoomRolloff[i] += Slot->effect.Reverb.RoomRolloffFactor;
483 DecayDistance[i] = Slot->effect.Reverb.DecayTime *
484 SPEEDOFSOUNDMETRESPERSEC;
485 RoomAirAbsorption[i] = Slot->effect.Reverb.AirAbsorptionGainHF;
487 else
489 DecayDistance[i] = 0.0f;
490 RoomAirAbsorption[i] = 1.0f;
493 else
495 /* If the slot's auxiliary send auto is off, the data sent to the
496 * effect slot is the same as the dry path, sans filter effects */
497 RoomRolloff[i] = Rolloff;
498 DecayDistance[i] = 0.0f;
499 RoomAirAbsorption[i] = AIRABSORBGAINHF;
502 ALSource->Params.Send[i].Slot = Slot;
505 /* Transform source to listener space (convert to head relative) */
506 if(ALSource->HeadRelative == AL_FALSE)
508 /* Translate position */
509 Position[0] -= ALContext->Listener.Position[0];
510 Position[1] -= ALContext->Listener.Position[1];
511 Position[2] -= ALContext->Listener.Position[2];
513 /* Transform source vectors */
514 aluMatrixVector(Position, 1.0f, Matrix);
515 aluMatrixVector(Direction, 0.0f, Matrix);
516 aluMatrixVector(Velocity, 0.0f, Matrix);
517 /* Transform listener velocity */
518 aluMatrixVector(ListenerVel, 0.0f, Matrix);
520 else
522 /* Transform listener velocity from world space to listener space */
523 aluMatrixVector(ListenerVel, 0.0f, Matrix);
524 /* Offset the source velocity to be relative of the listener velocity */
525 Velocity[0] += ListenerVel[0];
526 Velocity[1] += ListenerVel[1];
527 Velocity[2] += ListenerVel[2];
530 SourceToListener[0] = -Position[0];
531 SourceToListener[1] = -Position[1];
532 SourceToListener[2] = -Position[2];
533 aluNormalize(SourceToListener);
534 aluNormalize(Direction);
536 /* Calculate distance attenuation */
537 Distance = sqrtf(aluDotproduct(Position, Position));
538 ClampedDist = Distance;
540 Attenuation = 1.0f;
541 for(i = 0;i < NumSends;i++)
542 RoomAttenuation[i] = 1.0f;
543 switch(ALContext->SourceDistanceModel ? ALSource->DistanceModel :
544 ALContext->DistanceModel)
546 case InverseDistanceClamped:
547 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
548 if(MaxDist < MinDist)
549 break;
550 /*fall-through*/
551 case InverseDistance:
552 if(MinDist > 0.0f)
554 if((MinDist + (Rolloff * (ClampedDist - MinDist))) > 0.0f)
555 Attenuation = MinDist / (MinDist + (Rolloff * (ClampedDist - MinDist)));
556 for(i = 0;i < NumSends;i++)
558 if((MinDist + (RoomRolloff[i] * (ClampedDist - MinDist))) > 0.0f)
559 RoomAttenuation[i] = MinDist / (MinDist + (RoomRolloff[i] * (ClampedDist - MinDist)));
562 break;
564 case LinearDistanceClamped:
565 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
566 if(MaxDist < MinDist)
567 break;
568 /*fall-through*/
569 case LinearDistance:
570 if(MaxDist != MinDist)
572 Attenuation = 1.0f - (Rolloff*(ClampedDist-MinDist)/(MaxDist - MinDist));
573 Attenuation = maxf(Attenuation, 0.0f);
574 for(i = 0;i < NumSends;i++)
576 RoomAttenuation[i] = 1.0f - (RoomRolloff[i]*(ClampedDist-MinDist)/(MaxDist - MinDist));
577 RoomAttenuation[i] = maxf(RoomAttenuation[i], 0.0f);
580 break;
582 case ExponentDistanceClamped:
583 ClampedDist = clampf(ClampedDist, MinDist, MaxDist);
584 if(MaxDist < MinDist)
585 break;
586 /*fall-through*/
587 case ExponentDistance:
588 if(ClampedDist > 0.0f && MinDist > 0.0f)
590 Attenuation = powf(ClampedDist/MinDist, -Rolloff);
591 for(i = 0;i < NumSends;i++)
592 RoomAttenuation[i] = powf(ClampedDist/MinDist, -RoomRolloff[i]);
594 break;
596 case DisableDistance:
597 ClampedDist = MinDist;
598 break;
601 /* Source Gain + Attenuation */
602 DryGain = SourceVolume * Attenuation;
603 for(i = 0;i < NumSends;i++)
604 WetGain[i] = SourceVolume * RoomAttenuation[i];
606 /* Distance-based air absorption */
607 if(AirAbsorptionFactor > 0.0f && ClampedDist > MinDist)
609 ALfloat meters = maxf(ClampedDist-MinDist, 0.0f) * MetersPerUnit;
610 DryGainHF *= powf(AIRABSORBGAINHF, AirAbsorptionFactor*meters);
611 for(i = 0;i < NumSends;i++)
612 WetGainHF[i] *= powf(RoomAirAbsorption[i], AirAbsorptionFactor*meters);
615 if(WetGainAuto)
617 ALfloat ApparentDist = 1.0f/maxf(Attenuation, 0.00001f) - 1.0f;
619 /* Apply a decay-time transformation to the wet path, based on the
620 * attenuation of the dry path.
622 * Using the apparent distance, based on the distance attenuation, the
623 * initial decay of the reverb effect is calculated and applied to the
624 * wet path.
626 for(i = 0;i < NumSends;i++)
628 if(DecayDistance[i] > 0.0f)
629 WetGain[i] *= powf(0.001f/*-60dB*/, ApparentDist/DecayDistance[i]);
633 /* Calculate directional soundcones */
634 Angle = acosf(aluDotproduct(Direction,SourceToListener)) * ConeScale * (360.0f/F_PI);
635 if(Angle > InnerAngle && Angle <= OuterAngle)
637 ALfloat scale = (Angle-InnerAngle) / (OuterAngle-InnerAngle);
638 ConeVolume = lerp(1.0f, ALSource->OuterGain, scale);
639 ConeHF = lerp(1.0f, ALSource->OuterGainHF, scale);
641 else if(Angle > OuterAngle)
643 ConeVolume = ALSource->OuterGain;
644 ConeHF = ALSource->OuterGainHF;
646 else
648 ConeVolume = 1.0f;
649 ConeHF = 1.0f;
652 DryGain *= ConeVolume;
653 if(WetGainAuto)
655 for(i = 0;i < NumSends;i++)
656 WetGain[i] *= ConeVolume;
658 if(DryGainHFAuto)
659 DryGainHF *= ConeHF;
660 if(WetGainHFAuto)
662 for(i = 0;i < NumSends;i++)
663 WetGainHF[i] *= ConeHF;
666 /* Clamp to Min/Max Gain */
667 DryGain = clampf(DryGain, MinVolume, MaxVolume);
668 for(i = 0;i < NumSends;i++)
669 WetGain[i] = clampf(WetGain[i], MinVolume, MaxVolume);
671 /* Apply gain and frequency filters */
672 DryGain *= ALSource->DirectGain * ListenerGain;
673 DryGainHF *= ALSource->DirectGainHF;
674 for(i = 0;i < NumSends;i++)
676 WetGain[i] *= ALSource->Send[i].Gain * ListenerGain;
677 WetGainHF[i] *= ALSource->Send[i].GainHF;
680 /* Calculate velocity-based doppler effect */
681 if(DopplerFactor > 0.0f)
683 ALfloat VSS, VLS;
685 if(SpeedOfSound < 1.0f)
687 DopplerFactor *= 1.0f/SpeedOfSound;
688 SpeedOfSound = 1.0f;
691 VSS = aluDotproduct(Velocity, SourceToListener) * DopplerFactor;
692 VLS = aluDotproduct(ListenerVel, SourceToListener) * DopplerFactor;
694 Pitch *= clampf(SpeedOfSound-VLS, 1.0f, SpeedOfSound*2.0f - 1.0f) /
695 clampf(SpeedOfSound-VSS, 1.0f, SpeedOfSound*2.0f - 1.0f);
698 BufferListItem = ALSource->queue;
699 while(BufferListItem != NULL)
701 ALbuffer *ALBuffer;
702 if((ALBuffer=BufferListItem->buffer) != NULL)
704 /* Calculate fixed-point stepping value, based on the pitch, buffer
705 * frequency, and output frequency. */
706 ALsizei maxstep = BUFFERSIZE / ALSource->NumChannels;
707 maxstep -= ResamplerPadding[Resampler] +
708 ResamplerPrePadding[Resampler] + 1;
709 maxstep = mini(maxstep, INT_MAX>>FRACTIONBITS);
711 Pitch = Pitch * ALBuffer->Frequency / Frequency;
712 if(Pitch > (ALfloat)maxstep)
713 ALSource->Params.Step = maxstep<<FRACTIONBITS;
714 else
716 ALSource->Params.Step = fastf2i(Pitch*FRACTIONONE);
717 if(ALSource->Params.Step == 0)
718 ALSource->Params.Step = 1;
720 ALSource->Params.Resample = SelectResampler(Resampler, ALSource->Params.Step);
722 break;
724 BufferListItem = BufferListItem->next;
726 if(Device->Hrtf)
727 ALSource->Params.DryMix = SelectHrtfMixer();
728 else
729 ALSource->Params.DryMix = SelectDirectMixer();
730 ALSource->Params.WetMix = SelectSendMixer();
732 if(Device->Hrtf)
734 /* Use a binaural HRTF algorithm for stereo headphone playback */
735 ALfloat delta, ev = 0.0f, az = 0.0f;
737 if(Distance > 0.0f)
739 ALfloat invlen = 1.0f/Distance;
740 Position[0] *= invlen;
741 Position[1] *= invlen;
742 Position[2] *= invlen;
744 /* Calculate elevation and azimuth only when the source is not at
745 * the listener. This prevents +0 and -0 Z from producing
746 * inconsistent panning. Also, clamp Y in case FP precision errors
747 * cause it to land outside of -1..+1. */
748 ev = asinf(clampf(Position[1], -1.0f, 1.0f));
749 az = atan2f(Position[0], -Position[2]*ZScale);
752 /* Check to see if the HRIR is already moving. */
753 if(ALSource->Hrtf.Moving)
755 /* Calculate the normalized HRTF transition factor (delta). */
756 delta = CalcHrtfDelta(ALSource->Params.Direct.Hrtf.Gain, DryGain,
757 ALSource->Params.Direct.Hrtf.Dir, Position);
758 /* If the delta is large enough, get the moving HRIR target
759 * coefficients, target delays, steppping values, and counter. */
760 if(delta > 0.001f)
762 ALSource->Hrtf.Counter = GetMovingHrtfCoeffs(Device->Hrtf,
763 ev, az, DryGain, delta,
764 ALSource->Hrtf.Counter,
765 ALSource->Params.Direct.Hrtf.Coeffs[0],
766 ALSource->Params.Direct.Hrtf.Delay[0],
767 ALSource->Params.Direct.Hrtf.CoeffStep,
768 ALSource->Params.Direct.Hrtf.DelayStep);
769 ALSource->Params.Direct.Hrtf.Gain = DryGain;
770 ALSource->Params.Direct.Hrtf.Dir[0] = Position[0];
771 ALSource->Params.Direct.Hrtf.Dir[1] = Position[1];
772 ALSource->Params.Direct.Hrtf.Dir[2] = Position[2];
775 else
777 /* Get the initial (static) HRIR coefficients and delays. */
778 GetLerpedHrtfCoeffs(Device->Hrtf, ev, az, DryGain,
779 ALSource->Params.Direct.Hrtf.Coeffs[0],
780 ALSource->Params.Direct.Hrtf.Delay[0]);
781 ALSource->Hrtf.Counter = 0;
782 ALSource->Params.Direct.Hrtf.Gain = DryGain;
783 ALSource->Params.Direct.Hrtf.Dir[0] = Position[0];
784 ALSource->Params.Direct.Hrtf.Dir[1] = Position[1];
785 ALSource->Params.Direct.Hrtf.Dir[2] = Position[2];
788 else
790 ALfloat (*Matrix)[MaxChannels] = ALSource->Params.Direct.Gains;
791 ALfloat DirGain = 0.0f;
792 ALfloat AmbientGain;
794 for(i = 0;i < MaxChannels;i++)
796 for(j = 0;j < MaxChannels;j++)
797 Matrix[i][j] = 0.0f;
800 /* Normalize the length, and compute panned gains. */
801 if(Distance > 0.0f)
803 ALfloat invlen = 1.0f/Distance;
804 Position[0] *= invlen;
805 Position[1] *= invlen;
806 Position[2] *= invlen;
808 DirGain = sqrtf(Position[0]*Position[0] + Position[2]*Position[2]);
809 ComputeAngleGains(Device, atan2f(Position[0], -Position[2]*ZScale), 0.0f,
810 DryGain*DirGain, Matrix[0]);
813 /* Adjustment for vertical offsets. Not the greatest, but simple
814 * enough. */
815 AmbientGain = DryGain * sqrtf(1.0f/Device->NumChan) * (1.0f-DirGain);
816 for(i = 0;i < (ALint)Device->NumChan;i++)
818 enum Channel chan = Device->Speaker2Chan[i];
819 Matrix[0][chan] = maxf(Matrix[0][chan], AmbientGain);
822 for(i = 0;i < NumSends;i++)
823 ALSource->Params.Send[i].Gain = WetGain[i];
825 /* Update filter coefficients. */
826 cw = cosf(F_PI*2.0f * LOWPASSFREQREF / Frequency);
828 ALSource->Params.Direct.iirFilter.coeff = lpCoeffCalc(DryGainHF, cw);
829 for(i = 0;i < NumSends;i++)
831 ALfloat a = lpCoeffCalc(WetGainHF[i], cw);
832 ALSource->Params.Send[i].iirFilter.coeff = a;
837 static __inline ALfloat aluF2F(ALfloat val)
838 { return val; }
839 static __inline ALint aluF2I(ALfloat val)
841 if(val > 1.0f) return 2147483647;
842 if(val < -1.0f) return -2147483647-1;
843 return fastf2i((ALfloat)(val*2147483647.0));
845 static __inline ALuint aluF2UI(ALfloat val)
846 { return aluF2I(val)+2147483648u; }
847 static __inline ALshort aluF2S(ALfloat val)
848 { return aluF2I(val)>>16; }
849 static __inline ALushort aluF2US(ALfloat val)
850 { return aluF2S(val)+32768; }
851 static __inline ALbyte aluF2B(ALfloat val)
852 { return aluF2I(val)>>24; }
853 static __inline ALubyte aluF2UB(ALfloat val)
854 { return aluF2B(val)+128; }
856 #define DECL_TEMPLATE(T, func) \
857 static void Write_##T(ALCdevice *device, T *RESTRICT buffer, \
858 ALuint SamplesToDo) \
860 ALfloat (*RESTRICT DryBuffer)[BUFFERSIZE] = device->DryBuffer; \
861 ALuint numchans = ChannelsFromDevFmt(device->FmtChans); \
862 const enum Channel *ChanMap = device->DevChannels; \
863 ALuint i, j; \
865 for(j = 0;j < numchans;j++) \
867 T *RESTRICT out = buffer + j; \
868 enum Channel chan = ChanMap[j]; \
870 for(i = 0;i < SamplesToDo;i++) \
871 out[i*numchans] = func(DryBuffer[chan][i]); \
875 DECL_TEMPLATE(ALfloat, aluF2F)
876 DECL_TEMPLATE(ALuint, aluF2UI)
877 DECL_TEMPLATE(ALint, aluF2I)
878 DECL_TEMPLATE(ALushort, aluF2US)
879 DECL_TEMPLATE(ALshort, aluF2S)
880 DECL_TEMPLATE(ALubyte, aluF2UB)
881 DECL_TEMPLATE(ALbyte, aluF2B)
883 #undef DECL_TEMPLATE
886 ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
888 ALuint SamplesToDo;
889 ALeffectslot **slot, **slot_end;
890 ALsource **src, **src_end;
891 ALCcontext *ctx;
892 FPUCtl oldMode;
893 ALuint i, c;
895 SetMixerFPUMode(&oldMode);
897 while(size > 0)
899 SamplesToDo = minu(size, BUFFERSIZE);
900 for(c = 0;c < MaxChannels;c++)
901 memset(device->DryBuffer[c], 0, SamplesToDo*sizeof(ALfloat));
903 ALCdevice_Lock(device);
904 ctx = device->ContextList;
905 while(ctx)
907 ALenum DeferUpdates = ctx->DeferUpdates;
908 ALenum UpdateSources = AL_FALSE;
910 if(!DeferUpdates)
911 UpdateSources = ExchangeInt(&ctx->UpdateSources, AL_FALSE);
913 /* source processing */
914 src = ctx->ActiveSources;
915 src_end = src + ctx->ActiveSourceCount;
916 while(src != src_end)
918 if((*src)->state != AL_PLAYING)
920 --(ctx->ActiveSourceCount);
921 *src = *(--src_end);
922 continue;
925 if(!DeferUpdates && (ExchangeInt(&(*src)->NeedsUpdate, AL_FALSE) ||
926 UpdateSources))
927 ALsource_Update(*src, ctx);
929 MixSource(*src, device, SamplesToDo);
930 src++;
933 /* effect slot processing */
934 slot = ctx->ActiveEffectSlots;
935 slot_end = slot + ctx->ActiveEffectSlotCount;
936 while(slot != slot_end)
938 ALfloat offset = (*slot)->ClickRemoval[0];
939 if(offset < (1.0f/32768.0f))
940 offset = 0.0f;
941 else for(i = 0;i < SamplesToDo;i++)
943 (*slot)->WetBuffer[0][i] += offset;
944 offset -= offset * (1.0f/256.0f);
946 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
947 (*slot)->PendingClicks[0] = 0.0f;
949 if(!DeferUpdates && ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
950 ALeffectState_Update((*slot)->EffectState, device, *slot);
952 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
953 (*slot)->WetBuffer[0], device->DryBuffer);
955 for(i = 0;i < SamplesToDo;i++)
956 (*slot)->WetBuffer[0][i] = 0.0f;
958 slot++;
961 ctx = ctx->next;
964 slot = &device->DefaultSlot;
965 if(*slot != NULL)
967 ALfloat offset = (*slot)->ClickRemoval[0];
968 if(offset < (1.0f/32768.0f))
969 offset = 0.0f;
970 else for(i = 0;i < SamplesToDo;i++)
972 (*slot)->WetBuffer[0][i] += offset;
973 offset -= offset * (1.0f/256.0f);
975 (*slot)->ClickRemoval[0] = offset + (*slot)->PendingClicks[0];
976 (*slot)->PendingClicks[0] = 0.0f;
978 if(ExchangeInt(&(*slot)->NeedsUpdate, AL_FALSE))
979 ALeffectState_Update((*slot)->EffectState, device, *slot);
981 ALeffectState_Process((*slot)->EffectState, SamplesToDo,
982 (*slot)->WetBuffer[0], device->DryBuffer);
984 for(i = 0;i < SamplesToDo;i++)
985 (*slot)->WetBuffer[0][i] = 0.0f;
987 ALCdevice_Unlock(device);
989 /* Click-removal. Could do better; this only really handles immediate
990 * changes between updates where a predictive sample could be
991 * generated. Delays caused by effects and HRTF aren't caught. */
992 if(device->FmtChans == DevFmtMono)
994 ALfloat offset = device->ClickRemoval[FrontCenter];
995 if(offset < (1.0f/32768.0f))
996 offset = 0.0f;
997 else for(i = 0;i < SamplesToDo;i++)
999 device->DryBuffer[FrontCenter][i] += offset;
1000 offset -= offset * (1.0f/256.0f);
1002 device->ClickRemoval[FrontCenter] = offset + device->PendingClicks[FrontCenter];
1003 device->PendingClicks[FrontCenter] = 0.0f;
1005 else if(device->FmtChans == DevFmtStereo)
1007 /* Assumes the first two channels are FrontLeft and FrontRight */
1008 for(c = 0;c < 2;c++)
1010 ALfloat offset = device->ClickRemoval[c];
1011 if(offset < (1.0f/32768.0f))
1012 offset = 0.0f;
1013 else 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;
1021 if(device->Bs2b)
1023 float samples[2];
1024 for(i = 0;i < SamplesToDo;i++)
1026 samples[0] = device->DryBuffer[FrontLeft][i];
1027 samples[1] = device->DryBuffer[FrontRight][i];
1028 bs2b_cross_feed(device->Bs2b, samples);
1029 device->DryBuffer[FrontLeft][i] = samples[0];
1030 device->DryBuffer[FrontRight][i] = samples[1];
1034 else
1036 for(c = 0;c < MaxChannels;c++)
1038 ALfloat offset = device->ClickRemoval[c];
1039 if(offset < (1.0f/32768.0f))
1040 offset = 0.0f;
1041 else for(i = 0;i < SamplesToDo;i++)
1043 device->DryBuffer[c][i] += offset;
1044 offset -= offset * (1.0f/256.0f);
1046 device->ClickRemoval[c] = offset + device->PendingClicks[c];
1047 device->PendingClicks[c] = 0.0f;
1051 if(buffer)
1053 switch(device->FmtType)
1055 case DevFmtByte:
1056 Write_ALbyte(device, buffer, SamplesToDo);
1057 break;
1058 case DevFmtUByte:
1059 Write_ALubyte(device, buffer, SamplesToDo);
1060 break;
1061 case DevFmtShort:
1062 Write_ALshort(device, buffer, SamplesToDo);
1063 break;
1064 case DevFmtUShort:
1065 Write_ALushort(device, buffer, SamplesToDo);
1066 break;
1067 case DevFmtInt:
1068 Write_ALint(device, buffer, SamplesToDo);
1069 break;
1070 case DevFmtUInt:
1071 Write_ALuint(device, buffer, SamplesToDo);
1072 break;
1073 case DevFmtFloat:
1074 Write_ALfloat(device, buffer, SamplesToDo);
1075 break;
1079 size -= SamplesToDo;
1082 RestoreFPUMode(&oldMode);
1086 ALvoid aluHandleDisconnect(ALCdevice *device)
1088 ALCcontext *Context;
1090 ALCdevice_Lock(device);
1091 device->Connected = ALC_FALSE;
1093 Context = device->ContextList;
1094 while(Context)
1096 ALsource **src, **src_end;
1098 src = Context->ActiveSources;
1099 src_end = src + Context->ActiveSourceCount;
1100 while(src != src_end)
1102 if((*src)->state == AL_PLAYING)
1104 (*src)->state = AL_STOPPED;
1105 (*src)->BuffersPlayed = (*src)->BuffersInQueue;
1106 (*src)->position = 0;
1107 (*src)->position_fraction = 0;
1109 src++;
1111 Context->ActiveSourceCount = 0;
1113 Context = Context->next;
1115 ALCdevice_Unlock(device);